props 的写法

可以是对象也可以是数组

props为数组

  • 父组件
<template>
  <div>
  	<child id="1" :openReading="article.openReading" :title="article.title" :tags="article.tags" :author="article.author" />
  </div>
</template>
<script>
import Child from './components/Child'
 export default {
   components: { Child },
   data () {
    return {
      article: {
        id: 1,
        openReading: true,
        title: 'title',
        tags: ['vue', 'js'],
        author: {
          name: 'Jack'
        }
      }
    }
  }
 }
</script>

本例中,如果希望将article对象的所有属性都作为 prop 传入,可以使用不带参数的 v-bind

<template>
  <div>
  	<child v-bind="article" />
  </div>
</template>
  • 子组件
<template>
  <div>
    <div>{{id}} - {{openReading}} -{{title}}-{{tags}}-{{author.name}}</div>
  </div>
</template>

<script>
  export default {
    props: ['id', 'openReading', 'title', 'tags', 'author']
  }
</script>

给子组件prop 传入一个静态的值,该值将会是个字符串,如通过v-bind:(简写为:)传入则为一个表达式,通过这个方式即可为子组件传入动态的任意类型的值。
上例中,子组件得到的数据id为字符串1,openReading为布尔值true,title为字符串title,tags为数组[‘vue’, ‘js’],propE为对象{name: ‘Jack’}。

props为对象

在合作开发中,为了组件的健壮和可读性等需求,通常我们希望每个 prop 都有指定的值类型,默认值甚至验证传入的值是否规范等等,如将props设置为对象,则允许配置高级选项,如类型检测、自定义验证和设置默认值。
通过这些设置,遇到错误时浏览器的 JavaScript 控制台将会提示用户.

可使用的选项:

  • type:可以是下列原生构造函数中的一种:String、Number、Boolean、Array、Object、Date、Function、Symbol、任何自定义构造函数、或上述内容组成的数组。
  • default:any 指定默认值。如果该 prop 没有被传入,则换做用这个值。对象或数组的默认值必须从一个函数返回。
  • required:Boolean 用户定义该 prop 是否是必填项。
  • validator:Function

将子组件的配置项

props: ['id', 'openReading', 'title', 'tags', 'author']

改为

props: {
    id: {
      // 多个可能的类型
      type: [String, Number],
      required: true,
      // 自定义验证函数
      validator: (value) => {
        return parseInt(value) >= 0
      }
    },
    openReading: {
      type: Boolean,
      default: true
    },
    title: {
      type: String,
      default: ''
    },
    tags: {
      type: Array,
      default: () => [] // 对象或数组默认值必须从一个函数获取
    },
    author: {
      type: Object,
      default: () => {} // 对象或数组默认值必须从一个函数获取
    }
  }

Prop 的大小写

如果组件位于HTML中,必须将驼峰命名法的prop名改写为其等价的 kebab-case (短横线分隔命名)
,其他情况下两种写法等价。

<div id="app">
    <child parent-title="demo"></child>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
let Child = {
  template: `<div>{{parentTitle}}</div>`,
  props:['parentTitle']
}
new Vue({
  el:"#app",
  components: {Child}
});
</script>

使用.sync修饰符实现prop"双向绑定"

父组件

<child :id="1" :openReading.sync="article.openReading" :title="article.title" :tags="article.tags" :author="article.author" />

子组件

this.$emit('update:openReading', !this.openReading)

其中:openReading.sync="article.openReading"只是v-bind:openReading=“article.openReading” v-on:update:openReading="article.openReading= $event"的简写形式,并没有改变单向数据流
使用sync修饰符的时候,子组件传递的事件名必须为update:value,value必须与子组件中props中声明的名称完全一致(如上例中的openReading,不能使用open-reading

监听prop变化

如果来自父组件的prop发生了变化,在子组件生命周期beforeUpdate、updated能够监听到,通常子组件监听数据变化用watch监听数据变化
如下,监听id的变化

watch: {
   id: {
     handler (nVal, oVal) {
       console.log(nVal, oVal)
     },
     immediate: true // 该回调将会在侦听开始之后被立即调用
   }
 }

本例中,第一次打印出的数据是1 undefined

非Prop的 Attribute

指传向一个组件,但是该组件并没有相应 prop 定义的 attribute。

<child v-bind="article" style="color:red" class="article" className="article-list"/>

class将会自动挂载到子组件组件的组件根元素上,组件可以接受任意的 attribute

替换与合并

组件内部的Attribute与外部提供的Attribute发生重名的情况时,值会发生替换或合并
子组件

<div>
  <div style="font-size: 16px;" class="default" className="articleList">
    {{id}} - {{openReading}} -{{title}}-{{tags}}-{{author.name}}
  </div>
</div>

class 和 style和合并Attribute的值,其他的attribute ,父组件提供的值会替换掉组件内部设置好的值。

禁用

如果想禁用非 props 的 Attribute 属性的方法,可以给子组件增加配置项

inheritAttrs: false

inheritAttrs: false 选项不会影响 style 和 class 的绑定。

通过inheritAttrs: false 和 组件的$attrs,可以手动决定 attribute 被赋予哪个元素
子组件

<div>
  <div v-bind="$attrs">
    {{id}} - {{openReading}} -{{title}}-{{tags}}-{{author.name}}
  </div>
</div>