1. compostion API VS Option API
理解自定义 Hook
- 作用: 对多个组件重复的功能进行提取封装
- 在 vue2 中, 可以使用 mixin 技术, 在 vue3 中使用自定义 hooks 函数
需求 1
收集用户鼠标点击的页面坐标
hooks/useMousePosition.ts
ts
/*
自定义hooks: 收集用户鼠标点击的页面坐标
*/
import { ref, onMounted, onUnmounted } from "vue";
export default function useMousePosition() {
// 初始化坐标数据
const x = ref(-1);
const y = ref(-1);
// 用于收集点击事件坐标的函数
const updatePosition = (e: MouseEvent) => {
x.value = e.pageX;
y.value = e.pageY;
};
// 挂载后绑定点击监听
onMounted(() => {
document.addEventListener("click", updatePosition);
});
// 卸载前解绑点击监听
onUnmounted(() => {
document.removeEventListener("click", updatePosition);
});
return { x, y };
}
需求 2:
封装异步请求
hooks/useUrlLoader.ts
ts
/*
使用axios发送异步ajax请求
*/
import { ref } from "vue";
import axios from "axios";
export default function useUrlLoader(url: string) {
const result = ref();
const loading = ref(true);
const errorMsg = ref();
axios
.get(url)
.then((response) => {
loading.value = false;
result.value = response.data;
})
.catch((e) => {
loading.value = false;
errorMsg.value = e.message || "未知错误";
});
return {
loading,
result,
errorMsg,
};
}
在组件中使用自定义 hooks
vue<template> <div class="about"> <h2>x: {{ x }}, y: {{ y }}</h2> <hr /> <h2 v-if="loading">LOADING...</h2> <h2 v-else-if="errorMsg">{{ errorMsg }}</h2> <img v-if="result" :src="result.message" alt="" /> </div> </template> <script lang="ts"> import { ref } from "vue"; import useMousePosition from "../hooks/useMousePosition"; import useUrlLoader from "../hooks/useUrlLoader"; export default { setup() { const { x, y } = useMousePosition(); const { loading, result, errorMsg } = useUrlLoader( "https://dog.ceo/api/breeds/image/random" ); return { x, y, loading, result, errorMsg, }; }, }; </script>
泛型强化类型检查
ts
export default function useUrlLoader<T>(url: string) {
const result = ref<T>()
...
}
ts
<template>
<div class="about">
<h2>x: {{x}}, y: {{y}}</h2>
<hr>
<h2 v-if="loading">LOADING...</h2>
<h2 v-else-if="errorMsg">{{errorMsg}}</h2>
<img v-if="result" :src="result[0].url" alt="">
</div>
</template>
<script lang="ts">
import {
ref, watch
} from "vue"
import useMousePosition from '../hooks/useMousePosition'
import useUrlLoader from '../hooks/useUrlLoader'
interface DogResult {
message: string
status: string
}
interface CatResult {
id: string
url: string
width: number
height: number
}
export default {
setup() {
const {x, y} = useMousePosition()
// const {loading, result, errorMsg} = useUrlLoader<DogResult>('https://dog.ceo/api/breeds/image/random')
const {loading, result, errorMsg} = useUrlLoader<CatResult[]>('https://api.thecatapi.com/v1/images/search')
return {
x,
y,
loading,
result,
errorMsg
}
}
}
</script>