diff --git a/docs/examples-docs/toast.md b/docs/examples-docs/toast.md
index e889f580f..b1ee11ee2 100644
--- a/docs/examples-docs/toast.md
+++ b/docs/examples-docs/toast.md
@@ -1,7 +1,7 @@
@@ -11,7 +11,7 @@ import { Toast } from 'packages';
export default {
methods: {
- showSimpleToast() {
+ showToast() {
Toast('我是提示文案,建议不超过十五字~');
},
showLoadingToast() {
@@ -23,39 +23,23 @@ export default {
showFailToast() {
Toast.fail('失败文案');
},
- showForbidClickToast() {
- Toast({
- message: '背景不能点击',
- forbidClick: true
- })
- },
showCustomizedToast(duration) {
- let leftSec = duration / 1000;
- let toast = Toast({
- duration: duration + 1000,
- type: 'success',
- message: leftSec.toString()
+ const toast = Toast.loading({
+ duration: 0,
+ forbidClick: true,
+ message: '倒计时 3 秒'
});
- const id = window.setInterval(() => {
- if (leftSec <= 1) {
- window.clearInterval(id);
- toast.message = '跳转中...'
- return;
+
+ let second = 3;
+ const timer = setInterval(() => {
+ second--;
+ if (second) {
+ toast.message = `倒计时 ${second} 秒`;
+ } else {
+ clearInterval(timer);
+ Toast.clear();
}
- toast.message = (--leftSec).toString();
}, 1000);
- },
- showToast() {
- this.toast = Toast('我是提示文案,建议不超过十五字~');
- },
- closeToast() {
- this.toast.clear();
- },
- showHtmlToast() {
- Toast({
- type: 'html',
- message: 'HTML'
- })
}
}
};
@@ -65,63 +49,96 @@ export default {
### 使用指南
-`Toast`和其他组件不同,不是通过HTML结构的方式来使用,而是通过函数调用的方式。使用前需要先引入它。
-
-```js
+```javascript
import { Toast } from 'vant';
```
### 代码演示
-#### 基础用法
+#### 文字提示
-:::demo 基础用法
+:::demo 文字提示
```html
-普通文字提示
-加载Toast
-成功
-失败
-背景不能点击
-倒数5秒
+文字提示
```
```javascript
-import { Toast } from 'packages';
-
export default {
methods: {
- showSimpleToast() {
+ showToast() {
Toast('我是提示文案,建议不超过十五字~');
- },
+ }
+ }
+}
+```
+:::
+
+#### 加载提示
+
+:::demo 加载提示
+```html
+加载提示
+```
+
+```javascript
+export default {
+ methods: {
showLoadingToast() {
Toast.loading();
- },
+ }
+ }
+}
+```
+:::
+
+#### 成功/失败提示
+
+:::demo 成功/失败提示
+```html
+成功提示
+失败提示
+```
+
+```javascript
+export default {
+ methods: {
showSuccessToast() {
Toast.success('成功文案');
},
showFailToast() {
Toast.fail('失败文案');
- },
- showForbidClickToast() {
- Toast({
- message: '背景不能点击',
- forbidClick: true
- })
- },
- showCustomizedToast(duration) {
- let leftSec = duration / 1000;
- let toast = Toast({
- duration: duration + 1000,
- type: 'success',
- message: leftSec.toString()
+ }
+ }
+}
+```
+:::
+
+#### 高级用法
+
+:::demo 高级用法
+```html
+高级用法
+```
+
+```javascript
+export default {
+ methods: {
+ showCustomizedToast() {
+ const toast = Toast.loading({
+ duration: 0, // 持续展示 toast
+ forbidClick: true, // 禁用背景点击
+ message: '倒计时 3 秒'
});
- const id = window.setInterval(() => {
- if (leftSec <= 1) {
- window.clearInterval(id);
- toast.message = '跳转中...'
- return;
+
+ let second = 3;
+ const timer = setInterval(() => {
+ second--;
+ if (second) {
+ toast.message = `倒计时 ${second} 秒`;
+ } else {
+ clearInterval(timer);
+ Toast.clear();
}
- toast.message = (--leftSec).toString();
}, 1000);
}
}
@@ -129,74 +146,21 @@ export default {
```
:::
-#### 手动关闭
+### 方法
-:::demo 手动关闭
-```html
-打开
-关闭
-```
+| 方法名 | 参数 | 返回值 | 介绍 |
+|-----------|-----------|-----------|-------------|
+| Toast | `options | message` | toast 实例 | 展示提示 |
+| Toast.loading | `options | message` | toast 实例 | 展示加载提示 |
+| Toast.success | `options | message` | toast 实例 | 展示成功提示 |
+| Toast.fail | `options | message` | toast 实例 | 展示失败提示 |
+| Toast.clear | - | `void` | 关闭提示 |
-```javascript
-import { Toast } from 'packages';
-
-export default {
- methods: {
- showToast() {
- Toast('我是提示文案,建议不超过十五字~');
- },
- closeToast() {
- Toast.clear();
- }
- }
-};
-```
-:::
-
-### 基础用法
-
-#### Toast(options)
+### Options
| 参数 | 说明 | 类型 | 默认值 | 可选值 |
|-----------|-----------|-----------|-------------|-------------|
-| type | 类型 | String | 'text' | 'text', 'loading', 'success', 'fail', 'html' |
-| message | 内容 | String | '' | - |\| message | 内容 | String | '' | -
-| forbidClick | 不允许背景点击 | Boolean | false | true, false|
-| duration | 时长(ms) | Number | 3000ms | -|
-
-### 快速用法
-
-#### Toast(message) || Toast(message, options)
-
-| 参数 | 说明 | 类型 | 默认值 | 可选值 |
-|-----------|-----------|-----------|-------------|-------------|
-| message | 内容 | String | '' | - |
-| forbidClick | 不允许背景点击 | Boolean | false | true, false|
-| duration | 时长(ms) | Number | 3000ms | -|
-
-#### Toast.loading() || Toast.loading(message, options)
-
-| 参数 | 说明 | 类型 | 默认值 | 可选值 |
-|-----------|-----------|-----------|-------------|-------------|
-| forbidClick | 不允许背景点击 | Boolean | false | true, false|
-| duration | 时长(ms) | Number | 3000ms | -|
-
-#### Toast.success(message) || Toast.success(message, options)
-
-| 参数 | 说明 | 类型 | 默认值 | 可选值 |
-|-----------|-----------|-----------|-------------|-------------|
-| type | 类型 | String | 'text' | 'text', 'loading', 'success', 'failure' |
-| forbidClick | 不允许背景点击 | Boolean | false | true, false|
-| duration | 时长(ms) | Number | 3000ms | -|
-
-#### Toast.fail(message) || Toast.fail(message, options)
-
-| 参数 | 说明 | 类型 | 默认值 | 可选值 |
-|-----------|-----------|-----------|-------------|-------------|
-| type | 类型 | String | 'text' | 'text', 'loading', 'success', 'failure' |
-| forbidClick | 不允许背景点击 | Boolean | false | true, false|
-| duration | 时长(ms) | Number | 3000ms | -|
-
-#### Toast.clear()
-
-关闭toast。
+| type | 提示类型 | `String` | `text` | `loading` `success` `fail` `html` |
+| message | 内容 | `String` | `''` | - |
+| forbidClick | 禁止背景点击 | `Boolean` | `false` | - |
+| duration | 时长(ms) | `Number` | `3000` | 值为 0 时,toast 不会消失 |
diff --git a/packages/toast/index.js b/packages/toast/index.js
index 8113da876..afe934c2c 100644
--- a/packages/toast/index.js
+++ b/packages/toast/index.js
@@ -1,81 +1,57 @@
import Vue from 'vue';
-import ToastComponent from './toast';
+import VueToast from './toast';
-const ToastConstructor = Vue.extend(ToastComponent);
let instance;
-const getInstance = () => {
- if (instance) instance.clear();
-
- instance = new ToastConstructor({
- el: document.createElement('div')
- });
- return instance;
-};
-
-const removeDom = event => {
- /* istanbul ignore else */
- if (event.target.parentNode) {
- event.target.parentNode.removeChild(event.target);
+const defaultOptions = {
+ visible: true,
+ type: 'text',
+ duration: 3000,
+ forbidClick: false,
+ clear: () => {
+ instance.visible = false;
}
};
-var Toast = (options = {}) => {
- const duration = options.duration || 3000;
+const createInstance = () => {
+ if (!instance) {
+ const ToastConstructor = Vue.extend(VueToast);
+ instance = new ToastConstructor({
+ el: document.createElement('div')
+ });
+ document.body.appendChild(instance.$el);
+ }
+};
- const instance = getInstance();
+const Toast = (options = {}) => {
+ createInstance();
+
+ options = typeof options === 'string' ? { message: options } : options;
+ options = { ...defaultOptions, ...options };
+ Object.assign(instance, options);
- instance.closed = false;
clearTimeout(instance.timer);
- instance.type = options.type ? options.type : 'text';
- instance.message = typeof options === 'string' ? options : options.message;
- instance.forbidClick = options.forbidClick ? options.forbidClick : false;
- instance.clear = () => {
- if (instance.closed) return;
- instance.visible = false;
- instance.$el.addEventListener('transitionend', removeDom);
- instance.closed = true;
- };
- document.body.appendChild(instance.$el);
- Vue.nextTick(function() {
- instance.visible = true;
- instance.$el.removeEventListener('transitionend', removeDom);
- instance.timer = setTimeout(function() {
+ if (options.duration !== 0) {
+ instance.timer = setTimeout(() => {
instance.clear();
- }, duration);
- });
+ }, options.duration);
+ }
+
return instance;
};
-Toast.loading = (options) => {
- return new Toast({
- type: 'loading',
- ...options
- });
-};
-
-Toast.success = (options) => {
- const message = typeof options === 'string' ? options : options.message;
- return new Toast({
- type: 'success',
- message: message,
- ...options
- });
-};
-
-Toast.fail = (options) => {
- const message = typeof options === 'string' ? options : options.message;
- return new Toast({
- type: 'fail',
- message: message,
- ...options
- });
-};
+const createMethod = type => (options = {}) => Toast({
+ type,
+ message: typeof options === 'string' ? options : options.message,
+ ...options
+});
+Toast.loading = createMethod('loading');
+Toast.success = createMethod('success');
+Toast.fail = createMethod('fail');
Toast.clear = () => {
- /* istanbul ignore else */
- if (instance) instance.clear();
+ instance && instance.clear();
};
export default Toast;
diff --git a/packages/toast/toast.vue b/packages/toast/toast.vue
index 8bb168e49..71ec40c32 100644
--- a/packages/toast/toast.vue
+++ b/packages/toast/toast.vue
@@ -2,19 +2,18 @@
-
+
{{ message }}
-
-
-
+
+
+
-
- {{ message }}
+
+
+ {{ message }}
-
-
-
+
@@ -24,15 +23,8 @@ import Icon from '../icon';
import Loading from '../loading';
const TOAST_TYPES = ['text', 'html', 'loading', 'success', 'fail'];
-const DEFAULT_STYLE_LIST = ['success', 'fail'];
-/**
- * van-toast
- * @module components/toast
- * @desc toast
- * @param {string} [type=false] - 类型
- * @param {string} [message] - 信息
- *
- */
+const DEFAULT_STYLE_LIST = ['success', 'fail', 'loading'];
+
export default {
name: 'van-toast',
@@ -40,13 +32,12 @@ export default {
[Icon.name]: Icon,
[Loading.name]: Loading
},
+
props: {
type: {
type: String,
default: 'text',
- validator(value) {
- return TOAST_TYPES.indexOf(value) > -1;
- }
+ validator: value => TOAST_TYPES.indexOf(value) > -1
},
message: {
type: String,
@@ -57,14 +48,16 @@ export default {
default: false
}
},
+
data() {
return {
visible: false
};
},
+
computed: {
displayStyle() {
- return DEFAULT_STYLE_LIST.indexOf(this.type) > -1 ? 'default' : this.type;
+ return DEFAULT_STYLE_LIST.indexOf(this.type) !== -1 ? 'default' : this.type;
}
}
};
diff --git a/packages/vant-css/src/toast.css b/packages/vant-css/src/toast.css
index 03349bb48..4695fa79b 100644
--- a/packages/vant-css/src/toast.css
+++ b/packages/vant-css/src/toast.css
@@ -2,16 +2,19 @@
.van-toast {
position: fixed;
- z-index: 3001;
- border-radius: 5px;
- background-color: rgb(39, 39, 39, .7);
top: 50%;
left: 50%;
- transform: translate3d(-50%, -50%, 0);
- font-size: 12px;
+ display: flex;
color: $white;
- text-align: center;
- line-height: 12px;
+ z-index: 3001;
+ font-size: 12px;
+ line-height: 1.2;
+ border-radius: 5px;
+ align-items: center;
+ justify-content: center;
+ flex-direction: column;
+ transform: translate3d(-50%, -50%, 0);
+ background-color: rgb(39, 39, 39, .7);
&-wrapper {
transition: opacity .2s;
@@ -19,16 +22,12 @@
&__overlay {
position: fixed;
- left: 0;
top: 0;
- background: transparent;
- height: 100%;
+ left: 0;
width: 100%;
+ height: 100%;
z-index: 3000;
- }
-
- &--loading {
- padding: 45px;
+ background: transparent;
}
&--text {
@@ -37,18 +36,21 @@
}
&--default {
- width: 120px;
- height: 120px;
+ width: 90px;
+ min-height: 90px;
+ padding: 15px;
.van-toast__icon {
- padding-top: 20px;
font-size: 50px;
}
+ .van-loading {
+ margin: 10px 0 5px;
+ }
+
.van-toast__text {
- padding: 15px 0 20px;
font-size: 14px;
- line-height: 1.2;
+ padding-top: 10px;
}
}
}
diff --git a/test/unit/specs/toast.spec.js b/test/unit/specs/toast.spec.js
index 6078dc5b7..72806c33e 100644
--- a/test/unit/specs/toast.spec.js
+++ b/test/unit/specs/toast.spec.js
@@ -2,30 +2,22 @@ import Toast from 'packages/toast';
describe('Toast', () => {
afterEach(() => {
- const el = document.querySelector('.van-toast-wrapper');
- if (!el) return;
- if (el.parentNode) {
- el.parentNode.removeChild(el);
- }
Toast.clear();
});
it('create a empty toast', () => {
- const toast = Toast();
-
+ Toast();
expect(document.querySelector('.van-toast-wrapper')).to.exist;
});
- it('create a toast', (done) => {
+ it('create a toast', () => {
const toast = Toast('toast');
expect(document.querySelector('.van-toast-wrapper')).to.exist;
expect(toast.message).to.equal('toast');
expect(toast.type).to.equal('text');
- setTimeout(() => {
- expect(typeof toast.timer).to.equal('number');
- done();
- }, 500);
+ expect(toast.displayStyle).to.equal('text');
+ expect(typeof toast.timer).to.equal('number');
});
it('create a loading toast', () => {
@@ -39,7 +31,7 @@ describe('Toast', () => {
const toast = Toast.loading({
message: 'toast'
});
-
+
expect(document.querySelector('.van-toast-wrapper')).to.exist;
expect(toast.message).to.equal('toast');
expect(toast.type).to.equal('loading');
@@ -49,6 +41,7 @@ describe('Toast', () => {
const toast = Toast.success('success');
expect(document.querySelector('.van-toast-wrapper')).to.exist;
+ expect(toast.displayStyle).to.equal('default');
expect(toast.type).to.equal('success');
});
@@ -66,6 +59,7 @@ describe('Toast', () => {
const toast = Toast.fail('fail');
expect(document.querySelector('.van-toast-wrapper')).to.exist;
+ expect(toast.displayStyle).to.equal('default');
expect(toast.type).to.equal('fail');
});
@@ -79,17 +73,42 @@ describe('Toast', () => {
expect(toast.type).to.equal('fail');
});
-
it('create a forbidClick toast', (done) => {
Toast({
message: 'test',
forbidClick: true
});
-
+
expect(document.querySelector('.van-toast-wrapper')).to.exist;
setTimeout(() => {
expect(document.querySelector('.van-toast__overlay')).to.exist;
done();
+ }, 50);
+ });
+
+ it('toast disappeared after duration', (done) => {
+ Toast({
+ message: 'toast',
+ duration: 100
+ });
+
+ expect(document.querySelector('.van-toast-wrapper').style.display === 'none').to.be.false;
+
+ setTimeout(() => {
+ expect(document.querySelector('.van-toast-wrapper').style.display === 'none').to.be.true;
+ done();
+ }, 500);
+ });
+
+ it('toast duration 0', (done) => {
+ Toast({
+ message: 'toast',
+ duration: 0
+ });
+
+ setTimeout(() => {
+ expect(document.querySelector('.van-toast-wrapper').style.display === 'none').to.be.false;
+ done();
}, 500);
});
});