自定义指令官方文档 Vue.directive( id, [definition] )
自定义简单的指令v-onall,全局自定义
定义无参数的指令v-onall代码如下,注意,v-在定义时是省略的,Vue.directive第二个参数中传入有回调函数inserted,0表示元素插入到页面中时进行回调;
Vue.directive('onall', {
inserted: function (el) {
el.addEventListener('click', () => {
console.log("全局指令监听到点击事件!")
});
}
});
除了inserted回调函数,还有其他回调函数
使用v-onall指令:
<button v-onall>全局</button>
点击按钮【全局】,触发了按键监听事件;
自定义简单的指令v-onpart,局部定义
new Vue({
directives: {
part: {
inserted: function (el) {
el.addEventListener('mousedown', () => {
console.log("局部指令监听到事件!");
})
}
}
},
template: `
<div>
<button v-onpart>局部</button>
</div>
`,
}).$mount("#app");
模拟v-on2:click指令
定义是这样的,其中inof是指令后面的参数
directives: {
myon: {
inserted: function (el,info){
el.addEventListener(info.arg,info.value);
},
unbind: function (el,info){
el.removeEventListener(info.arg, info.value);
}
}
},
使用是这样的,其中mylog是一个函数
<button v-myon:click = "mylog">v-myon</button>
指令的作用
- 主要用于DOM操作
- Vue实例/组件用于数据绑定、事件监听、DOM更新
- Vue指令主要目的就是DOM操作
- 减少重复
- 对过某个DOM操作经常使用,可以封装为指令以减少重复
- 某个DOM操作比较复杂,也可以封装为指令
mixins,封装组件的公共部分,可以理解为智能复制
假设有3个组件,Child1,Child2,Child3,他们都有共同的data和钩子操作:
组件Child1如下:
<template>
<span>Child-1</span>
</template>
<script>
export default {
name: "Child1",
data(){
return {
name: "Child1",
time: undefined,
}
},
created() {
this.time = new Date();
console.log(`${this.name} created!`);
},
beforeDestroy() {
const stay = (new Date()) - this.time;
console.log(`${this.name} destroyed, stay ${stay}s`)
}
}
</script>
<style scoped>
</style>
类似的还有Child2,Child3,这三个组件中的data和钩子函数如created/beforDestroy都相同的部分你,怎么复用呢,拷贝出来!
mixins复用方法:
- 把公共部分抽出来,以对象的形式,放在一个js文件中,再暴露出来,
const log = {
data(){
return {
name: "Child1",
time: undefined,
}
},
created() {
this.time = new Date();
console.log(`${this.name} created!`);
},
beforeDestroy() {
const stay = (new Date()) - this.time;
console.log(`${this.name} destroyed, stay ${stay}s`)
}
}
export default log;
2.在控件中导入mxins文件,并自定义特有字段,比如下面例子中,time和created用的是mixins提供的公共数据,name和beforDestroy都是控件中特有的,会覆盖掉mixins提供的数据,这就是智能合并。
<script>
import log from "@/mixins/log";
export default {
name: "Child3",
data(){
return {
name: "Child3",
}
},
mixins:[log],
beforeDestroy() {
const wait = (new Date()) - this.time;
console.log(`最后一个出生的${this.name}死亡了,时间是${wait}`)
}
}
</script>
Extends继承、扩展,其实也是一种智能复制
- 创建Vue的扩展,里面包含了其他Vue组件用的公共数据,具体做法是创建一个MyVue.js文件,然后暴露出来,要特别注意,用的是
Vue.extend(),没有s
import Vue from "vue/dist/vue";
const MyVue = Vue.extend({
data(){
return {
name: "Child1",
time: undefined,
}
},
created() {
this.time = new Date();
console.log(`${this.name} created!`);
},
beforeDestroy() {
const stay = (new Date()) - this.time;
console.log(`${this.name} destroyed, stay ${stay}s`)
}
});
export default MyVue;
- 在组件中Extends组件
<script>
import MyVue from "@/MyVue";
export default {
name: "Child4",
data(){
return {
name: "Child4",
}
},
extends: MyVue,
}
</script>
provide和inject
父控件AppTheme中,定义全局的皮肤样式,保存在全局的data中,在AppTheme下的子控件Child1中,有一个换肤控件ChangeThemeButton,这个子控件如何修改全局的皮肤样式?
- 在父组件中用
provide()函数,通过一个对象把数据暴露出来
provide() {
return {
"themeName": this.themeName,
"themeNameFun": () => {
return this.themeName;
},
"changeThemeName": this.changeThemeName,
}
},
其中,"themeName"暴露的是数据,而且是基础类数据,但是这种暴露是一次性的,父组件改了,子组件不能响应式更新,"themeNameFun"暴露的是一个函数,返回基础类型数据,这种暴露是响应式的,子组件能够响应式更新,"changeThemeName"暴露的是一个函数,子组件可以调用;
2. 在子组件或者其他组件中用inject:["name"]对象注入父组件暴露的数据
<script>
export default {
name: "ChangeThemeButton",
inject: ["themeNameFun", "changeThemeName"],
methods: {
change() {
this.changeThemeName(this.themeNameFun() === "red" ? "blue" : "red")
}
}
}
</script>
在子组件中,themeNameFun是从外部注入的,但是注入后使用,就和在methods中定义的方法一样;
3. 父组件可以通过provide(){return{"name":object}}把对象暴露出来,其他组件响应式更新,但这样做并不值得提倡。