1 认识Composition API
Options API的弊端
setup函数
2 setup函数的参数
3 setup简单使用
1 注意不再有
响应式数据
要做到响应式数据需要在数据定义时使用ref
包装数据,并且在使用时,使用value
解包
2 注意template要使用的数据或者函数,必须要return 返回才能被使用
<template>
<div class="app">
<!-- template中ref对象自动解包 -->
<h2>当前计数: {{ counter }}</h2>
<button @click="increment">+1</button>
<button @click="decrement">-1</button>
</div>
</template>
<script>
import { ref } from 'vue'
export default {
setup() {
// 1.定义counter的内容
// 默认定义的数据都不是响应式数据
let counter = ref(100)
const increment = () => {
counter.value++
console.log(counter.value)
}
const decrement = () => {
counter.value--
}
return {
counter, increment, decrement
}
}
}
</script>
<style>
</style>
setup函数的返回值
4 为数据提供响应式的特性
1 Reactive API,复杂数据类型
2 Ref API,简单数据类型包装
ref可以简单数据类型包装,ref也可以定义复杂的数据
<template>
<div>
//普通数据
<h2>message: {{ message }}</h2>
<button @click="changeMessage">修改message</button>
<hr>
//通过Reactive提供响应式数据
<h2>账号: {{ account.username }}</h2>
<h2>密码: {{ account.password }}</h2>
<button @click="changeAccount">修改账号</button>
<hr>
//通过Ref提供响应式数据
<!-- 默认情况下在template中使用ref时, vue会自动对其进行解包(取出其中value) -->
<h2>当前计数: {{ counter }}</h2>
<button @click="increment">+1</button>
<button @click="counter++">+1</button>
</div>
</template>
<script>
import { reactive, ref } from 'vue'
export default {
setup() {
// 1.定义普通的数据: 可以正常的被使用
// 缺点: 数据不是响应式的
let message = "Hello World"
function changeMessage() {
message = "你好啊,李银河!"
console.log(message)
}
// 2.定义响应式数据
// 2.1.reactive函数: 定义复杂类型的数据
const account = reactive({
username: "coderwhy",
password: "123456"
})
function changeAccount() {
account.username = "kobe"
}
// 2.2.ref函数: 定义简单类型的数据(也可以定义复杂类型的数据)
// counter定义响应式数据
const counter = ref(0)
function increment() {
counter.value++
}
return {
message,
changeMessage,
account,
changeAccount,
counter,
increment,
info
}
}
}
</script>
<style scoped>
</style>
3 Reactive 和 ref 的应用场景
setup() {
// 定义响应式数据: reactive/ref
// 强调: ref也可以定义复杂的数据
const info = ref({})
console.log(info.value)
// 1.reactive的应用场景
// 1.1.条件一: reactive应用于本地的数据
// 1.2.条件二: 多个数据之间是有关系/联系(聚合的数据, 组织在一起会有特定的作用)
const account = reactive({
username: "coderwhy",
password: "1234567"
})
const username = ref("coderwhy")
const password = ref("123456")
// 2.ref的应用场景: 其他的场景基本都用ref(computed)
// 2.1.定义本地的一些简单数据
const message = ref("Hello World")
const counter = ref(0)
const name = ref("why")
const age = ref(18)
// 2.定义从网络中获取的数据也是使用ref
// const musics = reactive([])
const musics = ref([])
onMounted(() => {
const serverMusics = ["海阔天空", "小苹果", "野狼"]
musics.value = serverMusics
})
return {
account,
username,
password,
name,
age
}
}
}
</script>
5 computed
6 在setup中使用ref获取元素或者组件
7 生命周期钩子
8 侦听数据的变化 watch
<template>
<div>AppContent</div>
<button @click="message = '你好啊,李银河!'">修改message</button>
<button @click="info.friend.name = 'james'">修改info</button>
</template>
<script>
import { reactive, ref, watch } from 'vue'
export default {
setup() {
// 1.定义数据
const message = ref("Hello World")
const info = reactive({
name: "why",
age: 18,
friend: {
name: "kobe"
}
})
// 2.侦听数据的变化
watch(message, (newValue, oldValue) => {
console.log(newValue, oldValue)
})
watch(info, (newValue, oldValue) => {
console.log(newValue, oldValue)
console.log(newValue === oldValue)
}, {
//立即执行一次
immediate: true
})
// 3.监听reactive数据变化后, 获取普通对象,而不是代理对象
watch(() => ({ ...info }), (newValue, oldValue) => {
console.log(newValue, oldValue)
}, {
immediate: true,
deep: true
})
return {
message,
info
}
}
}
</script>
<style scoped>
</style>
侦听自动捕获依赖:watchEffect
<template>
<div>
<h2>当前计数: {{ counter }}</h2>
<button @click="counter++">+1</button>
<button @click="name = 'kobe'">修改name</button>
</div>
</template>
<script>
import { watchEffect, watch, ref } from 'vue'
export default {
setup() {
const counter = ref(0)
const name = ref("why")
// watch(counter, (newValue, oldValue) => {})
// 1.watchEffect传入的函数默认会直接被执行
// 2.在执行的过程中, 会自动的收集依赖(依赖哪些响应式的数据)
const stopWatch = watchEffect(() => {
console.log("-------", counter.value, name.value)
// 判断counter.value > 10
if (counter.value >= 10) {
//停止监听
stopWatch()
}
})
return {
counter,
name
}
}
}
</script>
<style scoped>
</style>
9 hook封装
Composition API的主要作用就是利用函数式编程,可以很容易的将可以复用的代码抽取出来(因为代码可以写在一起),这些被抽取的,单独功能的代码,被称为hook(钩子).不是真正的hook,而是类似hook的能力.
hook的作用和组件一样都是封装,然而组件偏向于UI的封装,而hook偏向于功能逻辑,状态管理.
也就是说Vue3可以利用Composition API将optionsAPI的内容,抽取为hook功能,给组件使用,组件的功能被抽取出来了,只剩下UI由组件实现.
1 hook封装,计数器
useCounter.js
import { ref, onMounted } from 'vue'
export default function useCounter() {
const counter = ref(0)
function increment() {
counter.value++
}
function decrement() {
counter.value--
}
//模拟网络环境,初始化值
onMounted(() => {
setTimeout(() => {
counter.value = 989
}, 1000);
})
return {
counter,
increment,
decrement
}
}
2 使用hook
<template>
<h2>About计数: {{ counter }}</h2>
<button @click="increment">+1</button>
<button @clcik="decrement">-1</button>
</template>
<script>
import useCounter from '../hooks/useCounter'
export default {
setup() {
//使用hook函数
//const { counter, increment, decrement } = useCounter()
// return {
// counter,
// increment,
// decrement,
// }
return {
//使用hook函数的等价写法
...useCounter()
}
}
}
</script>
10 script setup语法糖
使用这种语法糖,在需要使用组件时,不再需要使用components声明,只要import导入就可以直接使用