网站/小程序/APP个性化定制开发,二开,改版等服务,加扣:8582-36016

    这篇文章主要为大家详细介绍了Vue中自定义指令directive的使用方法,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下

    1. 一个指令定义对象可以提供如下几个钩子函数(均为可选)

    bind:只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置。

    inserted:被绑定元素插入父节点时调用(仅保证父节点存在,但不一定已被插入文档中)。

    update:只要当前元素不被移除,其他操作几乎都会触发这2个生命周期,先触发update后触发componentUpdate。虚拟DOM什么时候更新:只要涉及到元素的隐藏、显示(display)值的改变、内容的改变等都会触发虚拟DOM更新.

    componentUpdated:组件更新

    unbind:当使用指令的元素被卸载的时候会执行,就是当前元素被移除的时候,只调用一次

    Vue.directive 内置了五个钩子函数 :

    bind(绑定触发)、inserted(插入触发)、update(更新触发)、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:指令绑定的前一个值,仅在update和componentUpdated钩子中可用,无论值是否改变都可用。

    • expression: 绑定值的字符串形式。 例如 v-my-directive=“1 + 1” , expression 的值是 “1 + 1”。

    • arg: 传给指令的参数。例如 v-my-directive:foo, arg 的值是 “foo”。

    • modifiers: 一个包含修饰符的对象。 例如: v-my-directive.foo.bar, 修饰符对象 modifiers 的值是{ foo: true, bar: true }。

    • vnode: Vue 编译生成的虚拟节点

    • oldVnode: 上一个虚拟节点,仅在 update 和 componentUpdated 钩子中可用

    vnode:vue编译生成的虚拟节点

    oldVnode:上一个虚拟节点,仅在update和componentUpdated钩子中可用

    除了el之外,其他参数都应该是只读的,不能修改。如果需要在钩子之间共享数据,建议通过元素的 dataset 来进行。

    3.使用自定义指令场景的示例

    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)
            }
          })
        }
    })

    main.js中引入文件:

    import '@/assets/js/drag.js'

    页面使用:

    <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>

    看下效果吧:

    首先进入页面,

    1.第二个输入框会鼠标聚焦,

    2.点击按钮,会有防止重复点击

    3.图片加载前有默认背景色

    4.弹窗 可以随处移动。右边可拖拽变宽,右下角可以整体变大


    评论 0

    暂无评论
    0
    0
    0
    立即
    投稿
    发表
    评论
    返回
    顶部