# 逻辑复用
# 组合式函数
# 自定义指令
介绍:除了 Vue 内置的一系列指令 (比如 v-model 或 v-show) 之外,Vue 还允许你注册自定义的指令 (Custom Directives)。
- 私有自定义指令 , 就是在自己的组件中写着的
- 全局自定义指令
# 1 vue3 的写法
自己在项目中测试过的:
全局自定义指令:
<!-- 随意的文件 -->
<p v-bgcolor>测试测试测试</p>
1
2
2
//main.js
app.directive("bgcolor", {
// 指令钩子 有哪些可以看下面
// 及他自己的所有子节点都挂载完成后调用
mounted(el, binding, vnode, prevVnode) {
el.style.backgroundColor = "yellow"
},
})
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
私有自定义指令:
<!-- 同一个文件 -->
<p v-colors>测试测试测试</p>
1
2
2
// 同一个文件
<script>
const colors = {
mounted: (el) => { el.style.backgroundColor = "gray" }
}
const colorsize = (el, binding, vnode, prevNode) => {
el.style.fontSize = binding.value.fontsize + "px"
el.style.color = binding.value.color
}
export default {
name: 'ziDingYiZhiLing',
// 私有自定义指令的节点
directives: {
colors,
colorsize,
},
data() {
return {};
},
};
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
指令钩子
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) {}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<!-- 随意的文件 -->
<p v-textcolor="'gray'">测试测试测试</p>
<span v-colorsize="{fontsize:'14',color:'red'}">测试文字的大小和颜色</span>
1
2
3
4
2
3
4
// main.js
// 简化形式
const app = createApp(App)
app.directive("textcolor", (el, binding) => {
// 钩子参数 具体看下面
// 这会在 `mounted` 和 `updated` 时都调用
el.style.color = binding.value
})
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
钩子参数
指令的钩子会传递以下几种参数:
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 钩子中可用。
在组件上使用
可以在组件上使用 <MyComponent v-demo="test" />,会挂载到组件中的根节点上
但是,组件可能含有多个根节点 会抛出一个警告
所以 不推荐在组件上使用
# 案例
# 1. enter 聚焦到下一个input
自己写的一个,需要id 为#input data-index 来互相配合
// main.js
const app = createApp(App)
// 全局自定义指令 实现按下enter后,光标自动跳转下一个输入框
app.directive("enterNextInput", (el) => {
el.addEventListener("keypress", (e) => {
// console.log("keypress", e);
// 这个获取元素的属性index的名字是要配合 data-index 这边的名字的
// console.log("dataindex", e.srcElement.dataset.index);
let dataIndex = Number(e.srcElement.dataset.index);
// 触发的是enter键
if (e.key === "Enter") {
console.log("触发的是enter", e.key);
let dom = document.querySelectorAll("#input")
// console.log("获取所有的input", dom);
if (dataIndex >= 0 && dataIndex < dom.length - 1) {
// 有下一个input 就实现下一个聚焦
const element = dom[dataIndex + 1];
console.log("下一个的dom元素是:", element);
element.focus()
}
}
})
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<!-- 使用的文件中 -->
<template>
<div>
<div id="box" v-enterNextInput>
<input type="text" id="input">
<input type="text" id="input">
<input type="text" id="input">
<input type="text" id="input">
<input type="text" id="input">
</div>
</div>
</template>
<script>
export default {
name: 'anLiNextInput',
data() {
return { };
},
mounted() {
let box = document.querySelector("#box");
let dom = box.querySelectorAll("#input")
for (let i = 0; i < dom.length; i++) {
const element = dom[i];
element.setAttribute("data-index", i)
}
},
};
</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
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
# 2. 下载图片和文件
// main.js
const app = createApp(App)
app.directive('down', (el, binding) => {
el.style.cssText = 'cursor: pointer;color:write;'
el.addEventListener('click', () => {
console.log(binding.value)
let link = document.createElement('a')
// 文件的地址
// let url = baseDownloadUrl + binding.value
let url = binding.value.url
// 这里是将url转成blob地址,
fetch(url).then(res => res.blob()).then(blob => {
// 将链接地址字符内容转变成blob地址
link.href = URL.createObjectURL(blob)
console.log(link.href)
// 文件下载下来的名字
// link.download = ""
link.download = binding.value.name
document.body.appendChild(link)
link.click()
})
})
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<button v-down="msg">点击下载</button>
1
msg: {
url: "https://img-blog.csdnimg.cn/cfbbb44edb754049963feb7665b2ec66.png#pic_center",
name: "image"
}
1
2
3
4
2
3
4