props、attrs区别

277 阅读1分钟

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 的情形:

    1. 这个 prop 用来传递一个初始值;这个子组件接下来希望将其作为一个本地的 prop 数据来使用
props: {
    title: {
      type: String,
      default: '我的标题'
    }
},

// this
const { proxy } = getCurrentInstance()
console.log(proxy)

const myTitle = proxy.title
console.log('myTitle', myTitle)  // myTitle 我的标题
    1. 这个 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。常见的示例包括 classstyle 和 id attribute。可以通过 $attrs property 访问那些 attribute。

2.2 禁用 Attribute 继承

  • 如果你希望组件的根元素继承 attribute,可以在组件的选项中设置 inheritAttrs: false
  • 禁用 attribute 继承的常见场景是需要将 attribute 应用于根节点之外的其他元素。
  • 通过将 inheritAttrs 选项设置为 false,你可以使用组件的 $attrs property 将 attribute 应用到其它元素上,该 property 包括组件 props 和 emits property 中未包含的所有属性 (例如,classstylev-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
image.png image.png

inheritAttrs: false
image.png image.png

2.3 多个根节点上的 Attribute 继承

与单个根节点组件不同,具有多个根节点的组件不具有自动 attribute fallthrough (隐式贯穿) 行为。如果未显式绑定 $attrs,将发出运行时警告。

<template>
  <header>header</header>
  <main>main</main>
  <footer>footer</footer>
</template>
  • 注意:如果没有根节点,将会出现警告。不知道要将Attribute传递给哪个元素 image.png
  • 需要手动绑定 $attrs
<template>
  <header>header</header>
  <main v-bind="$attrs">
    main
  </main>
  <footer>footer</footer>
</template>