参考:丁丁的哔哩哔哩
11.组件基础
- 传递 props
1.父组件
<BlogPost title="My journey with Vue" />
子组件
<script setup>
defineProps(['title'])
</script>
<template>
<h4>{{ title }}</h4>
</template>
2.props第二种声明方式
对于以对象形式声明的每个属性,key 是 prop 的名称,而值则是该 prop 预期类型的构造函数。
比如,如果要求一个 prop 的值是 number 类型,则可使用 Number 构造函数作为其声明的值
// 使用 <script setup>
defineProps({
title: String,
likes: Number
})
如果你正在搭配 TypeScript 使用 <script setup>
,也可以使用类型标注来声明 props:
<script setup lang="ts">
defineProps<{
title?: string
likes?: number
}>()
</script>
属性还可以是对象的形式
// 使用 <script setup>
defineProps({
title: {
type: String,
default: "你好",
required: true
},
list: {
type: Array,
default(){ // 对象或数组的默认值必须从一个工厂函数返回
return [];
}
}
})
-
单向数据流
props 因父组件的更新而变化,自然地将新的状态向下流往子组件,而不会逆向传递
-
子组件向父组件传递数据
$emit自定义触发事件
<script setup>
defineProps(['title'])
defineEmits(['enlarge-text'])
</script>
-
父子组件的访问方式
1.父组件访问子组件:
$refs
ref:用来给元素或子组件注册引用信息
<p ref="p" ></p>
console.log($refs) // 获取到p元素的各种属性
2.子组件访问父组件:`$parent` 不建议使用,因为子组件的复用性很高
3.子组件访问根组件:`$root`
- 通过插槽来分配内容
<!-- AlertBox.vue -->
<template>
<div class="alert-box">
<strong>This is an Error for Demo Purposes</strong>
<slot />
</div>
</template>
<style scoped>
.alert-box {
/* ... */
}
</style>
<AlertBox>
Something bad happened.
</AlertBox>
Something bad happened.将会被放到<slot />
中
12.插槽
- 具名插槽
给插槽定义名字
<div class="container">
<slot name="header"></slot>
<slot></slot>
<slot name="footer"></slot>
</div>
使用<template v-slot:header>
来插入插槽内容
<BaseLayout>
<template v-slot:header>
<!-- header 插槽的内容放这里 -->
</template>
</BaseLayout>
- 渲染作用域
插槽内容无法访问子组件的数据。Vue 模板中的表达式只能访问其定义时所处的作用域
:
父组件模板中的表达式只能访问父组件的作用域;子组件模板中的表达式只能访问子组件的作用域。 - 默认内容
<button type="submit">
<slot>
Submit <!-- 默认内容 -->
</slot>
</button>
- 作用域插槽
插槽的内容访问到子组件的状态。
1 在子组件传参
<!-- <MyComponent> 的模板 -->
<div>
<slot :text="greetingMessage" :count="1"></slot>
</div>
2 在父组件使用 v-slot=slotProps 获取参数
<MyComponent v-slot="slotProps">
{{ slotProps.text }} {{ slotProps.count }}
</MyComponent>
- 具名作用域插槽
同时使用了具名插槽与默认插槽,则需要为默认插槽使用显式的<template>
标签
<!-- <MyComponent> template -->
<div>
<slot :message="hello"></slot>
<slot name="footer" />
</div>
<MyComponent>
<!-- 使用显式的默认插槽 -->
<template #default="{ message }"> // 使用解构
<p>{{ message }}</p>
</template>
<template #footer>
<p>Here's some contact info</p>
</template>
</MyComponent>
13.依赖注入
- Provide (提供)
要为组件后代提供数据,需要使用到 provide() 函数。
第一个参数被称为注入名,可以是一个字符串或是一个 Symbol。第二个参数是提供的值,值可以是任意类型,包括响应式的状态。
<script setup>
import { provide } from 'vue'
provide(/* 注入名 */ 'message', /* 值 */ 'hello!')
</script>
一个组件可以多次调用 provide(),使用不同的注入名,注入不同的依赖值。
- 应用层 Provide
编写插件时会特别有用
import { createApp } from 'vue'
const app = createApp({})
app.provide(/* 注入名 */ 'message', /* 值 */ 'hello!')
- Inject (注入)
如果提供的值是一个 ref,注入进来的会是该 ref 对象
,而不会自动解包为其内部的值
<script setup>
import { inject } from 'vue'
const message = inject('message')
</script>
- 和响应式数据配合使用
当提供 / 注入响应式的数据时,建议尽可能将任何对响应式状态的变更都保持在供给方组件中。
生命周期钩子
vue3组合式API
组合式API,将同一个逻辑关注点相关代码收集到一起
export default {
setup(){
// 组件被创建之前执行,所以不需要引用this,this不会指向实例
const msg = "hello";
console.log(msg);
},
beforeCreated(){
console.log("beforeCreated")
},
created(){
console.log("created")
}
}
setup函数会在beforeCreated和created之前执行,写在beforeCreated和created中的也可以写在setup函数中!
- setup函数—响应式变量使用
export default {
setup(){
// "hello" 被包裹在了对象的value属性中,使用时需要.value引用
const msg = ref("hello");
console.log(msg);
function changeMsg(){
msg.value="你好";
}
// 定义响应式引用类型的数据
const obj = reactive({
name:"james",
age:18
})
function changeName(){
obj.name="curry"
}
// toRefs(object)使解构后的数据重新获得响应式
// 通过ES6扩展运算符进行结构使得对象中的属性不是响应式的
// ...toRefs(obj)可以获得响应式
return { msg, changeMsg, ...obj }
},
}
将值封装在一个对象中,看似没有必要,但为了保持 JavaScript 中不同数据类型的行为统一,这是必须的。这是因为在 JavaScript中,Number或 string等基本类型是通过值而非引用传递的
。包裹在对象中,value属性值变化,就会响应式更新?
- setup函数—watch
const user = reactive({
username:"张三",
age: 18
})
watch(user.age)这种形式监视不了age属性。
可以用watchEffect。
// watchEffect(回调函数)注意不需要指定监听的属性,组件初始化的时候会执行一次回调函数,自动收集依赖
watchEffect( ()=>{
console.log(user.age)
}
)
watchEffect、watch的区别:
- watchEffect不需要指定监听的属性,自动收集依赖,只要在回调中引用到了响应式的属性,只要这些属性发生改变,回调就会执行;watch只能侦听指定的属性,做出回调函数的执行,可以侦听多个,vue3开始后
- watch可以获取到新值和旧值,watcheffect拿不到
- watchEffect在组件初始化的时候就会自动执行一次,用来收集依赖,watch不需要,一开始就指定了
- setup函数—参数(props, context)
在使用<script setup>
的单文件组件中,props 可以使用 defineProps() 宏来声明:
<script setup>
const props = defineProps(['foo'])
console.log(props.foo)
</script>
export default{
props:{
title: String
}
setup(props){
console.log(props.title)
}
}
context参数