• 关于我在项目中封装的一些自定义指令


    什么是指令

    Vue中提供了一套为数据驱动视图更为方便的操作,这些操作被称为指令系统。我们看到的v-来头的行内属性,都是指令,不同的指令可以完成或者实现不同的功能。

    除了核心功能默认内置的指令(v-model和v-show),Vue也允许注册自定义指令

    指令使用的几种方式:

    1. //会实例化一个指令,但这个指令没有参数
    2. `v-xxx`
    3. // -- 将值传到指令中
    4. `v-xxx="value"`
    5. // -- 将字符串传入到指令中,如`v-html="'

      内容

      '"`
    6. `v-xxx="'string'"`
    7. // -- 传参数(`arg`),如`v-bind:class="className"`
    8. `v-xxx:arg="value"`
    9. // -- 使用修饰符(`modifier`)
    10. `v-xxx:arg.modifier="value"`

    如何实现

    注册一个自定义指令类似于组件注册,分为全局注册和局部注册。

    • 全局注册:Vue.directive
    • 局部注册:组件directives属性

    举例如下:

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

    1. Vue.directive('focus',{
    2. inserted:function(el){
    3. // 聚焦元素
    4. el.focus();//页面加载完成之后自动让输入框获取到焦点的小功能
    5. }
    6. })

    局部注册通过在组件options选项中设置directive属性

    1. directive:{
    2. // 指令的定义
    3. focus:{
    4. inserted:function(el){
    5. el.focus()
    6. }
    7. }
    8. }

    然后可以在模板中任何元素上使用v-focus指令,如下:

    <input v-focus />

    自定义指令也想组件一样存在钩子函数:

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

    所有钩子函数的参数都有以下:

    • el:指令所绑定的元素,可以用来直接操作DOM
    • binding:一个对象,包含以下property:
      • name:指令名,不包含v-前缀
      • value:指令的绑定值,例如:v-my-directive=“1+1”中,绑定值为2。
      • oldValue:指令绑定的前一个值, 仅在update和componentUpdate钩子中可用。无论值是否改变都可用。
      • 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和componentUpdate钩子可用

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

    举个栗子:

    1. "{ color: 'white', text: 'hello!' }">
    2. <script>
    3. Vue.directive('demo', function (el, binding) {
    4. console.log(binding.value.color) // "white"
    5. console.log(binding.value.text) // "hello!"
    6. })
    7. script>

    应用场景

    使用自定义指令可以满足我们的日常一些场景,这里我列举几个我在项目中用到的自定义指令:

    • 表单防止重复提交
    • 一键copy的功能

    防止表单重复提交

    1. Vue.directive('throttle', {
    2. inserted(el, binding) {
    3. // 获取指令参数时间,没有则默认赋值为2000
    4. let throttleTime = parseInt(binding.value) || 2000
    5. el.addEventListener('click', () => {
    6. // 第一次执行
    7. if (!el.disabled) {
    8. // 如果是第一次执行则表示可以进行点击操作
    9. el.disabled = true
    10. setTimeout(() => {
    11. el.disabled = false
    12. }, throttleTime)
    13. }
    14. })
    15. }
    16. })
    17. // 2.为button标签设置v-throttle自定义指令
    18. <Button size="large" type="success" v-throttle="5000">新增Button>

     一键复制功能

    1. // 一键复制自定义指令
    2. Vue.directive('copy', {
    3. // 选取文本框内容
    4. // 执行浏览器复制命令
    5. // 复制命令会将当前选中的内容复制到剪切板中(这里就是创建的input标签)
    6. // Input要在正常的编辑状态下原生复制方法才会生效
    7. inserted (el, binding) {
    8. if (!binding.value) {
    9. Message.error('请传入需要复制的内容')
    10. return
    11. }
    12. el.addEventListener('click', () => {
    13. console.log('binding.value', binding.value)
    14. // 模拟输入框
    15. let cInput = document.createElement('input')
    16. if (binding.value.newAccount === '') {
    17. cInput.value = '密码' + ':' + binding.value.newPassword
    18. } else {
    19. cInput.value = `企业名称:${binding.value.newCompanyName} , 用户名:${binding.value.newWebAccount} , 密码:${binding.value.newPassword};`
    20. }
    21. document.body.appendChild(cInput);
    22. cInput.select();
    23. document.execCommand("copy");
    24. Message.success('复制成功')
    25. document.body.removeChild(cInput);
    26. this.dialogVisible = false;
    27. // 这个根据自己业务自定义
    28. Vue.prototype.$emit("afterComfirm");
    29. })
    30. },
    31. componentUpdated(el, { value }) {
    32. el.$value = value;
    33. },
    34. })
    35. // 为button标签设置v-copy自定义指令
    36. <Button size="large" type="success" v-copy="infoObj">新增Button>
    37. // 其中infoObj如下:
    38. infoObj:{
    39. newPassword:this.newPassword,
    40. newAccount:this.newAccount
    41. ...
    42. }
    43. // 后面可以扩展将字段为传入的字段,不要写死

  • 相关阅读:
    C语言:指针详解(5)
    Elasticsearch7从入门到精通(简介、部署、原理、开发、ELK)
    TCP的三次握手和四次挥手 | 查看网络状态
    WPF 通过依赖属性Value更新长历史图表
    Azure KeyVault(四)另类在 .NET Core 上操作 Secrets 的类库方法-----Azure.Security.KeyVault.Secrets
    C++ 罗马数字转整数
    MES如何提升企业数字化能力?
    机器学习入门基础02
    MLIR笔记(2)
    ijkplayer iOS编译问题之[-Wincompatible-function-pointer-types]
  • 原文地址:https://blog.csdn.net/weixin_46872121/article/details/136484391