Vue-自定义指令(懒加载)

513 阅读2分钟

图片懒加载

  • vue2官方文档

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

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

      • el:指令所绑定的元素,可以用来直接操作 DOM。
      • binding:一个对象,包含以下 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 来进行。

  •   // 全局注册
       Vue.directive('lazyload', {
         bind: function (el, binding) {
           console.log(el,binding);
           let lazyImageObserve = new IntersectionObserver((entries, observer) => {
             entries.forEach((entry, index) => {
               let lazyImage = entry.target
               if (entry.isIntersecting) {
                 setTimeout(() => {
                   lazyImage.src = binding.value
                   lazyImageObserve.unobserve(lazyImage)
                 },1000)
               }
             })
           })
           lazyImageObserve.observe(el)
         }
       })
    
  •   // 局部注册
      <!DOCTYPE html>
      <html lang="en">
    
      <head>
        <meta charset="UTF-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
    
        <!-- 引入vue文件 -->
        <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
        <style>
          [v-clock] {
            display: none;
          }
          .container {
            width: 80%;
            margin: 0 auto;
          }
          img {
            height: 300px;
            width: 100%;
          }
        </style>
    
      </head>
    
      <body>
        <div v-clock id="box">
          <h3 style="text-align: center;">{{title}}</h3>
          <p class="container" v-for="item in imgs">
            <img v-lazyload="item">
          </p>
        </div>
    
        <script>
          // 全局注册
          // Vue.directive('lazyload', {
          //   bind: function (el, binding) {
          //     console.log(el,binding);
          //     let lazyImageObserve = new IntersectionObserver((entries, observer) => {
          //       entries.forEach((entry, index) => {
          //         let lazyImage = entry.target
          //         if (entry.isIntersecting) {
          //           setTimeout(() => {
          //             lazyImage.src = binding.value
          //             lazyImageObserve.unobserve(lazyImage)
          //           },1000)
          //         }
          //       })
          //     })
          //     lazyImageObserve.observe(el)
          //   }
          // })
    
          const vm = new Vue({
            // 挂载元素
            el: '#box',
            // 局部注册
            directives: {
              lazyload: {
                bind: function (el, binding) {
                  let lazyImageObserve = new IntersectionObserver((entries, observer) => {
                    entries.forEach((entry, index) => {
                      let lazyImage = entry.target
                      if (entry.isIntersecting) {
                        lazyImage.src = binding.value
                        lazyImageObserve.unobserve(lazyImage)
                      }
                    })
                  })
                  lazyImageObserve.observe(el)
                }
              }
            },
            data: {
              title: '我的图片',
              imgs: []
            },
            created() {
              this.getImage()
            },
            methods: {
              getImage() {
                // 模拟数据请求
                new Promise((resolve, reject) => {
                  setTimeout(() => {
                    resolve([
                      './img/微信图片_1.jpg',
                      './img/微信图片_2.jpg',
                      './img/微信图片_3.jpg',
                      './img/微信图片_4.jpg',
                      './img/微信图片_5.jpg',
                      './img/微信图片_6.jpg',
                      './img/微信图片_7.jpg',
                      './img/微信图片_8.jpg',
                      './img/微信图片_9.jpg',
                    ])
                  }, 1000)
                }).then(res => {
                  this.imgs = res
                })
              }
            }
          })
        </script>
      </body>
    
      </html>