vue笔记(八)自定义指令 和 mixins混入

文档:https://cn.vuejs.org/v2/guide/custom-directive.html

注册指令:

注册与component注册完全一样:

  • 全局注册:Vue.directive(name,function | object) //object是配置对象,function将会被 `bind` 和 `update` 调用 
  • 局部注册:new Vue({directives:{ name: 配置对象 }})

模板中使用

  <input v-指令名: xx.a='yy'>这种比较齐全,可以不带.a,也可以不带yy,直接<input v-指令名>。带上的目的是对指令中的动作进行详细的控制

自定义指令的钩子函数:

  bind,执行一次,指令第一次绑定到元素时调用

  inserted:被绑定元素插入父节点时调用 (仅保证父节点存在,但不一定已被插入文档中)

  update:所在组件的 VNode 变更触发,包括其中的数据变化

 钩子函数的参数:
  • el:指令所绑定的元素,可以用来直接操作 DOM。
  • binding:一个对象,包含以下 property:
    • name:指令名,不包括 v- 前缀。
    • value:指令的绑定值,例如:v-my-directive="1 + 1" 中,绑定值为 2
    • oldValue:指令绑定的前一个值,仅在 update 和 componentUpdated 钩子中可用。无论值是否改变都可用。
    • expression:字符串形式的指令表达式。例如 v-my-directive="1 + 1" 中,表达式为 "1 + 1"
    • arg:传给指令的参数,可选。例如 v-my-directive:foo 中,参数为 "foo"
    • modifiers:一个包含修饰符的对象。例如:v-my-directive.foo.bar 中,修饰符对象为 { foo: true, bar: true }

组件钩子函数和指令钩子函数的执行顺序:created, bind, mouted, updata;

可见,在bind函数执行的时候,操作的是虚拟dom,在updata操作时候,执行的是真实的dom

vue笔记(八)自定义指令 和 mixins混入

例子:注册弹出加载动画的的指令

<template>
<div class="home-container" v-vLoading='loadingFlag' /> </template> export default { data() { return { loadingFlag: true, }; }, async created() { this.caroucels = await this.$http.get('/mock/banner'); this.loadingFlag = false; } }
import Vue from 'vue';
import loading from '@/assets/loading.svg';//动画文件
import style from './loading.module.less';//style文件


Vue.directive('vLoading', {
  bind (el) {//在第一次指令绑定时候,创建img,并加到绑指令定元素el中
    const img = new Image;
    img.src = loading;
    img.className = style.myLoading;
    img.setAttribute('data-img', 'myLoading');
    el.appendChild(img)
  },
  update(el, binding) {//在数据变化时候,如果img有,则需要删除
    const img = el.querySelector('img[data-img=myLoading]')
    if (!binding.value && img) el.removeChild(img);
  }
})

另一个自定义指令的例子:懒加载

import $bus from '@/utils/eventBus';
import defaultImg from '@/assets/default-img.jpg';
import debunce from '@/utils/debunce'

import Vue from 'vue';
  import vLazy from './lazy'

let imgArr = []; /** * 检测是否在屏幕上, * @param {*} dom img标签的对象 * @returns */ function inScreen(dom) { const clientHeight = document.body.clientHeight; const info = dom.getBoundingClientRect(); if (info.top + dom.offsetHeight >= 0 && info.top < clientHeight) { return true; } else { return false; } } //加载真实路径 function loadRealImage(img, src) { var temp = new Image(); temp.onload = function () { img.src = src; } temp.src = src; } /** * 防抖函数处理后的回调 */ const debunceDealer = debunce( function () { console.log(imgArr); imgArr = imgArr.filter((element) => { if (inScreen(element.el)) { loadRealImage(element.el, element.src); return false } else { return true } }) },200) $bus.$on('blogMainlScroll',debunceDealer )//当滚动条滚动时候,触发事件,执行debunceDealer export default { inserted(el, binding) { el.src = defaultImg; if (inScreen(el)) { loadRealImage(el, binding.value) } else { imgArr.push({ el, src: binding.value }) } }, unbind(el) { imgArr = [] } }
 

Vue.directive('vLazy',vLazy)
 <ul class="bloglist">
      <li v-for="item in data.rows" :key="item.id">
        <div class="img" v-if="item.thumb">
          <router-link
            :to="{
              name: 'blogDetail',
              params: {
                blogId: item.id,
              },
            }"
          >
            <img v-vLazy="item.thumb" :alt="item.title" :title="item.title" />
          </router-link>
        </div>

        <div class="content">
          <p class="title">
            <router-link
              :to="{
                name: 'blogDetail',
                params: {
                  blogId: item.id,
                },
              }"
            >
              {{ item.title }}
            </router-link>
          </p>

 混入mixins(vue2中的无奈选择)

mixins

  • 类型:Array<Object>

  • 详细:

    mixins 选项接收一个混入对象的数组。

  Mixin 钩子按照传入顺序依次调用,并在调用组件自身的钩子之前被调用。

var mixin = {
  created: function () { console.log(1) }
}
var vm = new Vue({
  created: function () { console.log(2) },
  mixins: [mixin]
})
// => 1
// => 2
//先执行混入钩子函数,在执行自身钩子函数

混入应用实例:

  各个组件中,在axios请求时候都会出现请求的动画,请求数据返回时,动画消失。可以提取这一共同特征,作为混入;

注意:必须标准化几个变量以后用起来方便:

loadingFlag:加载动画开始结束的锁
getData:真正的请求数据函数
mixinsGetData:mixin中的调用getData函数,
 
//mixin.js
//将请求的返回值data和请求数据的函数getData来 module.exports = function (data = []) { return { data() { return { data, //默认的请求返回的数据 loadingFlag: true //动画出现的锁 } }, methods: { async mixinsGetData() {
//以下两句和定义data以及
this.data = await this.getData(); //将getData函数标准化,每个组件的请求远程数据都是这个函数名 this.loadingFlag = false; } } } }
<template>
  <div class="home-container" v-vLoading='loadingFlag' >//自定义的loading动画,靠loadingFlag锁开关
  </div>
</template>
import mixin from './minxin.js'
export default{
  mixins:[mixin()]
  methods:{
      async getData(){
          return await this.$http.get('/mock/banner');
      }
  },
    async created() {
        this.mixinsGetData();//调用mixin的函数
  },  
}