目录
setup 选项
Vue3 引入了全新的 setup
选项,用于定义组件的初始状态和核心逻辑。
setup
函数采用 Composition API 的方式组织代码,显著提升了代码的可读性和灵活性。该函数接收 props
和 context
两个参数,并返回一个包含响应式状态和方法的对象,这些内容可直接在模板中使用。
这种设计不仅使组件结构更加清晰明了,还为逻辑复用提供了更好的支持。
原始复杂写法
<script>
export default {
setup() {
//数据
const message = 'Hello Vue 3!'
//函数
const sayHello = () => {
console.log(message)
}
//返回数据和函数
return {
message,
sayHello
}
}
}
</script>
语法糖写法
<script setup>
const message = 'Hello Vue 3!'
const sayHello = () => {
console.log(message)
}
</script>
reactive和ref函数
reactive()
作用:接受对象类型数据的参数传入并返回一个响应式的对象
核心步骤
<script setup>
import { reactive } from 'vue'
const state = reactive(对象类型数据)
</script>
- 从 vue 包中导入 reactive 函数
- 在
ref()
作用:接受任意类型数据的参数传入并返回一个响应式且可变的ref对象,通过.value属性访问和修改内部值。适用于基本类型数据和对象引用。更推荐使用ref(),因为在功能上覆盖了reactive()
核心步骤:
<script setup>
import { ref } from 'vue'
const count = ref(简单类型或者复杂类型数据) // 基本类型
</script>
示例-计数器按钮
<template>
<button @click="buttonClick">{{ count }}</button>
</template>
<script setup>
import { ref } from 'vue'
const count = ref(0)
function buttonClick(){
count.value++
}
</script>
computed 计算属性函数
计算属性基本思想和Vue2的完全一致,组合式API下的计算属性只是修改了写法
<script setup>
import { computed } from 'vue'
const computedState = computed(() => {
return 基于响应式数据做计算之后的值
})
</script>
- 导入computed函数
- 执行函数,在回调参数中return基于响应式数据做计算的值,用变量接收
示例-过滤数组
<template>
<div>原始响应式数组 - {{ list }}</div>
<div>过滤后响应式数组 - {{ computedList }}</div>
</template>
<script setup>
import { ref, computed } from 'vue';
const list = ref([1, 2, 3, 4, 5, 6, 7, 8]);
const computedList = computed(() => {
return list.value.filter(item => item > 2);
});
</script>
watch 函数
作用:侦听一个或者多个数据的变化,数据变化时执行回调函数
两个额外参数:1.immediate(立即执行)2.deep(深度侦听)
基础使用 - 侦听单个数据
- 导入watch函数
- 执行watch函数传入要侦听的响应式数据(ref对象)和回调函数
<script setup>
// 1. 导入watch
import { ref, watch } from 'vue'
const count = ref(0)
// 2. 调用watch 侦听变化
watch(count, (newValue, oldValue) => {
console.log(`count发生了变化,老值为${oldValue},新值为${newValue}`)
})
</script>
基础使用 - 侦听多个数据
说明:同时侦听多个响应式数据的变化,不管哪个数据变化都需要执行回调
<script setup>
import { ref, watch } from 'vue'
const count = ref(0)
const name = ref('cp')
// 侦听多个数据源
watch(
[count, name],
([newCount, newName], [oldCount, oldName]) => {
console.log('count或者name变化了', [newCount, newName], [oldCount, oldName])
}
)
</script>
deep 深度监听机制
在 Vue 的响应式系统中,通过 watch
监听的 ref 对象默认采用浅层侦听(shallow watch)机制。这意味着当直接修改嵌套的对象属性时,默认不会触发 watch 回调函数执行。
默认浅层监听的问题
const state = ref({ count: 0 })
// 默认浅层监听
watch(state, () => {
console.log('数据变化了') // 不会触发
})
const changeStateByCount = () => {
// 直接修改嵌套属性 - 不会触发回调
state.value.count++
}
在这个例子中,当我们修改 state.value.count
时,watch 回调不会执行,因为:
- ref 对象本身(state)的引用没有改变
- 默认的浅层监听不会追踪嵌套属性的变化
解决方案:开启 deep 选项
要实现深度监听,需要显式设置 deep: true
选项:
watch(
state,
() => {
console.log('深度监听:数据变化了')
},
{ deep: true } // 启用深度监听
)
开启深度监听后,watch 会:
- 递归追踪所有嵌套属性的变化
- 无论修改哪一层级的属性都会触发回调
- 注意性能开销,因为要追踪的对象可能很大
生命周期函数
Vue3的生命周期API(选项式VS组合式)
选项式 API | 组合式 API |
---|---|
beforeCreate/created | setup |
beforeMount | onBeforeMount |
mounted | onMounted |
beforeUpdate | onBeforeUpdate |
updated | onUpdated |
beforeUnmount | onBeforeUnmount |
unmounted | onUnmounted |
生命周期函数基本使用
- 导入生命周期函数
- 执行生命周期函数 传入回调
import { onMounted } from 'vue'
onMounted(() =? {
//自定义逻辑
})
父子通信
父传子
同样是通过props
实现,在vue3中有更简洁的写法:通过defineProps()
往里面传入数组或对象来接受父级传来的数据
<script setup>
const props = defineProps({
message:String,
count:Number
})
</script>
以下是一个示例
父组件
<template>
<div class="box">
<h1>props:我是父组件曹操</h1>
<hr />
<Child info="我是曹操" :money="money"></Child>
</div>
</template>
<script setup lang="ts">
import Child from "./Child.vue";
import { ref } from "vue";
let money = ref(10000);
</script>
<style scoped>
.box {
width: 100vw;
height: 400px;
background: yellowgreen;
}
</style>
子组件
<template>
<div class="son">
<h1>我是子组件:曹植</h1>
<p>{{info}}</p>
<p>{{money}}</p>
<button @click="updateProps">修改props数据</button>
</div>
</template>
<script setup lang="ts">
//需要使用到defineProps方法去接受父组件传递过来的数据
//defineProps是Vue3提供方法,不需要引入直接使用
let props = defineProps(['info','money']); //数组|对象写法都可以
//按钮点击的回调
const updateProps = ()=>{
// props.money+=10; props:只读的
console.log(props.info)
}
</script>
<style scoped>
.son{
width: 400px;
height: 200px;
background: hotpink;
}
</style>
子传父
基本思想
- 父组件中给子组件标签通过@绑定事件
- 子组件内部通过
$emit
方法触发事件
父组件
<script setup>
// 引入子组件
import sonComVue from './son-com.vue'
const getMessage = (msg) => {
console.log(msg)
}
</script>
<template>
<!-- 1. 绑定自定义事件 -->
<sonComVue @get-message="getMessage" />
</template>
子组件
<script setup>
// 2. 通过 defineEmits 编译器宏生成 emit 方法,以数组传入要生成的事件名称
const emit = defineEmits(['get-message'])
const sendMsg = () => {
// 3. 触发自定义事件 并传递参数
emit('get-message', 'this is son msg')
}
</script>
<template>
<button @click="sendMsg">sendMsg</button>
</template>
模板引用
通过ref标识获取真实的dom对象或者组件实例对象
如何使用(以获取dom为例 组件同理)
<template>
<!-- 2. 通过ref标识绑定ref对象 -->
<h1 ref="h1Ref">我是dom标签h1</h1>
</template>
<script setup>
import { ref } from 'vue'
// 1. 调用ref函数得到ref对象
const h1Ref = ref(null)
</script>
defineExpose()
默认情况下在
<script setup>
import { ref } from 'vue'
const testMessage = ref('this is test msg')
defineExpose({
testMessage
})
</script>
provide 和 inject
作用和场景
provide
和 inject
是 Vue.js 中用于实现跨层级组件通信的一对 API,主要用于解决组件多层嵌套时的数据传递问题。它们的作用是允许祖先组件向其所有后代组件(无论嵌套多深)传递数据和方法,而不需要逐层通过 props 传递。
典型应用场景包括:
- 主题切换功能(深层次子组件需要访问主题变量)
- 国际化实现(所有组件都需要语言包)
- 用户权限管理(深层组件需要判断权限)
- 全局状态共享(替代 Vuex 的轻量级方案)
跨层传递响应式数据
在 Vue 3 中,为了确保传递的数据保持响应式,需要在调用 provide 函数时将第二个参数设置为 ref 对象或 reactive 对象。这样当数据变化时,所有注入该数据的组件都能自动更新。
基本用法
顶层组件(提供数据)
import { ref, provide } from 'vue'
export default {
setup() {
// 创建响应式数据
const count = ref(0)
const userInfo = reactive({
name: '张三',
age: 25
})
// 提供数据给后代组件
provide('count-key', count)
provide('user-info-key', userInfo)
// 也可以提供方法
const increment = () => {
count.value++
}
provide('increment-method', increment)
return { count }
}
}
底层组件(注入数据)
import { inject } from 'vue'
export default {
setup() {
// 注入数据
const count = inject('count-key')
const userInfo = inject('user-info-key')
const increment = inject('increment-method')
// 可以设置默认值
const theme = inject('theme', 'light')
// 如果确定提供者会提供数据,可以使用非空断言
const requiredData = inject('required-key')!
return { count, userInfo, increment, theme }
}
}