[new feature] Toast: support multiple instance (#586)

This commit is contained in:
neverland 2018-01-29 17:19:01 +08:00 committed by GitHub
parent 7f055a4d2d
commit 1f19852118
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 115 additions and 56 deletions

View File

@ -62,6 +62,19 @@ export default {
} }
``` ```
#### Singleton
Toast use singleton mode by default, if you need to pop multiple Toast at the same time, you can refer to the following example
```js
Toast.allowMultiple();
const toast1 = Toast('First Toast');
const toast2 = Toast.success('Second Toast');
toast1.clear();
toast2.clear();
```
### Methods ### Methods
| Methods | Attribute | Return value | Description | | Methods | Attribute | Return value | Description |
@ -70,9 +83,10 @@ export default {
| Toast.loading | `options | message` | toast instance | Show loading toast | | Toast.loading | `options | message` | toast instance | Show loading toast |
| Toast.success | `options | message` | toast instance | Show success toast | | Toast.success | `options | message` | toast instance | Show success toast |
| Toast.fail | `options | message` | toast instance | Show fail toast | | Toast.fail | `options | message` | toast instance | Show fail toast |
| Toast.clear | `clearAll` | `void` | Close |
| Toast.allowMultiple | - | `void` | Allow multlple toast at the same time |
| Toast.setDefaultOptions | `options` | `void` | Set default options of all toasts | | Toast.setDefaultOptions | `options` | `void` | Set default options of all toasts |
| Toast.resetDefaultOptions | - | `void` | Reset default options of all toasts | | Toast.resetDefaultOptions | - | `void` | Reset default options of all toasts |
| Toast.clear | - | `void` | Close |
### Options ### Options

View File

@ -62,6 +62,18 @@ export default {
} }
``` ```
#### 单例模式
Toast 默认采用单例模式,即同一时间只会存在一个 Toast如果需要在同一时间弹出多个 Toast可以参考下面的示例
```js
Toast.allowMultiple();
const toast1 = Toast('第一个 Toast');
const toast2 = Toast.success('第二个 Toast');
toast1.clear();
toast2.clear();
```
### 方法 ### 方法
@ -72,9 +84,10 @@ export default {
| Toast.loading | `options | message` | toast 实例 | 展示加载提示 | | Toast.loading | `options | message` | toast 实例 | 展示加载提示 |
| Toast.success | `options | message` | toast 实例 | 展示成功提示 | | Toast.success | `options | message` | toast 实例 | 展示成功提示 |
| Toast.fail | `options | message` | toast 实例 | 展示失败提示 | | Toast.fail | `options | message` | toast 实例 | 展示失败提示 |
| Toast.clear | `clearAll` | `void` | 关闭提示 |
| Toast.allowMultiple | - | `void` | 允许同时存在多个 Toast |
| Toast.setDefaultOptions | `options` | `void` | 修改默认配置,对所有 Toast 生效 | | Toast.setDefaultOptions | `options` | `void` | 修改默认配置,对所有 Toast 生效 |
| Toast.resetDefaultOptions | - | `void` | 重置默认配置,对所有 Toast 生效 | | Toast.resetDefaultOptions | - | `void` | 重置默认配置,对所有 Toast 生效 |
| Toast.clear | - | `void` | 关闭提示 |
### Options ### Options

View File

@ -1,77 +1,88 @@
import Vue from 'vue'; import Vue from 'vue';
import VueToast from './toast'; import VueToast from './toast';
let instance;
const defaultOptions = { const defaultOptions = {
type: 'text', type: 'text',
mask: false, mask: false,
message: '',
visible: true, visible: true,
duration: 3000, duration: 3000,
position: 'middle', position: 'middle',
forbidClick: false, forbidClick: false
clear: () => {
instance.visible = false;
}
}; };
const parseOptions = message => typeof message === 'object' ? message : { message };
let currentDefaultOptions = { let queue = [];
...defaultOptions let singleton = true;
}; let currentOptions = { ...defaultOptions };
const createInstance = () => { function createInstance() {
if (!instance) { if (!queue.length || !singleton) {
const ToastConstructor = Vue.extend(VueToast); const toast = new (Vue.extend(VueToast))({
instance = new ToastConstructor({
el: document.createElement('div') el: document.createElement('div')
}); });
document.body.appendChild(instance.$el); document.body.appendChild(toast.$el);
queue.push(toast);
}
return queue[queue.length - 1];
};
function Toast(options = {}) {
const toast = createInstance();
options = {
...currentOptions,
...parseOptions(options),
clear() {
toast.visible = false;
} }
}; };
const Toast = (options = {}) => { Object.assign(toast, options);
createInstance(); clearTimeout(toast.timer);
options = typeof options === 'object' ? options : { message: options }; if (options.duration > 0) {
options = { ...currentDefaultOptions, ...options }; toast.timer = setTimeout(() => {
Object.assign(instance, options); toast.clear();
clearTimeout(instance.timer);
if (options.duration !== 0) {
instance.timer = setTimeout(() => {
instance.clear();
}, options.duration); }, options.duration);
} }
return instance; return toast;
}; };
const createMethod = type => (options = {}) => Toast({ const createMethod = type => options => Toast({
type, type, ...parseOptions(options)
message: typeof options === 'object' ? options.message : options,
...options
}); });
Toast.loading = createMethod('loading'); ['loading', 'success', 'fail'].forEach(method => {
Toast.success = createMethod('success'); Toast[method] = createMethod(method);
Toast.fail = createMethod('fail'); });
Toast.clear = () => { Toast.clear = all => {
instance && instance.clear(); if (queue.length) {
if (all) {
queue.forEach(toast => {
toast.clear();
});
queue = [];
} else if (singleton) {
queue[0].clear();
} else {
queue.shift().clear();
}
}
}; };
Toast.setDefaultOptions = (options = {}) => { Toast.setDefaultOptions = options => {
currentDefaultOptions = { Object.assign(currentOptions, options);
...currentDefaultOptions,
...options
};
}; };
Toast.resetDefaultOptions = () => { Toast.resetDefaultOptions = () => {
currentDefaultOptions = { currentOptions = { ...defaultOptions };
...defaultOptions
}; };
Toast.allowMultiple = (allow = true) => {
singleton = !allow;
}; };
Vue.prototype.$toast = Toast; Vue.prototype.$toast = Toast;

View File

@ -21,7 +21,7 @@
<script> <script>
import { create } from '../utils'; import { create } from '../utils';
const DEFAULT_STYLE_LIST = ['success', 'fail', 'loading']; const STYLE_LIST = ['success', 'fail', 'loading'];
export default create({ export default create({
name: 'van-toast', name: 'van-toast',
@ -48,7 +48,7 @@ export default create({
computed: { computed: {
displayStyle() { displayStyle() {
return DEFAULT_STYLE_LIST.indexOf(this.type) !== -1 ? 'default' : this.type; return STYLE_LIST.indexOf(this.type) !== -1 ? 'default' : this.type;
} }
} }
}); });

View File

@ -2,7 +2,7 @@ import Toast from 'packages/toast';
describe('Toast', () => { describe('Toast', () => {
afterEach(() => { afterEach(() => {
Toast.clear(); Toast.clear(true);
}); });
it('create a empty toast', () => { it('create a empty toast', () => {
@ -87,28 +87,49 @@ describe('Toast', () => {
}); });
it('toast disappeared after duration', (done) => { it('toast disappeared after duration', (done) => {
Toast({ const toast = Toast({
message: 'toast', message: 'toast',
duration: 10 duration: 10
}); });
expect(document.querySelector('.van-toast-wrapper').style.display === 'none').to.be.false;
setTimeout(() => { setTimeout(() => {
expect(document.querySelector('.van-toast-wrapper').style.display === 'none').to.be.true; expect(toast.$el.style.display === 'none').to.be.true;
Toast.clear();
done(); done();
}, 500); }, 500);
}); });
it('toast duration 0', (done) => { it('toast duration 0', () => {
Toast({ Toast.allowMultiple();
const toast = Toast({
message: 'toast', message: 'toast',
duration: 0 duration: 0
}); });
expect(toast.timer).to.equal(undefined);
Toast.allowMultiple(false);
});
setTimeout(() => { it('multiple toast', () => {
expect(document.querySelector('.van-toast-wrapper').style.display === 'none').to.be.false; Toast.allowMultiple();
done(); Toast.clear(true);
}, 500); const toast1 = Toast.success('1');
const toast2 = Toast.success('2');
Toast.clear();
expect(toast1.visible).to.be.false;
expect(toast2.visible).to.be.true;
Toast.clear();
Toast.clear();
expect(toast2.visible).to.be.false;
Toast.allowMultiple(false);
});
it('set default options', () => {
Toast.setDefaultOptions({ duration: 1000 });
const toast1 = Toast(1);
expect(toast1.duration).to.equal(1000);
Toast.resetDefaultOptions();
const toast2 = Toast(1);
expect(toast2.duration).to.equal(3000);
}); });
}); });