Vue3基础知识-1

本文介绍了Vue3中的setup函数及其参数props和context,详细讲解了响应式API,包括reactive、ref、readonly和toRefs。此外,还探讨了computed、ref模板引用、生命周期函数的变化、Provide/Inject的使用、watch和watchEffect的异同,以及defineProps、defineEmits和defineExpose的作用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

setup函数

官方文档
setup函数的参数,主要有两个:props和context

  • props: 父组件传过来的属性会被放到props对象中,如果需要在setup函数中使用,可通过props参数获取,规则和vue2一致。
  • context,包含三个参数:
    • attrs: 所有的非prop的attribute
    • slots: 父组件传递过来的插槽(这个在渲染函数返回时会有用)
    • emit:当我们组件内部需要发出事件时会用到emit(因为我们不能访问this,所以不可以通过this.$emit发出事件)
<template>
  <div>
    <!-- template会自动将ref解包 -->
    <h1>{{count}}</h1>
    <button @click="increase">+1</button>
  </div>
</template>

<script>
import { ref } from 'vue'
export default {
  setup() {
    let count = ref(0);
    const increase = () => {
      console.log(count);
      count.value++
    }
    return {
      count,
      increase
    }
}
}
</script>

在这里插入图片描述

响应式API

reactive()

返回一个对象的响应式代理,通常用于复杂类型,比如:对象、数组。如果用于基本类型,会发出警告。
为什么使用reactive会变成响应式呢?
原因:当我们使用reactive函数处理我们的数据之后,数据再次被使用时就会进行依赖收集。当数据发生改变时,所以收集到的依赖都是进行对应的响应式操作。事实上,我们编写的data属性,也是在内部交给了reactive函数将其编程响应式对象的。

const count = ref(1)
const obj = reactive({ count })

// ref 会被解包
console.log(obj.count === count.value) // true

// 会更新 `obj.count`
count.value++
console.log(count.value) // 2
console.log(obj.count) // 2

// 也会更新 `count` ref
obj.count++
console.log(obj.count) // 3
console.log(count.value) // 3

ref()

接受一个内部值,返回一个响应式的、可更改的 ref 对象,此对象只有一个指向其内部值的属性 .value。用常用于基本类型,比如:String、Number、Boolean

const count = ref(0)
console.log(count.value) // 0

count.value++
console.log(count.value) // 1

readonly()

接受一个对象 (不论是响应式还是普通的) 或是一个 ref,返回一个原值的只读代理。
详细信息: 只读代理是深层的:对任何嵌套属性的访问都将是只读的。它的 ref 解包行为与 reactive() 相同,但解包得到的值是只读的。

const original = reactive({ count: 0 })

const copy = readonly(original)

watchEffect(() => {
  // 用来做响应性追踪
  console.log(copy.count)
})

// 更改源属性会触发其依赖的侦听器
original.count++

// 更改该只读副本将会失败,并会得到一个警告
copy.count++ // warning!

toRefs

官方文档
将一个响应式对象转换为一个普通对象,这个普通对象的每个属性都是指向源对象相应属性的 ref。每个单独的 ref 都是使用 toRef() 创建的。

如果我们使用ES6的结构语法,对reactive返回的对象进行解构获取值,那么之后无论是修改解构后的变量,还是修改reactive返回的state对象,数据都不再是响应式的:

const state = reactive({
	name: "张三",
	age: 18
});
const { name, age } = state;

那么有没有办法让我们解构出来的属性是响应式的呢?
Vue为我们提供了一个toRefs的函数,可以将reactive返回的对象中的属性都转成ref,那么我们再次进行解构出来的name和age本身都是ref的:

// 此时,name和age都是响应式的
const { name, age } = toRefs(state);

然后修改name或者state.name中一个,另一个也会随着发生改变。

computed

官方文档
接受一个 getter 函数,返回一个只读的响应式 ref 对象。该 ref 通过 .value 暴露 getter 函数的返回值。它也可以接受一个带有 get 和 set 函数的对象来创建一个可写的 ref 对象。
创建一个只读的计算属性 ref:

const count = ref(1)
const plusOne = computed(() => count.value + 1)

console.log(plusOne.value) // 2

plusOne.value++ // 错误

创建一个可写的计算属性 ref:

const count = ref(1)
const plusOne = computed({
  get: () => count.value + 1,
  set: (val) => {
    count.value = val - 1
  }
})

plusOne.value = 1
console.log(count.value) // 0

ref模板引用

官方文档
在vue2.x中使用模板引用通过this.$refs.xxx进行获取,但是vue3.x的组合式API并没有this,那么该怎么使用模板引用呢?
通过ref()。
在这里插入图片描述

在这里插入图片描述

生命周期函数

vue3.x组合式API中,生命周期函数的用法都差不多,都是注册一个回调函数,在组件挂载完成后执行;
举个例子:
function onMounted(callback: () => void): void
在这里插入图片描述

在这里插入图片描述

Provide/Inject函数

官方文档

provide

provide() 接受两个参数:第一个参数是要注入的 key,可以是一个字符串或者一个 symbol,第二个参数是要注入的值。

<script setup>
import { ref, provide } from 'vue'
import { fooSymbol } from './injectionSymbols'

// 提供静态值
provide('foo', 'bar')

// 提供响应式的值
const count = ref(0)
provide('count', count)

// 提供时将 Symbol 作为 key
provide(fooSymbol, count)
</script>

inject

注入一个由祖先组件或整个应用 (通过 app.provide()) 提供的值。

第一个参数是注入的 key。Vue 会遍历父组件链,通过匹配 key 来确定所提供的值。如果父组件链上多个组件对同一个 key 提供了值,那么离得更近的组件将会“覆盖”链上更远的组件所提供的值。如果没有能通过 key 匹配到值,inject() 将返回 undefined,除非提供了一个默认值。

第二个参数是可选的,即在没有匹配到 key 时使用的默认值。它也可以是一个工厂函数,用来返回某些创建起来比较复杂的值。如果默认值本身就是一个函数,那么你必须将 false 作为第三个参数传入,表明这个函数就是默认值,而不是一个工厂函数。

<script setup>
import { inject } from 'vue'
import { fooSymbol } from './injectionSymbols'

// 注入值的默认方式
const foo = inject('foo')

// 注入响应式的值
const count = inject('count')

// 通过 Symbol 类型的 key 注入
const foo2 = inject(fooSymbol)

// 注入一个值,若为空则使用提供的默认值
const bar = inject('foo', 'default value')

// 注入一个值,若为空则使用提供的工厂函数
const baz = inject('foo', () => new Map())

// 注入时为了表明提供的默认值是个函数,需要传入第三个参数
const fn = inject('function', () => {}, false)
</script>

watch

官方文档
watch() 默认是懒侦听的,即仅在侦听源发生变化时才执行回调函数。

第一个参数是侦听器的源。这个来源可以是以下几种:
一个函数,返回一个值
一个 ref
一个响应式对象
…或是由以上类型的值组成的数组
第二个参数是在发生变化时要调用的回调函数。这个回调函数接受三个参数:新值、旧值,以及一个用于注册副作用清理的回调函数。该回调函数会在副作用下一次重新执行前调用,可以用来清除无效的副作用,例如等待中的异步请求。

当侦听多个来源时,回调函数接受两个数组,分别对应来源数组中的新值和旧值。

在这里插入图片描述

在这里插入图片描述

watchEffect

官方文档
立即运行一个函数,同时响应式地追踪其依赖,并在依赖更改时重新执行。

const count = ref(0)
// 只要count发生变化,下面函数就会自动执行
// count = 10 就停止
// watchEffect(() => console.log(count.value))
const stop = watchEffect(() => {
	console.log(count.value);
	if (stop > 10) {
		stop();
	}
})
// -> 输出 0

count.value++
// -> 输出 1


defineProps() 和 defineEmits()

官方文档

为了在声明 props 和 emits 选项时获得完整的类型推导支持,我们可以使用 defineProps 和 defineEmits API,它们将自动地在

<script setup>
const props = defineProps({
  foo: String
})

const emit = defineEmits(['change', 'delete'])
// setup 代码
// emit('change',...args);
</script>

  • defineProps 和 defineEmits 都是只能在 <script setup> 中使用的编译器宏。他们不需要导入,且会随着 <script setup> 的处理过程一同被编译掉。
  • defineProps 接收与 props 选项相同的值,defineEmits 接收与 emits 选项相同的值。
  • defineProps 和 defineEmits 在选项传入后,会提供恰当的类型推导。
  • 传入到 defineProps 和 defineEmits 的选项会从 setup 中提升到模块的作用域。因此,传入的选项不能引用在 setup 作用域中声明的局部变量。这样做会引起编译错误。但是,它可以引用导入的绑定,因为它们也在模块作用域内。

defineExpose

官方文档
使用 <script setup> 的组件是默认关闭的——即通过模板引用或者 $parent 链获取到的组件的公开实例,不会暴露任何在 <script setup> 中声明的绑定。

可以通过 defineExpose 编译器宏来显式指定在 <script setup> 组件中要暴露出去的属性:

<script setup>
import { ref } from 'vue'

const a = 1
const b = ref(2)

defineExpose({
  a,
  b
})
</script>

// 父组件就可以通过ref模板引用获取了(方法也是这样)
xxxRef.value.a;

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值