弹窗类组件设计思路: 它们在当前vue实例之外独立存在,通过JS动态创建,不需要在任何组件中声明,然后挂载在body上。
方式1: render()函数
实现创造函数
新建一个创造函数来实现。
src下新建一个utils文件夹,表示工具类文件,用来存放工具函数。再文件夹下新建一个swCreateBox.js文件,用来实现创建弹窗组件。
import Vue from 'vue';
// 函数接收两个参数:
// 参数1: 是组件配置对象
// 参数2: 是传递进来的参数(propsData)
function swCreateBox(Component, props) {}
export default swCreateBox;
第一步
借用Vue构造函数动态生成组件实例(得到虚拟dom):
const vm = new Vue({
render(h) { // render函数将传⼊组件配置对象转换为虚拟dom
// h是createElement别名,返回一个虚拟dom(VNode)
return h(Component, { props });
}
});
第二步
执⾏挂载函数来得到真实dom:
vm.$mount();// 但未指定挂载⽬标,表示只执⾏初始化⼯作,就会创建真实dom,但是不会追加操作
第三步
通过$el属性获取真实dom元素再添加到body:
document.body.appendChild(vm.$el);
第四步
得到组件实例:
const mycomponent = vm.$children[0];
第五步
因为弹框需要被关闭,所以给弹框添加销毁⽅法:
mycomponent.remove = () => {
document.body.removeChild(vm.$el);
vm.$destroy();
};
最后
返回这个组件实例
return mycomponent;
完整代码
import Vue from 'vue';
// 创建一个函数,动态生成组件实例挂载到body上
// Component:是组件配置对象
function swCreateBox(Component, props) {
// 创建⼀个Vue新实例:借用Vue构造函数来动态生成这个组件实例
const vm = new Vue({
render(h) { // render函数将传⼊组件配置对象转换为虚拟dom
// h是createElement别名,返回一个虚拟dom(VNode)
return h(Component, { props });
}
});
// 执⾏挂载函数,但未指定挂载⽬标,表示只执⾏初始化⼯作,可以得到真实dom
vm.$mount();
// 通过$el属性获取真实dom元素再添加到body
document.body.appendChild(vm.$el);
// 得到组件实例
const mycomponent = vm.$children[0];
// 再给组件实例添加销毁⽅法
mycomponent.remove = () => {
document.body.removeChild(vm.$el);
vm.$destroy();
};
return mycomponent;
}
export default swCreateBox;
将方法添加到vue原型
因为可能多处使用,所以我们将创造函数添加到vue原型上去:
main.js中:
import swCreateBox from '@/utils/swCreateBox.js'
Vue.prototype.$swCreateBox = swCreateBox;
新建通知组件
components下新建一个SwMsgBox.vue文件,组件里有一个状态isShow来判断是否显示,接收title(标题)、content(内容)、duration(延迟时间)三个prop属性:
<template>
<div v-if="isShow">
<!-- 标题 -->
<h3>{{ title }}</h3>
<!-- 内容 -->
<p>{{ content }}</p>
</div>
</template>
<script>
export default {
props: {
title: {
type: String,
default: "",
},
content: {
type: String,
default: "",
},
duration: {
// 延迟时间:多久之后关闭弹框(毫秒)
type: Number,
default: 1000,
},
},
data() {
return {
isShow: false, // 是否显示自己
};
},
methods: {
show() {
this.isShow = true;
setTimeout(this.hide, this.duration); // 指定时间之后执行hide方法
},
hide() {
this.isShow = false; // 隐藏自己
this.remove(); // 从body中卸载销毁自己 -> 写在创造方法中的
},
},
};
</script>
<style scoped>
div {
position: fixed;
min-width: 200px;
top: 16px;
left: 40%;
text-align: center;
pointer-events: none;
background-color: greenyellow;
}
</style>
使用
先引入:
import SwMsgbox from "@/components/messageBox/SwMsgBox";
在需要使用的地方使用:
click() {
this.$swCreateBox(SwMsgbox, {
title: "pyy",
content: "成功!",
duration: 3000,
}).show();
},
方式2: extend()函数
实现创造函数
utils文件夹下新建一个swExtendBox.js文件
import Vue from 'vue';
function swExtendBox(Component, props) {}
export default swExtendBox;
第一步
利用vue的extend()方法来得到组件的构造函数:
const MyConstructor = Vue.extend(Component); // 构造函数函数名首字母应该大写
因为参数2是propsData,所以不能在这儿传递,那么怎么传递参数呢?
第二步
通过构造函数创建组件实例,并传递prop参数:
const mycomponent = new MyConstructor({propsData: props});
第三步
执⾏挂载函数来得到真实dom:
mycomponent.$mount();
第四步
通过组件的$el属性获取真实dom元素再添加到body:
document.body.appendChild(mycomponent.$el);
第五步
因为弹框需要被关闭,所以给弹框添加销毁⽅法:
mycomponent.remove = () => {
document.body.removeChild(mycomponent.$el);
mycomponent.$destroy();
};
最后
返回这个组件实例
return mycomponent;
完整代码
import Vue from 'vue';
function swExtendBox(Component, props) {
// 利用vue的extend()方法来得到组件的构造函数
const MyConstructor = Vue.extend(Component);
// 通过构造函数创建组件实例,并传递prop参数
const mycomponent = new MyConstructor({ propsData: props });
// 执⾏挂载函数来得到真实dom
mycomponent.$mount();
// 通过组件的$el属性获取真实dom元素再添加到body
document.body.appendChild(mycomponent.$el);
// 给弹框添加销毁⽅法
mycomponent.remove = () => {
document.body.removeChild(mycomponent.$el);
mycomponent.$destroy();
};
return mycomponent;
}
export default swExtendBox;
将方法添加到vue原型
main.js中:
import swExtendBox from '@/utils/swExtendBox.js'
Vue.prototype.$swExtendBox = swExtendBox;
使用
参照方式1
封装成插件使用
在swCreateBox.js文件创造函数当中:
// 使⽤插件进⼀步封装便于使⽤
export default {
install(Vue) {
Vue.prototype.$swCreateBox = function (options) {
return swCreateBox(SwMsgbox, options);
}
}
}
在swExtendBox.js文件创造函数当中:
// 使⽤插件进⼀步封装便于使⽤
export default {
install(Vue) {
Vue.prototype.$swExtendBox = function (options) {
return swExtendBox(SwMsgbox, options);
}
}
}
main.js中:
import swCreateBox from '@/utils/swCreateBox.js'
import swExtendBox from '@/utils/swExtendBox.js'
Vue.use(swCreateBox);
Vue.use(swExtendBox);
在使用的vue文件中:
// 不需要再引入,直接使用
// this.$swCreateBox({
// title: "pyy",
// content: "成功!",
// duration: 3000,
// }).show();
this.$swExtendBox({
title: "wyz",
content: "成功!",
duration: 3000,
}).show();