> 文章列表 > vue 自定义指令directive的使用场景

vue 自定义指令directive的使用场景

vue 自定义指令directive的使用场景

1. 一个指令定义对象可以提供如下几个钩子函数(均为可选)

  • bind:只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置。
  • inserted:被绑定元素插入父节点时调用(仅保证父节点存在,但不一定已被插入文档中)。
  • update:只要当前元素不被移除,其他操作几乎都会触发这2个生命周期,先触发update后触发componentUpdate。虚拟DOM什么时候更新:只要涉及到元素的隐藏、显示(display)值的改变、内容的改变等都会触发虚拟DOM更新.
  • componentUpdated:组件更新
  • unbind:当使用指令的元素被卸载的时候会执行,就是当前元素被移除的时候,只调用一次

Vue.directive 内置了五个钩子函数 :
bind(绑定触发)、inserted(插入触发)、update(更新触发)、componentUpdated(组件更新触发)和unbind(解绑触发)函

 // 注册Vue.directive('my-directive',{bind:  function () {},         inserted: function () {},update: function () {},componentUpdated: function () {},unbind: function() {}})

2.指令钩子函数会被传入以下参数

  • el:指定所绑定的元素,可以用来直接操作DOM
  • binding:一个对象,包含以下属性:
    • name:指令名,不包含前缀v-
    • value:指令的绑定值,例如:v-my-directive="1+1"中,绑定值为2
    • oldValue:指令绑定的前一个值,仅在update和componentUpdated钩子中可用,无论值是否改变都可用。
    • expression: 绑定值的字符串形式。 例如 v-my-directive=“1 + 1” , expression 的值是 “1 + 1”。
    • arg: 传给指令的参数。例如 v-my-directive:foo, arg 的值是 “foo”。
    • modifiers: 一个包含修饰符的对象。 例如: v-my-directive.foo.bar, 修饰符对象 modifiers 的值是{ foo: true, bar: true }。
    • vnode: Vue 编译生成的虚拟节点
    • oldVnode: 上一个虚拟节点,仅在 update 和 componentUpdated 钩子中可用
  • vnode:vue编译生成的虚拟节点
  • oldVnode:上一个虚拟节点,仅在update和componentUpdated钩子中可用

除了el之外,其他参数都应该是只读的,不能修改。如果需要在钩子之间共享数据,建议通过元素的 dataset 来进行。

3.使用自定义指令场景的示例

drag.js

import Vue from 'vue'
import { Message } from 'element-ui';// 自定义指令示例1:弹窗拖拽
Vue.directive('dialogDrag',{bind(el,binding,vnode,oldVnode){const dialogHeader = el.querySelector('.el-dialog__header');const dialogDom = el.querySelector('.el-dialog');dialogHeader.style.cursor = 'move'/* 不同浏览器获取行内样式属性* ie浏览器:       dom元素.currentStyle* 火狐浏览器:window.getComputedStyle(dom元素, null)*/const sty = dialogDom.currentStyle || window.getComputedStyle(dialogDom, null)dialogHeader.onmousedown = (e) => {//按下鼠标,获取点击的位置 距离 弹窗的左边和上边的距离//点击的点距离左边窗口的距离 - 弹窗距离左边窗口的距离const distX = e.clientX - dialogHeader.offsetLeft;const distY = e.clientY - dialogHeader.offsetTop;//弹窗的left属性值和top属性值let styL, styT//注意在ie中,第一次获取到的值为组件自带50%,移动之后赋值为Pxif(sty.left.includes('%')){styL = +document.body.clientWidth * (+sty.left.replace(/%/g,'') / 100)styT = +document,body.clientHeight * (+sty.top.replace(/%/g,'') / 100)}else{styL = +sty.left.replace(/px/g,'');styT = +sty.top.replace(/px/g,'');}document.onmousemove = function(e) {//通过事件委托,计算移动距离const l = e.clientX - distXconst t = e.clientY - distY//移动当前的元素dialogDom.style.left = `${l + styL}px`dialogDom.style.top = `${t + styT}px`}document.onmouseup = function(e){document.onmousemove = nulldocument.onmouseup = null}}}
})// 自定义指令示例2:图片加载前填充背景色
Vue.directive('imgUrl',function(el,binding){var color=Math.floor(Math.random()*1000000);//设置随机颜色el.style.backgroundColor='#'+color;var img=new Image();img.src=binding.value;// -->binding.value指的是指令后的参数img.onload=function(){el.style.backgroundColor='';el.src=binding.value;      }})// 自定义指令示例3:输入框聚焦
Vue.directive("focus", {// 当被绑定的元素插入到 DOM 中时……inserted (el) {// 聚焦元素el.querySelector('input').focus()},});// 自定义指令示例4:设置防抖自定义指令
Vue.directive('throttle', {bind: (el, binding) => {let setTime = binding.value; // 可设置防抖时间if (!setTime) { // 用户若不设置防抖时间,则默认2ssetTime = 1000;}let cbFun;el.addEventListener('click', event => {if (!cbFun) { // 第一次执行cbFun = setTimeout(() => {cbFun = null;}, setTime);} else {/*如果多个事件监听器被附加到相同元素的相同事件类型上,当此事件触发时,它们会按其被添加的顺序被调用。如果在其中一个事件监听器中执行 stopImmediatePropagation() ,那么剩下的事件监听器都不会被调用*/event && event.stopImmediatePropagation();}}, true);},});// 自定义指令示例5:点击按钮操作频繁给出提示Vue.directive('preventReClick', {inserted: function (el, binding) {el.addEventListener('click', () => {if (!el.disabled) {el.disabled = trueMessage.warning('操作频繁')setTimeout(() => {el.disabled = false//可设置时间}, binding.value || 3000)}})}
})

main.js中引入文件:

import '@/assets/js/drag.js'

页面使用:

<template><div><el-button type="text" @click="dialogVisible = true">点击打开 Dialog</el-button><div style="display:flex"><img v-imgUrl="url"></img> <img v-imgUrl="url"></img> <img v-imgUrl="url"></img> <img v-imgUrl="url"></img> <img v-imgUrl="url"></img> <img v-imgUrl="url"></img> <img v-imgUrl="url"></img> <img v-imgUrl="url"></img> </div><div><el-input  placeholder="请选择日期" suffix-icon="el-icon-date"  v-model="input1"></el-input><el-input v-focus placeholder="请输入内容" prefix-icon="el-icon-search" v-model="input2"></el-input></div><div><el-button type="danger" v-throttle @click="throttleBtn">危险按钮</el-button><el-button @click="submitForm()">创建</el-button></div><el-dialog title="提示" v-dialogDrag :visible.sync="dialogVisible" width="30%" :before-close="handleClose"><span>这是一段信息</span><span slot="footer" class="dialog-footer"><el-button @click="dialogVisible = false">取 消</el-button><el-button type="primary" @click="dialogVisible = false">确 定</el-button></span></el-dialog></div>
</template><script>export default {data() {return {dialogVisible: false,url:'//www.baidu.com/img/flexible/logo/pc/result.png',input1: '',input2: '',}},methods: {handleClose(done) {console.log('弹窗打开')  },throttleBtn(){console.log('我的用来测试防抖的按钮')},submitForm(){this.$message.error('Message 消息提示每次只能1个');}},
}
</script>
<style>
img{width: 100px;height: 100px;
}
</style>

看下效果吧:
首先进入页面,

  1. 第二个输入框会鼠标聚焦,
  2. 点击按钮,会有防止重复点击
  3. 图片加载前有默认背景色
  4. 弹窗可以移动
    vue 自定义指令directive的使用场景