本篇内容主要讲解“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%,移动之后赋值为Px if(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 - distX const t = e.clientY - distY //移动当前的元素 dialogDom.style.left = `${l + styL}px` dialogDom.style.top = `${t + styT}px` } document.onmouseup = function(e){ document.onmousemove = null document.onmouseup = null } } } }) //自定义指令示例2:v-dialogDragWidth 可拖动弹窗宽度(右侧边) Vue.directive('dragWidth',{ bind(el) { const dragDom = el.querySelector('.el-dialog'); const lineEl = document.createElement('div'); lineEl.style = 'width: 5px; background: inherit; height: 80%; position: absolute; right: 0; top: 0; bottom: 0; margin: auto; z-index: 1; cursor: w-resize;'; lineEl.addEventListener('mousedown', function (e) { // 鼠标按下,计算当前元素距离可视区的距离 const disX = e.clientX - el.offsetLeft; // 当前宽度 const curWidth = dragDom.offsetWidth; document.onmousemove = function (e) { e.preventDefault(); // 移动时禁用默认事件 // 通过事件委托,计算移动的距离 const l = e.clientX - disX; if(l > 0){ dragDom.style.width = `${curWidth + l}px`; } }; document.onmouseup = function (e) { document.onmousemove = null; document.onmouseup = null; }; }, false); dragDom.appendChild(lineEl); } }) // 自定义指令示例3:v-dialogDragWidth 可拖动弹窗高度(右下角) Vue.directive('dragHeight',{ bind(el) { const dragDom = el.querySelector('.el-dialog'); const lineEl = document.createElement('div'); lineEl.style = 'width: 6px; background: inherit; height: 10px; position: absolute; right: 0; bottom: 0; margin: auto; z-index: 1; cursor: nwse-resize;'; lineEl.addEventListener('mousedown', function(e) { // 鼠标按下,计算当前元素距离可视区的距离 const disX = e.clientX - el.offsetLeft; const disY = e.clientY - el.offsetTop; // 当前宽度 高度 const curWidth = dragDom.offsetWidth; const curHeight = dragDom.offsetHeight; document.onmousemove = function(e) { e.preventDefault(); // 移动时禁用默认事件 // 通过事件委托,计算移动的距离 const xl = e.clientX - disX; const yl = e.clientY - disY dragDom.style.width = `${curWidth + xl}px`; dragDom.style.height = `${curHeight + yl}px`; }; document.onmouseup = function(e) { document.onmousemove = null; document.onmouseup = null; }; }, false); dragDom.appendChild(lineEl); } }) // 自定义指令示例4:图片加载前填充背景色 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; } }) // 自定义指令示例5:输入框聚焦 Vue.directive("focus", { // 当被绑定的元素插入到 DOM 中时…… inserted (el) { // 聚焦元素 el.querySelector('input').focus() }, }); // 自定义指令示例6:设置防抖自定义指令 Vue.directive('throttle', { bind: (el, binding) => { let setTime = binding.value; // 可设置防抖时间 if (!setTime) { // 用户若不设置防抖时间,则默认2s setTime = 1000; } let cbFun; el.addEventListener('click', event => { if (!cbFun) { // 第一次执行 cbFun = setTimeout(() => { cbFun = null; }, setTime); } else { /*如果多个事件监听器被附加到相同元素的相同事件类型上,当此事件触发时, 它们会按其被添加的顺序被调用。如果在其中一个事件监听器中执行 stopImmediatePropagation() ,那么剩下的事件监听器都不会被调用*/ event && event.stopImmediatePropagation(); } }, true); }, }); // 自定义指令示例7:点击按钮操作频繁给出提示 Vue.directive('preventReClick', { inserted: function (el, binding) { el.addEventListener('click', () => { if (!el.disabled) { el.disabled = true Message.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 > <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 v-dragWidth v-dragHeight :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>