ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
>[success] # 自定义指令 1. `vue`除了官方提供的指令 ,也支持自定义指令,自定义指令主要是为了重用涉及普通元素的底层 DOM 访问的逻辑 * **自定义局部指令**:组件中通过 `directives `选项,只能在当前组件中使用; ~~~js <template> <div> 1111 <input v-focus /> </div> </template> <script> export default { directives: { focus: { // 生命周期的函数(自定义指令) mounted(el) { console.log('v-focus应用的元素被挂载了', el) el?.focus() }, }, }, } </script> <style></style> ~~~ * **自定义全局指令**:app的 directive 方法,可以在任意组件中被使用 ~~~ import { createApp } from 'vue' const app = createApp(App) app.directive('focus', { // 生命周期的函数(自定义指令) mounted(el) { // console.log("v-focus应用的元素被挂载了", el) el?.focus() }, }) app.mount('#app') ~~~ * 本地的自定义指令在`<script setup>`中不需要显式注册,但他们必须遵循`vNameOfDirective`这样的命名规范 ~~~html <script setup> const vMyDirective = { beforeMount: (el) => { // 在元素上做些操作 } } </script> <template> <h1 v-my-directive>This is a Heading</h1> </template> ~~~ 如果指令是从别处导入的,可以通过重命名来使其符合命名规范: ~~~html <script setup> import { myDirective as vMyDirective } from './MyDirective.js' </script> ~~~ >[info] ## 指令的生命周期 **created**:在绑定元素的 attribute 或事件监听器被应用之前调用; **beforeMount**:当指令第一次绑定到元素并且在挂载父组件之前调用; **mounted**:在绑定元素的父组件被挂载后调用; **beforeUpdate**:在更新包含组件的 VNode 之前调用; **updated**:在包含组件的 VNode 及其子组件的 VNode 更新后调用; **beforeUnmount**:在卸载绑定元素的父组件之前调用; **unmounted**:当指令与元素解除绑定且父组件已卸载时,只调用一次; >[danger] ##### 生命周期的钩子函数 注意 :除了`el`外,其他参数都是只读的,不要更改它们 ~~~ const myDirective = { // 在绑定元素的 attribute 前 // 或事件监听器应用前调用 created(el, binding, vnode, prevVnode) { // 下面会介绍各个参数的细节 }, // 在元素被插入到 DOM 前调用 beforeMount(el, binding, vnode, prevVnode) {}, // 在绑定元素的父组件 // 及他自己的所有子节点都挂载完成后调用 mounted(el, binding, vnode, prevVnode) {}, // 绑定元素的父组件更新前调用 beforeUpdate(el, binding, vnode, prevVnode) {}, // 在绑定元素的父组件 // 及他自己的所有子节点都更新后调用 updated(el, binding, vnode, prevVnode) {}, // 绑定元素的父组件卸载前调用 beforeUnmount(el, binding, vnode, prevVnode) {}, // 绑定元素的父组件卸载后调用 unmounted(el, binding, vnode, prevVnode) {} } ~~~ * 钩子函数的参数 * `el`:指令绑定到的元素。这可以用于直接操作 DOM。 * `binding`:一个对象,包含以下属性。 * `value`:传递给指令的值。例如在`v-my-directive="1 + 1"`中,值是`2`。 * `oldValue`:之前的值,仅在`beforeUpdate`和`updated`中可用。无论值是否更改,它都可用。 * `arg`:传递给指令的参数 (如果有的话)。例如在`v-my-directive:foo`中,参数是`"foo"`。 * `modifiers`:一个包含修饰符的对象 (如果有的话)。例如在`v-my-directive.foo.bar`中,修饰符对象是`{ foo: true, bar: true }`。 * `instance`:使用该指令的组件实例。 * `dir`:指令的定义对象。 * `vnode`:代表绑定元素的底层 VNode。 * `prevNode`:之前的渲染中代表指令所绑定元素的 VNode。仅在`beforeUpdate`和`updated`钩子中可用。 >[danger] ##### 指令传参 ~~~ <template> <div> 1111 <input v-focus:foo.bar="'baz'" /> </div> </template> <script> export default { directives: { focus: { // 生命周期的函数(自定义指令) mounted(el, binding) { console.log(binding) el?.focus() }, }, }, } </script> <style></style> ~~~ * 打印结果 ~~~ { arg: 'foo', modifiers: { bar: true }, value: /* `baz` 的值 */, oldValue: /* 上一次更新时 `baz` 的值 */ } ~~~ ![](https://img.kancloud.cn/3e/97/3e97b46e3739d4731771a25a8af731eb_576x172.png) ***** * 传入的是字面量 ~~~ <div v-demo="{ color: 'white', text: 'hello!' }"></div> ~~~ ~~~ app.directive('demo', (el, binding) => { console.log(binding.value.color) // => "white" console.log(binding.value.text) // => "hello!" }) ~~~ >[danger] ##### 动态传值 ~~~ <div v-example:[arg]="value"></div> ~~~ >[danger] ##### 缩写 对于自定义指令来说,一个很常见的情况是仅仅需要在`mounted`和`updated`上实现相同的行为,除此之外并不需要其他钩子。这种情况下我们可以直接用一个函数来定义指令,如下所示: ~~~ <div v-color="color"></div> ~~~ ~~~ app.directive('color', (el, binding) => { // 这会在 `mounted` 和 `updated` 时都调用 el.style.color = binding.value }) ~~~ >[info] ## 绑定全局 推荐创建一个`directives`文件夹 进行统一管理 ![](https://img.kancloud.cn/a5/77/a57798283dfdcdc7c22f8ba0f56f72ec_242x126.png) * 在`index.js` 统一导出 ~~~ import directiveFocus from "./focus" import directiveUnit from "./unit" import directiveFtime from "./ftime" // export default function useDirectives(app) { // directiveFocus(app) // directiveUnit(app) // directiveFtime(app) // } export default function directives(app) { directiveFocus(app) directiveUnit(app) directiveFtime(app) } ~~~ * 在main.js 注册 ~~~ import directives from "../directives/index" createApp(App).use(directives).mount("#app") ~~~ * 以 `focus.js` 为例可以写成 ~~~ export default function directiveFocus(app) { app.directive("focus", { // 生命周期的函数(自定义指令) mounted(el) { // console.log("v-focus应用的元素被挂载了", el) el?.focus() } }) } ~~~ >[danger] ##### 时间格式化指令 ~~~ import dayjs from 'dayjs' export default function directiveFtime(app) { app.directive("ftime", { mounted(el, bindings) { // 1.获取时间, 并且转化成毫秒 let timestamp = el.textContent if (timestamp.length === 10) { timestamp = timestamp * 1000 } timestamp = Number(timestamp) // 2.获取传入的参数 let value = bindings.value if (!value) { value = "YYYY-MM-DD HH:mm:ss" } // 3.对时间进行格式化 const formatTime = dayjs(timestamp).format(value) el.textContent = formatTime } }) } ~~~ * 使用 ~~~html <h2 v-ftime="'YYYY/MM/DD'">{{ timestamp }}</h2> <h2 v-ftime>{{ 1551111166666 }}</h2> ~~~ >[info] ## 官网 https://cn.vuejs.org/guide/reusability/custom-directives.html#object-literals