Vue 3 页面常见结构、生命周期与核心用法
Vue 3 页面结构、核心语法与生命周期
一、.vue 文件整体结构
Vue 3 页面通常使用 .vue 单文件组件。
一个 .vue 文件主要由三部分组成:
<template><!-- 页面结构 --></template><script setup lang="ts">// 页面逻辑</script><style scoped>/* 页面样式 */</style>
二、<template>:页面结构
template 相当于 HTML 页面结构。
例如:
<template><div class="user-page"><h1>{{ username }}</h1><button @click="handleSave">保存</button></div></template>
这里主要负责:
展示页面显示数据绑定属性绑定事件条件显示循环列表
例如:
显示变量
<div>{{ username }}</div>
绑定属性
<button :disabled="loading">保存</button>
绑定点击事件
<button @click="handleSave">保存</button>
条件显示
<div v-if="loading">加载中</div>
循环
<divv-for="item in list":key="item.id">{{ item.name }}</div>
三、<script setup>:页面逻辑区
Vue 3 项目现在通常使用:
<script setup lang="ts"></script>
这里是整个页面的逻辑核心。
通常会放这些内容:
<script setup>1. import↓2. 响应式数据↓3. computed 计算属性↓4. 普通业务方法↓5. watch 数据监听↓6. 生命周期
一个典型结构:
<script setup lang="ts">import {computed,onBeforeUnmount,onMounted,ref,watch} from 'vue'// 1. 响应式数据const loading = ref(false)const username = ref('')// 2. 计算属性const displayName = computed(() => {return username.value || '未登录'})// 3. 普通方法function loadData(): void {console.log('加载数据')}// 4. 数据监听watch(username, () => {console.log('username 改变')})// 5. 生命周期onMounted(() => {loadData()})onBeforeUnmount(() => {console.log('组件准备销毁')})</script>
后面的 ref、computed、watch、onMounted,其实全部都是围绕这个 <script setup> 逻辑区展开的。
四、import:引入需要使用的功能
Vue 不会自动提供所有功能。
需要什么,就从 Vue 中引入什么。
例如:
import {computed,nextTick,onBeforeUnmount,onMounted,ref,watch} from 'vue'
分别表示:
ref→ 响应式数据computed→ 计算属性watch→ 监听数据变化nextTick→ 等待 DOM 更新onMounted→ 生命周期onBeforeUnmount→ 生命周期
除了 Vue 本身,还可以引入其他模块:
import { useRoute } from 'vue-router'import { ElMessage } from 'element-plus'
五、响应式数据:页面的数据从哪里来
Vue 页面通常需要保存一些状态。
例如:
用户名加载状态列表当前任务当前页码弹窗是否打开
这些数据通常使用:
ref()reactive()
来定义。
1. ref():最常用的响应式数据
例如:
const loading = ref(false)const username = ref('')const count = ref(0)
表示创建三个响应式变量。
修改:
loading.value = trueusername.value = '张三'count.value++
在 TypeScript 中需要:
.value
但是在 template 中:
<div>{{ username }}</div>
不需要:
{{ username.value }}
Vue 会自动处理。
整个过程:
const username = ref('')↓创建响应式变量↓username.value = '张三'↓Vue 发现数据变化↓自动更新 template
2. reactive():响应式对象
例如:
const userInfo = reactive({name: '',age: 0,phone: ''})
修改时:
userInfo.name = '张三'userInfo.age = 30
不需要 .value。
简单记:
ref→ 单个变量最常见reactive→ 一整个对象
六、普通函数:页面业务逻辑
定义好数据以后,页面通常需要执行各种业务逻辑。
例如:
加载数据保存删除提交表单打开页面关闭窗口刷新列表
Vue 3 <script setup> 中直接写普通函数:
function loadData(): void {console.log('加载数据')}function handleSave(): void {console.log('保存数据')}
template 可以直接调用:
<button @click="handleSave">保存</button>
执行关系:
用户点击按钮↓@click↓handleSave()↓执行 TypeScript 逻辑
Vue 2 经常看到:
methods: {}
Vue 3 <script setup> 一般不需要这样写。
直接:
function handleSave() {}
即可。
七、computed():根据已有数据计算新数据
有时候我们并不需要保存一个新的状态。
而是根据现有数据计算出来。
例如:
const firstName = ref('龙')const lastName = ref('志煜')const fullName = computed(() => {return firstName.value + lastName.value})
这里:
firstNamelastName
是原始数据。
而:
fullName
是计算出来的数据。
执行关系:
firstName / lastName↓computed↓fullName
当:
firstName.value = '陈'
发生变化时:
computed 自动重新计算
不需要自己手动更新 fullName。
常见场景
例如按钮是否可以操作:
const canStart = computed(() => {return snapshot.value.status === 'idle'})
例如从路由获取 ID:
const automationId = computed(() => {return String(route.params.automationId)})
简单理解:
computed=根据现有数据自动计算另一个结果
八、watch():监听数据变化后执行操作
watch() 和 computed() 很容易混淆。
watch() 的作用不是计算数据。
而是:
某个数据变化↓我要执行一段代码
例如:
const username = ref('')watch(username, (newValue, oldValue) => {console.log('旧值:', oldValue)console.log('新值:', newValue)})
当:
username.value = '张三'
执行:
username 发生变化↓watch 被触发↓执行回调函数
常见用途
例如:
路由 ID 变化↓重新加载数据
代码:
watch(automationId, (newId) => {loadAutomation(newId)})
或者:
搜索关键词变化↓重新搜索
computed 和 watch 的区别
这是重点。
computed↓我要得到一个新的“值”
例如:
价格 × 数量↓总价
而:
watch↓某个值变化以后我要“做一件事”
例如:
automationId 改变↓重新调用接口
所以:
computed = 算东西watch = 监听变化做事情
九、Vue 生命周期是什么
前面的:
refcomputedwatchfunction
都是页面运行过程中的功能。
而生命周期描述的是:
一个 Vue 组件从创建,到显示,再到最终销毁的整个过程。
可以理解成:
组件开始创建↓组件挂载到页面↓用户正在使用↓数据不断变化↓组件离开页面↓组件被销毁
Vue 在这些关键阶段提供了一些生命周期方法。
十、onMounted():组件挂载完成
最常见生命周期之一。
onMounted(() => {loadData()})
意思是:
Vue 组件已经挂到页面↓执行这里的代码
常用于:
加载初始化数据注册事件监听创建 ResizeObserver初始化第三方组件获取 DOM启动定时器
例如:
onMounted(() => {window.addEventListener('resize', handleResize)})
十一、onBeforeUnmount():组件销毁前
组件准备被销毁之前执行。
例如:
onBeforeUnmount(() => {window.removeEventListener('resize', handleResize)})
主要用途就是:
清理之前创建的资源
例如:
removeEventListenerclearIntervalclearTimeoutResizeObserver.disconnect()移除 IPC listener关闭 WebSocket
最经典的组合:
onMounted(() => {window.addEventListener('resize', handleResize)})onBeforeUnmount(() => {window.removeEventListener('resize', handleResize)})
可以直接记:
onMounted↓创建onBeforeUnmount↓清理
十二、其他 Vue 生命周期
Vue 3 常见生命周期:
组件准备挂载↓onBeforeMount↓组件挂载完成↓onMounted↓组件正常使用数据变化↓onBeforeUpdate↓DOM 更新↓onUpdated↓组件准备销毁↓onBeforeUnmount↓组件已经销毁↓onUnmounted
对应:
| 生命周期 | 含义 |
|---|---|
onBeforeMount |
挂载 DOM 前 |
onMounted |
DOM 挂载完成 |
onBeforeUpdate |
DOM 更新前 |
onUpdated |
DOM 更新完成 |
onBeforeUnmount |
组件销毁前 |
onUnmounted |
组件已经销毁 |
实际项目最常见的是:
onMountedonBeforeUnmount
十三、nextTick():等待 Vue 更新 DOM
Vue 修改数据以后,不一定马上同步修改 DOM。
例如:
loading.value = false
这时候 Vue 会安排 DOM 更新。
如果你需要:
修改数据↓等页面真的更新完↓再操作 DOM
就使用:
await nextTick()
例如:
message.value = '加载完成'await nextTick()console.log('页面已经更新完成')
常见场景:
修改列表后滚动到底部打开弹窗后获取弹窗尺寸元素显示后执行 focus布局变化后重新计算位置
十四、template 和 script setup 是怎么连接起来的
现在把前面的东西连起来。
例如:
<script setup lang="ts">import { computed, ref } from 'vue'const count = ref(0)const doubleCount = computed(() => {return count.value * 2})function add(): void {count.value++}</script><template><div><div>数量:{{ count }}</div><div>双倍:{{ doubleCount }}</div><button @click="add">+1</button></div></template>
执行过程:
<script setup>创建 count↓创建 doubleCount↓创建 add()↓template 开始显示↓用户点击按钮↓@click="add"↓add()↓count.value++↓count 改变↓computed 自动重新计算 doubleCount↓Vue 自动更新 template
这就是 Vue 最核心的数据驱动思想:
修改数据而不是手动修改 HTML
十五、Vue Router:页面路由
Vue 项目通常还会看到:
import {useRoute,useRouter} from 'vue-router'
它们不是 Vue 生命周期。
而是路由功能。
useRoute()
用于:
读取当前页面路由信息
例如:
const route = useRoute()const automationId = computed(() => {return String(route.params.automationId)})
假设地址:
/workspace/1001
那么可能得到:
automationId = 1001
useRouter()
用于主动跳转页面:
const router = useRouter()router.push('/admin')
简单记:
route→ 当前在哪router→ 我要去哪
十六、父子组件通信
Vue 页面往往不是一个巨大文件。
而是:
页面↓拆成多个组件
例如:
WorkspacePage.vue├── Toolbar.vue├── BrowserPanel.vue└── LogPanel.vue
组件之间需要传递数据。
defineProps():父传子
子组件:
const props = defineProps<{title: stringcount: number}>()
父组件:
<UserCardtitle="用户信息":count="10"/>
执行关系:
父组件↓props↓子组件
defineEmits():子通知父
子组件:
const emit = defineEmits<{save: [id: string]}>()function handleSave(): void {emit('save', '1001')}
父组件:
<UserCard @save="handleSave" />
执行关系:
子组件↓emit↓父组件
所以:
父 → 子props子 → 父emit
十七、一个完整 Vue 3 页面怎么看
以后看到:
<script setup lang="ts">import {computed,nextTick,onBeforeUnmount,onMounted,ref,watch} from 'vue'import { useRoute } from 'vue-router'
不要把它们看成一堆陌生方法。
应该分类看:
Vue 页面│├── 数据│ └── ref│├── 数据计算│ └── computed│├── 数据监听│ └── watch│├── DOM 更新辅助│ └── nextTick│├── 生命周期│ ├── onMounted│ └── onBeforeUnmount│└── 路由└── useRoute
十八、典型页面执行流程
一个普通 Vue 3 页面,可以理解成:
打开页面↓执行 <script setup>↓创建 ref 数据↓创建 computed↓注册 watch↓定义 function↓注册生命周期↓渲染 template↓DOM 挂载完成↓onMounted()↓页面正常运行│├── 用户点击│ ↓│ function│├── ref 数据变化│ ↓│ Vue 自动更新页面│├── computed 依赖变化│ ↓│ 自动重新计算│└── watch 监听的数据变化↓执行 watch 回调用户离开组件↓onBeforeUnmount()↓清理资源↓组件销毁
十九、最核心的几个概念
刚开始看 Vue 3,先掌握下面这些就够了:
template→ 页面结构script setup→ 页面逻辑ref→ 保存响应式数据function→ 执行业务逻辑computed→ 根据已有数据计算新数据watch→ 监听数据变化然后做事情onMounted→ 组件挂载完成后执行onBeforeUnmount→ 组件销毁前清理资源nextTick→ 等待 DOM 更新完成
最终关系:
.vue│├── template│ ↓│ 展示数据、触发事件│├── script setup│ ││ ├── ref│ │ └── 页面数据│ ││ ├── computed│ │ └── 计算数据│ ││ ├── function│ │ └── 业务逻辑│ ││ ├── watch│ │ └── 监听变化│ ││ └── lifecycle│ ├── onMounted│ └── onBeforeUnmount│└── style↓页面样式
理解这张关系图以后,再去看 Vue 3 页面代码,就不会觉得 ref、computed、watch、onMounted 是突然冒出来的一堆函数了。

浙公网安备 33010602011771号