[vue] vue 사용자 지정 명령 지시문의 사용 시나리오:


1. Vue.directive 후크 기능(둘 다 선택 사항임)


Vue.directive 에는 bind(바인딩 트리거), insert(삽입 트리거), update(업데이트 트리거), componentUpdated(구성 요소 업데이트 트리거) 및 unbind(바인딩 해제 트리거)의 다섯 가지 내장 후크 기능이 있습니다 .

bind: 디렉티브가 요소에 처음 바인딩될 때 한 번만 호출됩니다. 여기에서 일회성 초기화 설정을 수행할 수 있습니다.
inserted: 바인딩된 요소가 부모 노드에 삽입될 때 호출됩니다(부모 노드만 존재하는 것이 보장되지만 반드시 문서에 삽입되는 것은 아님).
update: 현재 요소가 제거되지 않는 한 거의 모든 다른 작업은 이 두 가지 수명 주기를 트리거합니다. 먼저 업데이트를 트리거한 다음 componentUpdate를 트리거합니다. 가상 DOM 업데이트 시기: 요소 숨기기, 표시 값 변경, 내용 변경 등이 포함되는 한 가상 DOM 업데이트가 트리거됩니다. :컴포넌트 업데이트: 명령을 사용하는 요소가 언로드될 때 실행됩니다.
componentUpdated현재 요소 입니다
unbind. 제거되면 한 번만 호출됩니다.

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

2. 명령 후크 기능은 다음 매개변수로 전달됩니다.

el: DOM을 직접 조작하는 데 사용할 수 있는 바인딩된 요소를 지정합니다.
binding: 다음 속성을 포함하는 객체:
name: 접두사 v-가 없는 지시문 이름
value: 지시문의 바인딩 값(예: v-my-directive=") 1+1 ", 바인딩 값은 2입니다
oldValue. 값이 변경되었는지 여부에 관계없이 업데이트 및 componentUpdated 후크에서만 사용할 수 있는 지시문에 의해 바인딩된 이전 값입니다.
expression: 바운드 값의 문자열 형식입니다. 예를 들어 v-my-directive="1 + 1"인 경우 expression의 값은 "1 + 1"입니다.
arg: 명령에 전달된 매개변수입니다. 예를 들어 v-my-directive:foo에서 arg의 값은 "foo"입니다.
modifiers: 수정자를 포함하는 개체입니다. 예: v-my-directive.foo.bar, 수정자 개체 수정자의 값은 { foo: true, bar: true }입니다.
vnode: Vue 컴파일로 생성된 가상 노드
oldVnode: 이전 가상 노드, 업데이트 및 componentUpdated 후크에서만 사용 가능
vnode: vue 컴파일로 생성된 가상 노드
oldVnode: 이전 가상 노드, 업데이트 및 componentUpdated 후크에서만 사용 가능
除了el之外,其他参数都应该是只读的,不能修改。如果需要在钩子之间共享数据,建议通过元素的 dataset 来进行。

3. 사용자 지정 명령 시나리오 사용 예

【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] main.js에 파일을 소개합니다.
import '@/utils/drag.js'
【3】페이지 사용:
<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】효과:
第二个输入框会鼠标聚焦,
点击按钮,会有防止重复点击
图片加载前有默认背景色
弹窗 可以随处移动。右边可拖拽变宽,右下角可以整体变大

추천

출처blog.csdn.net/weixin_53791978/article/details/130145155