[vue] The usage scenarios of vue custom instruction directive:


1. Vue.directive hook function (both are optional)

Vue.directive has five built-in hook functions:
bind (binding trigger), inserted (insert trigger), update (update trigger), componentUpdated (component update trigger) and unbind (unbind trigger)

bind: Called only once, when the directive is bound to the element for the first time. One-time initialization settings can be performed here.
inserted: Called when the bound element is inserted into the parent node (only the parent node is guaranteed to exist, but not necessarily inserted into the document).
update: As long as the current element is not removed, almost all other operations will trigger these two life cycles, first triggering update and then triggering componentUpdate. When is the virtual DOM updated: As long as it involves the hiding of elements, changes in display (display) values, changes in content, etc., virtual DOM updates will be triggered. :Component update: It will be executed when the
componentUpdatedelement
unbindusing the instruction is unloaded, which is the current element When removed, only called once

// 注册
Vue.directive('my-directive',{
    
    
  bind:  function () {
    
    },         
  inserted: function () {
    
    },
  update: function () {
    
    },
  componentUpdated: function () {
    
    },
  unbind: function() {
    
    }
})

2. The instruction hook function will be passed in the following parameters

el: Specifies the bound element, which can be used to directly manipulate the DOM
binding: An object, including the following attributes:
name: Directive name, without the prefix v-
value: Binding value of the directive, for example: v-my-directive="1+1 ", the binding value is 2
oldValue: the previous value bound by the directive, which is only available in the update and componentUpdated hooks, regardless of whether the value has changed.
expression: The string form of the bound value. For example v-my-directive="1 + 1", the value of expression is "1 + 1".
arg: Parameters passed to the command. For example v-my-directive:foo, the value of arg is "foo".
modifiers: An object containing modifiers. For example: v-my-directive.foo.bar, the value of the modifier object modifiers is { foo: true, bar: true }.
vnode: Virtual node generated by Vue compilation
oldVnode: previous virtual node, only available in update and componentUpdated hooks
vnode: virtual node generated by vue compilation
oldVnode: previous virtual node, available only in update and componentUpdated hooks
除了el之外,其他参数都应该是只读的,不能修改。如果需要在钩子之间共享数据,建议通过元素的 dataset 来进行。

3. Example of using custom command scenarios

【1】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)
        }
      })
    }
})
[2] Introduce files in main.js:
import '@/utils/drag.js'
【3】Page use:
<template>
  <div>
    <el-button type="text" @click="dialogVisible = true">点击打开 Dialog</el-button>
    <div style="display:flex">
      <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>
【4】Effect:
第二个输入框会鼠标聚焦,
点击按钮,会有防止重复点击
图片加载前有默认背景色
弹窗 可以随处移动。右边可拖拽变宽,右下角可以整体变大

Guess you like

Origin blog.csdn.net/weixin_53791978/article/details/130145155