>[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
- 官网给的工具
- 声明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 源码解读
- 开发感悟
- 练手项目