1x1 精读Vue官方文档 - Prop

发布于 2022年 02月 23日 04:22

精读 Vue 官方文档系列 🎉

Prop 的大小写

Prop 的命名支持以下两种方式:

  • camelCase : 驼峰命名法中的小驼峰。
  • kebab-case : 分隔符命名法

虽然 Vue 模板的编译器可以同时支持以上两种命名方式,但受限于浏览器对大小写字母的不敏感,再加上 W3C 推荐的是 kebab-case 方式来作为自定义元素的命名规范,所以,在最佳实践中,我们会以 kebaba-case 方式来命名元素与 Attribute,而在组件的逻辑中,则使用 camelCase 方式。

<blog-post :post-id="post.id" :post-content="post-content" name="article" />
export default {
    name:'MyComponent',
    props:['postId','postContent']
}

Prop 类型

使用 props 属性来声明组件使用到的 prop

只有通过 props 选项声明后的 prop 才能被组件实例访问,值通常是一个字符串数组

prop 类型

如果希望为每个 prop 指定值的类型,那么可以通过对象的形式列出 prop。 为 prop 值指定类型的好处:

  • 规范组件文档。
  • 类型检测与提示。

默认类型

将浏览器内置的原生构造函数作为类型。 例如:NumberStringDateBooleanObjectArrayPromiseFunctionSymbol

自定义类型

prop 值的类型也可以是一个自定义构造函数,Vue 会自动通过 instanceof 运算符去比较。

props:{
    jack:Human
}

传递静态或动态 Prop

传递静态数据

传递静态数据,普通字符串,直接使用 HTML Attribute 的方式赋值。

<my-component name="article" />

传递动态数据

传递动态数据、变量或响应式对象、需要使用 v-bind 指令动态赋值。

<my-component :post-id="post.id" />

静态赋值与动态赋值对比

传输字符串类型

<my-component name="article" />
<my-component2 :name="'article'" />

传入对象类型

<!--组件接收的实际上是一个字符串,需要自己 JSON.parse-->
<my-component post="{name:'article',content:'content'}" /> 
<my-component2 :post="data.post" />

传入一个对象的所有 property

将一个对象的所有”键值对“作为 prop 传递到子组件。 实现非常简单,为v-bind指令赋值。

export default {
    data(){
        return {
            post:{title:'post title'},
            property:{name:'name', title:'title', description:'desc'}
        }
    }
}
<my-component v-bind="property" :post-title="post.title"/>
export default {
    name:'MyComponent',
    props:['title', 'name', 'description', 'postTitle']
}

单向数据流

为了让数据流向更加清晰,Vue 规定父子之间的 Prop 传递只能是一个单向下行绑定,即父级 prop 的更新会向下流到子组件中,并触发子组件更新,但反过来则不行,以防止子组件意外变更父级的状态。

如果强行在子组件中变更父级传递的 prop,则 Vue 会在控制台抛出警告⚠️

需要变更 prop 的常见情形有:

接收父组件通过 prop 传递的一个初始值,并且需要对这个值进行变更。

建议将父级的 prop 转换为组件自身的 `data`。

父组件传入的 prop 需要进行转换方能使用

推荐使用 `computed` 属性。

对于引用类型的值,例如数组或对象,很容易会在子组件中被误改,从而影响父组件的状态。

Prop 验证与类型检查

为 props 中的值提供一个具有验证功能的对象,而不是单单一个字符串数组。

简单的类型验证与自定义类型验证:

{
    props:{
        name:String,
        post:[Object, Array],
        author:Person,
        symb:Symbol
    }
}

默认值或必填值:

{
    props:{
        name:{
            type:String,
            default:'jack'
        },
        age:{
            type:Number,
            default:function(){
                if(sex==='male'){
                    return 10;
                }
                
                return 9;
            }
        },
        sex:{
            type:Number,
            required:true
        }
    }
}

自定义验证函数:

{
    props:{
        propF: {
          validator: function (value) {
            // 这个值必须匹配下列字符串中的一个
            return ['success', 'warning', 'danger'].indexOf(value) !== -1
          }
        }
    }
}

当 prop 验证失败的时候,(开发版本) Vue 将会产生一个控制台的警告。 注意这些 prop 会在组件的实例创建之前便会进行验证,所以对于 defaultvalidator 等函数中是访问不到组件的实例的。

非 Prop 的 Attribute

Prop 一定是 Attribute,但并不是所有的 Attrbiute 都是 Prop。只有在组件的 props 选项中声明的 Attribute 才会是 Prop。

组件默认接收所有 Attribute 并添加到组件的根元素上,好处在于未来组件的扩展。

Attribute 的继承

通过组件的 inheritAttrs:true|false 选项便可以开启/关闭组件的 Attribute 继承。 默认为启用继承,此时为组件添加的非 Prop 的 Attribute 会自动附加在组件的根元素上。

export default {
  name: "MyInput",
  inheritAttrs:true,
  template:'<input />'
};
<my-input type="text" size="15" placeholder="please enter your username" />

最终渲染的HTML结果为:

<input type="text" size="15" placeholder="please enter your username">

如果设置 inheritAttrsfalse,则渲染的结果为

<input>

Attribute 的替换与合并

Attribute 的继承又带来了新的问题,如果组件的根元素已经存在了与父级传入相同的 Attribute,那么 Vue 会用传入的值替换组件内设置好的值。但是对于 classstyle 两个 Attribute 会稍微智能一些,Vue 会合并传入的值,而不是进行替换操作。

Attribue 的分发

为了增强撰写基础组件的能力,我们有时会需要禁用 Attribute 的继承,并不总是希望组件的根元素去继承 Attribute,而是可以由开发者手动分配。庆幸的是通过组件实例的 $attrs 属性结合组件 inheritAttrs 选项,我们可以手动决定 Attribute 应该要被赋予哪些元素上。

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 元素,而不会担心哪个元素是真正的根元素。

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

推荐文章