8个非常实用的Vue自定义指令( 二 )

  • 在移动端要考虑 touchstart , touchend 事件
  • const longpress = {bind: function (el, binding, vNode) {if (typeof binding.value !== 'function') {throw 'callback must be a function'}// 定义变量let pressTimer = null// 创建计时器( 2秒后执行函数 )let start = (e) => {if (e.type === 'click' && e.button !== 0) {return}if (pressTimer === null) {pressTimer = setTimeout(() => {handler()}, 2000)}}// 取消计时器let cancel = (e) => {if (pressTimer !== null) {clearTimeout(pressTimer)pressTimer = null}}// 运行函数const handler = (e) => {binding.value(e)}// 添加事件监听器el.addEventListener('mousedown', start)el.addEventListener('touchstart', start)// 取消计时器el.addEventListener('click', cancel)el.addEventListener('mouseout', cancel)el.addEventListener('touchend', cancel)el.addEventListener('touchcancel', cancel)},// 当传进来的值更新的时候触发componentUpdated(el, { value }) {el.$value = https://www.isolves.com/it/cxkf/qd/2022-02-25/value},// 指令与元素解绑的时候 , 移除事件绑定unbind(el) {el.removeEventListener('click', el.handler)},} export default longpress复制代码使用:给 Dom 加上 v-longpress 及回调函数即可
    <template><button v-longpress="longpress">长按</button></template> <script> export default {methods: {longpress () {alert('长按指令生效')}}} </script>复制代码v-debounce背景:在开发中 , 有些提交保存按钮有时候会在短时间内被点击多次 , 这样就会多次重复请求后端接口 , 造成数据的混乱 , 比如新增表单的提交按钮 , 多次点击就会新增多条重复的数据 。
    需求:防止按钮在短时间内被多次点击 , 使用防抖函数限制规定时间内只能点击一次 。
    思路:
    1. 定义一个延迟执行的方法 , 如果在延迟时间内再调用该方法 , 则重新计算执行时间 。
    2. 将时间绑定在 click 方法上 。
    const debounce = {inserted: function (el, binding) {let timerel.addEventListener('keyup', () => {if (timer) {clearTimeout(timer)}timer = setTimeout(() => {binding.value()}, 1000)})},} export default debounce复制代码使用:给 Dom 加上 v-debounce 及回调函数即可
    <template><button v-debounce="debounceClick">防抖</button></template> <script> export default {methods: {debounceClick () {console.log('只触发一次')}}} </script>复制代码v-emoji背景:开发中遇到的表单输入 , 往往会有对输入内容的限制 , 比如不能输入表情和特殊字符 , 只能输入数字或字母等 。
    我们常规方法是在每一个表单的 on-change 事件上做处理 。
    <template><input type="text" v-model="note" @change="vaidateEmoji" /></template> <script> export default {methods: {vaidateEmoji() {var reg = /[^u4E00-u9FA5|d|a-zA-Z|rns,.?! ,  。?!…—&$=()-+/*{}[]]|s/gthis.note = this.note.replace(reg, '')},},} </script>复制代码这样代码量比较大而且不好维护 , 所以我们需要自定义一个指令来解决这问题 。
    需求:根据正则表达式 , 设计自定义处理表单输入规则的指令 , 下面以禁止输入表情和特殊字符为例 。
    let findEle = (parent, type) => {return parent.tagName.toLowerCase() === type ? parent : parent.querySelector(type)} const trigger = (el, type) => {const e = document.createEvent('htmlEvents')e.initEvent(type, true, true)el.dispatchEvent(e)} const emoji = {bind: function (el, binding, vnode) {// 正则规则可根据需求自定义var regRule = /[^u4E00-u9FA5|d|a-zA-Z|rns,.?! ,  。?!…—&$=()-+/*{}[]]|s/glet $inp = findEle(el, 'input')el.$inp = $inp$inp.handle = function () {let val = $inp.value$inp.value = https://www.isolves.com/it/cxkf/qd/2022-02-25/val.replace(regRule, '')trigger($inp, 'input')}$inp.addEventListener('keyup', $inp.handle)},unbind: function (el) {el.$inp.removeEventListener('keyup', el.$inp.handle)},} export default emoji复制代码使用:将需要校验的输入框加上 v-emoji 即可
    <template><input type="text" v-model="note" v-emoji /></template>复制代码v-LazyLoad背景:在类电商类项目 , 往往存在大量的图片 , 如 banner 广告图 , 菜单导航图 , 美团等商家列表头图等 。图片众多以及图片体积过大往往会影响页面加载速度 , 造成不良的用户体验 , 所以进行图片懒加载优化势在必行 。


    推荐阅读