Vue进阶属性:directives指令、mixins混入、extends继承、provide提供、inject注入
directives指令
自定义指令
一,声明一个全局指令
Vue.directive('x',directiveOptions)
你就可以在任何组件里用v-x了
例子:元素在插入到页面时,就绑定click事件
Vue.directive('x',{inserted:function(el){el.addEventListener('click',()=>{console.log('x')})}})
二,声明一个局部指令,只能在这个组件里使用
export default{name:'hello',directives:{'x':{inserted(el){el.addEventListener('click',()=>{})}}}}
directiveOptions
五个函数属性
bind(el,info,vnode,oldVnode) -类似created
inserted(el,info,vnode,oldVnode)-类似mounted
update(el,info,vnode,oldVnode)-类似updated
componentUpdated(el,info,vnode,oldVnode)- 用的不多
unbind(el,info,vnode,oldVnode)- 类似destroyed
举例:
new Vue({directives:{//声明on2指令on2:{inserted(el,info){console.log(info)//info.value是用户传来的值,这里会接到一个方法el.addEventListener(info.arg, info.value)},//元素销毁时unbind(el,info){//解绑事件el.removeEventListener(info.arg, info.value)}}},template:`<button v-on2:click="hi">点我</button>`,methods:{hi(){console.log('hi')}}})
如何缩写下面这部分?其实一般不缩写的!如何写请查文档!
inserted(el,info){console.log(info)//info.value是用户传来的值,这里会接到一个方法el.addEventListener(info.arg, info.value)},//元素销毁时unbind(el,info){//解绑事件el.removeEventListener(info.arg, info.value)}
指令的作用
主要用于DOM操作
Vue实例/组件用于数据绑定、事件监听、DOM更新
Vue指令主要目的就是原生DOM操作
减少重复
如果某个DOM操作你经常使用,就可以封装为指令
如果某个DOM操作比较复杂,也可以封装为指令
mixins混入
类比
directives的作用是减少DOM操作的重复
mixins的作用是减少data、methods、钩子的重复
场景
假设我们需要在每个组件上添加name和time
在created时,打出提示,并报出存活时间
一共有五个组件,请问你怎么做?
1 给每个组件添加dat和钩子,共五次
2 或者使用mixins减少重复
创建mixins文件夹和其下面的log.js文件
const log = {//data里的属性会自动和下方Child1.vue的属性智能合并,undefined会被值:Child1覆盖掉data(){return{name:undefined,time:undefined}},created(){ //created也会智能合并//如果this.name不存在if(!this.name){throw new Error('需要name')}this.time = new Date()console.log(`${this.name}出生了`)},beforeDestroy(){const now = new Date()console.log(`${this.name}死亡了,共生存了${now - this.time}`)}}export default log
有Child1.vue,Child2.vue,Child3.vue,Child4.vue,Child5.vue
每个文件里,都导入log
这是Child1.vue:
<script>import log from '../mixins/log.js'export default{data(){return {name:'Child1'}},mixins:[log] //等于把log及其内容复制到了这里}</script>
所以每个vue组件内都有了log的内容。
如果所有组件都要有log功能
可以在main.js中使用Vue.mixin
Vue.mixin({data(){return{name:undefined,time:undefined}},created(){ //created也会智能合并//如果this.name不存在if(!this.name){throw new Error('需要name')}this.time = new Date()console.log(`${this.name}出生了`)},beforeDestroy(){const now = new Date()console.log(`${this.name}死亡了,共生存了${now - this.time}`)}})
全部组件就自动有了这些内容了。
这个方式不太好!
Extends 继承、扩展
实现与mixins同样的需求
声明一个MyVue.js
import Vue from 'vue'const MyVue = Vue.extend({ //关键词extenddata(){return{name:undefined,time:undefined}},created(){ //created也会智能合并//如果this.name不存在if(!this.name){throw new Error('需要name')}this.time = new Date()console.log(`${this.name}出生了`)},beforeDestroy(){const now = new Date()console.log(`${this.name}死亡了,共生存了${now - this.time}`)}})
Child1.vue
import MyVue from '../MyVue.js'export default{extends:MyVue, //关键词data(){}}
extends是比mixins更抽象一点的封装,用得少
Provide提供 和 Inject注入
换肤例子
App.vue
<template><div :class="`app theme-${themeName}`"><Child1 /></div></template><script>export default{name:"App",data(){return {themeName:"blue",fontSize:"normal"}}}</script>
components文件夹下的ChangeThemeButton.vue文件
<template><div><button>换肤</button></div></template>
components文件夹下的Child1.vue文件,另外还有Child2.vue,Child3.vue,Child4.vue,Child5.vue
<template><div>Child1<change-theme-button /> //注意这里的大小写</div></template><script>import ChangeThemeButton from "./ChangeThemeButton.vue" //引入文件export default{components:{ChangeThemeButton //大小写}}</script>
问题来了,在ChangeThemeButton.vue里,如何改变App.vue的data来让皮肤变色???
答:用provide
App.vue:
<template><div :class="`app theme-${themeName}`"><Child1 /></div></template><script>export default{name:"App",//提供一个themeName的复制品出去provide(){return {themeName:this.themeName,//这里提供出去的只是一个新的值,所以那边改也无效,除非提供出去的是引用,但是不推荐,因为容易失控changeTheme:this.changeTheme}},data(){return {themeName:"blue",fontSize:"normal"}},methods:{changeTheme(){if(this.themeName === 'blue'){this.themeName = 'red'}else{this.themeName = 'blue'}}}}</script>
ChangeThemeButton.vue
<template><div><button @click="x">换肤</button></div></template><script>export default{inject:['themeName','changeTheme'], //注入上面代码提供的themeNamemethods:{x(){this.changeTheme()}}}</script>
总结
作用:共用大范围的data和method
注意:不能只传themeName不传changeTheme,因为themeName的值是被复制给provide的
资料来源:饥人谷
