Evan's blog Evan's blog
首页
关于
  • 分类
  • 标签
  • 归档
  • H5&CSS3
  • JS
  • TS
  • Node
  • Webpack
  • Vue2
  • Vue3
  • 微信小程序
  • Andorid
  • Flutter
推荐
GitHub (opens new window)

conanan

真相只有一个
首页
关于
  • 分类
  • 标签
  • 归档
  • H5&CSS3
  • JS
  • TS
  • Node
  • Webpack
  • Vue2
  • Vue3
  • 微信小程序
  • Andorid
  • Flutter
推荐
GitHub (opens new window)
  • 基础

  • 组件

  • 动画

  • Composition Api

  • 高级语法

    • h 函数 & JSX
    • 自定义指令
      • 介绍
      • 默认的实现方式
      • 局部自定义指令
      • 全局自定义指令 🔥
      • 指令的生命周期、参数、修饰符 🔥
      • 时间戳格式化指令 🔥🔥🔥
    • Teleport
    • 插件
    • nextTick与eventloop
    • historyApiFallback
  • Vue源码

  • VueCLI&Vite

  • VueRouter

  • Vuex

  • 项目

  • Vue3.x
  • 高级语法
xugaoyi
2022-03-24
目录

自定义指令

# 自定义指令

# 介绍

在Vue的模板语法中我们学习过各种各样的指令:v-show、v-for、v-model等等,除了使用这些指令之外,Vue 也允许我们来自定义自己的指令。

  • 注意:在Vue中,代码的复用和抽象主要还是通过组件;
  • 通常在某些情况下,你需要对DOM元素进行底层操作,这个时候就会用到自定义指令;

自定义指令分为两种 :

  • 自定义局部指令:组件中通过 directives 选项,只能在当前组件中使用;
  • 自定义全局指令:app的 directive 方法,可以在任意组件中被使用;

比如我们来做一个非常简单的案例:当某个元素挂载完成后可以自定获取焦点

  • 实现方式一:如果我们使用默认的实现方式;
  • 实现方式二:自定义一个 v-focus 的局部指令;
  • 实现方式三:自定义一个 v-focus 的全局指令;

# 默认的实现方式

<template>
  <div>
    <input type="text" ref="input">
  </div>
</template>

<script>
  import { ref, onMounted } from "vue";

  export default {
    setup() {
      const input = ref(null);

      onMounted(() => {
        input.value.focus();
      })

      return {
        input
      }
    }
  }
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

# 局部自定义指令

  • 在组件 options 选项中使用 directives 即可
  • 它是一个对象,在对象中编写我们自定义指令的名称(注意:这里不需要加v-)
  • 自定义指令有一个生命周期,是在组件挂载后调用的 mounted,我们可以在其中完成操作
<template>
  <div>
    <input type="text" v-focus>
  </div>
</template>

<script>
  export default {
    // 局部指令
    directives: {
      focus: {
        mounted(el, bindings, vnode, preVnode) {
          console.log("focus mounted");
          el.focus();
        }
      }
    }
  }
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

# 全局自定义指令 🔥

上面的局部自定义指令修改:

main.js

import { createApp } from 'vue'

const app = createApp(App)

app.directive("focus", {
  mounted(el, bindings, vnode, preVnode) {
    console.log("focus mounted");
    el.focus();
  }
})

app.mount('#app')
1
2
3
4
5
6
7
8
9
10
11
12

然后直接使用即可!!!

# 指令的生命周期、参数、修饰符 🔥

一个指令定义的对象,Vue提供了如下的几个钩子函数:

  • created:在绑定元素的 attribute 或事件监听器被应用之前调用;
  • beforeMount:当指令第一次绑定到元素并且在挂载父组件之前调用;
  • mounted:在绑定元素的父组件被挂载后调用;
  • beforeUpdate:在更新包含组件的 VNode 之前调用;
  • updated:在包含组件的 VNode 及其子组件的 VNode 更新后调用;
  • beforeUnmount:在卸载绑定元素的父组件之前调用;
  • unmounted:当指令与元素解除绑定且父组件已卸载时,只调用一次;

在我们的生命周期中,我们可以通过 bindings 获取到对应的参数(value)和修饰符对象(modifiers)

<template>
  <div>
    <button v-if="counter < 2" v-why.aaaa.bbbb="'coderwhy'" @click="increment">当前计数: {{counter}}</button>
  </div>
</template>

<script>
  import { ref } from "vue";

  export default {
    // 局部指令
    directives: {
      why: {
        // preVnode 在 updated 节点会有值
        created(el, bindings, vnode, preVnode) {
          console.log("why created", el, bindings, vnode, preVnode);
          console.log(bindings.value);// 字符串
          console.log(bindings.modifiers);// 是个对象
        },
        beforeMount() {
          console.log("why beforeMount");
        },
        mounted() {
          console.log("why mounted");
        },
        beforeUpdate() {
          console.log("why beforeUpdate");
        },
        updated() {
          console.log("why updated");
        },
        beforeUnmount() {
          console.log("why beforeUnmount");
        },
        unmounted() {
          console.log("why unmounted");
        }
      }
    },
    setup() {
      const counter = ref(0);
      const increment = () => counter.value++;

      return {
        counter,
        increment
      }
    }
  }
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50

# 时间戳格式化指令 🔥🔥🔥

开发要求:

  • 在开发中,大多数情况下从服务器获取到的都是时间戳;
  • 我们需要将时间戳转换成具体格式化的时间来展示;
  • 在Vue2中我们可以通过过滤器来完成;
  • 在Vue3中我们可以通过 计算属性(computed) 或者 自定义一个方法(methods) 来完成;
  • 其实我们还可以通过一个自定义的指令来完成;

实现一个可以自动对时间格式化的指令v-format-time

/src/directives/index.js

import registerFormatTime from './format-time';

export default function registerDirectives(app) {
  registerFormatTime(app);
}
1
2
3
4
5

/src/directives/format-time.js

import dayjs from 'dayjs'

export default function (app) {
  app.directive('format-time', {
    created(el, bindings) {
      bindings.formatString = 'YYYY-MM-DD HH:mm:ss'
      if (bindings.value) {
        bindings.formatString = bindings.value
      }
    },
    // 都放入 mounted 也一样!
    mounted(el, bindings) {
      const textContent = el.textContent
      let timestamp = parseInt(textContent)
      if (textContent.length === 10) {
        timestamp = timestamp * 1000
      }
      el.textContent = dayjs(timestamp).format(bindings.formatString)
    },
  })
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

/src/main.js

import registerDirectives from './directives'
registerDirectives(app)
1
2
编辑 (opens new window)
上次更新: 2022/03/24, 16:45:21
h 函数 & JSX
Teleport

← h 函数 & JSX Teleport→

最近更新
01
重点
04-12
02
搭建项目
04-04
03
TS补充
03-30
更多文章>
Theme by Vdoing | Copyright © 2019-2022 conanan | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式