Vue | 13 组件深入-Props

内容提要:

  1. Prop的大小写与类型
  2. 传递动态和静态的Props
  3. 单向数据流
  4. Prop的验证
  5. 非Prop属性

这页假设你已经读了Components Basics,如果你不了解组件首先读它。

Prop大小写(cameCase vs kebab-case)

HTML属性名是大小写不敏感的,所以浏览器将解释任何大小字符作为小写字母。那意味着当你在DOM模板里使用的时候,camelCased(驼峰命名法) prop 名字会用它的等价物kebab-cased(以连字符分隔):

Vue.component('blog-post',{
    // cameCase in JavaScript
    props: ['postTitle'],
    template: '<h3>{{ postTitle }}</h3>'
})
<!-- kebab-case in HTML -->
<blog-post post-title="hello"!></blog-post>

此外,如果你使用字符串模板,这个限制不适用。

Prop 类型

到目前为止,我们仅仅看到props 被列作为字符串的数组:

props:['title','likes','isPublished','commentIds','author']

通常,你想要每一个prop具有一个特定的值类型,在这些例子中,你能列出props作为一个对象,属性的名字和值分别包含prop名字和类型:

props:{
    title: String,
    likes: Number,
    isPulished: Boolean,
    commentIds: Array,
    author: Object       
}

这不仅可以记录你的组件,而且如果你传错了类型也可以在浏览器的JavaScript 控制台警告用户,你能学到更多关于类型检查和其他prop校验在本页的后面type checks and other prop validations

传递静态或动态Props

到目前为止,你已经知道props传递一个静态值,像这样:

<blog-post title="My journey with Vue"></blog-post>

你也知道props用`v-bind动态赋值,像这样:

<!-- Dynamically assgin the value of a variable -->
<blog-post v-bind:title="post.title"></blog-post>

<!-- 动态分配一个复杂表达式的值 -->
<blog-post v-bind:title="post.title + ' by ' + post.author.name">

在上面的两个例子里,我们碰巧传递了字符串的值,但任何类型的值实际上都能传递给prop.

传递一个Number

<!-- 即使‘42’是一个静态的,我们需要 v-bind 去告诉Vue 这是一个JavaScript表达式而不是一个字符串 -->
<blog-post v-bind:likes="42"></blog-post>

传递一个布尔值

<!-- 包含无值的prop意味着‘true’ -->
<blog-post is-published></blog-post>

<!-- 虽然‘false’是静态的,我们需要v-bind告诉Vue,这是一个JavaScript表达式,而非一个字符串 -->
<blog-post v-bind:is-pubiished="false"></blog-post>

<!-- 动态分配一个变量的值 -->
<blog-post v-bind:is-published="post.isPublished"></blog-post>

传递一个数组

<!-- 虽然数组是静态的,我们需要v-bind告诉Vue -->
<blog-post v-bind:comment-ids="[234, 266, 273]"></blog-post>

<!-- 动态的分配变量的值 -->
<blog-post v-bind:comment-ids="post.commentIds"></blog-post>

传递一个对象

<!-- 虽然对象是静态的,我们需要v-bind 告诉Vue 这是一个JavaScript表达式而不是一个字符串-->
<blog-post v-bind:author="{name: 'Veronica', company: 'Veridian Dynamics'}"></blog-post>

<!-- 动态分配一个变量的值 -->
<blog-post v-bind:author="post.author"></blog-post>

传递一个对象的属性

如果你想传递一个对象的所有属性作为一个props,你可以使用v-bind不携带参数(v-bind 代替 v-bind:prop-name)例如,给一个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>

单向数据流

所有props表单在子属性和父节点形成一个单向向下绑定:当父属性更新的时候,它将流向子节点。但是反过来则不行。这样是为了阻止子节点意外的改变父节点的状态,造成你的应用数据流难于理解。

此外,每一次父组件被更新,所有在子组件的props都会被用最新的值刷新。这意味着你不应该在子组件内部改变一个prop,如果你这样做了,Vue将在控制台警告你。

这里有两个例子:试图去改变一个prop:

  1. prop被用于传递一个初始值,子组件想要以后用它作为一个本地数据属性。在这个例子里,最好用于去定义一个本地数据属性去使用prop作为初始值:

    props:['initialCounter']
    data: function: () {
        return {
            counter:this.initialCounter
        }
    }
    
  2. prop 被传递作为一个未处理的需要被转化的值。在这个例子里,最好定义一个计算属性用于prop’s的值:

    props:['size'],
        computed: {
            normalizedSize: function () {
                return this.size.trim().toLowerCase()
            }
        }
    

注意:对象和数组在JavaScript中通过引用被传递,所以如果prop是一个数组或对象,在子组件改变对象或数组本身将影响父组件的状态。

Prop 验证

组件可能指定条件对于props,如你所看到的类型。如果一个条件没有满足要求,Vue将会在浏览器的JavaScript后台给你警告。这在开发供别人使用的组件时尤其有用。

对于特定的prop校验,你能提供一个校验条件的对象给到props的值。代替一个数组字符串,例如:

Vue.component('my-component',{
    props:{
        // 基本类型检查(‘null’匹配任何类型)
        propA: Number,
        // 多个可能的类型
        propB:[String, Number],
        // 要求是字符串
        propC:{
            type: String,
            required: true
        },
        // 数字并给一个默认值
        propD:{
			type: Number,
            default: 100
        },
        // 用一个默认值的对象
        propE:{
			type:Object,
            // 对象或数组默认必须返回从一个工厂函数
            default: function() {
                return { message: 'hello' }
			}
        }
		// 自定义验证函数
        propF:{
            validator: function (value) {
                // The value must match one of these strings
                return ['success','warning','danger'].indexOf(value) !== -1
            }
        }
    }
})

当prop验证失败,Vue将产生一个后台警告(如果使用开发环境构建)

注意:props被验证需要在一个组件实例被创建之前,所以实例属性(e.g. data, computed, etc)将不可用在defaultvalidator函数。

类型检查

type可以是以下原生构造函数之一:

  • String
  • Number
  • Boolean
  • Array
  • Object
  • Date
  • Function
  • Symbol

此外,type也能够是自定义构造函数,并且断言将使用instanceof检查。例如,

给以下现成的构造函数:

function Person(firstName, lastName) {
    this.firstName = firstName
    this.lastName = lastName
}

你能用:

Vue.component('blog-post', {
    props: {
        author: Person
    }
})

去验证author的值是否使用new Person创建的。

非Prop 属性

一个非prop属性也是用于传递该组件的一个属性,但是没有相应的prop定义。

而显示的定义props更适合传递信息给子组件,组件库的作者不能总是预见组件总是被使用的上下文。这也是组件为什么能接受任意属性的原因。这就是为什么组件能接受任何属性被添加到组件的根元素的原因。

例如,假设我们使用一个第三方Bootstrap插件上的bootstrap-date-input,它需要一个inputdata-date-picker属性。我们能增加这个属性给我们的组件实例:

<bootstrap-date-input data-date-picker="activated"></bootstrap-date-input>

date-date-picker="activated"将自动被添加到bootstrap-date-input的根元素。

用已经存在的属性替换/合并

假设这是bootstrap-date-input的模板:

<input type="date" class="form-control">

为我们的日期选择插件指定一个主题,我们可能需要增加一个特定的类,例如:

<bootstrap-date-input
                      data-date-picker="activated"
                      class="date-picker-theme-dark">
</bootstrap-date-input>

在这个例子里,class被定义了两个不同的值。

  • form-control通过组件在它的模板中设的值
  • date-picker-theme-dark,通过它的父视图传递给组件

对于大部分属性,值被提供给组件将替换组件设置的值,例如这里,传递type=“text”将替换type=“date”并且破坏它,庆幸的是,classstyle属性更智能一点,他们的值被合并了,组成最后的值:form-control date-picker-theme-dark

禁用属性继承

如果你不希望组件的根元素去继承属性,你能在组件的操作项里设置inheritAttrs:false,例如:

Vue.component('my-component',{
    inheritAttrs: false,
})

这在与$attrs实例属性一起使用的时候特别有用,该属性包含属性的名字和值被传递给组件,例如:

{
    class: 'username-input',
    placeholder: 'Enter your username'
}

使用 inheritAttrs:false$attrs,你可以手动决定将属性转给哪一个元素,通常用基本组件base components描述:

Vue.component('base-input',{
    inheritAttrs: false,
    props: ['label','value'],
    template: `
    <label>
		{{ label }}
        <input
           v-bind="$attrs"
		   v-bind:value="value"
           v-on:input="$emit('input',$event.target.value)">
    </label>
`
})

该模式允许你想使用原生HTML元素那样使用基本组件,而不用担心哪个元素是真正的根元素:

<base-input
            v-model="username"
            class="username-input"
            placeholder="Enter your username ">
</base-input>

猜你喜欢

转载自blog.csdn.net/wudizhanshen/article/details/84778103