04-Hooks封装
码路教育 7/24/2022
# 一、Hooks
# 1,为什么要封装Hooks
- 我们都知道,在Vue2中,在同一个.vue组件中,当 data、methods、computed、watch 的体量较大时,代码将变得臃肿。为了解决代码臃肿问题,我们除了拆分组件外,别无它法。
- 在Vue3中,同样存在这样的问题:当我们的组件开始变得更大时,逻辑关注点将越来越多,这会导致组件难以阅读和理解。但是,在Vue3中,我们除了可以拆分组件,还可以使用 Hooks封装来解决这一问题。
- 所谓 Hooks封装,就是把不同的逻辑关注点抽离出来,以达到业务逻辑的独立性。这一思路,也是Vue3 对比Vue2的最大亮点之一。
# 2,如何封装Hooks
- 在 setup 组合的开发模式下,把具体某个业务功能所用到的 ref、reactive、watch、computed、watchEffect 等,提取到一个以 use* 开头的自定义函数中去。
- 封装成 use* 开头的Hooks函数,不仅可以享受到封装带来的便利性,还有利于代码逻辑的复用。Hooks函数的另一个特点是,被复用时可以保持作用域的独立性,即,同一个Hooks函数被多次复用,彼此是不干扰的。
# 3,在哪些情况下需要封装Hooks
- 两种场景:一种是功能类Hooks,即为了逻辑复用的封装;另一种是业务类Hooks,即为了逻辑解耦的封装。下面我给两组代码,说明这两种使用场景。
# 二,实践
# 1,useCounter
// src/hooks/useCounter.ts
import { ref } from "vue"
export default function(){
let counter = ref(0)
let add = ()=>counter.value++
let sub = ()=>counter.value--
return {
counter,
add,
sub
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
组件中使用之,如下:
// Demo.vue
<template>
<h1>useCounter</h1>
<h4>{{ counter }}</h4>
<button @click="add">+1</button>
<button @click="sub">-1</button>
</template>
<script setup>
import useCounter from "./hooks/useCounter";
let { counter, add, sub } = useCounter();
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
# 2,useTitle
// src/hooks/useTitle.ts
import {ref,watch} from "vue"
export default function(title="默认的title"){
let titleRef = ref(title)
watch(titleRef,(newValue,oldNew)=>{
document.title = newValue;
},{
immediate:true
})
return titleRef;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
组件中使用之,如下:
// Demo.vue
<template>
<h1>useTitle</h1>
</template>
<script setup>
import useTitle from "./hooks/useTitle";
let titleRef = useTitle();
setTimeout(() => {
titleRef.value = "hi vue3";
}, 3000);
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
# 3,useScrollPosition
// src/hooks/useScrollPosition.ts
import { ref } from "vue"
export default function(){
let scrollX = ref(0)
let scrollY = ref(0)
document.addEventListener("scroll",()=>{
scrollX.value = window.scrollX
scrollY.value = window.scrollY
})
return {
scrollX,
scrollY
};
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
组件中使用之,如下:
// Demo.vue
<template>
<h1>useScrollPosition</h1>
<div class="content"></div>
<div class="scroll">
<div class="scroll-x">scrollX:{{ scrollX }}</div>
<div class="scroll-y">scrollY:{{ scrollY }}</div>
</div>
</template>
<script setup>
import useScrollPosition from "./hooks/useScrollPosition";
let { scrollX, scrollY } = useScrollPosition();
</script>
<style scoped>
.content {
width: 3000px;
height: 5000px;
}
.scroll {
position: fixed;
right: 30px;
bottom: 30px;
}
</style>
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
# 4,useMousePosition
// src/hooks/useMousePosition.ts
import { ref } from "vue"
export default function(){
let mouseX = ref(0)
let mouseY = ref(0)
window.addEventListener("mousemove",(e)=>{
mouseX.value = e.pageX;
mouseY.value = e.pageY;
})
return {
mouseX,
mouseY,
};
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
组件中使用之,如下:
// Demo.vue
<template>
<h1>useMousePosition</h1>
<div class="mouse">
<div class="mouse-x">mouseX:{{ mouseX }}</div>
<div class="mouse-y">mouseY:{{ mouseY }}</div>
</div>
</template>
<script setup>
import useMousePosition from "./hooks/useMousePosition";
let { mouseX, mouseY } = useMousePosition();
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 5,useLocalStoage
// src/hooks/useLocalStoage.ts
import { ref, watch } from "vue"
// useLocalStoage("token","68656789fsadfsadf78765fasdfadsf")
// useLocalStoage("token")
export default function(key,value){
let data = ref(value)
if(value){
// 存
window.localStorage.setItem(key,JSON.stringify(value))
}else{
// 取
data.value = JSON.parse(window.localStorage.getItem(key))
}
watch(data,(newValue)=>{
window.localStorage.setItem(key,JSON.stringify(newValue))
})
return data;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
组件中使用之,如下:
// Demo.vue
<template>
<h1>useMousePosition</h1>
<button @click="changeData">修改数据</button>
</template>
<script setup>
import useLocalStoage from "./hooks/useLocalStoage";
let data = useLocalStoage("token", "123456789");
console.log("data:", data);
let changeData = () => (data.value = "987654321");
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14