Vue_ Custom Instruction Practical Encyclopedia

 v-permission

Background: In some background management systems, we may need to judge some operation permissions according to the user role. In many cases, we roughly add an element to  v-if / v-show display and hide, but if the judgment conditions are cumbersome and multiple places need to be judged, this The code in this way is not only inelegant but also redundant. For this situation, we can handle it through global custom directives.

Requirement: Customize a permission command to display and hide Dom that needs permission judgment.

Ideas:

  1. Customize a permission array
  2. Determine whether the user's permissions are in this array, if so, display it, otherwise remove the Dom
    function checkArray(key) {
      let arr = ['1', '2', '3', '4']
      let index = arr.indexOf(key)
      if (index > -1) {
        return true // 有权限
      } else {
        return false // 无权限
      }
    }
    
    const permission = {
      inserted: function (el, binding) {
        let permission = binding.value // 获取到 v-permission的值
        if (permission) {
          let hasPermission = checkArray(permission)
          if (!hasPermission) {
            // 没有权限 移除Dom元素
            el.parentNode && el.parentNode.removeChild(el)
          }
        }
      },
    }
    
    export default permission

    Use:  v-permission Just give the assignment judgment

    <div class="btns">
      <!-- 显示 -->
      <button v-permission="'1'">权限按钮1</button>
      <!-- 不显示 -->
      <button v-permission="'10'">权限按钮2</button>
    </div>

v-LazyLoad

Background: In e-commerce projects, there are often a large number of pictures, such as banner advertisement pictures, menu navigation pictures, and merchant list header pictures such as Meituan. Too many pictures and too large pictures often affect the loading speed of the page, resulting in a bad user experience, so it is imperative to optimize the lazy loading of pictures.

Requirements: Implement a lazy image loading command, which only loads images in the visible area of ​​the browser.

Ideas:

  1. The principle of lazy loading of pictures is mainly realized by the core logic of judging whether the current picture has reached the visible area
  2. Get all the picture Dom, traverse each picture to judge whether the current picture is within the range of the visible area
  3. If it arrives, set  src the properties of the picture, otherwise display the default picture

There are two ways to achieve lazy loading of images. One is to bind  srcoll events to monitor, and the other is to use it  IntersectionObserver to judge whether the image has reached the visible area, but there are browser compatibility issues.

The following encapsulates a lazy loading instruction compatible with the two methods to determine whether the browser supports  IntersectionObserver the API. If it supports it, use it  IntersectionObserver to implement lazy loading, otherwise use  srcoll the method of event monitoring + throttling.

const LazyLoad = {
  // install方法
  install(Vue, options) {
    const defaultSrc = options.default
    Vue.directive('lazy', {
      bind(el, binding) {
        LazyLoad.init(el, binding.value, defaultSrc)
      },
      inserted(el) {
        if (IntersectionObserver) {
          LazyLoad.observe(el)
        } else {
          LazyLoad.listenerScroll(el)
        }
      },
    })
  },
  // 初始化
  init(el, val, def) {
    el.setAttribute('data-src', val)
    el.setAttribute('src', def)
  },
  // 利用IntersectionObserver监听el
  observe(el) {
    var io = new IntersectionObserver((entries) => {
      const realSrc = el.dataset.src
      if (entries[0].isIntersecting) {
        if (realSrc) {
          el.src = realSrc
          el.removeAttribute('data-src')
        }
      }
    })
    io.observe(el)
  },
  // 监听scroll事件
  listenerScroll(el) {
    const handler = LazyLoad.throttle(LazyLoad.load, 300)
    LazyLoad.load(el)
    window.addEventListener('scroll', () => {
      handler(el)
    })
  },
  // 加载真实图片
  load(el) {
    const windowHeight = document.documentElement.clientHeight
    const elTop = el.getBoundingClientRect().top
    const elBtm = el.getBoundingClientRect().bottom
    const realSrc = el.dataset.src
    if (elTop - windowHeight < 0 && elBtm > 0) {
      if (realSrc) {
        el.src = realSrc
        el.removeAttribute('data-src')
      }
    }
  },
  // 节流
  throttle(fn, delay) {
    let timer
    let prevTime
    return function (...args) {
      const currTime = Date.now()
      const 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

Use, replace the label inside the component  src with v-LazyLoad

<img v-LazyLoad="xxx.jpg" />

Guess you like

Origin blog.csdn.net/qq_41916378/article/details/111298391