Vue 自定义指令有全局注册和局部注册两种方式。先来看看注册全局指令的方式,通过 Vue.directive( id, [definition] ) 方式注册全局指令。然后在入口文件中进行 Vue.use() 调用。
批量注册指令,新建 directives/index.js 文件
1 | import copy from './copy' |
在 main.js 引入并调用
1 | import Vue from 'vue' |
指令定义函数提供了几个钩子函数(可选):
- bind: 只调用一次,指令第一次绑定到元素时调用,可以定义一个在绑定时执行一次的初始化动作。
- inserted: 被绑定元素插入父节点时调用(父节点存在即可调用,不必存在于 document 中)。
- update: 被绑定元素所在的模板更新时调用,而不论绑定值是否变化。通过比较更新前后的绑定值。
- componentUpdated: 被绑定元素所在模板完成一次更新周期时调用。
- unbind: 只调用一次, 指令与元素解绑时调用。
下面分享几个实用的 Vue 自定义指令
- 复制粘贴指令 v-copy
- 长按指令 v-longpress
- 输入框防抖指令 v-debounce
- 禁止表情及特殊字符 v-emoji
- 图片懒加载 v-lazyload
- 权限校验指令 v-permission
- 实现页面水印 v-waterMarker
- 拖拽指令 v-draggable
v-copy
需求
实现一键复制文本内容,用于鼠标右键粘贴。
思路
动态创建 textarea 标签,并设置 readOnly 属性及移出可视区域
将要复制的值赋给 textarea 标签的 value 属性,并插入到 body
选中值 textarea 并复制
将 body 中插入的 textarea 移除
在第一次调用时绑定事件,在解绑时移除事件
1 | const copy = { |
使用
给 Dom 加上 v-copy 及复制的文本即可
1 | <template> |
v-longpress
需求
实现长按,用户需要按下并按住按钮几秒钟,触发相应的事件
思路
创建一个计时器, 2 秒后执行函数
当用户按下按钮时触发 mousedown 事件,启动计时器;用户松开按钮时调用 mouseout 事件。
如果 mouseup 事件 2 秒内被触发,就清除计时器,当作一个普通的点击事件
如果计时器没有在 2 秒内清除,则判定为一次长按,可以执行关联的函数。
在移动端要考虑 touchstart,touchend 事件
1 | const longpress = { |
使用
给 Dom 加上 v-longpress 及回调函数即可
1 | <template> |
v-debounce
背景
在开发中,有些提交保存按钮有时候会在短时间内被点击多次,这样就会多次重复请求后端接口,造成数据的混乱,比如新增表单的提交按钮,多次点击就会新增多条重复的数据。
需求
防止按钮在短时间内被多次点击,使用防抖函数限制规定时间内只能点击一次。
思路
定义一个延迟执行的方法,如果在延迟时间内再调用该方法,则重新计算执行时间。
将时间绑定在 click 方法上。
1 | const debounce = { |
使用
给 Dom 加上 v-debounce 及回调函数即可
1 | <template> |
v-emoji
背景
开发中遇到的表单输入,往往会有对输入内容的限制,比如不能输入表情和特殊字符,只能输入数字或字母等。
我们常规方法是在每一个表单的 on-change 事件上做处理。
1 | <template> |
这样代码量比较大而且不好维护,所以我们需要自定义一个指令来解决这问题。
需求
根据正则表达式,设计自定义处理表单输入规则的指令,下面以禁止输入表情和特殊字符为例。
1 | let findEle = (parent, type) => { |
使用
将需要校验的输入框加上 v-emoji 即可
1 | <template> |
v-lazyload
背景
在类电商类项目,往往存在大量的图片,如 banner 广告图,菜单导航图,美团等商家列表头图等。图片众多以及图片体积过大往往会影响页面加载速度,造成不良的用户体验,所以进行图片懒加载优化势在必行。
需求
实现一个图片懒加载指令,只加载浏览器可见区域的图片。
思路
图片懒加载的原理主要是判断当前图片是否到了可视区域这一核心逻辑实现的
拿到所有的图片 Dom ,遍历每个图片判断当前图片是否到了可视区范围内
如果到了就设置图片的 src 属性,否则显示默认图片
图片懒加载有两种方式可以实现,一是绑定 scroll 事件进行监听,二是使用 IntersectionObserver 判断图片是否到了可视区域,但是有浏览器兼容性问题。
下面封装一个懒加载指令兼容两种方法,判断浏览器是否支持 IntersectionObserver API,如果支持就使用 IntersectionObserver 实现懒加载,否则则使用 scroll 事件监听 + 节流的方法实现。
1 | const lazyload = { |
使用
将组件内 标签的 src 换成 v-lazyload
1 | <img v-lazyload="xxx.jpg" /> |
v-permission
背景
在一些后台管理系统,我们可能需要根据用户角色进行一些操作权限的判断,很多时候我们都是粗暴地给一个元素添加 v-if / v-show 来进行显示隐藏,但如果判断条件繁琐且多个地方需要判断,这种方式的代码不仅不优雅而且冗余。针对这种情况,我们可以通过全局自定义指令来处理。
需求
自定义一个权限指令,对需要权限判断的 Dom 进行显示隐藏。
思路
自定义一个权限数组
判断用户的权限是否在这个数组内,如果是则显示,否则则移除 Dom
1 | function checkArray(key) { |
使用
给 v-permission 赋值判断即可
1 | <div class="btn"> |
v-waterMarker
需求
给整个页面添加背景水印
思路
使用 canvas 特性生成 base64 格式的图片文件,设置其字体大小,颜色等。
将其设置为背景图片,从而实现页面或组件水印效果
1 | function addWaterMarker(str, parentNode, font, textColor) { |
使用,设置水印文案,颜色,字体大小即可
1 | <template> |
v-draggable
需求
实现一个拖拽指令,可在页面可视区域任意拖拽元素。
思路
设置需要拖拽的元素为相对定位,其父元素为绝对定位。
鼠标按下(onmousedown)时记录目标元素当前的 left 和 top 值。
鼠标移动(onmousemove)时计算每次移动的横向距离和纵向距离的变化值,并改变元素的 left 和 top 值
鼠标松开(onmouseup)时完成一次拖拽
1 | const draggable = { |
使用
在 Dom 上加上 v-draggable 即可
1 | <template> |