曹可爱之最可爱-Vue.js入门(十)组件2

Prop

使用Prop传递数据

组件实例的作用域是孤立的。这意味着不能在子组件的模版内直接引用父组件的数据,父组件的数据需要通过prop才能下发到子组件中。

子组件要显式地用props选项声明它预期的数据:

Vue.component('child', {
    // 声明props
    props: ['message'],
    // 就像data一样,prop也可以在模版中使用
    // 同样也可以在vm实例中通过 this.message来使用
    template: '<span>{{ message }}</span>
})

然后我们可以这样向它传入一个普通字符串:

<child message="hello!"></child>

camelCase vs.kebab-case

HTML特性是不区分大小写的。所以,当使用的不是字符串模版时,camelCase(驼峰式命名)的prop需要转换为相对应的kebab-case(短横线分隔式命名):

Vue.component('child' {
    // 在JavaScript中使用camelCase
    props: ['myMessage'],
    template: '<span>{{ myMessage }}</span>
})
<!-- 在 HTML 中使用 kebab-case -->
<child my-message="hello!"></child>

动态Prop

与绑定到任何普通HTML特性相类似,我们可以用v-bind来动态地将prop绑定到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件。

<div>
    <input v-model="parentMsg">
    <br>
    <child :my-message="parentMsg"></child>

如果你想把一个对象的所有属性作为prop进行传递,可以使用不带任何参数的v-bind。例如,已知一个todo对象:


todo: {
    text: 'Learn Vue',
    isComplete: false
}

然后:

<todo-item v-bind="todo"></todo-item>

将等价于:

<todo-item
    v-bind:text="todo.text"
    v-bind:is-complete="todo.isComplete"
></todo-item>

字面量语法 vs 动态语法

初学者常犯的一个错误是使用字面量语法传递数值:

<!-- 传递了一个字符串 "1" -->
<comp some-prop="1"></comp>

因为它是一个字面量prop,它的值是字符串”1” 而不是一个数值。如果想传递一个真正的js数值,则需要使用v-bind,从而让它的值被当作js表达式计算:

<!-- 传递真正的数值 -->
<comp v-bind:some-prop="1"></comp>

单向数据流

Prop是单向绑定的:当父组件的属性变化时,将传导给子组件,但是反过来不会。这是为了防止子组件无意间修改了父组件的状态,来避免应用变得难以理解。

另外,每次父组件更新时,子组件的所有prop都会更新为最新值。这意味着不应该在子组件内部改变prop。如果这么做了,Vue会在控制台给出警告。

在两种情况下,我们很容易忍不住想去修改prop中数据:

1.Prop作为初始值传入后,子组件想把它当作局部数据来用;
2.Prop作为原始数据传入,由子组件处理成其它数据输出。

对这两种情况,正确的应对方式是:

1.定义一个局部变量,并用prop的值初始化它:

props: ['initialCounter'],
data: function() {
    return { counter: this.initialCounter }
}

2.定义一个计算属性,处理prop的值并返回:

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

Prop验证

我们可以为组件的prop指定验证规则。如果传入的数据不符合要求,Vue会发出警告。对于开发给他人使用的组件非常有用。

要指定验证规则,需要用对象的形式来定义prop,而不能用字符串数组:

Vue.component('example', {
    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) {
                return value > 10
            }
        }
    }
})

type可以是下面原生构造器:

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

type也可以是一个自定义构造器函数,使用 instanceof检测。


非Prop特性

所谓非prop特性,是指它可以直接传入组件,而不需要定义相应的prop。

尽管为组件定义明确的 prop 是推荐的传参方式,组件的作者却并不总能预见到组件被使用的场景。所以,组件可以接收任意传入的特性,这些特性都会被添加到组件的根元素上。

例如,假设我们使用了第三方组件 bs-date-input,它包含一个 Bootstrap 插件,该插件需要在 input 上添加 data-3d-date-picker 这个特性。这时可以把特性直接添加到组件上 (不需要事先定义 prop):

<bs-data-input data-3d-data-picker="true"></bs-data-input>

添加属性 data-3d-date-picker=”true” 之后,它会被自动添加到 bs-date-input 的根元素上。


替换/合并现有的特性

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


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

为了给该日期选择器插件增加一个特殊的主题,我们可能需要增加一个特殊的 class,比如:

<bs-date-input
  data-3d-date-picker="true"
  class="date-picker-theme-dark"
></bs-date-input>

在这个例子当中,我们定义了两个不同的 class 值:
form-control,来自组件自身的模板
date-picker-theme-dark,来自父组件

我们对待 class 和 style 特性会更聪明一些,这两个特性的值都会做合并 (merge) 操作,让最终生成的值为:form-control date-picker-theme-dark。

总结:不想说什么,好烦。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值