>[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` 的值 */
}
~~~

*****
* 傳入的是字面量
~~~
<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`文件夾 進行統一管理

* 在`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
- 官網給的工具
- 聲明vue2 和 vue3
- 指令速覽
- Mustache -- 語法
- v-once -- 只渲染一次
- v-text -- 插入文本
- v-html -- 渲染html
- v-pre -- 顯示原始的Mustache標簽
- v-cloak -- 遮蓋
- v-memo(新)-- 緩存指定值
- v-if/v-show -- 條件渲染
- v-for -- 循環
- v-bind -- 知識
- v-bind -- 修飾符
- v-on -- 點擊事件
- v-model -- 雙向綁定
- 其他基礎知識速覽
- 快速使用
- 常識知識點
- key -- 作用 (后續要更新)
- computed -- 計算屬性
- watch -- 偵聽
- 防抖和節流
- vue3 -- 生命周期
- vue-cli 和 vite 項目搭建方法
- vite -- 導入動態圖片
- 組件
- 單文件組件 -- SFC
- 組件通信 -- porp
- 組件通信 -- $emit
- 組件通信 -- Provide / Inject
- 組件通信 -- 全局事件總線mitt庫
- 插槽 -- slot
- 整體使用案例
- 動態組件 -- is
- keep-alive
- 分包 -- 異步組價
- mixin -- 混入
- v-model-- 組件
- 使用計算屬性
- v-model -- 自定義修飾符
- Suspense -- 實驗屬性
- Teleport -- 指定掛載
- 組件實例 -- $ 屬性
- Option API VS Composition API
- Setup -- 組合API 入口
- api -- reactive
- api -- ref
- 使用ref 和 reactive 場景
- api -- toRefs 和 toRef
- api -- readonly
- 判斷性 -- API
- 功能性 -- API
- api -- computed
- api -- $ref 使用
- api -- 生命周期
- Provide 和 Inject
- watch
- watchEffect
- watch vs. watchEffect
- 簡單使用composition Api
- 響應性語法糖
- css -- 功能
- 修改css -- :deep() 和 var
- Vue3.2 -- 語法
- ts -- vscode 配置
- attrs/emit/props/expose/slots -- 使用
- props -- defineProps
- props -- defineProps Ts
- emit -- defineEmits
- emit -- defineEmits Ts
- $ref -- defineExpose
- slots/attrs -- useSlots() 和 useAttrs()
- 自定義指令
- Vue -- 插件
- Vue2.x 和 Vue3.x 不同點
- $children -- 移除
- v-for 和 ref
- attribute 強制行為
- 按鍵修飾符
- v-if 和 v-for 優先級
- 組件使用 v-model -- 非兼容
- 組件
- h -- 函數
- jsx -- 編寫
- Vue -- Router
- 了解路由和vue搭配
- vueRouter -- 簡單實現
- 安裝即使用
- 路由懶加載
- router-view
- router-link
- 路由匹配規則
- 404 頁面配置
- 路由嵌套
- 路由組件傳參
- 路由重定向和別名
- 路由跳轉方法
- 命名路由
- 命名視圖
- Composition API
- 路由守衛
- 路由元信息
- 路由其他方法 -- 添加/刪除/獲取
- 服務器配置映射
- 其他
- Vuex -- 狀態管理
- Option Api -- VUEX
- composition API -- VUEX
- module -- VUEX
- 刷新后vuex 數據同步
- 小技巧
- Pinia -- 狀態管理
- 開始使用
- pinia -- state
- pinia -- getter
- pinia -- action
- pinia -- 插件 ??
- Vue 源碼解讀
- 開發感悟
- 練手項目