了解Prop的使用

本文详细介绍了Vue组件中Prop的使用,包括大小写约定、类型定义、静态与动态传递、数值与布尔值传递、数组与对象传递、对象所有属性的传递以及单向数据流原则。同时,讨论了Prop验证的重要性,展示了如何定义和验证Prop类型,以及如何处理非Prop的attribute。此外,还提到了避免直接修改Prop和如何利用$attrs来管理组件的attribute。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Prop的大小写

HTML中的attribute(属性)名是大小写不敏感的,所以浏览器会把所有大写字符解释为小写字符,这样也就意味着aaBb(驼峰命名法)的prop名 等价于 aa-bb(短横线分隔命名)命名:
因此,在Vue2中,会约定(也算个人写法),使用class类名时,直接使用短横线分隔命名;而在使用函数命名时使用驼峰命名法,这样后期维护找相应的代码也好找

Vue.component('blog-post', {
    // 在js中最好使用 驼峰命名法
    props: ['postTitle'],
    template: '<h3>{{ postTitle }}</h3>'
})
<!-- 在HTML中 使用 短横线命名法 -->
<blog-post post-title="hello"></blog-post>

如果使用的是 字符串模板,那么这个限制就不存在了

Prop类型

我们只看到以字符串数组形式列出的prop:

props: ['title', 'content', 'author']

这时,我们就可以以对象形式列出prop,这些property的名称和值分别是prop各自的名称和类型:

props: {
    title: String,
    links: Number,
    isOver: Boolean,
    todoLists: Array,
    author: Object,
    callBack: Function,
    contactsPromise: Promise
}

这样对面传来不同类型的值,prop也会进行类型检查

传递静态或动态Prop

给prop传入一个静态的值:

<blog-post title="this is a title"></blog-post>

当然,我们也知道如何通过v-bind / :来动态赋值:

<!-- 动态赋予一个变量的值 -->
<blog-post :title="post.title"></blog-post>

<!-- 动态赋予一个比之前复杂的值,这个时候更喜欢 模板字符串 -->
<blog-post :title="`${post.title} by ${post.name}`"></blog-post>

上面两个例子中,传入的值都是字符串类型,但实际上任何类型我们都可以传递给prop,接下去慢慢看

传入一个数字

<!-- 即便是一个42是静态的,但是我们仍然需要使用 v-bind 来告诉Vue -->
<!-- 这是一个js表达式,而不是字符串 -->
<blog-post :number="42"></blog-post>

<!-- 最常见的便是使用变量 来进行动态赋值 -->
<blog-post :number="post.number"></blog-post>

传入一个布尔值

<!-- 包含prop没有值的情况在内,都意味着 true,比如于elemeneUI的属性 -->
<blog-post is-over></blog-post>

<!-- 这是一个js表达式 -->
<blog-post :is-over="false"></blog-post>

<!-- 用一个变量来赋值 -->
<blog-post :is-over="post.isOver"></blog-post>

传入一个数组

<!-- 这是一个js表达式 -->
<blog-post :comment="[24, 65, 85]"></blog-post>

<!-- 用一个变量来动态控制 -->
<blog-post :comment="post.commentList"></blog-post>

传入一个对象

<!-- 这是一个js表达式 -->
<blog-post
  :author="{
    name: 'post.name',
    age: 'post.name'
  }">  
</blog-post>

<!-- 用一个变量来控制 -->
<blog-post :author="post.author"></blog-post>

传入一个对象的所有property

如果想要将一个的对象的所有property都作为prop传入,可以使用不带参数的 v-bind(取代 v-bind: prop-name),例如,对于一个给定的对象post:

post: {
  id: 123,
  title: 'this is a title'
}

模板为:

<blog-post v-bind="post"></blog-post>

<!-- 等价于 -->
<blog-post
  :id="post.id"
  :title="post.title"
></blog-post>

单向数据流

所有的prop都使得父子prop之间形成了单向下行绑定:父级prop的更新会向下流动到子组件中,但是发过来就不行。这样会防止从子组件意外变更父级组件的状态,从而导致自己的数据流向难以理解。
看完prop,可以尝试看看 sync修饰符的原理和作用(Vue高级)
还有,每次父级组件数据省变更时,子组件中所有的prop都将会刷新为最新的值。这意味着你不应该在一个子组件内部改变prop,这样做,Vue会在浏览器的控制台中发出警告
这里有两种常见的试图变更一个prop的情形:(不应该做的)

  1. 这个prop用来传递一个初始值;这个子组件接下来希望将其作为一个本地的prop数据来使用。在这种情况下,最好定义一个本地的data property 并将这个prop用作其初始值:
props: ['initCiunter'],
data: function() {
    return {
        counter: this.initCounter
    }
}
  1. 这个prop以一种原始的值传入且需要进行转换。在这种情况下,最好使用这个prop的值来定义一个 计算属性 :
props: ['size'],
computed: {
    normalSize: funtion() {
        return this.size.trim().toLowerCase()
    }
}

*注意:*在js中对象和数组是通过引用传入的,所以对于一个数组或对象类型的prop来说,在子组件中改变变更这个对象或数组本身将会影响到父组件的状态:

Prop验证

我们在和别人合作(一起写组件)时,为防止对方传来的值类型错误,导致报错,我们都希望每个prop都有指定的值类型。

为了定制prop的验证方式,可以为props中的值提供一个带有验证需求的对象,而不是一个字符串数组:

Vue.component('my-component', {
  props: {
      // 基础类型的检查(null/undefined 会通过任何类型的验证)
      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(val) {
              // 这个值必须匹配以下字符串中的一个
              return ['success', 'warning', 'danger'].includes(val)
          }
      }
  }
  }  
})

当prop验证失败时,会在开发环境构建版本的 Vue ,产生一个控制台的警告。

*注意:*prop会在组件实例创建之前进行验证,所以实例的property(如data、computed等)在default或validator函数中是不可用的

类型检查

prop中 type 可以是下列原生构造函数中的一个:

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

还有,type 还可以是一个自定义的构造函数,并且通过 instanceof 来进行检查确认,比如,给定下列现成的构造函数

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

// 也可以使用
Vue.component('blog-post', {
    props: {
        author: Person
    }
})

来验证 author prop的值是否是通过 new Person 创建的

非prop的attribute

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

我们需要组件有什么样的attribute就需要将相应的attribute添加到这个组件的根元素上。

比如,我们现在需要使用Bootstrap插件使用第三方<bootstrap-date-input>组件,这个插件需要在其<input>上用到一个data-date-picker attribute,这时我们就可以将这个 attribute 添加到相应的组件实例上:

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

然后这个 data-date-picker="activated" attribute 就会自动添加到 <bootstrap-date-input> 的根元素上

替换/合并已有的Attribute

如果<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 这是从组件的父级传入的

对于绝大多数attribute来说,从外部提供给组件的值会替换组件内部设置好的值。所以如果传入 type="text" 就会替换掉 type="date" 并把它破坏。

还好,classstyle attribute会稍微智能些,两边的值会合并起来,从而得到最终的值:

form-control date-picker-theme-dark

禁用Attribute继承

如果不希望组件的根元素继承 attribute,可以在 组件的选项中设置 inheritAttrs: false

Vue.component('blog-post', {
    inheritAttrs: false,
    // ...
})

这十分适合配合 $attrs property使用,该property包含了传递给一个组件的 attribute 名和 attribute 值:

{
    require: true,
    placeholder: 'Enter your age'
}

有了 inheritAttrs: false$attrs,你就可以决定这些attribute会被赋予哪个元素,一般在写 基础组件 的时候是常用到的:

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

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

这个模式允许你在使用基础组件的时候更像是使用原始的HTML元素,而不会担心哪个元素是真正的根元素:

<base-input
	label="UserName:"            
    v-model="userName"
    required
    placeholder="请输入你的名字"
></base-input>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

@乐知者@

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值