Vue自定义指令的妙用在使用Element组件库的时候,有些需要的函数没有包含在组件库中,自定义指令就是用来解决这些问题的。代码仓库vue-element-utils也是提供npm包下载usingyarnaddvue-element-utilsnpminstallvue-element-utils入口文件介绍:importelementUtilsfrom'vue-element-utils'Vue.use(elementUtils);例如:选择滚动加载(延迟加载)Dialog拖动位置Dialog拖动宽度和高度Vue自定义指令概念Vue提供内置指令v-model、v-show等,也允许注册自定义指令。在大多数情况下,代码重用和抽象的主要形式是组件。在某些情况下,您仍然需要对普通DOM元素执行低级操作,然后您将使用自定义指令。钩子函数绑定:只调用一次,当指令第一次绑定到元素上时。这里可以进行一次性初始化设置inserted:绑定元素插入到父节点时调用(只保证父节点存在,不一定插入到文档中)update:组件的VNode时调用被更新componentUpdated:组件的VNode在其所有子VNodes更新后调用unbind:只调用一次,当指令与元素解除绑定时调用钩子函数。除了el,其他参数应该是只读的。如果需要在hook之间共享数据,建议通过元素的数据集来完成。el:指令绑定的元素,可用于直接操作DOMbinding:一个对象,包括以下属性:name:指令的名称,不包括v-prefixvalue:指令的绑定值,例如:v-my-directive="1+1",绑定值为2oldValue:指令绑定的前一个值,仅在update和componentUpdatedhooks中可用。是否改变值,expression:字符串形式的指令表达式。例如:在v-my-directive="1+1"中,表达式为"1+1"arg:传递给指令的参数,可选。例如,在v-my-directive:foo中,修饰符对象是“foo”修饰符:一个包含修饰符的对象。比如在v-my-directive.foo.bar中,修饰符对象为{foo:true,bar:true}vnode:Vue编译生成的虚拟节点oldVnode:最后一个虚拟节点,仅在update和componentUpdated中可用hooksSelect滚动加载(延迟加载)当Select组件需要显示大量数据时,滚动加载可以作为一种优化手段,当然还有其他更好的方式,可以参考Vue项目优化总结。Display:exportdefault{bind(el,binding){//获取element-ui定义的滚动框constselectWrap=el.querySelector('.el-select-dropdown.el-select-dropdown__wrap');selectWrap.addEventListener('scroll',function(){/***scrollHeight获取元素内容的高度(只读)**scrollTop获取或设置元素的偏移量,常用于:计算元素内容的位置滚动条,当元素的容器没有方向滚动条时,其scrollTop值默认为0**clientHeight读取元素的可见高度(只读)**如果元素滚动到底部,等式`ele.scrollHeight-ele.scrollTop===ele.clientHeight;`返回true,没有则返回false*/constcondition=this.scrollHeight-this.scrollTop<=this.clientHeight;condition&&binding.value();});}}对话框拖动显示:exportdefault{bind(el){constdialogHeaderEl=el.querySelector('.el-dialog__header');constdragDom=el.querySelector('.el-dialog');dialogHeaderEl.style.cssText+=';光标:移动;';//获取原始属性即domelement.currentStyleFirefoxGooglewindow.getComputedStyle(domelement,null);conststy=dragDom.currentStyle||window.getComputedStyle(dragDom,null);dialogHeaderEl.onmousedown=(e)=>{//当鼠标按下时,计算当前元素到可见区域的距离constdisX=e.clientX-dialogHeaderEl.offsetLeft;constdisY=e.clientY-dialogHeaderEl.offsetTop;//获取到的值替换成px正则匹配letstyL,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){//通过事件委托,计算移动距离constl=e.clientX-disX;constt=e.clientY-disY;//移动当前元素dragDom.style.left=`${l+styL}px`;dragDom.style.top=`${t+styT}px`;//发送当前位置//binding.value({x:e.pageX,y:e.pageY})};document.onmouseup=function(e){document.onmousemove=null;文档.onmouseup=null;};};}}Dialog拖动宽度显示:exportdefault{bind(el){constdragDom=el.querySelector('.el-dialog');constlineEl=document.createElement('div');lineEl.style='宽度:2px;背景:继承;高度:80%;位置:绝对;右:0;顶部:0;底部:0;保证金:自动;z-索引:1;光标:w-调整大小;';lineEl.addEventListener('mousedown',function(e){//当鼠标按下时,计算当前元素与可见区域的距离constdisX=e.clientX-el.offsetLeft;//当前宽度constcurWidth=dragDom.offsetWidth;document.onmousemove=function(e){e.preventDefault();//移动时禁用默认事件//通过事件委托,计算移动距离constl=e.clientX-disX;dragDom.style.width=`${curWidth+l}px`;};document.onmouseup=function(e){document.onmousemove=null;文档.onmouseup=null;};},错误的);拖动域。appendChild(lineEl);}}剪贴板剪贴板显示:consteventUtil={addHandler(element,type,handler){if(element.addEventListener){element.addEventListener(type,handler,false);}elseif(element.attachEvent){element.attachEvent('on'+type,handler);}else{element['on'+type]=handler;}},removeHandler(元素,类型,处理器er){如果(element.removeEventListener){element.removeEventListener(type,handler,false);}elseif(element.detachEvent){element.detachEvent('on'+type,handler);}else{element['on'+type]=null;}}};functionclipboard(text){returnnewPromise((reslove,reject)=>{constinput=document.createElement('input');input.setAttribute('readonly','readonly');input.setAttribute('value',text);document.body.appendChild(input);input.focus();input.setSelectionRange(0,9999);if(document.execCommand('copy')){document.execCommand('copy');reslove(text);}else{reject(newError('复制失败'));}document.body.removeChild(input);});}const$clipboard=clipboard;export{$clipboard}exportdefault{bind:function(el,binding,vnode){if(binding.arg==='成功'){el._clipboard_success=binding.value;}elseif(binding.arg==='error'){el._clipboard_error=binding.value;}else{el._clipboard_message=binding.value;eventUtil.addHandler(el,'click',()=>{//日志(el._clipboard_message);剪贴板(el._clipboard_message).then(msg=>{el._clipboard_success(msg);}).catch(err=>{el._clipboard_error(err);});});}},解除绑定:function(el,binding){if(binding.arg==='success'){deleteel._clipboard_success;}elseif(binding.arg==='error'){deleteel._clipboard_error;}else{删除el._clipboard_message;eventUtil.removeHandler(el,'点击');}}}结语将一些操作DOM的方法改成指令,在Vue中可以大大减少工作量。在npm上打包一些高度可扩展的自定义指令,可供多个项目使用,减少CtrlC代码,可维护性高,也方便有相同需求的同学直接使用
