一、前言
这次分享一下之前仿写过的element-ul的messageBox组件,只实现了简单的效果,样式还有很大的欠缺,在开始之前需要先了解一个方法vue.extend,在后面封装的时候需要用到。
二、vue.extend
作用: 生成一个新的带有默认参数的vue的子类,所以生成的这个子类它也是vue,它也具备vue的所有功能,这玩意儿说白了就是给vue产生默认值,如果你有,那么就使用你的,如果你没有,那么就使用我的默认值。
好处: 我们可以通过 Vue.extend 方法来创建符合我们业务需求的定制化组件构造器,让我们的应用逻辑更加清晰和模块化。
与new关键字实例化的区别:
Vue.extend返回的是一个组件构造器,而不是一个具体的组件实例。通过这个构造器,可以创建多个相同的组件实例。而直接使用new关键字实例化,则直接得到一个组件实例。使用
Vue.extend创建了一个组件构造器,可以根据这个构造器来创建多个组件实例。而直接使用new关键字实例化,则只能得到一个组件实例。使用
Vue.extend定义的组件构造器,可以使用 mixin、父子组件通信等高级特性,使得开发更加灵活。而直接使用new关键字实例化的组件,则不能很方便地使用以上这些高级特性。
使用:
// 举例:
const vueChild = Vue.extend({
data() {
return {
msg: 2
}
}
})
const vm = new vueChild({
// 如果这里不写data的这个配置项,那么就使用上面的默认值的data,
// 使用this.msg的话呢得到的结果是2
// 如果这里书写了data的配置项那么就会以自己的为准,跟之前说过的
// 混入有点类似,这里的this.msg的值为3
data() {
return {
msg: 3
}
}
})
三、messageBox组件的结构和样式
// messageBox组件的main.vue
<template>
// 使用v-if控制messageBox的显示与隐藏
<div class="co-message-box" v-if="messageBoxVisible">
<div class="co-message-box__header">{{ title }}</div>
<div class="co-message-box__content">{{ message }}</div>
<div class="co-message-box__btns">
<Button @click="cancel">{{ options.cancelButtonText }}</Button>
<Button @click="confirm" type="primary">{{
options.confirmButtonText
}}</Button>
</div>
</div>
</template>
<script>
// 引入之前封装好的button按钮
import Button from '@/components/Button/main.vue';
export default {
name: 'co-message-box',
components: { Button },
methods: {
hide() {
this.messageBoxVisible = false;
// this.$nextTick() 是 Vue.js 中的一个方法,表示在下一个 DOM
// 更新周期之前执行一个回调函数,这里将messageBox隐藏起来属于
// 异步操作,而将messageBox销毁属于同步操作,如果不做任何改变
// 那这里会出现还没将messageBox隐藏起来就被销毁了,会出现报错,
// 所以这里需要this.$nextTick()来将销魂放在更新完毕之后才执行
this.$nextTick(() => this.$destroy());
},
cancel() {
this.reject();
this.hide();
},
confirm() {
this.resolve();
this.hide();
},
},
};
</script>
// scoped的作用:当样式重名的时候并不会相互影响
<style lang="scss" scoped>
.co-message-box {
display: inline-block;
width: 420px;
padding-bottom: 10px;
vertical-align: middle;
background-color: #fff;
border-radius: 4px;
border: 1px solid #ebeef5;
font-size: 18px;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
text-align: left;
overflow: hidden;
backface-visibility: hidden;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -100%);
&__header {
position: relative;
padding: 15px;
padding-bottom: 10px;
}
&__content {
padding: 10px 15px;
color: #606266;
font-size: 14px;
}
&__btns {
padding: 5px 15px 0;
text-align: right;
}
}
</style>
四、messageBox组件的核心逻辑
// messageBox组件的index.js
import Main from './main.vue';
let Vue = null;
// 将实例化messageBox的逻辑封装成为一个函数,如果不封装的话呢它就会不
// 受控制的执行。
function message(
// 使用时可以传递的参数,如果不传的话,就使用给的默认值
message = '我是一条消息!',
title = '标题',
options = {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'info',
}
) {
// 这个函数返回的东西就是将messageBox组件渲染出来,然后根据文档上面的格式,
// 会使用到catch和then的方法,那么这个函数会返回一个promise,里面的resolve
// 和reject就是确认按钮和取消按钮所执行的回调函数,然后这两个方法可以通过
// methods的配置项将其传递到组件内部来提供给按钮使用。
return new Promise((resolve, reject) => {
// 生成一个带有默认参数的vue
const MessageBox = Vue.extend(Main);
// 实例化MessageBox组件并传参
const messagebox = new MessageBox({
data() {
return {
message,
title,
options,
messageBoxVisible: true,
};
},
methods: {
resolve,
reject,
},
});
// 调用$mount()不传递参数 触发模板编译流程
messagebox.$mount();
// 通过messagebox实例的$el属性获取到编译后的结果 手动添加到页面中
document.body.appendChild(messagebox.$el);
});
}
// 万物皆对象,函数也属于对象的一种,所以我可以为它添加一个install的方法,
// 方便使用use去实例化
message.install = function (_Vue) {
Vue = _Vue;
// 将message这个函数绑定到vue的原型上面,这样就可以通过vue.$message来
// 执行这个函数了。
_Vue.prototype.$message = this;
};
// 函数封装完成之后再将其导出,然后在使用的地方将这个函数导入使用,通过变量
// 来控制这个弹框的显示与隐藏。
export default message;