1. props
1.1 区别:
| 区别 | |||
|---|---|---|---|
| props | 需要先声明才能获取值 | props声明过的属性,attrs里面不会在出现 | 不包含事件 |
| attrs | 不用声明 | 包含事件 |
4.props支持string以外的类型,而attrs只有string类型
vue3中使用组件时,默认属性添加到组件的根元素上,如果想把属性放在指定的元素上,可以用v-bind="$attrs",但是这样做会把所有属性都导入进去,如果想指定元素添加的话,可以在setup(props,context)中 const {析构属性名, ...其他元素} = context.attrs,然后在通过v-bind绑定指定元素
1.2 作用
- 由来:通过 Prop 向子组件传递数据
- 当一个值被传递给一个 prop attribute 时,它就成为该组件实例中的一个 property
- 使用
v-bind来动态传递 prop。这在你一开始不清楚要渲染的具体内容,是非常有用的。
// 传入静态的porp
<blog-post title="My journey with Vue"></blog-post>
// 传入动态的porp (setTitle是自定义的变量)
<blog-post :title="setTitle"></blog-post>
// prop 可以传入数字
<blog-post :likes="42"></blog-post>
// prop 可以传入布尔值
<blog-post is-published></blog-post>
// prop 可以传入数组
<blog-post :comment-ids="[234, 266, 273]"></blog-post>
// prop 可以传入对象
<blog-post
:author="{
name: 'Veronica',
company: 'Veridian Dynamics'
}"
></blog-post>
post: {
id: 1,
title: 'My Journey with Vue'
}
<blog-post v-bind="post"></blog-post>
// 等价于:
<blog-post v-bind:id="post.id" v-bind:title="post.title"></blog-post>
// 可用于还不知道要传递什么内容时,可以使用v-bind传入一个变量(对象)
1.3 应用
单向数据流
所有的 prop 都使得其父子 prop 之间形成了一个单向下行绑定:父级 prop 的更新会向下流动到子组件中,但是反过来则不行。这样会防止从子组件意外变更父级组件的状态,从而导致你的应用的数据流向难以理解。
另外,每次父级组件发生变更时,子组件中所有的 prop 都将会刷新为最新的值。这意味着你不应该在一个子组件内部改变 prop。如果你这样做了,Vue 会在浏览器的控制台中发出警告。
这里有两种常见的试图变更一个 prop 的情形:
-
- 这个 prop 用来传递一个初始值;这个子组件接下来希望将其作为一个本地的 prop 数据来使用。
props: {
title: {
type: String,
default: '我的标题'
}
},
// this
const { proxy } = getCurrentInstance()
console.log(proxy)
const myTitle = proxy.title
console.log('myTitle', myTitle) // myTitle 我的标题
-
- 这个 prop 以一种原始的值传入且需要进行转换。在这种情况下,最好使用这个 prop 的值来定义一个计算属性:
props: {
newName: {
type: String,
default: 'zhangsan'
}
},
computed: {
getNewName () {
return this.newName.trim().toLowerCase()
}
}
注意: 对于一个数组或对象类型的 prop 来说,在子组件中改变这个对象或数组本身将会影响到父组件的状态,且 Vue 无法为此向你发出警告。作为一个通用规则,应该避免修改任何 prop,包括对象和数组,因为这种做法无视了单向数据绑定,且可能会导致意料之外的结果。
1.4 Prop 的大小写命名
HTML 中的 attribute 名是大小写不敏感的,所以浏览器会把所有大写字符解释为小写字符。这意味着当你使用 DOM 中的模板时,camelCase (驼峰命名法) 的 prop 名需要使用其等价的 kebab-case (短横线分隔命名) 命名:
<blog-post post-title="hello!"></blog-post>
props: {
postTitle: { // 在 JavaScript 中使用驼峰 camelCase
type: String,
default: ''
}
}
2. attrs
2.1 非 Prop 的 Attribute
- 一个非 prop 的 attribute 是指传向一个组件,但是该组件并没有相应 props 或 emits 定义的 attribute。常见的示例包括
class、style和idattribute。可以通过$attrsproperty 访问那些 attribute。
2.2 禁用 Attribute 继承
- 如果你不希望组件的根元素继承 attribute,可以在组件的选项中设置
inheritAttrs: false。 - 禁用 attribute 继承的常见场景是需要将 attribute 应用于根节点之外的其他元素。
- 通过将
inheritAttrs选项设置为false,你可以使用组件的$attrsproperty 将 attribute 应用到其它元素上,该 property 包括组件props和emitsproperty 中未包含的所有属性 (例如,class、style、v-on监听器等)。
<template>
<div>
<h2>
Father
</h2>
<Son
:id="newId"
:title-val="titleValue"
class="son-box"
/>
</div>
</template>
setup () {
const titleValue = ref('这是父组件传来的标题')
const newId = ref(123)
return {
titleValue,
newId
}
}
<style scoped lang="scss">
.son-box {
background-color: wheat;
}
</style>
//------------------------------------
<template>
<div>
<h3>Son</h3>
<p>{{ titleVal }}</p>
</div>
</template>
<script>
import {
defineComponent,
getCurrentInstance
} from 'vue'
import { useStore } from 'vuex'
export default defineComponent({
name: 'Son',
components: {},
inheritAttrs: true,
props: {
titleVal: {
type: String,
default: ''
}
},
setup () {
return {
}
}
})
</script>
inheritAttrs: true
inheritAttrs: false
2.3 多个根节点上的 Attribute 继承
与单个根节点组件不同,具有多个根节点的组件不具有自动 attribute fallthrough (隐式贯穿) 行为。如果未显式绑定 $attrs,将发出运行时警告。
<template>
<header>header</header>
<main>main</main>
<footer>footer</footer>
</template>
- 注意:如果没有根节点,将会出现警告。不知道要将Attribute传递给哪个元素
- 需要手动绑定
$attrs
<template>
<header>header</header>
<main v-bind="$attrs">
main
</main>
<footer>footer</footer>
</template>