文档: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
例子:注册弹出加载动画的的指令
<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的函数 },
}