先上效果图...
Toast需求:
- 弹出Toast自动关闭
- 多少(N)秒后自动关闭
- 弹出Toast用户可点击关闭
- 用户点击关闭后回调(fn)
- 保证只有一个Toast弹出,不会同时出现两个。
用法:
import Vue from 'vue'
import plugin from './plugin/index'
Vue.use(plugin)
this.$toast('操作成功!!!')
Github:欢迎Star
这里是分割线
开始面对面,看代码...
不管在哪里都可以直接使用this.$toast
,具体如何实现??? 请看Vue官方文档
1、main.js
Vue.prototype.$toast = function () {
console.log('我是苏宋霖');
}
2、App.vue
export default {
name: 'app',
methods: {
xxx() {
this.$toast()
},
}
}
点击按钮控制台是不是打印出了我是苏宋霖
,做到这里你已经成功一半了
但是这样并不是我们想要的,使用插件形式install
,让用户主动去使用。
继续改造✨
新建plugin/index.js
export default {
install(Vue,options){
Vue.prototype.$toast = function(message){
console.log(message);
}
}
}
main.js
import plugin from './plugin/index'
Vue.use(plugin)
使用
this.$toast('我是苏宋霖')
控制一样打印出我是苏宋霖
, 说明你距离成功不远了 (这句话跟高中老师一样,经常对我们学生说前脚已经跨进北大的校门了,后来我们毕业了才知道北大是可以随便进出,哪怕登记一下就好)
Vue.use
会自动阻止多次注册相同插件,届时即使多次调用也只会注册一次该插件。
继续改造✨✨
新建components/Toast.vue
在引入Toast.vue之前有个问题如何在js使用vue实例 ??
1、方应杭的Vue 动态创建实例
2、滴滴的cube-ui专门为这个场景实现了一个create-api, 可以将任意自定义组件制作成调用时动态创建的插件
plugin/index.js 引入Toast.vue
import Toast from '@/components/Toast.vue'
export default {
install(Vue,options){
Vue.prototype.$toast = function(message){
let Constructor = Vue.extend(Toast)
let toast = new Constructor()
toast.$mount()
document.body.appendChild(toast.$el) //添加到页面中
}
}
}
通过代码可以实现动态创建实例(别用原生js实现如: let div = document.createElement("div"); document.body.appendChild(div)
,这样无法使用到vue的各种生命周期及Api)
继续改造✨✨✨
Toast.vue 文件不变,index.js通过插槽传值给Toast.vue
问题:如果在js中使用插槽传值啊??? 我的天
看文档渲染函数 & JSX
this.$slots.default // 子节点数组
注意这里接收的是数组 数组 数组
import Toast from '@/components/Toast.vue'
export default {
install(Vue,options){
Vue.prototype.$toast = function(message){
let Constructor = Vue.extend(Toast)
let toast = new Constructor()
toast.$slots.default = [message] //slots必须要放在mount之前
toast.$mount()
document.body.appendChild(toast.$el)
}
}
}
添加简单样式
继续改造✨✨✨✨
实现3s后自动关闭,
props: {
// 自动关闭
autoClose: {
type: Boolean,
default: true
},
// 关闭时间
autoCloseDelay: {
type: Number,
default: 3
}
},
mounted() {
if (this.autoClose) {
setTimeout(() => {
this.close();
}, this.autoCloseDelay * 1000);
}
},
methods: {
close() {
this.$el.remove(); //删除
this.$destroy(); //清除绑定的一些事件
}
}
继续改造✨✨✨✨✨
弹出Toast用户可点击关闭
{{closeButton.text}}
plugin/index.js
import Toast from '@/components/Toast.vue'
export default {
install(Vue,options){
Vue.prototype.$toast = function(message,toaseOptions){
let Constructor = Vue.extend(Toast)
let toast = new Constructor({
propsData:toaseOptions
})
toast.$slots.default = [message]
toast.$mount()
document.body.appendChild(toast.$el)
}
}
}
使用
this.$toast('我是苏宋霖',{
closeButton:{
text:'知道了',
callback(){
console.log('苏宋霖点击知道了');
}
}
})
手动测试发现一个问题,内容过多的时候Toast并没有变化,
关闭按钮被挤压
如下:
改造吧支持多行文字
使用js去给line添加高度,因为父元素的高度变成min-height。
//html
{{closeButton.text}}
//js
mounted(){
this.updateStyle()
},
methods: {
updateStyle() {
this.$nextTick(() => {
this.$refs.line.style.height =
`${this.$refs.toast.getBoundingClientRect().height}px`
})
},
}
//css 新增的
继续改造✨✨✨✨✨✨
Toast的位置
在.toast上加:class="toastClasses"
,通过props传过来的属性position
动态添加class
//html
{{closeButton.text}}
//js
props:{
// 位置
position: {
type: String,
default: "top",
validator(value) {
return ["top", "bottom", "middle"].indexOf(value) >= 0;
}
}
}
computed: {
toastClasses() {
return {
[`position-${this.position}`]: true
};
}
},
//css
&.position-top {
top: 0;
transform: translateX(-50%);
}
&.position-bottom {
bottom: 0;
transform: translateX(-50%);
}
&.position-middle {
top: 50%;
transform: translate(-50%, -50%);
}
使用
新问题:
用户重复点击Toast,会出现多个DOM??
解决方案:
如果已经有一个Toast,就把之前的给删了
plugin/index.js
import Toast from '@/components/Toast.vue'
export default {
install(Vue,options){
let currentToast ;
Vue.prototype.$toast = function(message,toaseOptions){
if(currentToast){currentToast.close()}//如果有Toast就删除上一个
currentToast = createToast({Vue,propsData:toaseOptions,message})
}
}
}
function createToast({Vue,propsData,message}) {
let Constructor = Vue.extend(Toast)
let toast = new Constructor({ propsData})
toast.$slots.default = [message]
toast.$mount()
document.body.appendChild(toast.$el)
return toast
}
ps:样式啥的请自行修改。
轮子完毕!!! 接下来测试用例..
未完待续...
提示:
npm 配置淘宝源:npm config set registry https://registry.npm.taobao.org/