基于Promise将Vue组件封装为插件
2018-08-17 本文已影响0人
一蓑烟雨任平生_cui
项目中有些组件在很多场景下都会用到,比如toast、messageBox、alert等,如果作为组件使用,则每个用到的地方都需要引入、注册等操作;如果把组件封装成插件,并作为实例的公共方法,则在整个应用中即可随处调用。
以messageBox为例,封装插件。
步骤如下:
- 编写组件
- 调用Vue.extend()方法,创建构造器
- 创建组件实例
- 挂载并插入文档
- 往构造器上添加回调,监听用户的操作,取消还是确定
- 创建Promise的实例
- 添加方法到Vue的原型和实例上
- 监听浏览器的前进、后退事件,当离开页面的时候,隐藏组件
具体如下:
- 首先编写组件:
<template>
<div v-show="show">
<!-- ui-mask为自己封装的组件 -->
<ui-mask :showMask="show" :opacity="0.2"></ui-mask>
<div class="message-box">
<h1 class="message-title" v-show="title">{{title}}</h1>
<p class="content">{{content}}</p>
<div class="message-button">
<p class="fl" @click="cancleMessage" v-show="cancle">{{cancle}}</p>
<p class="fr" @click="sureMessage">{{sure}}</p>
</div>
</div>
</div>
</template>
- 样式使用scss
样式省略...
- js部分代码
data() {
return {
show: false,
title: '',
content: '',
sure: '确定',
cancle: ''
}
},
methods: {
sureMessage() {
this.show = false;
this.callback && this.callback('confirm');
},
cancleMessage() {
this.show = false;
this.callback && this.callback();
}
}
封装插件
- 如果插件是一个对象,则必须提供install方法,Vue.use的时候调用install方法
- 如果插件是函数,函数将作为install方法执行。
index.js
import messageBox from './messageBox.vue';
export default {
install(Vue, options = {}) {
// 创建构造函数
const MessageBox = Vue.extend(messageBox);
let instance;
let currentMsg;
// 绑定window的history事件
window.addEventListener('popstate', () => {
if (instance) {
insatnce.show = false;
instance = null;
currentMsg = null;
}
});
let messageBoxFunc = (options = {}) => {
if (!instance) {
// 创建实例
instance = new MessageBox({
// 需要挂在到某一个元素上
el: document.createElement('div')
});
// 如果没有传el,则需要调用实例的$mount方法,传入元素
// instance = new MessageBox().$mount(document.createElement('div'));
// 如果没有传递el选项、$mount()方法也没有传递任何参数,则模板将被渲染为文档之外的元素,亦是可行的。
// 插入到DOM中
document.body.appendChild(instance.$el)
}
// 合并参数与实例
Object.assign(instance, options);
// 在构造器的原型上扩展一个回调,修改promise的状态
MessageBox.prototype.callback = defaultCallback;
return new Promise((resolve, reject) => {
// 保存两个回调,在action改变的时候执行
currentMsg = {
resolve,
reject
}
})
};
function defaultCallback(action) {
if (action === 'confirm') {
currentMsg.resolve('confirm');
}
currentMsg.reject('cancle');
}
// 将方法扩展到Vue的原型和实例上
Vue.prototype.$messageBox = Vue.messageBox = messageBoxFunc;
}
}
这样一个messageBox插件就封装好了,在应用的任何地方都可以调用。可以使用Promise的方式then、catch,亦可使用async/await的方式。
Usage
// 方式一
this.$messageBox()
.then(res => {
})
.catch(err => {
})
// 方式二
// 所在的方法一定是async函数
try {
await this.$messageBox();
// do something
}
catch(e) {
// do...
}
总结:
用到的知识点Promise、原型链、async/await。