vue3基础知识
书接上文,这篇继续来学习vue3的核心语法,可以先看上一篇再来看这篇效果更好。
1. computed
computed
用于创建 计算属性,即基于其他响应式数据的值动态计算并缓存的属性。它的主要作用是优化性能和提高代码的可维护性,避免不必要的重复计算。
a. 基本语法
computed
是通过 computed()
函数创建的。在 setup()
函数中,你可以使用 computed
来定义计算属性。
import { computed, ref } from 'vue';
export default {
setup() {
const count = ref(0);
const doubledCount = computed(() => count.value * 2);
return { count, doubledCount };
}
};
解释:
count
是一个响应式数据,初始值为0
。doubledCount
是一个计算属性,它依赖于count
,并返回count
的两倍。- 当
count
的值发生变化时,doubledCount
会自动重新计算。
b. 计算属性的缓存
computed
的一个重要特性是 缓存。只有当计算属性依赖的响应式数据发生变化时,computed
才会重新计算,否则会直接返回上一次计算的结果。
import { computed, ref } from 'vue';
export default {
setup() {
const count = ref(0);
// 计算属性:返回 count 的平方
const squaredCount = computed(() => {
console.log('Computing squared count');
return count.value * count.value;
});
return { count, squaredCount };
}
};
在上面的例子中,如果你多次访问 squaredCount
,你会看到 “Computing squared count” 只会在 count
改变时打印一次,而不会在每次访问时都打印,这就是 computed
的缓存机制。
c. 使用 computed
的场景
-
计算派生状态:当你需要基于现有的响应式数据计算新的值时,
computed
很有用。例如,计算一个总价、折扣后价格、过滤后的列表等。const price = ref(100); const discount = ref(0.2); const discountedPrice = computed(() => price.value * (1 - discount.value));
-
优化性能:通过缓存计算结果,
computed
可以避免重复计算,提升性能。 -
条件渲染:你可以使用
computed
来做一些复杂的条件判断,而不需要在模板中使用大量的v-if
。
与 watch
的对比
watch
用于观察响应式数据的变化,并执行副作用操作,如更新外部状态或执行异步操作。它适合处理需要副作用的场景,而 computed
更适合处理计算派生状态并返回值。
import { watch, ref } from 'vue';
const count = ref(0);
// 使用 watch
watch(count, (newValue) => {
console.log('Count changed:', newValue);
});
// 使用 computed
const doubledCount = computed(() => count.value * 2);
watch
用于监听count
的变化,并在变化时执行某个副作用。computed
用于计算并返回派生值,在模板中或其他地方直接使用。
2. watch
在 Vue 3 中,watch
是用于 监听响应式数据的变化 并在数据变化时执行副作用操作的 API。它特别适用于处理那些需要在数据变化时执行的逻辑,例如异步请求、数据处理、或者与外部系统交互。
watch
的基本概念
- 监听:
watch
允许你监控一个或多个响应式数据的变化。 - 副作用:当被监听的数据发生变化时,
watch
会执行一个回调函数,你可以在回调中执行任何副作用操作(例如,发起异步请求、更新外部状态等)。 - 深度监听:
watch
也可以深度监听对象或数组的变化,适合用于嵌套对象或数组的更新。
a. 基本语法
watch
接受三个参数:
- 第一个参数:要观察的响应式数据或计算属性。
- 第二个参数:回调函数,监听到数据变化时会调用它。
- 第三个参数(可选):配置对象,可以设置一些附加选项,如
immediate
和deep
。
最简单的使用方式
import { ref, watch } from 'vue';
export default {
setup() {
const count = ref(0);
// 监听 count 的变化
watch(count, (newValue, oldValue) => {
console.log(`count changed from ${oldValue} to ${newValue}`);
});
return { count };
}
};
解释:
watch
监听count
的变化,每当count
发生变化时,会调用回调函数。- 回调函数接收两个参数:
newValue
(新的值)和oldValue
(旧的值),可以在回调中执行任何副作用操作。
b. watch
的高级用法
监听多个响应式数据
你可以同时监听多个响应式数据,当它们中的任意一个变化时,回调都会被触发。
import { ref, watch } from 'vue';
export default {
setup() {
const count = ref(0);
const name = ref('Alice');
// 同时监听 count 和 name 的变化
watch([count, name], ([newCount, newName], [oldCount, oldName]) => {
console.log(`count changed from ${oldCount} to ${newCount}`);
console.log(`name changed from ${oldName} to ${newName}`);
});
return { count, name };
}
};
深度监听对象或数组
默认情况下,watch
只会监听对象或数组的 引用变化,而不会递归监听其内部属性或元素。要实现深度监听,可以使用 deep: true
配置选项。
import { ref, watch } from 'vue';
export default {
setup() {
const user = ref({
name: 'Alice',
age: 25
});
// 深度监听 user 对象的变化
watch(user, (newValue, oldValue) => {
console.log('User changed:', newValue);
}, { deep: true });
return { user };
}
};
立即执行(immediate
)
watch
默认在被监听的数据发生变化时才会执行回调。如果你希望在监听开始时立即执行回调,可以使用 immediate: true
配置。
import { ref, watch } from 'vue';
export default {
setup() {
const count = ref(0);
// 监听 count 的变化,并立即执行回调
watch(count, (newValue, oldValue) => {
console.log(`count changed from ${oldValue} to ${newValue}`);
}, { immediate: true });
return { count };
}
};
执行异步操作
watch
是非常适合用于执行异步操作的。比如,当某个数据变化时,你可能需要去发起一个 API 请求。
import { ref, watch } from 'vue';
export default {
setup() {
const searchQuery = ref('');
// 监听 searchQuery 的变化,发起一个异步操作
watch(searchQuery, async (newQuery) => {
if (newQuery) {
const results = await fetch(`https://api.example.com/search?q=${newQuery}`);
console.log(await results.json());
}
});
return { searchQuery };
}
};
2.1 watchEffect
的使用
watchEffect
是 watch
的一个变体,它会在组件挂载时立即执行,并且会自动追踪作用域内所有的响应式依赖。与 watch
主要是用于监听特定数据的变化不同,watchEffect
会自动检测你使用的所有响应式数据。
import { ref, watchEffect } from 'vue';
export default {
setup() {
const count = ref(0);
// watchEffect 会自动监听 count 的变化
watchEffect(() => {
console.log(`Count has changed: ${count.value}`);
});
return { count };
}
};
watchEffect
和 watch
的区别:
watch
:用于精确监听一个或多个特定的数据源,并可以对变化做出响应。watchEffect
:自动追踪你在其作用域内使用的所有响应式数据,并在数据变化时重新执行回调。
c. watch
的使用场景
- 监听数据变化并执行副作用:例如,发起 API 请求、更新外部状态等。
- 异步操作:比如在数据变化时发起一个网络请求或进行复杂的数据处理。
- 表单验证:在表单字段变化时执行验证逻辑。
- 数据持久化:监听数据变化并将数据持久化到本地存储或服务器。
3. props
props
是父组件向子组件传递数据的一种方式。通过 props
,父组件可以将数据或参数传递给子组件,从而实现组件之间的通信。
a. 基本概念
- 父组件 -> 子组件:
props
是单向数据流(单向绑定)的机制,数据只能从父组件传递到子组件,子组件不能直接修改从父组件接收的props
。 - 类型验证:Vue 允许对传递的
props
进行类型验证和默认值设置,从而确保数据的正确性。
b. 基本使用
父组件
<script lang="ts" setup name="App">
import Person from './components/Person.vue'
import {reactive} from 'vue'
import {type Persons} from './types'
let persons = reactive<Persons>([
{id:'e98219e12', name:'张三', age:18},
{id:'e98219e13', name:'李四', age:19},
{id:'e98219e14', name:'王五', age:20}
])
</script>
子组件
<script lang="ts" setup name="Person">
import {defineProps} from 'vue'
// types中包含了Persons类型
import {type Persons} from '@/types'
// 第一种写法:仅接收
// const props = defineProps(['list'])
// 第二种写法:接收 + 限制类型
// defineProps<{list:Persons}>()
// 第三种写法:接收 + 限制类型 + 指定默认值 + 限制必要性
// list后如果加?表示可传可不传,不加则必须传
let props = withDefaults(defineProps<{list?:Persons}>(),{
list:()=>[{id:'asdasg01',name:'小猪佩奇',age:18}]
})
console.log(props)
</script>
通过 props
,Vue 提供了一种简单而高效的组件通信方式,非常适合用于父子组件之间的数据传递和状态共享。
4. Hooks
- 什么是hook?—— 本质是一个函数,把setup函数中使用的Composition API进行了封装,类似于vue2.x中的mixin。
- 自定义hook的优势:复用代码, 让setup中的逻辑更清楚易懂。
示例代码:
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()
})
//向外部暴露数据
return {sum,increment,decrement}
}
useDog.ts
:
import {reactive,onMounted} from 'vue'
import axios,{AxiosError} from 'axios'
export default function(){
let dogList = reactive<string[]>([])
// 方法
async function getDog(){
try {
// 发请求
let {data} = await axios.get('https://dog.ceo/api/breed/pembroke/images/random')
// 维护数据
dogList.push(data.message)
} catch (error) {
// 处理错误
const err = <AxiosError>error
console.log(err.message)
}
}
// 挂载钩子
onMounted(()=>{
getDog()
})
//向外部暴露数据
return {dogList,getDog}
}
App.vue
:
<template>
<h2>当前求和为:{{sum}}</h2>
<button @click="increment">点我+1</button>
<button @click="decrement">点我-1</button>
<hr>
<img v-for="(u,index) in dogList.urlList" :key="index" :src="(u as string)">
<span v-show="dogList.isLoading">加载中......</span><br>
<button @click="getDog">再来一只狗</button>
</template>
<script lang="ts">
import {defineComponent} from 'vue'
export default defineComponent({
name:'App',
})
</script>
<script setup lang="ts">
import useSum from './hooks/useSum'
import useDog from './hooks/useDog'
let {sum,increment,decrement} = useSum()
let {dogList,getDog} = useDog()
</script>
是的,hook 可以帮助实现模块化开发,尤其在 Vue 3 中,结合 组合式 API (Composition API) 使用时,它极大地提高了代码的可复用性和模块化程度。
分析:
- 模块化:通过将数据获取和表单处理的逻辑分别提取到
useSum
和useDog
hook 中,逻辑更加清晰和模块化。 - 复用性:这两个 hook 可以在不同的组件中复用,而无需重复编写相同的代码。
- 解耦:不同的功能模块(如数据请求、表单验证等)被清晰地分离开来,组件只负责调用这些 hook,减少了组件内部的复杂度。
如果你能看到这里给你点个赞,如果对你有帮助的话不妨点赞支持一下~
参考:张天禹老师b站课程
原文地址:https://blog.csdn.net/m0_73969414/article/details/144182090
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!