zoukankan      html  css  js  c++  java
  • vue项目中常用自定义指令的使用

    一、vue项目中使用自定义指令

    1、在src目录下新建directives/index.js

    import copy from './js/copy';
    import longPress from './js/longPress';
    import debounce from './js/debounce';
    import inputNumber from './js/inputNumber';
    import waterMarker from './js/waterMarker';
    import draggable from './js/draggable';
    
    const directives = {
      copy,
      longPress,
      debounce,
      inputNumber,
      waterMarker,
      draggable
    }
    
    export default {
      install(Vue){
        Object.keys(directives).forEach(key=>{
          Vue.directive(key, directives[key])
        })
      }
    }
    

    2、在 main.js 引入并调用

    //引入自定义指令
    import Vue from 'vue'
    import Directives from './directives/index';
    Vue.use(Directives);
    

    二、项目中几个常用自定义指令

    1、v-copy

    /*
      需求:实现一键复制文本内容,用于鼠标右键粘贴。
      思路:
        1、动态创建 textarea 标签,并设置 readOnly 属性及移出可视区域
        2、将要复制的值赋给 textarea 标签的 value 属性,并插入到 body
        3、选中值 textarea 并复制
        4、将 body 中插入的 textarea 移除
        5、在第一次调用时绑定事件,在解绑时移除事件
      使用:给 Dom 加上 v-copy 及复制的文本即可
      例子:<button v-copy="copyText">一键复制</button>
    */
    export default {
      bind(el, { value }) {
        el.$value = value
        el.handler = () => {
          if (!el.$value) {
            // 值为空的时候,给出提示。可根据项目UI仔细设计
            console.log('无复制内容')
            return
          }
          // 动态创建 textarea 标签
          const textarea = document.createElement('textarea')
          // 将该 textarea 设为 readonly 防止 iOS 下自动唤起键盘,同时将 textarea 移出可视区域
          textarea.readOnly = 'readonly'
          textarea.style.position = 'absolute'
          textarea.style.left = '-9999px'
          // 将要 copy 的值赋给 textarea 标签的 value 属性
          textarea.value = el.$value
          // 将 textarea 插入到 body 中
          document.body.appendChild(textarea)
          // 选中值并复制
          textarea.select()
          const result = document.execCommand('Copy')
          if (result) {
            console.log('复制成功') // 可根据项目UI仔细设计
          }
          document.body.removeChild(textarea)
        }
        // 绑定点击事件,就是所谓的一键 copy 啦
        el.addEventListener('click', el.handler)
      },
      // 当传进来的值更新的时候触发
      componentUpdated(el, { value }) {
        el.$value = value
      },
      // 指令与元素解绑的时候,移除事件绑定
      unbind(el) {
        el.removeEventListener('click', el.handler)
      },
    }
    

    2、v-debounce

    /*
      需求:防止按钮在短时间内被多次点击,使用防抖函数限制规定时间内只能点击一次。
    
      思路:
        1、第一次点击,立即调用方法并禁用按钮,等延迟结束再次激活按钮
        2、将需要触发的方法绑定在指令上
      
      使用:给 Dom 加上 v-debounce 及回调函数即可
      <button v-debounce="debounceClick">防抖提交</button>
    */
    export default {
      inserted: function (el, binding) {
        let timer
        el.addEventListener('click', () => {
          if (timer) {
            clearTimeout(timer)
          }
          if (!el.disabled) {
            el.disabled = true;
            binding.value();
            timer = setTimeout(() => {
              el.disabled = false
            }, 1000)
          }
        })
      },
    }
    

    3、v-longPress

    /*
      需求:实现长按,用户需要按下并按住按钮几秒钟,触发相应的事件
      思路:
        1、创建一个计时器, 2 秒后执行函数
        2、当用户按下按钮时触发 mousedown 事件,启动计时器;用户松开按钮时调用 mouseout 事件。
        3、如果 mouseup 事件 2 秒内被触发,就清除计时器,当作一个普通的点击事件
        4、如果计时器没有在 2 秒内清除,则判定为一次长按,可以执行关联的函数。
        5、在移动端要考虑 touchstart,touchend 事件
      使用:<button v-longpress="longpress">长按</button>
    */
    
    export default {
      bind: function (el, binding) {
        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 = value
      },
      // 指令与元素解绑的时候,移除事件绑定
      unbind(el) {
        el.removeEventListener('click', el.handler)
      }
    }
    

    4、v-inputNumber

    /*
      需求:根据正则表达式,设计自定义处理表单输入规则的指令,这里只能输入正整数
      
      使用:将需要校验的输入框加上 v-inputNumber 即可
       <input type="text" v-model="note" v-inputNumber />
    */
    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)
    }
    export default {
      bind: function (el, binding, vnode) {
        // 正则规则可根据需求自定义
        var regRule = /[^0-9]/g
        let $inp = findEle(el, 'input')
        el.$inp = $inp
        $inp.handle = function () {
          let val = $inp.value
          $inp.value = val.replace(regRule, '')
    
          trigger($inp, 'input')
        }
        $inp.addEventListener('keyup', $inp.handle)
      },
      unbind: function (el) {
        el.$inp.removeEventListener('keyup', el.$inp.handle)
      }
    }
    

    5、v-waterMarker

    /*
      需求:给整个页面添加背景水印。
    
      思路:
        1、使用 canvas 特性生成 base64 格式的图片文件,设置其字体大小,颜色等。
        2、将其设置为背景图片,从而实现页面或组件水印效果
      
      使用:设置水印文案,颜色,字体大小即可
      <div v-waterMarker="{text:'版权所有',textColor:'rgba(180, 180, 180, 0.4)'}"></div>
    */
    
    function addWaterMarker(str, parentNode, font, textColor) {
      // 水印文字,父元素,字体,文字颜色
      var can = document.createElement('canvas')
      parentNode.appendChild(can)
      can.width = 200
      can.height = 150
      can.style.display = 'none'
      var cans = can.getContext('2d')
      cans.rotate((-20 * Math.PI) / 180)
      cans.font = font || '16px Microsoft JhengHei'
      cans.fillStyle = textColor || 'rgba(180, 180, 180, 0.3)'
      cans.textAlign = 'left'
      cans.textBaseline = 'Middle'
      cans.fillText(str, can.width / 10, can.height / 2)
      parentNode.style.backgroundImage = 'url(' + can.toDataURL('image/png') + ')'
    }
    
    export default {
      bind: function (el, binding) {
        addWaterMarker(binding.value.text, el, binding.value.font, binding.value.textColor)
      }
    }
    

    6、v-draggable

    /*
      需求:实现一个拖拽指令,可在父元素区域任意拖拽元素。
    
      思路:
        1、设置需要拖拽的元素为absolute,其父元素为relative。
        2、鼠标按下(onmousedown)时记录目标元素当前的 left 和 top 值。
        3、鼠标移动(onmousemove)时计算每次移动的横向距离和纵向距离的变化值,并改变元素的 left 和 top 值
        4、鼠标松开(onmouseup)时完成一次拖拽
      
      使用:在 Dom 上加上 v-draggable 即可
      <div class="dialog-model" v-draggable></div>
    */
    export default {
      inserted: function (el) {
        el.style.cursor = 'move';
        el.style.position="absolute";
        el.onmousedown = function (e) {
          let disx = e.pageX - el.offsetLeft
          let disy = e.pageY - el.offsetTop
          document.onmousemove = function (e) {
            let x = e.pageX - disx
            let y = e.pageY - disy
            let maxX = parseInt(window.getComputedStyle(el.parentNode).width) - parseInt(window.getComputedStyle(el).width)
            let maxY = parseInt(window.getComputedStyle(el.parentNode).height) - parseInt(window.getComputedStyle(el).height)
            if (x < 0) {
              x = 0
            } else if (x > maxX) {
              x = maxX
            }
    
            if (y < 0) {
              y = 0
            } else if (y > maxY) {
              y = maxY
            }
            el.style.left = x + 'px'
            el.style.top = y + 'px'
          }
          document.onmouseup = function () {
            document.onmousemove = document.onmouseup = null
          }
        }
      }
    }
    
  • 相关阅读:
    77. Combinations
    319. Bulb Switcher
    222.Count Complete Tree Nodes
    842.Split Array into Fibonacci Sequence
    306.Additive Number
    747.Largest Number At Least Twice of Others
    并查集
    HDU-3371 Connect the Cities
    HDU-1863 畅通工程
    HDU-1879 继续畅通工程
  • 原文地址:https://www.cnblogs.com/sgs123/p/14171408.html
Copyright © 2011-2022 走看看