From 18268799dfa8d9901c96aa652e0b440c9dd851f0 Mon Sep 17 00:00:00 2001 From: maiguangyang Date: Mon, 27 Mar 2017 14:40:56 +0800 Subject: [PATCH] =?UTF-8?q?Toast=E7=BB=84=E4=BB=B6=E8=87=AA=E5=8A=A8?= =?UTF-8?q?=E5=8C=96=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/toast/component.js | 13 ++- src/toast/index.jade | 6 +- src/toast/index.js | 14 ++-- src/toast/index.spec.js | 174 ++++++++++++++++++++++++++++++++++++++++ src/toast/service.js | 8 +- 5 files changed, 201 insertions(+), 14 deletions(-) create mode 100644 src/toast/index.spec.js diff --git a/src/toast/component.js b/src/toast/component.js index 96a2a4e..97c42c4 100644 --- a/src/toast/component.js +++ b/src/toast/component.js @@ -15,7 +15,10 @@ export default function ($timeout) { options : '=?toastOptions', }, link ($scope, $element) { - let defaults = _.defaults(Config, $scope.options); + let defaults = _.defaultsDeep($scope.options, Config); + + $scope.isOpen = false; + $scope.type = defaults.type || ''; /** * 显示 @@ -30,6 +33,7 @@ export default function ($timeout) { $timeout(() => { $element.addClass(options.enterClass); $timeout(callback.bind(null), options.during); + $scope.isOpen = true; }); }; @@ -43,8 +47,9 @@ export default function ($timeout) { options = _.defaults(defaults, options); - $element.addClass(options.leaveClass); + $element.removeClass(options.enterClass).addClass(options.leaveClass); $timeout(callback.bind(null), options.during); + $scope.isOpen = false; }; /** @@ -63,10 +68,12 @@ export default function ($timeout) { $scope.show(function () { setTimeout(function () { - $scope.hide(); + $scope.dismiss(); }, defaults.delay || 1500); }); + + $scope.$digest(); } }; } \ No newline at end of file diff --git a/src/toast/index.jade b/src/toast/index.jade index 1f945ff..62449db 100644 --- a/src/toast/index.jade +++ b/src/toast/index.jade @@ -1 +1,5 @@ -.toast(ng-transclude) +.toast(ng-class='{\ + correct : "correct" === type,\ + error : "error" === type,\ + info : "info" === type,\ +}', ng-transclude) diff --git a/src/toast/index.js b/src/toast/index.js index f36f506..8bf1ec1 100644 --- a/src/toast/index.js +++ b/src/toast/index.js @@ -1,9 +1,9 @@ -if (window.angular && window.angular.env && window.angular.env.QT_UI_LOG) { - window.console.log('qt-angular-ui/src/toast load'); -} - import './index.scss'; +import angular from 'angular'; +import Component from './component'; +import Service from './service'; -import component from './_index'; - -export default component; \ No newline at end of file +export default angular.module('qtAngularUi.toast', []) +.directive('toast', Component) +.provider('$toast', Service) +.name; diff --git a/src/toast/index.spec.js b/src/toast/index.spec.js new file mode 100644 index 0000000..a37f7cb --- /dev/null +++ b/src/toast/index.spec.js @@ -0,0 +1,174 @@ +/* eslint max-nested-callbacks: off */ +/* eslint-env mocha */ +/* global expect */ + +import _ from 'lodash'; +import angular from 'angular'; +import 'angular-mocks'; + +import sinon from 'sinon'; +import $ from 'jquery'; +import Toast from './index'; +import Config from './config'; + +describe('Toast 组件', function () { + const NEST_CONTENT = 'Message'; + const { module, inject } = angular.mock; + + beforeEach(function () { + // 设置延迟消失时间为 0 + Config.during = 10; + Config.delay = 10; + + // 初始化 Toast 组件 + module(Toast); + + // 清场 + document.body.innerHTML = ''; + }); + + + describe('结构规范', function () { + it('会返回组件名称', function () { + expect('Toast').to.be.a('string'); + }); + + it('能进行初始化, 并且能自定义信息', function () { + inject(function ($rootScope, $compile) { + let $scope = $rootScope.$new(); + let $toast = $compile(`${NEST_CONTENT}`)($scope); + + expect($toast.text()).to.equal(NEST_CONTENT); + }); + }); + + it('拥有自己的作用域', function () { + inject(function ($rootScope, $compile) { + let $scope = $rootScope.$new(); + let $element = $compile(`${NEST_CONTENT}`)($scope); + let $nestScope = angular.element($element[0].childNodes[0]).scope(); + + expect($scope.$id).to.not.equal($nestScope.$id); + }); + }); + + it('应该拥有额定的结构', function () { + inject(function ($rootScope, $compile) { + let $element = $compile(`${NEST_CONTENT}`)($rootScope.$new()); + let $scope = angular.element($element[0].childNodes[0]).scope(); + + expect($scope.show).to.be.a('function'); + expect($scope.hide).to.be.a('function'); + expect($scope.dismiss).to.be.a('function'); + expect($scope.isOpen).to.be.a('boolean'); + }); + }); + + }); + + describe('触发流程', function () { + it('能够自动完成淡入淡出', function (done) { + this.timeout(1000); + + inject(function ($rootScope, $compile, $timeout) { + let $element = $compile(`${NEST_CONTENT}`)($rootScope.$new()); + let $scope = angular.element($element[0].childNodes[0]).scope(); + + angular.element(document.body).append($element); + expect($scope.isOpen).to.be.false; + expect(document.getElementsByClassName('toast').length).to.equal(1); + + let hideCompleted = function () { + expect($scope.isOpen).to.be.false; + expect(document.getElementsByClassName('toast').length).to.equal(0); + done(); + }; + + let delayCompleted = function () { + expect($scope.dismiss.calledOnce).to.be.true; + expect($scope.hide.called).to.be.true; + expect($scope.isOpen).to.be.false; + + $timeout.flush(); + setTimeout(hideCompleted, Config.during); + }; + + let showCompleted = function () { + expect($scope.isOpen).to.be.true; + + $timeout.flush(); + setTimeout(delayCompleted, Config.delay); + }; + + // 监听 hide 事件 + sinon.spy($scope, 'dismiss'); + sinon.spy($scope, 'hide'); + + // 开始淡入窗口 + $timeout.flush(); + setTimeout(showCompleted, Config.during); + + }); + }); + }); + + describe('服务', function () { + + it('能淡入到 body 中', function (done) { + this.timeout(1000); + + inject(function ($toast, $timeout) { + $toast.create(NEST_CONTENT, Config); + + let $jqToast = $('.toast'); + let $scope = angular.element($jqToast[0].childNodes[0]).scope(); + + // 检查 DOM 节点 + expect($jqToast.length).to.equal(1); + expect($jqToast.text()).to.equal(NEST_CONTENT); + + + // 检查属性 + expect($scope.isOpen).to.be.false; + + // FadeIn + $timeout.flush(); + setTimeout(function () { + expect($scope.isOpen).to.be.true; + + // FadeOut + $timeout.flush(); + setTimeout(function () { + expect($scope.isOpen).to.be.false; + + done(); + }, Config.during + Config.delay + 10); + }, 1); + }); + }); + + it('能更改类型', function () { + inject(function ($toast) { + _.forEach(['correct', 'error', 'info'], function (type) { + $toast.create(NEST_CONTENT, _.assign(Config, { type })); + + let $jqToast = $(`.toast.${type}`); + + let scope = angular.element($jqToast[0].childNodes[0]).scope(); + expect(scope.type).to.equal(type); + expect($(`.toast.${type}`).length).to.equal(1); + }); + }); + }); + + it('能同时触发', function () { + inject(function ($toast) { + $toast.create(NEST_CONTENT); + $toast.create(NEST_CONTENT); + + expect(document.getElementsByClassName('toast').length).to.equal(2); + }); + }); + + }); +}); diff --git a/src/toast/service.js b/src/toast/service.js index ace5542..362ec5b 100644 --- a/src/toast/service.js +++ b/src/toast/service.js @@ -16,6 +16,10 @@ export default class toastService { return { create (message, options = defaults) { + if (_.isString(options)) { + return this.create(message, { type: options }); + } + let $toast = angular.element(`${message}`); let $scope = $rootScope.$new(); @@ -24,9 +28,7 @@ export default class toastService { } let $element = $compile($toast)($scope); - angular.element(document).ready(function () { - angular.element(document.body).append($element); - }); + angular.element(document.body).append($element); openScopes.push($scope); },