Vue3 入坑 Chapter 3
声明周期
Vue2生命周期

vue2_lifecycle.png
Vue3声明周期

vue3_lifecycle.jpg
Vue2 与 Vue3 版本生命周期相对应的组合式 API
beforeCreate -> 使用 setup()
created -> 使用 setup()
beforeMount -> onBeforeMount
mounted -> onMounted
beforeUpdate -> onBeforeUpdate
updated -> onUpdated
beforeDestroy -> onBeforeUnmount
destroyed -> onUnmounted
errorCaptured -> onErrorCaptured
示例代码
父组件中
<template>
<div class="lifeCycleTest">
<h2>APP父级组件</h2>
<button @click="isShow=!isShow">切换显示</button>
<hr />
<lifecycle-child-test v-if="isShow"></lifecycle-child-test>
<hr />
<lifecycle-child-test2 v-if="isShow"></lifecycle-child-test2>
</div>
</template>
<script lang="ts">
import LifecycleChildTest from '@/components/LifecycleChildTest.vue'
import LifecycleChildTest2 from '@/components/LifecycleChildTest2.vue'
import { defineComponent, ref } from 'vue'
export default defineComponent({
name: 'LifecycleTest',
// 注册组件
components: {
LifecycleChildTest,
LifecycleChildTest2
},
setup () {
const isShow = ref(true)
return {
isShow
}
}
})
</script>
<style lang="scss" scoped>
</style>
子组件1中(Vue2)
<template>
<div class="LifecycleChildTest">
<h2>Child子级组件, Vue2的用法</h2>
<h4>msg: {{ msg }}</h4>
<button @click="update">更新数据</button>
</div>
</template>
<script lang="ts">
import { defineComponent, ref } from 'vue'
export default defineComponent({
name: 'LifecycleChildTest',
beforeCreate () {
console.log('Vue2中的beforeCreate...')
},
created () {
console.log('Vue2中的created...')
},
beforeMount () {
console.log('Vue2中的beforeMount...')
},
mounted () {
console.log('Vue2中的mounted...')
},
beforeUpdate () {
console.log('Vue2中的beforeUpdate...')
},
updated () {
console.log('Vue2中的updated...')
},
beforeUnmount () {
console.log('Vue2中的beforeDestroy...')
},
unmounted () {
console.log('Vue2中的created...')
},
setup () {
// 响应式数据
const msg = ref('abc')
// 按钮点击事件的回调
const update = () => {
msg.value += '==='
}
return { msg, update }
}
})
</script>
<style lang="scss" scoped>
</style>
子组件2中(Vue3)
<template>
<div class="LifecycleChildTest">
<h2>Child子级组件2, Vue3的用法</h2>
</div>
</template>
<script lang="ts">
import { defineComponent, ref, onBeforeMount, onMounted, onBeforeUpdate, onUpdated, onBeforeUnmount, onUnmounted } from 'vue'
export default defineComponent({
name: 'LifecycleChildTest',
setup () {
console.log('Vue3中的 setup')
// 响应式数据
const msg = ref('abc')
// 按钮点击事件的回调
const update = () => {
msg.value += '==='
}
onBeforeMount(() => {
console.log('Vue3中的onBeforeMount...')
})
onMounted(() => {
console.log('Vue3中的onMounted')
})
onBeforeUpdate(() => {
console.log('Vue3中的onBeforeUpdate')
})
onUpdated(() => {
console.log('Vue3中的onUpdated')
})
onBeforeUnmount(() => {
console.log('Vue3中的onBeforeUnmount')
})
onUnmounted(() => {
console.log('Vue3中的onUnmounted')
})
}
})
</script>
<style lang="scss" scoped>
</style>
自定义Hook函数
自定义Hook函数: useMousePosition.ts
import { onBeforeUnmount, onMounted, ref } from 'vue'
// 此处应该写出函数的返回值类型
// eslint-disable-next-line
export default function () {
const x = ref(-1)
const y = ref(-1)
// 点击事件的回调函数
const clickHandler = (event: MouseEvent) => {
x.value = event.pageX
y.value = event.pageY
}
// 页面已经加载完毕了, 再进行点击的操作
// 页面加载完毕的生命周期
onMounted(() => {
window.addEventListener('click', clickHandler)
})
// 页面卸载之前的声明周期组合API
onBeforeUnmount(() => {
window.removeEventListener('click', clickHandler)
})
return { x, y }
}
自定义Hook函数: useRequest.ts (用于发送AJAX请求)
import { ref } from 'vue'
// 引入 axios
import axios from 'axios'
// 发送 ajax 请求, 此处应该写出函数的返回值类型
// eslint-disable-next-line
export default function <T> (url: string) {
// 加载的状态
const loading = ref(true)
// 请求成功的数据
const data = ref<T | null>(null) // 坑
// 错误信息
const errorMsg = ref('')
// 发送请求
axios.get(url).then(rs => {
// 改变加载状态
loading.value = false
data.value = rs.data
})
.catch(error => {
loading.value = false
errorMsg.value = error.message || '未知错误'
})
return {
loading,
data,
errorMsg
}
}
业务组件中 CustomHookTest.vue
<template>
<div class="customHookTest">
<h2>自定义hook函数操作</h2>
<h2>x: {{ x }}, y: {{ y }}</h2>
<h3 v-if="loading">正在加载中...</h3>
<h3 v-else-if="errorMsg">错误信息: {{ errorMsg }}</h3>
<ul v-else>
<li>id: {{ data.id }}</li>
<li>address: {{ data.address }}</li>
<li>distance: {{ data.distance }}</li>
</ul>
<hr>
<!-- 数组数据 -->
<ul v-for="item in data" :key="item.id">
<li>id: {{ item.id }}</li>
<li>title: {{ item.title }}</li>
<li>price: {{ item.price }}</li>
</ul>
</div>
</template>
<script lang="ts">
import { defineComponent, watch } from 'vue'
import useMousePosition from '@/hooks/useMousePosition'
import useRequest from '@/hooks/useRequest'
// 定义接口, 约束对象的类型
// eslint-disable-next-line @typescript-eslint/no-unused-vars
interface IAddressData {
id: number,
address: string,
distance: string,
}
interface IProductData {
id: string,
title: string,
price: number,
}
export default defineComponent({
name: 'customHookTest',
// 需求1: 用户给在页面中点击页面, 把点击的位置的横纵坐标收集并展示出来
setup () {
const { x, y } = useMousePosition()
// const { loading, data, errorMsg } = useRequest<IAddressData>('/mock/address.json') // 获取对象数据
const { loading, data, errorMsg } = useRequest<IProductData[]>('/mock/products.json') // 获取数组数据
// 监视
watch(data, () => {
if (data.value) {
console.log(data.value.length)
}
})
return {
x, y, loading, data, errorMsg
}
}
})
</script>
<style lang="scss" scoped>
</style>