序言
Vue 日常开发中模块化,组件化开发思想必不可少。 对于一些通用,常用及多次使用与某一处等场景,怎样的组件API设计及使用方式能更好的方便使用者快速使用。这里也许能给你一些参考。
拿Element UI 中的组件举例,主要结合了三中方式: 常规组件, Vue原型链组件, 指令/混淆组件。
常规组件
大多数开发场景下使用的方式: 通用性不是很高,与业务挂钩及个性化的关联较性强。 拆成组件方式主要是方便插拔,开发协作,模块化组织思想,提高可维护性等。
该方式较为常规,这里不在举例…
结合 Vue.prototype 组件
这种模式主要方便在Vue 项目中以类Vue API 的方式使用。 在组件数据交互及控制上显得更直观和简易。其结合了常规组件的基础上设计开发。
简例:
// component name: Msg
<template> <div class="error-msg" v-if="isShow">错误提示!</div></template>
// extend comp
const installMsg = Vue.extend(Msg)// Msg = import Msg from '.../../Msg.vue'
$Msg = new installMsg({data:{isShow: false, }, el: xxxxx})
document.body.appendChild($Msg.$mount().$el)
let msgOpt = {
show(){ $Msg.isShow = ture },
hide(){$Msg.isShow = false}
}
if(!Vue.$msg) {
Vue.$msg = msgOpt
}
Vue.prototype.$msg = Vue.$msg
// client use Msg by Vue Component
handleShowMsg (){
this.$msg.show()/hiden()
}
结合 指令,mixin 组件
- 通过指令directive允许我们在需要的组件便签上使用 ‘v-指令名’来控制及交互我们的组件
<div v-loading="true">Loding....</div>
- 通过==mixin == 允许我们指定具体混淆到全局组件的某个具体位置(比如: created , beforeCreated等钩子函数初始化时)
mixin 特点:
*1. 优先级: 全局mixin, 局部mixin, 组件构造函数; *
2. 相同钩子函数执行两边 ,mixin内的优先限执行;
3. data 同名属性,同名时组件中的值优先级高;
4. methods 内方法: 同名时则组件覆盖mixin 的方法;
Vue.mixin({
created() {
this.$loading = Vue.$loading;
}
})
注: mixin 在vue中使用的是被混淆的对应钩子,被混入的组件如果存在相同属性等,则会被覆盖
实例:
组件部分代码
<template>
<div
v-show="visible"
>
laoding....
<p class="loading-text">{{text}}</p>
</div>
</template>
<script>
export default {
data(){
return {
text: null,
visible: false
}
},
methods: {
setText(text) {
this.text = text;
}
}
}
</script>
插件部分代码 directive.js:
import Vue from 'vue'
import Loading from './Loading'
const Mask = Vue.extend(Loading);
const loadingDirective = {};
loadingDirective.install = (Vue, options) => {
let mask = new Mask({
el: document.createElement('div'),
data: {
text: "你好...",
}
});
// 指令在使用的时候对应要加 “v-指令名”
Vue.directive('loading', {
/*
el: 设置指令的对应标签dom
binding: {
name: "loading"
rawName: "v-loading"
value: true // 使用指令是赋的值
expression: "true"
modifiers: {}
def: {bind: ƒ, update: ƒ, unbind: ƒ}
}
*/
bind: (el, binding, vnode) => { // 指令与被绑定元素第一次绑定时触发,通常做一些事件监听的初始化
console.log("bind():", el, binding, vnode, oldVnode);
const vm = vnode.context;
mask.visible = binding.value;
el.instance = mask;
el.mask = mask.$el;
el.maskStyle = {};
Vue.nextTick(() => {
document.body.appendChild(mask.$mount().$el)
})
},
update: (el, binding) => { // 被绑定元素内容发生变化时触发,可接受参数,在这里也可以进行事件监听的初始化
console.log("update():", el, binding)
},
unbind: (el) => { // 指令与元素解绑时触发,比如通过路由转跳页面时需要解绑指令
console.log("unbind():", el, binding)
},
inserted: function () {},// 绑定元素插入父节点时调用(父节点存在即可调用,不必存在于 document 中)。
componentUpdated: function () {},// 被绑定元素所在模板完成一次更新周期时调用。
});
let loading = {
show() { mask.visible = true },
hide() { mask.visible = false },
setText(text){ mask.text = text}
};
if (!Vue.$loading) {
Vue.$loading = loading;
}
Vue.mixin({
created() {
this.$loading = Vue.$loading;
}
})
};
export default loadingDirective;
测试插件的使用
首先,在主入口文件间处 引入"directive.js" 并通过 Vue.use(Loading) 注册插件, 然后就可以在各个组件中使用了。
<template>
<div class="hello">
<p v-loading="true">
通过指令方式控制loading 展示
</p>
</div>
</template>
<script>
export default {
name: 'HelloWorld',
props: {
msg: String
},
mounted(){
// 通过minix 操作loading 的数据及交互功能
this.$loading.setText("手动复制.....")
setTimeout(()=>{
this.$loading.hide();
}, 3000)
},
}
</script>