Vue-5个进阶属性(指令等)

2,430 阅读6分钟

Vue-5个进阶构造属性

本章介绍:directive、mixin、extend、provide&inject这5个Vue的进阶构造属性。

Directive-指令

  • 什么是指令?

    其实之前我们就已经学习了指令,如:v-ifv-for,类似这些以 v- 开头的就是指令,而v-ifv-for这些属于内置指令,除此之外我们还可以自定义指令。

  • 全局自定义指令

    全局自定义指令:在全局作用域下自定义指令,同时这个指令也能够用于全局,即任何组件都能够使用这个全局指令。如要声明多个全局指令,多次调用Vue.directive

    // 声明全局指令,注意在全局作用域下
    Vue.directive('x',directiveOptions)
    
    // 使用全局指令,在任何组件中都可以使用 v-x
    <myComponent v-x ></myComponent>
    
  • 局部自定义指令

    局部自定义指令:在某个组件Vue对象下进行声明,只能在该Vue组件的实例中使用。注意局部声明时的 directives

    // 声明局部指令
    <script>
        export default {
            ...
            directives:{
            	"x":directiveOptions,
            	"y":directiveOptions
        	}
        }
    </script>
    
    // 只能在该组件中使用局部指令
    <template>
    	<div v-x v-y></div>
    </template>
    
  • directiveOptions

    在上面的声明中,我们只是演示了指令的声明,并没有研究如何赋予指令功能,而指令的功能是通过directiveOptions中的5个钩子函数来实现的。

    1. directiveOptions中的5个钩子函数:
      1. bind:可以看成Vue中的created函数,即:当使用该指令的VNode(虚拟DOM)加载到内存中时执行的钩子函数。
      2. inserted:被绑定元素插入父节点时调用。
      3. update:所在组件的 VNode 更新时调用,但是可能发生在其子 VNode 更新之前。
      4. componentUpdated:指令所在组件的 VNode 及其子 VNode 全部更新后调用。
      5. unbind:只调用一次,指令与元素解绑时调用。
    2. 钩子函数被传入的4个参数:(el,binding,vnode,oldVnode)
      1. 第一个参数el:指令所绑定的元素,可以用来直接操作DOM。
      2. 第二个参数binding:这是一个对象,包含下列属性
        • name:指令名,不包括v-前缀
        • value:指令的绑定值,如:v-on:click='sayhi',这个sayhi就是指令绑定值。
        • oldValue:指令绑定的前一个值,仅在 updatecomponentUpdated 钩子中可用。无论值是否改变都可用。
        • expression:字符串形式的指令表达式,如:v-on:click='sayhi',这里'sayhi'就是指令表达式。
        • arg:传给指令的参数,如:v-on:click='sayhi',这个click就是传给指令的参数。
        • modifiers:一个包含修饰符的对象。 例如:v-my-directive.foo.bar 中,修饰符对象为 { foo: true, bar: true }
      3. 第三个参数vnode:Vue 编译生成的虚拟节点。
      4. 第四个参数oldVnode:Vue 编译生成的上一个虚拟节点。
  • 使用directiveOptions完整声明一个指令

    下面我们通过一个小例子,来简单实现Vue内置指令v-on的绑定事件的功能。

    new Vue({
        directives: {
            "myOn": {
                inserted: (el, info) => {
                    el.addEventListener(info.arg, info.value)
                }
            }
        }
    })
    
  • 指令的作用以及使用场景

    Vue组件/实例的主要用于数据绑定、事件监听、DOM更新,而指令的作用主要是完成原生DOM操作

    当我们需要重复多次相同的原生DOM操作,或者是进行一些比较复杂的原生DOM操作时,可以借助指令来完成。

mixins-组合

  • 什么是mixins?

    简单来说就是“复制”。有时候我们需要使用多次相同的组件,这些组件的代码几乎一样,为了节省代码量,我们可以将这些相同的部分提取出来,然后通过mixin组合到各自组件中。mixins中的操作会合并到其他Vue实例中后,当作一个整体运行:比如:mixin中没有某个变量,但是其它Vue实例中有,这种情况下并不会报错,因是先合并了才运行。

  • mixins的意义

    mixins可以减少data、methods、钩子的重复使用。

  • mixins的使用

    // 相同部分提取 log.js
    export default {
        data(){
            return {
                a:'a'
            }
        },
        methods:{
            hw:function(){ console.log('helloWorld') }
        },
        created:function(){
        	console.log('created')
    	}
    }
    
    // 在组件中使用提取的部分 myComponent.vue
    import log from './log.js'
    export default {
        // 这里是个数组,说明可以使用多个mixins
        mixins:[log],
        data(){
       	 	return {
        		b:'b'
    		}
    	}
    }
    // 此时,这组件就可以使用mixins中的 a数据 ,hw方法 ,created ,以及自身的 b数据
    
  • mixins是智能合并的

    相同data当前实例优先级更高,而相同的钩子函数则会把两边的操作都合并起来。

  • 全局mixin

    Vue.mixin({mixin对象})
    

    注意:全局mixin声明时没有s(mixin)。使用全局mixin后,所有的组件包括App.vue都会默认合并这个全局mixin,所以不建议使用全局mixin。

extends-继承

  • extends的作用

    extends的作用和mixins一样,但是形式不同。

  • extends的使用

    1.局部extends的使用

    // 声明扩展内容
    const myVue = {}
    // 使用
    export default {
        // 注意这里不是数组
        extends:myVue,
        data(){ return {} }
    }
    
    1. 全局extends的使用

      // 全局声明
      const myVue = Vue.extend({扩展内容})
      // 继承式声明Vue实例
      new myVue({vueOptions}) 
      
    2. extends与extends&mixins

      extends声明的扩展内容还能够使用extends和mixins。

      import log from './log.js' // mixin
      const com1 = {}
      
      const com2 = {
          extends:com1,
          mixins:[log]
      }
      

provide提供&inject注入

  • 什么是provide和inject?

    上级组件可以通过provide传递data与method,而下级组件可以通过inject获取上级组件传递的data与method。

    provide和inject能够大范围传递data和methods

  • provide和inject的使用方法

    // 上级组件
    export default {
        data(){
            return { n:'n'}
        },
        methods:{
            add(){
                console.log('add')
            }  
        },
        provide(){
            return {
                n:this.n,
                add:this.add
            }
        }
    }
    
    // 下级组件
    // 我们就可以在下级组件中,使用n与add
    export default {
        inject:['n','add']
    }
    
  • provide和inject使用细节

    传递的data时,父组件把自身data的地址复制了一份传递了,子组件能够获取data的值,但如果想在子组件中修改父组件的某些data(简单类型如Number、String)是不允许的,因为我们修改的只是复制的变量的值。但是我们可以通过在子组件中调用父组件传递过里啊的method来修改父组件的data,因为传递过来的method内部关联的是父组件的data。

    但是如果父组件provide的data是一个对象,由于上级组件复制的是一个地址,所以子组件访问的也是同一个对象,那么在子组件中是能够修改这个对象,进而影响到父组件的。不推荐传递一个provide一个对象,因为如果都使用这个方法,那么在组件较多的情况下很难确定那个对象当前是出于什么状态。