组件三大API之一: prop

  • prop的大小写
  • prop接收类型
    • 字符串数组形式
    • 对象形式: type / required / default / validator
  • prop传递类型: 静态传递 / 动态绑定
  • 单向数据流
  • 非prop:替换或合并 / 禁用inheritAttrs:false / $attrs

上节对组件的概念讲到,组件是可复用的Vue实例,并且组件可以嵌套,组件间可以相互通信。

两个嵌套的组件通信,父组件向子组件传值,常规的做法就是采用prop

先看个一个例子直观感受下:

<div id="app">
<p>这个一个父子组件传值的例子</p>
<my-child text-color="red"></my-child>
</div>
new Vue({
el: '#app',
components: {
MyChild: {
template: `<div :style="{color: textColor}">The text will be colorfully</div>`,
props: ['textColor']
// 在子组件中可以像使用data数据一样使用props中的数据。
}
}
})

prop的大小写

在组件命名规范中提到过,HTML是大小写不敏感的,在DOM模板中必须使用 kebab-case,即连字符-形式。在JS域中,prop使用camelCase ,即小驼峰形式。区别于组件名的PascalCase大驼峰形式。

prop接收值类型

简单的传值可以采用数组形式,但更建议使用语义更明确,且带有数值验证功能的对象形式。这样当 prop 验证失败的时候,开发环境下, Vue 将会在控制台产生一个警告。

字符串数组形式

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

带验证功能的对象形式:type / required / default / validator

// 官方示例
Vue.component('my-component', {
props: {
// 基础的类型检查 (`null` 和 `undefined` 会通过任何类型验证)
// type类型可以是:String Number Boolean Array Function Object Date Symbol
// type也可以是自定义的构造函数,内部将通过 instanceof 检查确认
propA: Number,
// 多个可能的类型
propB: [String, Number],
// 必填的字符串
propC: {
type: String,
required: true
},
// 带有默认值的数字
propD: {
type: Number,
default: 100
},
// 带有默认值的对象
propE: {
type: Object,
// 对象或数组默认值必须从一个工厂函数获取,原因同data一样
default: function () {
return { message: 'hello' }
}
},
// 自定义验证函数,通过true 不通过false
propF: {
validator: function (value) {
// 这个值必须匹配下列字符串中的一个
return ['success', 'warning', 'danger'].indexOf(value) !== -1
}
}
}
})

父级组件传递prop的方式

静态传值

静态传值,始终将值以字符串形式传递到子组件接收。

<my-child text-color="red"></my-child>

<!-- 子组件接收的到number值是字符串类型1,而不是数值1。 -->
<my-child number="1"></my-child>
<!-- isUse接收到是字符串"false",如果对isUse验证布尔值,将当作true验证通过。 -->
<my-child is-user="false"></my-child>

如果传值要符合预期,就要使用动态传值,将prop值用v-bind / :绑定。

如果是将父组件的响应式数据,如data/computed数据传递,也必须用v-bind / : 绑定,这样父组件中的值变化,也会响应更新到子组件使用对应prop的地方。

动态传值

引用官方示例,需要查看官方原文请点击

传入一个响应式动态变量

<!-- 传递一个动态变量color可以在data或computed中声明 -->
<my-child :text-color="color"></my-child>

传入一个数字

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

传入一个布尔值

<!-- 即使该is-published没有值的情况在内,都意味着 `true`。-->
<blog-post is-published></blog-post> <!-- 即便 `false` 是静态的,我们仍然需要 `v-bind` 来告诉 Vue -->
<!-- 这是一个 JavaScript 表达式而不是一个字符串。-->
<blog-post v-bind:is-published="false"></blog-post> <!-- 用一个变量进行动态赋值。-->
<blog-post v-bind:is-published="post.isPublished"></blog-post>

传入一个数组

<!-- 即便数组是静态的,我们仍然需要 `v-bind` 来告诉 Vue -->
<!-- 这是一个 JavaScript 表达式而不是一个字符串。-->
<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="author"
></blog-post>
data: {
author: {
name: 'Veronica',
company: 'Veridian Dynamics'
}
}
<!-- 组件接收时格式:组件可以通过打点访问对象的属性 -->
Vue.component('child', {
props: ['author'],
template: '<span >{{ author.name }} {{author.company}}</span>'
}) <!-- 将一个对象的所有属性都作为 prop 传入-->
<blog-post v-bind="author"></blog-post>
<!-- 组件接收格式:props需要声明对象的每个属性 -->
Vue.component('child', {
props: ['name','company'],
template: '<span >{{ name }} {{company}}</span>'
})

单向数据流

prop使父子组件间形成了一个单向数据绑定,父组件的值可以供子组件调用。在使用v-bind动态绑定时,每当父组件传入的值发生更新,子组件也会将对应的prop刷新。但是子组件无法对prop值直接进行修改,如果这样做,控制台会发出警告。

这就是组件prop的单向数据流特性。

但是在实现项目中,子组件内部在使用prop值的地方并不是一直不变的,可能初始值使用prop传入的值,但后面在子组件内还会更新此处的值,但受限于无法在子组件内直接修改prop,所以可以尝试以下两种方式:

  • 将传入的prop赋值给data作为初始值

    此时prop仅会被使用一次,当赋值给data后,即使父组件更新prop值也不会对子组件有影响。
props: ['initialCounter'],
data: function () {
return {
// 在前面讲解生命周期章节中有标示,在初始化阶段Vue内部initProp在initMethods/initData之前开始,所以可以在data中直接使用this.prop进行赋值
counter: this.initialCounter
}
}
  • 将传入的prop使用计算属性包装一层使用,此时父组件更新prop仍会使子组件更新,而且可以通过计算属性的setter对赋值操作进行拦截处理
props: ['size'],
computed: {
normalizedSize: function () {
return this.size.trim().toLowerCase()
}
}
  • 注意对prop传入引用类型数据(对象、数组)的修改产生的影响

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

非prop的特性

一个非 prop 特性是指父组件有传向子组件,但是子组件并没有在 props中定义的特性。

此时这些非prop特性会按以下规则处理:

  • 直接作用于组件的根元素上。

    • 如果子组件的根元素上已经定义过这个特性,那么外部传入的特性将会覆盖子组件内部定义的特性,外部优先权更大
    • class 和 style 会智能的进行合并,而不是简单的覆盖
  • 如果不想子组件根元素接收这些非prop特性,则需要在子组件内部声明inheritAttrs: false。但这条声明对class 和 style 智能合并行为无效,即class/style仍会合并非prop

  • 不管根元素是默认接收非prop特性,还是显示声明了拒绝接收,这些非prop特性都会被vue内部定义的$attrs对象接收(除class/style)。并且这个对象在子组件内部可以通过this.$attrs进行正常调用。

    比如:v-bind='$attrs'动态传入当前子组件的子组件,或仍绑定在当前子组件上,进行兜底。

<div id="app">
<base-input
label='示例'
v-model="username"
autofocus
placeholder="Enter your username"
></base-input>
</div>
// v-bind="$attrs",相当于将整个$attrs对象值作用于元素上。见上面动态绑定一个对象所有属性示例
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)"
>
{{ $attrs }}
</label>
`,
created(){
console.log('$attrs in baseInput',this.$attrs)
}
})
const vm = new Vue({
el: "#app",
data: {
username: '',
},
mounted() {
this.$nextTick(() => {
console.log('$attrs in vm',this.$attrs)
})
}
})
$attrs in baseInput: {autofocus: "", placeholder: "Enter your username"}
$attrs in vm: {}

vue-learning:26 - component - 组件三大API之一:prop的更多相关文章

  1. vue-learning:29 - component - 组件三大API之三:slot

    组件三大API之三: slot <slot>标签 v-slot指令 普通插槽 有默认值的插槽 具名插槽 作用域插槽 v-slot是Vue 2.6.0引入的一个新语法指令,目的是统一之前sl ...

  2. vue-learning:27 - component - 组件三大API之二:event

    组件三大API之二: event 在上一节中讲到prop单向下行数据绑定的特征,父组件向子组件传值通过prop实现,那如果有子组件需要向父组件传值或其它通信请求,可以通过vue的事件监听系统(触发事件 ...

  3. Vue.js 组件的三个 API:prop、event、slot

    组件的构成 一个再复杂的组件,都是由三部分组成的:prop.event.slot,它们构成了 Vue.js 组件的 API.如果你开发的是一个通用组件,那一定要事先设计好这三部分,因为组件一旦发布,后 ...

  4. 第六章 组件 59 组件切换-使用Vue提供的component元素实现组件切换

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8&quo ...

  5. Vue.js——60分钟组件快速入门(下篇)

    概述 上一篇我们重点介绍了组件的创建.注册和使用,熟练这几个步骤将有助于深入组件的开发.另外,在子组件中定义props,可以让父组件的数据传递下来,这就好比子组件告诉父组件:"嘿,老哥,我开 ...

  6. Vue.js——60分钟组件快速入门

    一.组件简介 组件系统是Vue.js其中一个重要的概念,它提供了一种抽象,让我们可以使用独立可复用的小组件来构建大型应用,任意类型的应用界面都可以抽象为一个组件树: 那么什么是组件呢?组件可以扩展HT ...

  7. Vue.js——60分钟组件快速入门(下篇)

    转自:https://www.cnblogs.com/keepfool/p/5637834.html 概述 上一篇我们重点介绍了组件的创建.注册和使用,熟练这几个步骤将有助于深入组件的开发.另外,在子 ...

  8. 简述在Vue脚手架中,组件以及父子组件(非父子组件)之间的传值

    1.组件的定义 组成: template:包裹HTML模板片段(反映了数据与最终呈现给用户视图之间的映射关系) 只支持单个template标签: 支持lang配置多种模板语法: script:配置Vu ...

  9. Vue:Vue的介绍以及组件剖析

    介绍 现在,随着基于JavaScript的单页应用程序(SPA)和服务器端渲染(SSR)的兴起,可以用JavaScript编写整个前端应用程序,并整洁地管理和维护该应用程序的前端代码.诸如Angula ...

随机推荐

  1. 中国境内PE\VC\投资公司名单

    中国境内PE\VC\投资公司名单 1.青云创投 2.高盛 3.红杉资本 4.鼎晖创投 5.枫丹国际 6.派杰投资银行 7.凯雷投资 8.长安私人资本 9.格林雷斯 10.汉能资本 11.启明创投 12 ...

  2. 【JZOJ4888】【NOIP2016提高A组集训第14场11.12】最近公共祖先

    题目描述 YJC最近在学习树的有关知识.今天,他遇到了这么一个概念:最近公共祖先.对于有根树T的两个结点u.v,最近公共祖先LCA(T,u,v)表示一个结点x,满足x是u.v的祖先且x的深度尽可能大. ...

  3. 2019.9.10附加题while练习

    题目:企业发放的奖金根据利润提成.利润(I)低于或等于10万元时,奖金可提10%:利润高于10万元,低于20万元时,低于10万元的部分按10%提成,高于10万元的部分,可提成7.5%:20万到40万之 ...

  4. iOS 后台定位

    http://www.cocoachina.com/ios/20150724/12735.html 前言 之前的文章说过 我现在做的是LBS定位的社交APP 其中主要的一个功能就是能够实时定位社交圈中 ...

  5. Java练习 SDUT-3339_计算长方形的周长和面积(类和对象)

    计算长方形的周长和面积(类和对象) Time Limit: 1000 ms Memory Limit: 65536 KiB Problem Description 设计一个长方形类Rect,计算长方形 ...

  6. 阿里开源新一代 AI 算法模型,由达摩院90后科学家研发

    最炫的技术新知.最热门的大咖公开课.最有趣的开发者活动.最实用的工具干货,就在<开发者必读>! 每日集成开发者社区精品内容,你身边的技术资讯管家. 每日头条 阿里开源新一代 AI 算法模型 ...

  7. 《C语言深度解剖》学习笔记之关键字

    第一章 关键字 C语言共有32个关键字. 关键字   auto 声明自动变量 int 声明整型变量 long 声明长整型变量 char 声明字符型变量 float 声明浮点型变量 short 声明短整 ...

  8. C++:只用初始化列表初始化变量的几种情况

    1.类成员函数中const变量的初始化(也就是第一点) 有几个容易混淆的地方: (1)const 的变量只能通过构造函数的初始化列表进行初始化:(貌似在C++11中可以正常编译) (2)static ...

  9. hdu 2473 Junk-Mail Filter (暴力并查集)

    Problem - 2473 为什么标题写的是暴力并查集?因为我的解法跟网上的有所不同,方法暴力很多. 先解释题意,这是一个模拟处理垃圾邮件的问题.垃圾邮件要根据它们的性质进行分类.对于10w个邮件, ...

  10. js 过滤富文本标签数据

    var str = '<p><code>uni-app</code> 完整支持 <code>Vue</code> 实例的生命周期,同时还新增 ...