[improvement] rename packages dir to src (#3659)
This commit is contained in:
@@ -0,0 +1,125 @@
|
||||
import { createNamespace, isDef } from '../utils';
|
||||
import { PopupMixin } from '../mixins/popup';
|
||||
import Icon from '../icon';
|
||||
import Loading from '../loading';
|
||||
|
||||
const [createComponent, bem] = createNamespace('toast');
|
||||
|
||||
export default createComponent({
|
||||
mixins: [PopupMixin],
|
||||
|
||||
props: {
|
||||
icon: String,
|
||||
className: null,
|
||||
loadingType: String,
|
||||
forbidClick: Boolean,
|
||||
message: [String, Number],
|
||||
type: {
|
||||
type: String,
|
||||
default: 'text'
|
||||
},
|
||||
position: {
|
||||
type: String,
|
||||
default: 'middle'
|
||||
},
|
||||
lockScroll: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
clickable: false
|
||||
};
|
||||
},
|
||||
|
||||
mounted() {
|
||||
this.toggleClickable();
|
||||
},
|
||||
|
||||
destroyed() {
|
||||
this.toggleClickable();
|
||||
},
|
||||
|
||||
watch: {
|
||||
value() {
|
||||
this.toggleClickable();
|
||||
},
|
||||
|
||||
forbidClick() {
|
||||
this.toggleClickable();
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
toggleClickable() {
|
||||
const clickable = this.value && this.forbidClick;
|
||||
if (this.clickable !== clickable) {
|
||||
this.clickable = clickable;
|
||||
const action = clickable ? 'add' : 'remove';
|
||||
document.body.classList[action]('van-toast--unclickable');
|
||||
}
|
||||
},
|
||||
|
||||
/* istanbul ignore next */
|
||||
onAfterEnter() {
|
||||
this.$emit('opened');
|
||||
|
||||
if (this.onOpened) {
|
||||
this.onOpened();
|
||||
}
|
||||
},
|
||||
|
||||
onAfterLeave() {
|
||||
this.$emit('closed');
|
||||
}
|
||||
},
|
||||
|
||||
render(h) {
|
||||
const { type, icon, message, loadingType } = this;
|
||||
|
||||
const hasIcon = icon || (type === 'success' || type === 'fail');
|
||||
|
||||
function ToastIcon() {
|
||||
if (hasIcon) {
|
||||
return <Icon class={bem('icon')} name={icon || type} />;
|
||||
}
|
||||
|
||||
if (type === 'loading') {
|
||||
return <Loading class={bem('loading')} color="white" type={loadingType} />;
|
||||
}
|
||||
}
|
||||
|
||||
function Message() {
|
||||
if (!isDef(message) || message === '') {
|
||||
return;
|
||||
}
|
||||
|
||||
if (type === 'html') {
|
||||
return <div class={bem('text')} domPropsInnerHTML={message} />;
|
||||
}
|
||||
|
||||
return <div class={bem('text')}>{message}</div>;
|
||||
}
|
||||
|
||||
return (
|
||||
<transition
|
||||
name="van-fade"
|
||||
onAfterEnter={this.onAfterEnter}
|
||||
onAfterLeave={this.onAfterLeave}
|
||||
>
|
||||
<div
|
||||
vShow={this.value}
|
||||
class={[
|
||||
bem([this.position, { text: !hasIcon && type !== 'loading' }]),
|
||||
this.className
|
||||
]}
|
||||
>
|
||||
{ToastIcon()}
|
||||
{Message()}
|
||||
</div>
|
||||
</transition>
|
||||
);
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,167 @@
|
||||
<template>
|
||||
<demo-section>
|
||||
<demo-block :title="$t('title1')">
|
||||
<van-button
|
||||
type="primary"
|
||||
@click="$toast($t('text'))"
|
||||
>
|
||||
{{ $t('title1') }}
|
||||
</van-button>
|
||||
<van-button
|
||||
type="primary"
|
||||
@click="$toast($t('longText'))"
|
||||
>
|
||||
{{ $t('longTextButton') }}
|
||||
</van-button>
|
||||
</demo-block>
|
||||
|
||||
<demo-block :title="$t('title2')">
|
||||
<van-button
|
||||
type="primary"
|
||||
@click="showLoadingToast"
|
||||
>
|
||||
{{ $t('title2') }}
|
||||
</van-button>
|
||||
</demo-block>
|
||||
|
||||
<demo-block :title="$t('title3')">
|
||||
<van-button
|
||||
type="info"
|
||||
@click="showSuccessToast"
|
||||
>
|
||||
{{ $t('success') }}
|
||||
</van-button>
|
||||
<van-button
|
||||
type="danger"
|
||||
@click="showFailToast"
|
||||
>
|
||||
{{ $t('fail') }}
|
||||
</van-button>
|
||||
</demo-block>
|
||||
|
||||
<demo-block
|
||||
v-if="!$attrs.weapp"
|
||||
:title="$t('customIcon')"
|
||||
>
|
||||
<van-button
|
||||
type="primary"
|
||||
@click="showIconToast"
|
||||
>
|
||||
{{ $t('customIcon') }}
|
||||
</van-button>
|
||||
|
||||
<van-button
|
||||
type="primary"
|
||||
@click="showImageToast"
|
||||
>
|
||||
{{ $t('customImage') }}
|
||||
</van-button>
|
||||
</demo-block>
|
||||
|
||||
<demo-block :title="$t('advancedUsage')">
|
||||
<van-button
|
||||
type="primary"
|
||||
@click="showCustomizedToast"
|
||||
>
|
||||
{{ $t('advancedUsage') }}
|
||||
</van-button>
|
||||
</demo-block>
|
||||
</demo-section>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
i18n: {
|
||||
'zh-CN': {
|
||||
title1: '文字提示',
|
||||
title2: '加载提示',
|
||||
title3: '成功/失败提示',
|
||||
success: '成功提示',
|
||||
fail: '失败提示',
|
||||
text: '提示内容',
|
||||
longText: '这是一条长文字提示,超过一定字数就会换行',
|
||||
text2: '成功文案',
|
||||
text3: '失败文案',
|
||||
customIcon: '自定义图标',
|
||||
customImage: '展示图片',
|
||||
text4: second => `倒计时 ${second} 秒`,
|
||||
longTextButton: '长文字提示'
|
||||
},
|
||||
'en-US': {
|
||||
title1: 'Text',
|
||||
title2: 'Loading',
|
||||
title3: 'Success/Fail',
|
||||
success: 'Success',
|
||||
fail: 'Fail',
|
||||
text: 'Some messages',
|
||||
longText: 'This is a long message, text will wrap when over a certain length',
|
||||
text2: 'Success',
|
||||
text3: 'Fail',
|
||||
customIcon: 'Custom Icon',
|
||||
customImage: 'Custom Image',
|
||||
text4: second => `${second} seconds`,
|
||||
longTextButton: 'Long Text'
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
showLoadingToast() {
|
||||
this.$toast.loading({ mask: true, message: this.$t('loading') });
|
||||
},
|
||||
|
||||
showSuccessToast() {
|
||||
this.$toast.success(this.$t('text2'));
|
||||
},
|
||||
|
||||
showFailToast() {
|
||||
this.$toast.fail(this.$t('text3'));
|
||||
},
|
||||
|
||||
showIconToast() {
|
||||
this.$toast({
|
||||
message: this.$t('customIcon'),
|
||||
icon: 'like-o'
|
||||
});
|
||||
},
|
||||
|
||||
showImageToast() {
|
||||
this.$toast({
|
||||
message: this.$t('customImage'),
|
||||
icon: 'https://img.yzcdn.cn/vant/logo.png'
|
||||
});
|
||||
},
|
||||
|
||||
showCustomizedToast() {
|
||||
const toast = this.$toast.loading({
|
||||
duration: 0,
|
||||
forbidClick: true,
|
||||
loadingType: 'spinner',
|
||||
message: this.$t('text4', 3)
|
||||
});
|
||||
|
||||
let second = 3;
|
||||
const timer = setInterval(() => {
|
||||
second--;
|
||||
if (second) {
|
||||
toast.message = this.$t('text4', second);
|
||||
} else {
|
||||
clearInterval(timer);
|
||||
this.$toast.clear();
|
||||
}
|
||||
}, 1000);
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
@import "../../style/var";
|
||||
|
||||
.demo-toast {
|
||||
background-color: @white;
|
||||
|
||||
.van-button {
|
||||
margin-left: 15px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,127 @@
|
||||
# Toast
|
||||
|
||||
### Install
|
||||
|
||||
```javascript
|
||||
import { Toast } from 'vant';
|
||||
|
||||
Vue.use(Toast);
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
### Text
|
||||
|
||||
```javascript
|
||||
Toast('Some messages');
|
||||
```
|
||||
|
||||
### Loading
|
||||
|
||||
```javascript
|
||||
Toast.loading({
|
||||
mask: true,
|
||||
message: 'Loading...'
|
||||
});
|
||||
```
|
||||
|
||||
### Success/Fail
|
||||
|
||||
```javascript
|
||||
Toast.success('Success');
|
||||
Toast.fail('Fail');
|
||||
```
|
||||
|
||||
### Custom Icon
|
||||
|
||||
```js
|
||||
Toast({
|
||||
message: 'Custom Icon',
|
||||
icon: 'like-o'
|
||||
});
|
||||
|
||||
Toast({
|
||||
message: 'Custom Image',
|
||||
icon: 'https://img.yzcdn.cn/vant/logo.png'
|
||||
});
|
||||
```
|
||||
|
||||
### Advanced Usage
|
||||
|
||||
```javascript
|
||||
const toast = Toast.loading({
|
||||
duration: 0, // continuous display toast
|
||||
forbidClick: true, // forbid click background
|
||||
loadingType: 'spinner',
|
||||
message: '3 seconds'
|
||||
});
|
||||
|
||||
let second = 3;
|
||||
const timer = setInterval(() => {
|
||||
second--;
|
||||
if (second) {
|
||||
toast.message = `${second} seconds`;
|
||||
} else {
|
||||
clearInterval(timer);
|
||||
Toast.clear();
|
||||
}
|
||||
}, 1000);
|
||||
```
|
||||
|
||||
### $toast Method
|
||||
|
||||
After import the Toast component, the $toast method is automatically mounted on Vue.prototype, making it easy to call within a vue component.
|
||||
|
||||
```js
|
||||
export default {
|
||||
mounted() {
|
||||
this.$toast('Some messages');
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 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();
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
### Methods
|
||||
|
||||
| Methods | Attribute | Return value | Description |
|
||||
|------|------|------|------|
|
||||
| Toast | `options | message` | toast instance | Show toast |
|
||||
| Toast.loading | `options | message` | toast instance | Show loading toast |
|
||||
| Toast.success | `options | message` | toast instance | Show success toast |
|
||||
| Toast.fail | `options | message` | toast instance | Show fail toast |
|
||||
| Toast.clear | `clearAll: boolean` | `void` | Close toast |
|
||||
| Toast.allowMultiple | - | `void` | Allow multlple toast at the same time |
|
||||
| Toast.setDefaultOptions | `options` | `void` | Set default options of all toasts |
|
||||
| Toast.resetDefaultOptions | - | `void` | Reset default options of all toasts |
|
||||
|
||||
### Options
|
||||
|
||||
| Attribute | Description | Type | Default |
|
||||
|------|------|------|------|
|
||||
| type | Can be set to `loading` `success` `fail` `html` | `String` | `text` |
|
||||
| position | Can be set to `top` `middle` `bottom` | `String` | `middle` |
|
||||
| message | Message | `String` | `''` |
|
||||
| icon | Custom icon | `String` | - |
|
||||
| mask | Whether to show mask | `Boolean` | `false` |
|
||||
| forbidClick | Whether to forbid click background | `Boolean` | `false` |
|
||||
| loadingType | Loading icon type, can be set to `spinner` | `String` | `circular` |
|
||||
| duration | Toast duration(ms), won't disappear if value is 0 | `Number` | `3000` |
|
||||
| className | Custom className | `String | Array | Object` | - |
|
||||
| onOpened | Callback function after opened | `Function` | - |
|
||||
| onClose | Callback function after close | `Function` | - |
|
||||
| getContainer | Return the mount node for Toast | `String | () => HTMLElement` | `body` |
|
||||
@@ -0,0 +1,147 @@
|
||||
import Vue from 'vue';
|
||||
import VueToast from './Toast';
|
||||
import { isObj, isServer } from '../utils';
|
||||
|
||||
const defaultOptions = {
|
||||
icon: '',
|
||||
type: 'text',
|
||||
mask: false,
|
||||
value: true,
|
||||
message: '',
|
||||
className: '',
|
||||
onClose: null,
|
||||
onOpened: null,
|
||||
duration: 3000,
|
||||
position: 'middle',
|
||||
forbidClick: false,
|
||||
loadingType: undefined,
|
||||
getContainer: 'body',
|
||||
overlayStyle: null
|
||||
};
|
||||
|
||||
let queue = [];
|
||||
let multiple = false;
|
||||
let currentOptions = {
|
||||
...defaultOptions
|
||||
};
|
||||
|
||||
function parseOptions(message) {
|
||||
if (isObj(message)) {
|
||||
return message;
|
||||
}
|
||||
|
||||
return { message };
|
||||
}
|
||||
|
||||
function createInstance() {
|
||||
/* istanbul ignore if */
|
||||
if (isServer) {
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!queue.length || multiple) {
|
||||
const toast = new (Vue.extend(VueToast))({
|
||||
el: document.createElement('div')
|
||||
});
|
||||
queue.push(toast);
|
||||
}
|
||||
|
||||
return queue[queue.length - 1];
|
||||
}
|
||||
|
||||
// transform toast options to popup props
|
||||
function transformOptions(options) {
|
||||
options.overlay = options.mask;
|
||||
return options;
|
||||
}
|
||||
|
||||
function Toast(options = {}) {
|
||||
const toast = createInstance();
|
||||
|
||||
// should add z-index if previous toast has not disappeared
|
||||
if (toast.value) {
|
||||
toast.updateZIndex();
|
||||
}
|
||||
|
||||
options = {
|
||||
...currentOptions,
|
||||
...parseOptions(options),
|
||||
clear() {
|
||||
toast.value = false;
|
||||
|
||||
if (options.onClose) {
|
||||
options.onClose();
|
||||
}
|
||||
|
||||
if (multiple && !isServer) {
|
||||
toast.$on('closed', () => {
|
||||
clearTimeout(toast.timer);
|
||||
queue = queue.filter(item => item !== toast);
|
||||
|
||||
const parent = toast.$el.parentNode;
|
||||
if (parent) {
|
||||
parent.removeChild(toast.$el);
|
||||
}
|
||||
|
||||
toast.$destroy();
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Object.assign(toast, transformOptions(options));
|
||||
clearTimeout(toast.timer);
|
||||
|
||||
if (options.duration > 0) {
|
||||
toast.timer = setTimeout(() => {
|
||||
toast.clear();
|
||||
}, options.duration);
|
||||
}
|
||||
|
||||
return toast;
|
||||
}
|
||||
|
||||
const createMethod = type => options =>
|
||||
Toast({
|
||||
type,
|
||||
...parseOptions(options)
|
||||
});
|
||||
|
||||
['loading', 'success', 'fail'].forEach(method => {
|
||||
Toast[method] = createMethod(method);
|
||||
});
|
||||
|
||||
Toast.clear = all => {
|
||||
if (queue.length) {
|
||||
if (all) {
|
||||
queue.forEach(toast => {
|
||||
toast.clear();
|
||||
});
|
||||
queue = [];
|
||||
} else if (!multiple) {
|
||||
queue[0].clear();
|
||||
} else {
|
||||
queue.shift().clear();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Toast.setDefaultOptions = options => {
|
||||
Object.assign(currentOptions, options);
|
||||
};
|
||||
|
||||
Toast.resetDefaultOptions = () => {
|
||||
currentOptions = { ...defaultOptions };
|
||||
};
|
||||
|
||||
Toast.allowMultiple = (value = true) => {
|
||||
multiple = value;
|
||||
};
|
||||
|
||||
Toast.install = () => {
|
||||
Vue.use(VueToast);
|
||||
};
|
||||
|
||||
Vue.prototype.$toast = Toast;
|
||||
|
||||
export default Toast;
|
||||
@@ -0,0 +1,69 @@
|
||||
@import '../style/var';
|
||||
|
||||
.van-toast {
|
||||
position: fixed;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
box-sizing: content-box;
|
||||
|
||||
// hack for avoid max-width when use left & fixed
|
||||
width: @toast-default-width;
|
||||
max-width: @toast-max-width;
|
||||
min-height: @toast-default-min-height;
|
||||
padding: @toast-default-padding;
|
||||
color: @toast-text-color;
|
||||
font-size: @toast-font-size;
|
||||
line-height: @toast-line-height;
|
||||
|
||||
// allow newline charactor
|
||||
white-space: pre-wrap;
|
||||
text-align: center;
|
||||
word-break: break-all;
|
||||
background-color: @toast-background-color;
|
||||
border-radius: @toast-border-radius;
|
||||
transform: translate3d(-50%, -50%, 0);
|
||||
|
||||
// should not add pointer-events: none directly to body tag
|
||||
// that will cause unexpected tap-highlight-color in mobile safari
|
||||
&--unclickable {
|
||||
* {
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
|
||||
&--text {
|
||||
width: fit-content;
|
||||
min-width: @toast-text-min-width;
|
||||
min-height: unset;
|
||||
padding: @toast-text-padding;
|
||||
|
||||
.van-toast__text {
|
||||
margin-top: 0;
|
||||
}
|
||||
}
|
||||
|
||||
&--top {
|
||||
top: @toast-position-top-distance;
|
||||
}
|
||||
|
||||
&--bottom {
|
||||
top: auto;
|
||||
bottom: @toast-position-bottom-distance;
|
||||
}
|
||||
|
||||
&__icon {
|
||||
font-size: @toast-icon-size;
|
||||
}
|
||||
|
||||
&__loading {
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
&__text {
|
||||
margin-top: 10px;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`renders demo correctly 1`] = `
|
||||
<div>
|
||||
<div><button class="van-button van-button--primary van-button--normal"><span class="van-button__text">
|
||||
文字提示
|
||||
</span></button> <button class="van-button van-button--primary van-button--normal"><span class="van-button__text">
|
||||
长文字提示
|
||||
</span></button></div>
|
||||
<div><button class="van-button van-button--primary van-button--normal"><span class="van-button__text">
|
||||
加载提示
|
||||
</span></button></div>
|
||||
<div><button class="van-button van-button--info van-button--normal"><span class="van-button__text">
|
||||
成功提示
|
||||
</span></button> <button class="van-button van-button--danger van-button--normal"><span class="van-button__text">
|
||||
失败提示
|
||||
</span></button></div>
|
||||
<div><button class="van-button van-button--primary van-button--normal"><span class="van-button__text">
|
||||
自定义图标
|
||||
</span></button> <button class="van-button van-button--primary van-button--normal"><span class="van-button__text">
|
||||
展示图片
|
||||
</span></button></div>
|
||||
<div><button class="van-button van-button--primary van-button--normal"><span class="van-button__text">
|
||||
高级用法
|
||||
</span></button></div>
|
||||
</div>
|
||||
`;
|
||||
@@ -0,0 +1,28 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`create a forbidClick toast 1`] = `
|
||||
<div class="van-toast van-toast--middle" style="z-index: 2000;" name="van-fade"><i class="van-icon van-icon-success van-toast__icon">
|
||||
<!----></i></div>
|
||||
`;
|
||||
|
||||
exports[`icon prop 1`] = `
|
||||
<div class="van-toast van-toast--middle" style="z-index: 2004;" name="van-fade"><i class="van-icon van-icon-star-o van-toast__icon">
|
||||
<!----></i>
|
||||
<div class="van-toast__text">Message</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`show html toast 1`] = `
|
||||
<div class="van-toast van-toast--middle van-toast--text" style="z-index: 2003;" name="van-fade">
|
||||
<div class="van-toast__text">
|
||||
<div>Message</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`show loading toast 1`] = `
|
||||
<div class="van-toast van-toast--middle" style="z-index: 2002;" name="van-fade">
|
||||
<div class="van-loading van-loading--circular van-toast__loading"><span class="van-loading__spinner van-loading__spinner--circular" style="color: white;"><svg viewBox="25 25 50 50" class="van-loading__circular"><circle cx="50" cy="50" r="20" fill="none"></circle></svg></span></div>
|
||||
<div class="van-toast__text">Message</div>
|
||||
</div>
|
||||
`;
|
||||
@@ -0,0 +1,4 @@
|
||||
import Demo from '../demo';
|
||||
import demoTest from '../../../test/demo-test';
|
||||
|
||||
demoTest(Demo);
|
||||
@@ -0,0 +1,140 @@
|
||||
import Vue from 'vue';
|
||||
import Toast from '..';
|
||||
import ToastVue from '../Toast';
|
||||
import { transitionStub, later } from '../../../test/utils';
|
||||
|
||||
transitionStub();
|
||||
|
||||
test('create a forbidClick toast', async () => {
|
||||
const toast = Toast({
|
||||
forbidClick: true,
|
||||
type: 'success'
|
||||
});
|
||||
|
||||
await later();
|
||||
expect(toast.$el.outerHTML).toMatchSnapshot();
|
||||
|
||||
await later();
|
||||
expect(document.body.classList.contains('van-toast--unclickable')).toBeTruthy();
|
||||
toast.forbidClick = false;
|
||||
|
||||
await later();
|
||||
expect(document.body.classList.contains('van-toast--unclickable')).toBeFalsy();
|
||||
});
|
||||
|
||||
it('toast disappeared after duration', async () => {
|
||||
const toast = Toast({
|
||||
duration: 10
|
||||
});
|
||||
|
||||
await later(50);
|
||||
expect(toast.$el.style.display).toEqual('none');
|
||||
});
|
||||
|
||||
test('show loading toast', async () => {
|
||||
const toast = Toast.loading({
|
||||
message: 'Message'
|
||||
});
|
||||
|
||||
await later();
|
||||
expect(toast.$el.outerHTML).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('show html toast', async () => {
|
||||
const toast = Toast({
|
||||
type: 'html',
|
||||
message: '<div>Message</div>'
|
||||
});
|
||||
|
||||
await later();
|
||||
expect(toast.$el.outerHTML).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('icon prop', async () => {
|
||||
const toast = Toast({
|
||||
message: 'Message',
|
||||
icon: 'star-o'
|
||||
});
|
||||
|
||||
await later();
|
||||
expect(toast.$el.outerHTML).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('clear toast', () => {
|
||||
const toast1 = Toast();
|
||||
expect(toast1.value).toBeTruthy();
|
||||
Toast.clear();
|
||||
expect(toast1.value).toBeFalsy();
|
||||
|
||||
Toast.allowMultiple();
|
||||
const toast2 = Toast('2');
|
||||
const toast3 = Toast('3');
|
||||
Toast.clear(true);
|
||||
expect(toast2.value).toBeFalsy();
|
||||
expect(toast3.value).toBeFalsy();
|
||||
Toast.allowMultiple(false);
|
||||
});
|
||||
|
||||
test('clear multiple toast', () => {
|
||||
Toast.allowMultiple();
|
||||
Toast.clear(true);
|
||||
const toast1 = Toast.success('1');
|
||||
const toast2 = Toast.success('2');
|
||||
Toast.clear();
|
||||
expect(toast1.value).toBeFalsy();
|
||||
expect(toast2.value).toBeTruthy();
|
||||
Toast.clear();
|
||||
Toast.clear();
|
||||
expect(toast2.value).toBeFalsy();
|
||||
Toast.allowMultiple(false);
|
||||
});
|
||||
|
||||
test('remove toast DOM when cleared in multiple mode', async () => {
|
||||
Toast.allowMultiple();
|
||||
Toast.clear(true);
|
||||
const toast = Toast({ message: '1' });
|
||||
await later();
|
||||
|
||||
// mock onAfterLeave
|
||||
toast.clear();
|
||||
toast.onAfterLeave();
|
||||
await later();
|
||||
|
||||
expect(toast.$el.parentNode).toEqual(null);
|
||||
Toast.allowMultiple(false);
|
||||
});
|
||||
|
||||
test('set default options', () => {
|
||||
Toast.setDefaultOptions({ duration: 1000 });
|
||||
expect(Toast().duration).toEqual(1000);
|
||||
Toast.resetDefaultOptions();
|
||||
expect(Toast().duration).toEqual(3000);
|
||||
});
|
||||
|
||||
test('toast duration 0', () => {
|
||||
Toast.allowMultiple();
|
||||
const toast = Toast({
|
||||
message: 'toast',
|
||||
duration: 0
|
||||
});
|
||||
expect(toast.timer).toBeFalsy();
|
||||
Toast.allowMultiple(false);
|
||||
});
|
||||
|
||||
test('onClose callback', () => {
|
||||
Toast.allowMultiple();
|
||||
const onClose = jest.fn();
|
||||
const toast = Toast({
|
||||
message: 'toast',
|
||||
onClose
|
||||
});
|
||||
|
||||
toast.clear();
|
||||
Toast.allowMultiple(false);
|
||||
expect(onClose).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
test('register component', () => {
|
||||
Vue.use(Toast);
|
||||
expect(Vue.component(ToastVue.name)).toBeTruthy();
|
||||
});
|
||||
@@ -0,0 +1,127 @@
|
||||
# Toast 轻提示
|
||||
|
||||
### 引入
|
||||
|
||||
```js
|
||||
import { Toast } from 'vant';
|
||||
|
||||
Vue.use(Toast);
|
||||
```
|
||||
|
||||
## 代码演示
|
||||
|
||||
### 文字提示
|
||||
|
||||
```js
|
||||
Toast('提示内容');
|
||||
```
|
||||
|
||||
### 加载提示
|
||||
|
||||
```js
|
||||
Toast.loading({
|
||||
mask: true,
|
||||
message: '加载中...'
|
||||
});
|
||||
```
|
||||
|
||||
### 成功/失败提示
|
||||
|
||||
```js
|
||||
Toast.success('成功文案');
|
||||
Toast.fail('失败文案');
|
||||
```
|
||||
|
||||
### 自定义图标
|
||||
|
||||
```js
|
||||
Toast({
|
||||
message: '自定义图标',
|
||||
icon: 'like-o'
|
||||
});
|
||||
|
||||
Toast({
|
||||
message: '展示图片',
|
||||
icon: 'https://img.yzcdn.cn/vant/logo.png'
|
||||
});
|
||||
```
|
||||
|
||||
### 高级用法
|
||||
|
||||
```js
|
||||
const toast = Toast.loading({
|
||||
duration: 0, // 持续展示 toast
|
||||
forbidClick: true, // 禁用背景点击
|
||||
loadingType: 'spinner',
|
||||
message: '倒计时 3 秒'
|
||||
});
|
||||
|
||||
let second = 3;
|
||||
const timer = setInterval(() => {
|
||||
second--;
|
||||
if (second) {
|
||||
toast.message = `倒计时 ${second} 秒`;
|
||||
} else {
|
||||
clearInterval(timer);
|
||||
Toast.clear();
|
||||
}
|
||||
}, 1000);
|
||||
```
|
||||
|
||||
### 组件内调用
|
||||
|
||||
引入 Toast 组件后,会自动在 Vue 的 prototype 上挂载 $toast 方法,便于在组件内调用。
|
||||
|
||||
```js
|
||||
export default {
|
||||
mounted() {
|
||||
this.$toast('提示文案');
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 单例模式
|
||||
|
||||
Toast 默认采用单例模式,即同一时间只会存在一个 Toast,如果需要在同一时间弹出多个 Toast,可以参考下面的示例
|
||||
|
||||
```js
|
||||
Toast.allowMultiple();
|
||||
|
||||
const toast1 = Toast('第一个 Toast');
|
||||
const toast2 = Toast.success('第二个 Toast');
|
||||
|
||||
toast1.clear();
|
||||
toast2.clear();
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
### 方法
|
||||
|
||||
| 方法名 | 参数 | 返回值 | 介绍 |
|
||||
|------|------|------|------|
|
||||
| Toast | `options | message` | toast 实例 | 展示提示 |
|
||||
| Toast.loading | `options | message` | toast 实例 | 展示加载提示 |
|
||||
| Toast.success | `options | message` | toast 实例 | 展示成功提示 |
|
||||
| Toast.fail | `options | message` | toast 实例 | 展示失败提示 |
|
||||
| Toast.clear | `clearAll: boolean` | `void` | 关闭提示 |
|
||||
| Toast.allowMultiple | - | `void` | 允许同时存在多个 Toast |
|
||||
| Toast.setDefaultOptions | `options` | `void` | 修改默认配置,对所有 Toast 生效 |
|
||||
| Toast.resetDefaultOptions | - | `void` | 重置默认配置,对所有 Toast 生效 |
|
||||
|
||||
### Options
|
||||
|
||||
| 参数 | 说明 | 类型 | 默认值 | 版本 |
|
||||
|------|------|------|------|------|
|
||||
| type | 提示类型,可选值为 `loading` `success`<br>`fail` `html` | `String` | `text` | - |
|
||||
| position | 位置,可选值为 `top` `bottom` | `String` | `middle` | - |
|
||||
| message | 文本内容,支持通过`\n`换行 | `String` | `''` | - | - |
|
||||
| icon | 自定义图标,支持传入图标名称或图片链接,可选值见 Icon 组件 | `String` | - | 2.0.1 |
|
||||
| mask | 是否显示背景遮罩层 | `Boolean` | `false` | - |
|
||||
| forbidClick | 是否禁止背景点击 | `Boolean` | `false` | - |
|
||||
| loadingType | 加载图标类型, 可选值为 `spinner` | `String` | `circular` | 1.1.3 |
|
||||
| duration | 展示时长(ms),值为 0 时,toast 不会消失 | `Number` | `3000` | - |
|
||||
| className | 自定义类名 | `String | Array | Object` | - | 1.6.0 |
|
||||
| onOpened | 完全展示后的回调函数 | `Function` | - | 2.0.0 |
|
||||
| onClose | 关闭时的回调函数 | `Function` | - | 1.6.10 |
|
||||
| getContainer | 指定挂载的节点,可以传入选择器,<br>或一个返回节点的函数 | `String | () => HTMLElement` | `body` | 1.6.3 |
|
||||
Reference in New Issue
Block a user