vue自定义指令

320 阅读4分钟

自定义指令的基本语法

Vue.js 的自定义指令可以通过 Vue.directive 函数进行注册。该函数接受两个参数:指令名称和一个对象。对象包含指令的定义,其属性名对应着钩子函数,可以按照需要进行实现。

下面是一个示例代码:

Vue.directive('my-directive', {
  bind: function (el, binding) {
    // 绑定时的逻辑
  },
  inserted: function (el, binding) {
    // 插入到 DOM 中后的逻辑
  },
  update: function (el, binding) {
    // 组件更新时的逻辑
  },
  unbind: function (el, binding) {
    // 取消绑定时的逻辑
  }
})

上述代码中,我们使用 Vue.directive 函数来注册一个名为 my-directive 的指令,并传递了一个包含钩子函数的对象作为第二个参数。这些钩子函数将在指令生命周期的不同阶段被调用。

钩子函数

自定义指令的每个钩子函数都有其特定的用途:

  • bind:只调用一次,在指令第一次绑定到元素时调用。在这里可以进行一些初始化设置。
  • inserted:当被绑定的元素插入到 DOM 中时调用。
  • update:当组件更新时被调用,但是可能会被频繁触发,因此要注意性能问题。
  • unbind:只调用一次,在指令与元素解绑时调用。

下面是一个示例代码,其中我们将在 my-directive 指令的 bind 钩子函数中为元素设置样式:

Vue.directive('my-directive', {
  bind: function (el, binding) {
    el.style.backgroundColor = binding.value
  }
})

上述代码中,我们获取了指令的绑定值,并将其用作元素的背景色。

自定义指令的参数

除了钩子函数外,你还可以向自定义指令传递参数。指令参数可以通过指令名称后跟冒号和参数名的方式传递,例如 v-my-directive:param1="value"

在自定义指令中,参数可以通过 binding.arg 进行访问,例如:

Vue.directive('my-directive', {
  bind: function (el, binding) {
    console.log(binding.arg) // 输出 param1
  }
})

自定义指令的修饰符

除了参数外,Vue.js 的自定义指令还支持修饰符。修饰符是以点号 . 开头的特殊后缀,用于调整指令行为。例如,v-my-directive.foo 将添加一个名为 foo 的修饰符。

在自定义指令中,修饰符可以通过 binding.modifiers 进行访问,例如:

Vue.directive('my-directive', {
  bind: function (el, binding) {
    if (binding.modifiers.foo) {
      // 在这里处理 foo 修饰符
    }
  }
})

项目中常用的自定义指令

1. 只允许输入数字的指令

Vue.directive('number-only', {
  bind: function (el) {
    el.addEventListener('input', function () {
      this.value = this.value.replace(/[^\d]/g, '') // 只保留数字
    })
  }
})

该指令绑定到输入框上,只允许用户输入数字,其他字符将被自动删除。

2. 自动聚焦的指令

Vue.directive('autofocus', {
  inserted: function (el) {
    el.focus()
  }
})

该指令绑定到输入框上,页面加载后会自动聚焦到该输入框。

3. 滚动时固定表头的指令

Vue.directive('fixed-header', {
  inserted: function (el, binding) {
    const tableElem = el.querySelector('.table')
    const headerElem = el.querySelector('.header')
    const wrapperElem = el.querySelector('.wrapper')

    wrapperElem.style.overflowY = 'scroll'
    wrapperElem.style.maxHeight = binding.value + 'px'

    tableElem.style.width = '100%'
    headerElem.style.position = 'sticky'
    headerElem.style.top = 0
    headerElem.style.zIndex = 1
  }
})

该指令绑定到表格包裹元素上,在滚动时固定表头。其中,binding.value 表示表格内容的最大高度。

4. 点击元素外部关闭弹框的指令

Vue.directive('click-outside', {
  bind: function (el, binding) {
    const handler = function (e) {
      if (!el.contains(e.target)) { // 判断点击位置是否在绑定元素内部
        binding.value()
      }
    }
    el.__vueClickOutside__ = handler
    document.addEventListener('click', handler)
  },
  unbind: function (el) {
    document.removeEventListener('click', el.__vueClickOutside__)
    delete el.__vueClickOutside__
  }
})

该指令绑定到需要关闭的弹框元素上,当用户点击元素外部时,会触发 binding.value 中的回调函数来关闭弹框。

5. 点击回车触发事件的指令

Vue.directive('enter', {
  bind: function (el, binding) {
    el.addEventListener('keyup', function (e) {
      if (e.keyCode === 13) {
        binding.value()
      }
    })
  }
})

该指令绑定到输入框上,当用户按下回车键时,会触发 binding.value 中的回调函数来执行相应的操作。

6. 图片懒加载的指令

Vue.directive('lazyload', {
  inserted: function (el, binding) {
    const img = new Image()
    img.src = binding.value // 绑定值为图片真实地址
    img.onload = function () {
      el.setAttribute('src', img.src)
    }
  }
})

该指令绑定到需要懒加载的图片元素上,当图片元素进入可视区域时,会将 binding.value 中的图片地址设置为 el 元素的 src 属性,从而实现图片懒加载。需要注意的是,该指令只适用于静态图片。对于动态生成的图片,可以使用第三方库,如 vue-lazyload

7. 控制元素显示/隐藏的指令

Vue.directive('show', {
  bind: function (el, binding) {
    el.style.display = binding.value ? 'block' : 'none'
  },
  update: function (el, binding) {
    el.style.display = binding.value ? 'block' : 'none'
  }
})

该指令绑定到需要控制显示/隐藏的元素上,当 binding.value 为真时,元素会显示;否则,元素会隐藏。特别地,该指令在 update 钩子函数中也进行了处理,以便于在动态修改绑定值时可以实时更新元素的显示状态。

8. 禁用右键菜单的指令

Vue.directive('disable-right-click', {
  bind: function (el) {
    el.addEventListener('contextmenu', function (e) {
      e.preventDefault()
    })
  }
})

该指令绑定到需要禁用右键菜单的元素上,当用户右击该元素时,会阻止浏览器默认的右键菜单弹出事件,从而实现禁用右键菜单的效果。