Vue3核心语法
setup() 函数
基本概念
setup() 是 Vue 3 Composition API 的入口点,在组件创建之前执行。
代码示例
<script lang="ts">
export default {
name: 'Person',
setup() {
console.log(this) // undefined,Vue3弱化this
let name = '张三'
let age = 18
let tel = '13888888888'
function changeName() {
name = 'zhang-san' // 修改了,但页面不会更新
}
return { name, age, tel, changeName }
}
}
</script>
关键点
setup()中的this是undefined- 必须通过
return将数据和方法暴露给模板 - 普通变量不是响应式的,修改后页面不会更新
setup 语法糖 + defineOptions
setup 语法糖基本概念
更简洁的 Composition API 写法,自动暴露顶层变量和函数。
<script lang="ts" setup>
defineOptions({
name: 'Person123',
})
let name = '张三'
let age = 18
let tel = '13888888888'
function changName() {
name = 'zhangsan' // 非响应式,页面不更新
}
</script>
defineOptions 详细介绍
功能:
- 在
<script setup>中定义组件选项 - Vue 3.3+ 新增的宏函数
- 解决无法在
<script setup>中直接设置name等选项的问题
支持的选项:
defineOptions({
name: 'ComponentName', // 组件名
inheritAttrs: false, // 是否继承属性
components: { ... }, // 注册组件
directives: { ... }, // 注册指令
// 和其他组件选项
})
优势
- 代码更简洁
- 自动暴露变量和函数
- 不需要写
return语句 - 可以在
<script setup>中定义组件名等选项
ref() 函数
基本概念
ref() 用于创建响应式数据,可以包装基本类型和对象类型。
代码示例
<script lang="ts" setup>
import { ref } from 'vue'
defineOptions({
name: 'Person',
})
// 使用 ref() 创建响应式数据
let name = ref('张三') // 字符串 - 响应式
let age = ref(18) // 数字 - 响应式
let tel = '13888888888' // 普通字符串 - 非响应式
// 方法
function changeName() {
name.value = 'zhang-san' // JS中操作ref对象时候需要.value
console.log(name.value)
}
function changeAge() {
age.value += 1 // JS中操作ref对象时候需要.value
console.log(age.value)
}
function showTel() {
alert(tel) // 普通变量直接使用
}
</script>
ref() 特性:
- 基本类型:
ref(0)、ref('字符串')、ref(false) - 对象类型:
ref({ name: '张三' }) - 访问:JS 中需要
.value,模板中自动解包
reactive() 函数
基本概念
reactive() 用于创建响应式对象,当对象属性变化时,视图会自动更新。
代码示例
<script setup>
import { reactive } from 'vue'
const person = reactive({
name: '张三',
age: 18
})
function changeName() {
person.name = '李四' // 直接修改属性
}
</script>
ref() vs reactive() 对比
| 特性 | ref() | reactive() |
|---|---|---|
| 数据类型 | 基本类型 + 对象类型 | 只接受对象类型 |
| 访问方式 | JS中需要 .value,模板中自动解包 | 直接访问属性 |
| 模板使用 | {{ name }} | {{ obj.property }} |
| 重新赋值 | name.value = 新值 | 不能直接重新赋值整个对象 |
使用原则:
- 若需要一个基本类型的响应式数据,必须使用
ref - 若需要一个响应式对象,层级不深,
ref、reactive都可以 - 若需要一个响应式对象,且层级较深,推荐使用
reactive
toRefs 与 toRef
- 作用:将响应式对象的属性转换为 ref 对象
- 区别:
toRefs:批量转换对象的所有属性toRef:转换对象的单个属性
<script setup>
import { reactive, toRefs, toRef } from 'vue'
let person = reactive({ name: '张三', age: 18, gender: '男' })
// 批量转换
let { name, gender } = toRefs(person)
// 单个转换
let age = toRef(person, 'age')
// 使用时需要 .value
function changeName() {
name.value += '~'
}
</script>
computed 计算属性
- 作用:基于响应式数据计算新值
<script setup>
import { ref, computed } from 'vue'
let firstName = ref('zhang')
let lastName = ref('san')
// 只读计算属性
let fullName = computed(() => firstName.value + '-' + lastName.value)
// 可读可写计算属性
let fullName = computed({
get() {
return firstName.value + '-' + lastName.value
},
set(val) {
[firstName.value, lastName.value] = val.split('-')
}
})
function changeFullName() {
fullName.value = 'li-si'
}
</script>
watch 监视
情况一:监视 ref 定义的【基本类型】数据
直接写数据名即可,监视的是其 value 值的改变。
<script setup>
import { ref, watch } from 'vue'
let sum = ref(0)
// 监视基本类型
const stopWatch = watch(sum, (newValue, oldValue) => {
console.log('sum变化了', newValue, oldValue)
if(newValue >= 10) {
stopWatch() // 停止监视
}
})
function changeSum() {
sum.value += 1
}
</script>
情况二:监视 ref 定义的【对象类型】数据
直接写数据名,监视的是对象的【地址值】,若想监视对象内部的数据,要手动开启深度监视。
<script setup>
import { ref, watch } from 'vue'
let person = ref({
name: '张三',
age: 18
})
// 监视对象类型,需要手动开启深度监视
watch(person, (newValue, oldValue) => {
console.log('person变化了', newValue, oldValue)
}, { deep: true })
function changeName() {
person.value.name += '~' // newValue和oldValue都是新值
}
function changePerson() {
person.value = { name: '李四', age: 90 } // newValue是新值,oldValue是旧值
}
</script>
情况三:监视 reactive 定义的【对象类型】数据
默认开启了深度监视,且无法关闭。
<script setup>
import { reactive, watch } from 'vue'
let person = reactive({
name: '张三',
age: 18,
car: {
brand: 'BMW'
}
})
// reactive对象默认深度监视
watch(person, (newValue, oldValue) => {
console.log('person变化了', newValue, oldValue)
})
function changeCarBrand() {
person.car.brand = 'Audi' // 深层变化也会被监视到
}
</script>
情况四:监视 ref 或 reactive 定义的【对象类型】数据中的某个属性
<script setup>
import { reactive, watch } from 'vue'
let person = reactive({
name: '张三',
age: 18,
car: {
c1: '奔驰',
c2: '宝马'
}
})
// 情况四:监视基本类型属性(必须写成函数形式)
watch(() => person.name, (newValue, oldValue) => {
console.log('name变化了', newValue, oldValue)
})
// 情况四:监视对象类型属性(推荐写成函数形式)
watch(() => person.car, (newValue, oldValue) => {
console.log('car变化了', newValue, oldValue)
}, { deep: true })
</script>
情况五:监视多个数据
<script setup>
import { reactive, watch } from 'vue'
let person = reactive({
name: '张三',
age: 18,
car: {
c1: '奔驰',
c2: '宝马'
}
})
// 情况五:监视多个数据
watch([() => person.name, () => person.car], (newValue, oldValue) => {
console.log('多个数据变化了', newValue, oldValue)
}, { deep: true })
</script>
watchEffect
- 特点:自动追踪函数内用到的响应式数据
- 与watch区别:不需要明确指定监视的数据
<script setup>
import { ref, watchEffect } from 'vue'
let temp = ref(0)
let height = ref(0)
const stopWatch = watchEffect(() => {
// 自动追踪 temp 和 height
if (temp.value >= 50 || height.value >= 20) {
console.log('联系服务器')
}
// 可停止监视
if (temp.value === 100) {
stopWatch()
}
})
</script>
ref 属性
- 作用:获取DOM元素或组件实例
<template>
<!-- 获取DOM元素 -->
<h1 ref="title">标题</h1>
<button @click="showLog">打印</button>
<!-- 获取组件实例 -->
<Person ref="personComp"/>
</template>
<script setup>
import { ref } from 'vue'
import Person from './Person.vue'
let title = ref()
let personComp = ref()
function showLog() {
console.log(title.value) // DOM元素
console.log(personComp.value) // 组件实例
}
</script>
<!-- 子组件要使用 defineExpose 暴露内容 -->
<script setup>
import { ref, defineExpose } from 'vue'
let name = ref('张三')
let age = ref(18)
// 暴露给父组件
defineExpose({ name, age })
</script>
props 父传子
定义类型
// types.ts
export interface PersonInter {
id: string
name: string
age: number
}
export type Persons = PersonInter[]
使用 props
<!-- 父组件 -->
<template>
<Person :list="persons"/>
</template>
<script setup>
import { reactive } from 'vue'
import Person from './Person.vue'
import { type Persons } from './types'
let persons = reactive<Persons>([
{ id: '1', name: '张三', age: 18 }
])
</script>
<!-- 子组件 -->
<script setup>
import { defineProps, withDefaults } from 'vue'
import { type Persons } from './types'
// 接收props + 类型限制 + 默认值
let props = withDefaults(defineProps<{
list?: Persons
}>(), {
list: () => [{ id: '1', name: '默认', age: 0 }]
})
</script>
生命周期
-
概念:Vue组件实例在创建时要经历一系列的初始化步骤
-
四个阶段:创建、挂载、更新、卸载
-
Vue2的生命周期创建阶段:
beforeCreate、created挂载阶段:
beforeMount、mounted更新阶段:
beforeUpdate、updated销毁阶段:
beforeDestroy、destroyed -
Vue3的生命周期创建阶段:
setup挂载阶段:
onBeforeMount、onMounted更新阶段:
onBeforeUpdate、onUpdated卸载阶段:
onBeforeUnmount、onUnmounted -
示例代码:
<template>
<div class="person">
<h2>当前求和为:{{ sum }}</h2>
<button @click="changeSum">点我sum+1</button>
</div>
</template>
<script setup>
import {
ref,
onBeforeMount,
onMounted,
onBeforeUpdate,
onUpdated,
onBeforeUnmount,
onUnmounted
} from 'vue'
let sum = ref(0)
function changeSum() {
sum.value += 1
}
// 生命周期钩子
onBeforeMount(() => {
console.log('挂载之前')
})
onMounted(() => {
console.log('挂载完毕') // 常用:发送请求、操作DOM
})
onBeforeUpdate(() => {
console.log('更新之前')
})
onUpdated(() => {
console.log('更新完毕') // 常用:数据更新后操作
})
onBeforeUnmount(() => {
console.log('卸载之前') // 常用:清理定时器、取消订阅
})
onUnmounted(() => {
console.log('卸载完毕')
})
</script>
常用钩子:onMounted、onUpdated、onBeforeUnmount
自定义hook
- 本质:一个函数,封装 Composition API
- 优势:复用代码,让setup逻辑更清晰
useSum.ts中内容如下:
// hooks/useSum.ts
import { ref, onMounted } from 'vue'
export default function() {
let sum = ref(0)
const increment = () => {
sum.value += 1
}
const decrement = () => {
sum.value -= 1
}
onMounted(() => {
increment() // 挂载时自动+1
})
return { sum, increment, decrement }
}
useDog.ts中内容如下:
// hooks/useDog.ts
import { reactive, onMounted } from 'vue'
import axios from 'axios'
export default function() {
let dogList = reactive({
urlList: [] as string[],
isLoading: false
})
async function getDog() {
dogList.isLoading = true
try {
const { data } = await axios.get('https://dog.ceo/api/breed/pembroke/images/random')
dogList.urlList.push(data.message)
} catch (error) {
console.log('请求失败', error)
} finally {
dogList.isLoading = false
}
}
onMounted(() => {
getDog() // 挂载时自动获取
})
return { dogList, getDog }
}
- 组件中具体使用:
<template>
<h2>当前求和为:{{ sum }}</h2>
<button @click="increment">+1</button>
<button @click="decrement">-1</button>
<hr>
<img v-for="(url, index) in dogList.urlList" :key="index" :src="url">
<span v-show="dogList.isLoading">加载中...</span>
<button @click="getDog">再来一只狗</button>
</template>
<script setup>
import useSum from './hooks/useSum'
import useDog from './hooks/useDog'
const { sum, increment, decrement } = useSum()
const { dogList, getDog } = useDog()
</script>
优势:逻辑复用、代码清晰、便于维护
1553

被折叠的 条评论
为什么被折叠?



