feat: migrate Toast component

This commit is contained in:
chenjiahan 2020-08-07 07:16:33 +08:00
parent 17c64b24e7
commit 5d2cd516ed
5 changed files with 96 additions and 87 deletions

View File

@ -45,4 +45,5 @@ module.exports = [
'sticky',
'picker',
'dialog',
'toast',
];

View File

@ -2,20 +2,18 @@
import { createNamespace, isDef } from '../utils';
import { lockClick } from './lock-click';
// Mixins
import { PopupMixin } from '../mixins/popup';
// Components
import Icon from '../icon';
import Popup from '../popup';
import Loading from '../loading';
const [createComponent, bem] = createNamespace('toast');
export default createComponent({
mixins: [PopupMixin()],
props: {
icon: String,
show: Boolean,
clear: Function,
className: null,
iconPrefix: String,
loadingType: String,
@ -40,6 +38,8 @@ export default createComponent({
},
},
emits: ['opened', 'closed', 'update:show'],
data() {
return {
clickable: false,
@ -55,7 +55,7 @@ export default createComponent({
},
watch: {
value: 'toggleClickable',
show: 'toggleClickable',
forbidClick: 'toggleClickable',
},
@ -67,7 +67,7 @@ export default createComponent({
},
toggleClickable() {
const clickable = this.value && this.forbidClick;
const clickable = this.show && this.forbidClick;
if (this.clickable !== clickable) {
this.clickable = clickable;
@ -124,23 +124,20 @@ export default createComponent({
render() {
return (
<transition
name={this.transition}
onAfterEnter={this.onAfterEnter}
onAfterLeave={this.onAfterLeave}
<Popup
show={this.show}
class={[
bem([this.position, { [this.type]: !this.icon }]),
this.className,
]}
transition={this.transition}
onOpened={this.onAfterEnter}
onClosed={this.onAfterLeave}
onClick={this.onClick}
>
<div
vShow={this.value}
class={[
bem([this.position, { [this.type]: !this.icon }]),
this.className,
]}
onClick={this.onClick}
>
{this.genIcon()}
{this.genMessage()}
</div>
</transition>
{this.genIcon()}
{this.genMessage()}
</Popup>
);
},
});

View File

@ -1,14 +1,10 @@
import Vue from 'vue';
import VueToast from './Toast';
import { isObject, isServer } from '../utils';
import { removeNode } from '../utils/dom/node';
import { createApp, nextTick } from 'vue';
import VanToast from './Toast';
import { isObject, inBrowser } from '../utils';
const defaultOptions = {
icon: '',
type: 'text',
// @deprecated
mask: false,
value: true,
message: '',
className: '',
overlay: false,
@ -45,18 +41,69 @@ function parseOptions(message) {
function createInstance() {
/* istanbul ignore if */
if (isServer) {
if (!inBrowser) {
return {};
}
if (!queue.length || multiple) {
const toast = new (Vue.extend(VueToast))({
el: document.createElement('div'),
const root = document.createElement('div');
document.body.appendChild(root);
const app = createApp({
data() {
return {
timer: null,
toastProps: {
show: false,
},
};
},
methods: {
clear() {
this.toggle(false);
},
toggle(show, duration) {
this.toastProps.show = show;
if (show) {
clearTimeout(this.timer);
if (duration > 0) {
this.timer = setTimeout(() => {
this.clear();
}, duration);
}
}
},
setProps(props) {
this.toastProps = {
...props,
duration: undefined,
};
},
onClosed() {
if (multiple && inBrowser) {
clearTimeout(this.timer);
queue = queue.filter((item) => item !== this);
app.unmount();
document.body.removeChild(root);
}
},
},
render() {
return (
<VanToast
{...{
...this.toastProps,
onClosed: this.onClosed,
'onUpdate:show': this.toggle,
}}
/>
);
},
});
toast.$on('input', (value) => {
toast.value = value;
});
const toast = app.mount(root);
queue.push(toast);
}
@ -64,16 +111,6 @@ function createInstance() {
return queue[queue.length - 1];
}
// transform toast options to popup props
function transformOptions(options) {
return {
...options,
overlay: options.mask || options.overlay,
mask: undefined,
duration: undefined,
};
}
function Toast(options = {}) {
const toast = createInstance();
@ -89,32 +126,11 @@ function Toast(options = {}) {
...options,
};
options.clear = () => {
toast.value = false;
toast.setProps(options);
if (options.onClose) {
options.onClose();
}
if (multiple && !isServer) {
toast.$on('closed', () => {
clearTimeout(toast.timer);
queue = queue.filter((item) => item !== toast);
removeNode(toast.$el);
toast.$destroy();
});
}
};
Object.assign(toast, transformOptions(options));
clearTimeout(toast.timer);
if (options.duration > 0) {
toast.timer = setTimeout(() => {
toast.clear();
}, options.duration);
}
nextTick(() => {
toast.toggle(true, options.duration);
});
return toast;
}
@ -165,10 +181,9 @@ Toast.allowMultiple = (value = true) => {
multiple = value;
};
Toast.install = () => {
Vue.use(VueToast);
Toast.install = (app) => {
app.use(VanToast);
app.config.globalProperties.$toast = Toast;
};
Vue.prototype.$toast = Toast;
export default Toast;

View File

@ -1,9 +1,6 @@
@import '../style/var';
.van-toast {
position: fixed;
top: 50%;
left: 50%;
display: flex;
flex-direction: column;
align-items: center;
@ -25,7 +22,6 @@
word-wrap: break-word;
background-color: @toast-background-color;
border-radius: @toast-border-radius;
transform: translate3d(-50%, -50%, 0);
&--unclickable {
// lock scroll

View File

@ -106,10 +106,10 @@ module.exports = {
path: 'style',
title: 'Style 内置样式',
},
// {
// path: 'toast',
// title: 'Toast 轻提示',
// },
{
path: 'toast',
title: 'Toast 轻提示',
},
],
},
{
@ -440,10 +440,10 @@ module.exports = {
path: 'style',
title: 'Built-in style',
},
// {
// path: 'toast',
// title: 'Toast',
// },
{
path: 'toast',
title: 'Toast',
},
],
},
{