# 逻辑复用

官方传送门 (opens new window)

# 组合式函数

官方传送门 (opens new window)

# 自定义指令

官方传送门 (opens new window)

介绍:除了 Vue 内置的一系列指令 (比如 v-model 或 v-show) 之外,Vue 还允许你注册自定义的指令 (Custom Directives)。

  • 私有自定义指令 , 就是在自己的组件中写着的
  • 全局自定义指令

# 1 vue3 的写法

官方传送门 (opens new window)

自己在项目中测试过的:

全局自定义指令:

<!-- 随意的文件 -->
<p v-bgcolor>测试测试测试</p>
1
2
//main.js
app.directive("bgcolor", {
    // 指令钩子 有哪些可以看下面
    // 及他自己的所有子节点都挂载完成后调用
    mounted(el, binding, vnode, prevVnode) {
        el.style.backgroundColor = "yellow"
    },
})
1
2
3
4
5
6
7
8

私有自定义指令:

<!-- 同一个文件 -->
<p v-colors>测试测试测试</p>
1
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
指令钩子
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
<!-- 随意的文件 -->
<p v-textcolor="'gray'">测试测试测试</p>
<span v-colorsize="{fontsize:'14',color:'red'}">测试文字的大小和颜色</span>

1
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
钩子参数

指令的钩子会传递以下几种参数:

  • el:指令绑定到的元素。这可以用于直接操作 DOM。

  • binding:一个对象,包含以下属性。

    1. value:传递给指令的值。例如在 v-my-directive="1 + 1" 中,值是 2。

    2. oldValue:之前的值,仅在 beforeUpdate 和 updated 中可用。无论值是否更改,它都可用。

    3. arg:传递给指令的参数 (如果有的话)。例如在 v-my-directive:foo 中,参数是 "foo"。

    4. modifiers:一个包含修饰符的对象 (如果有的话)。例如在 v-my-directive.foo.bar 中,修饰符对象是 { foo: true, bar: true }。

    5. instance:使用该指令的组件实例。

    6. 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
<!-- 使用的文件中 -->
<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. 下载图片和文件

// 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
<button v-down="msg">点击下载</button>
1
msg: {
    url: "https://img-blog.csdnimg.cn/cfbbb44edb754049963feb7665b2ec66.png#pic_center",
    name: "image"
}
1
2
3
4
Last Updated: 9/14/2022, 1:33:27 PM