7.2 如何定义和使用组合式函数
18_composition/91_composition_mouse_hooks.html
<!DOCTYPE html>
<html lang='en'>
<head>
<meta charset='UTF-8'>
<meta http-equiv='X-UA-Compatible' content='IE=edge'>
<meta name='viewport' content='width=device-width, initial-scale=1.0'>
<title>鼠标跟随</title>
</head>
<body>
<div id='app'>
鼠标的位置:({{x}}, {{y}})
</div>
</body>
<script src='../lib/vue.global.js'></script>
<script>
const { createApp, ref, onMounted, onUnmounted } = Vue
function useMouse () {
const x = ref(0)
const y = ref(0)
function updatePosition (event) {
x.value = event.pageX
y.value = event.pageY
}
onMounted(() => {
window.addEventListener('mousemove', updatePosition, false)
})
onUnmounted(() => {
window.removeEventListener('mousemove', updatePosition, false)
})
return { x, y }
}
createApp({
setup () {
const { x, y } = useMouse()
return {
x, y
}
}
}).mount('#app')
</script>
</html>
如你所见,核心逻辑完全一致,我们做的只是把它移到一个外部函数中去,并返回需要暴露的状态。和在组件中一样,你也可以在组合式函数中使用所有的组合式 API。现在,useMouse()
的功能可以在任何组件中轻易复用了。
更酷的是,你还可以嵌套多个组合式函数:一个组合式函数可以调用一个或多个其他的组合式函数。
18_composition/92_composition_mouse_more_hooks.html
<!DOCTYPE html>
<html lang='en'>
<head>
<meta charset='UTF-8'>
<meta http-equiv='X-UA-Compatible' content='IE=edge'>
<meta name='viewport' content='width=device-width, initial-scale=1.0'>
<title>鼠标跟随</title>
</head>
<body>
<div id='app'>
鼠标的位置:({{x}}, {{y}})
</div>
</body>
<script src='../lib/vue.global.js'></script>
<script>
const { createApp, ref, onMounted, onUnmounted } = Vue
function useEventListener (target, event, callback) {
onMounted(() => {
target.addEventListener(event, callback, false)
})
onUnmounted(() => {
target.removeEventListener(event, callback, false)
})
}
function useMouse () {
const x = ref(0)
const y = ref(0)
// function updatePosition (event) {
// x.value = event.pageX
// y.value = event.pageY
// }
// onMounted(() => {
// window.addEventListener('mousemove', updatePosition, false)
// })
// onUnmounted(() => {
// window.removeEventListener('mousemove', updatePosition, false)
// })
useEventListener(window, 'mousemove', (event) => {
x.value = event.pageX
y.value = event.pageY
})
return { x, y }
}
createApp({
setup () {
const { x, y } = useMouse()
return {
x, y
}
}
}).mount('#app')
</script>
</html>
7.3 异步状态
在做异步数据请求时,我们常常需要处理不同的状态:加载中、加载成功和加载失败。
18_composition/93_composition_async.html
<!DOCTYPE html>
<html lang='en'>
<head>
<meta charset='UTF-8'>
<meta http-equiv='X-UA-Compatible' content='IE=edge'>
<meta name='viewport' content='width=device-width, initial-scale=1.0'>
<title>异步状态</title>
</head>
<body>
<div id='app'>
<div v-if="error">{{ error }}</div>
<div v-else-if="data">
<ul>
<li v-for="item of data" :key="item.proid">{{ item.proname }}</li>
</ul>
</div>
<div v-else>加载中....</div>
</div>
</body>
<script src='../lib/vue.global.js'></script>
<script>
const { createApp, ref, onMounted } = Vue
createApp({
setup () {
const data = ref(null)
const error = ref(null)
onMounted(() => {
// http://121.89.205.189:3000/apidoc/
// fetch 可以用来做数据的请求,基于promise的
// 请求到的数据需要转换为json 对象,然后再使用
fetch('http://121.89.205.189:3000/api/pro/list')
.then(res => { return res.json() }) // 转换为json格式
.then(res => {
console.log(res)
data.value = res.data
}).catch(err => {
error.value = err
})
})
return {
data, error
}
}
}).mount('#app')
</script>
</html>
如果在每个需要获取数据的组件中都要重复这种模式,那就太繁琐了。让我们把它抽取成一个组合式函数:
18_composition/94_composition_async_hooks.html
<!DOCTYPE html>
<html lang='en'>
<head>
<meta charset='UTF-8'>
<meta http-equiv='X-UA-Compatible' content='IE=edge'>
<meta name='viewport' content='width=device-width, initial-scale=1.0'>
<title>异步状态</title>
</head>
<body>
<div id='app'>
<div v-if="error">{{ error }}</div>
<div v-else-if="data">
<ul>
<li v-for="item of data" :key="item.proid">{{ item.proname }}</li>
</ul>
</div>
<div v-else>加载中....</div>
</div>
</body>
<script src='../lib/vue.global.js'></script>
<script>
const { createApp, ref, onMounted } = Vue
function useFetch (url) {
const data = ref(null)
const error = ref(null)
onMounted(() => {
// http://121.89.205.189:3000/apidoc/
// fetch 可以用来做数据的请求,基于promise的
// 请求到的数据需要转换为json 对象,然后再使用
fetch(url)
.then(res => { return res.json() }) // 转换为json格式
.then(res => {
console.log(res)
data.value = res.data
}).catch(err => {
error.value = err
})
})
return { data, error }
}
createApp({
setup () {
const { data, error } = useFetch('http://121.89.205.189:3000/api/pro/list')
return {
data, error
}
}
}).mount('#app')
</script>
</html>
useFetch()
接收一个静态的 URL 字符串作为输入,所以它只执行一次请求,然后就完成了。但如果我们想让它在每次 URL 变化时都重新请求呢?那我们可以让它同时允许接收 ref 作为参数:
95_composition_async_hooks_urls.html
- 思考题