Vue props用法详解(小结)


Posted in Javascript onJuly 03, 2018

Vue props用法详解

组件接受的选项之一 props 是 Vue 中非常重要的一个选项。父子组件的关系可以总结为:

props down, events up

父组件通过 props 向下传递数据给子组件;子组件通过 events 给父组件发送消息。

父子级组件

比如我们需要创建两个组件 parent 和 child。需要保证每个组件可以在相对隔离的环境中书写,这样也能提高组件的可维护性。

这里我们先定义父子两个组件和一个 Vue 对象:

var childNode = {
 template: `
  <div>childNode</div>
  `
};
var parentNode = {
 template: `
  <div>
   <child></child>
   <child></child>
  </div>
  `,
 components: {
 child: childNode
 }
};
new Vue({
 el: "#example",
 components: {
 parent: parentNode
 }
});
<div id="example">
 <parent></parent>
</div>

这里的 childNode 定义的 template 是一个 div,并且内容是"childNode"字符串。

而在 parentNode 的 template 中定义了 div 的 class 名叫 parent 并且包含了两个 child 组件。

如果大家想对VUE.JS有更加深入系统的学习,可以参阅 Vue.js实战 PDF高质量扫描版 这本经典读物

静态 props

组件实例的作用域是孤立的。这意味着不能(也不应该)在子组件的模板中直接饮用父组件的数据。要让子组件使用父组件的数据,需要通过子组件的 props 选项。

父组件向子组件传递数据分为两种方式:动态和静态,这里先介绍静态方式。

子组件要显示的用 props 声明它期望获得的数据

修改上例中的代码,给 childNode 添加一个 props 选项和需要的forChildMsg数据;

然后在父组件中的占位符添加特性的方式来传递数据。

var childNode = {
 template: `
  <div>
   {{forChildMsg}}
  </div>
  `,
 props: ["for-child-msg"]
};
var parentNode = {
 template: `
  <div>
   <p>parentNode</p>
   <child for-child-msg="aaa"></child>
   <child for-child-msg="bbb"></child>
  </div>
  `,
 components: {
 child: childNode
 }
};

命名规范

对于 props 声明的属性,在父组件的 template 模板中,属性名需要使用中划线写法;

子组件 props 属性声明时,使用小驼峰或者中划线写法都可以;而子组件的模板使用从父组件传来的变量时,需要使用对应的小驼峰写法。别担心,Vue 能够正确识别出小驼峰和下划线命名法混用的变量,如这里的forChildMsgfor-child-msg是同一值。

动态 props

在模板中,要动态地绑定父组件的数据到子组件模板的 props,和绑定 Html 标签特性一样,使用v-bind绑定;

基于上述静态 props 的代码,这次只需要改动父组件:

var parentNode = {
 template: `
  <div>
   <p>parentNode</p>
   <child :for-child-msg="childMsg1"></child>
   <child :for-child-msg="childMsg2"></child>
  </div>
  `,
 components: {
 child: childNode
 },
 data: function() {
 return {
  childMsg1: "Dynamic props msg for child-1",
  childMsg2: "Dynamic props msg for child-2"
 };
 }
};

在父组件的 data 的 return 数据中的 childMsg1 和 childMsg2 会被传入子组件中,

props 验证

验证传入的 props 参数的数据规格,如果不符合数据规格,Vue 会发出警告。

能判断的所有种类(也就是 type 值)有:String, Number, Boolean, Function, Object, Array, Symbol

Vue.component("example", {
 props: {
 // 基础类型检测, null意味着任何类型都行
 propA: Number,
 // 多种类型
 propB: [String, Number],
 // 必传且是String
 propC: {
  type: String,
  required: true
 },
 // 数字有默认值
 propD: {
  type: Number,
  default: 101
 },
 // 数组、默认值是一个工厂函数返回对象
 propE: {
  type: Object,
  default: function() {
  console.log("propE default invoked.");
  return { message: "I am from propE." };
  }
 },
 // 自定义验证函数
 propF: {
  isValid: function(value) {
  return value > 100;
  }
 }
 }
});
let childNode = {
 template: "<div>{{forChildMsg}}</div>",
 props: {
 "for-child-msg": Number
 }
};
let parentNode = {
 template: `
   <div class="parent">
   <child :for-child-msg="msg"></child>
   </div>
  `,
 components: {
 child: childNode
 },
 data() {
 return {
  // 当这里是字符串 "123456"时会报错
  msg: 123456
 };
 }
};

还可以在 props 定义的数据中加入自定义验证函数,当函数返回 false 时,输出警告。

比如我们把上述例子中的 childNode 的for-child-msg修改成一个对象,并包含一个名叫validator的函数,该命名是规定叫validator的,自定义函数名不会生效。

let childNode = {
 template: "<div>{{forChildMsg}}</div>",
 props: {
 "for-child-msg": {
  validator: function(value) {
  return value > 100;
  }
 }
 }
};

在这里我们给for-child-msg变量设置了validator函数,并且要求传入的值必须大于 100,否则报出警告。

单向数据流

props 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。这是为了防止子组件五一修改父组件的状态。

所以不应该在子组件中修改 props 中的值,Vue 会报出警告。

let childNode = {
 template: `
   <div class="child">
   <div>
    <span>子组件数据</span>
    <input v-model="forChildMsg"/>
   </div>
   <p>{{forChildMsg}}</p>
   </div>`,
 props: {
 "for-child-msg": String
 }
};
let parentNode = {
 template: `
   <div class="parent">
   <div>
    <span>父组件数据</span>
    <input v-model="msg"/>
   </div>
   <p>{{msg}}</p>
   <child :for-child-msg="msg"></child>
   </div>
  `,
 components: {
 child: childNode
 },
 data() {
 return {
  msg: "default string."
 };
 }
};

这里我们给父组件和子组件都有一个输入框,并且显示出父组件数据和子组件的数据。当我们在父组件的输入框输入新数据时,同步的子组件数据也被修改了;这就是 props 的向子组件传递数据。而当我们修改子组件的输入框时,浏览器的控制台则报出错误警告

[Vue warn]: Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders. Instead, use a data or computed property based on the prop's value. Prop being mutated: "forChildMsg"

修改 props 数据

通常有两种原因:

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

应对办法是

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

但是由于定义的 ownChildMsg 只能接受 forChildMsg 的初始值,当父组件要传递的值变化发生时,ownChildMsg 无法收到更新。

let childNode = {
 template: `
   <div class="child">
   <div>
    <span>子组件数据</span>
    <input v-model="forChildMsg"/>
   </div>
   <p>{{forChildMsg}}</p>
   <p>ownChildMsg : {{ownChildMsg}}</p>
   </div>`,
 props: {
 "for-child-msg": String
 },
 data() {
 return { ownChildMsg: this.forChildMsg };
 }
};

这里我们加了一个<p>用于查看 ownChildMsg 数据是否变化,结果发现只有默认值传递给了 ownChildMsg,父组件改变只会变化到 forChildMsg,不会修改 ownChildMsg。

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

由于是计算属性,所以只能显示值,不能设置值。我们这里设置的是一旦从父组件修改了 forChildMsg 数据,我们就把 forChildMsg 加上一个字符串"---ownChildMsg",然后显示在屏幕上。这时是可以每当父组件修改了新数据,都会更新 ownChildMsg 数据的。

let childNode = {
 template: `
   <div class="child">
   <div>
    <span>子组件数据</span>
    <input v-model="forChildMsg"/>
   </div>
   <p>{{forChildMsg}}</p>
   <p>ownChildMsg : {{ownChildMsg}}</p>
   </div>`,
 props: {
 "for-child-msg": String
 },
 computed: {
 ownChildMsg() {
  return this.forChildMsg + "---ownChildMsg";
 }
 }
};

更加妥帖的方式是使用变量存储 prop 的初始值,并用 watch 来观察 prop 值得变化。发生变化时,更新变量的值。

let childNode = {
 template: `
   <div class="child">
   <div>
    <span>子组件数据</span>
    <input v-model="forChildMsg"/>
   </div>
   <p>{{forChildMsg}}</p>
   <p>ownChildMsg : {{ownChildMsg}}</p>
   </div>`,
 props: {
 "for-child-msg": String
 },
 data() {
 return {
  ownChildMsg: this.forChildMsg
 };
 },
 watch: {
 forChildMsg() {
  this.ownChildMsg = this.forChildMsg;
 }
 }
};

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
根据分辨率不同,调用不同的css文件
Aug 25 Javascript
Javascript(AJAX)解析XML的代码(兼容FIREFOX/IE)
Jul 11 Javascript
ExtJS 入门
Oct 29 Javascript
Easy.Ajax 部分源代码 支持文件上传功能, 兼容所有主流浏览器
Feb 24 Javascript
js计算两个时间之间天数差的实例代码
Nov 19 Javascript
js和jQuery设置Opacity半透明 兼容IE6
May 24 Javascript
jQuery插件EasyUI设置datagrid的checkbox为禁用状态的方法
Aug 05 Javascript
vue.js表单验证插件(vee-validate)的使用教程详解
May 23 Javascript
微信小程序实现商城倒计时
Nov 01 Javascript
vue+elementUi图片上传组件使用详解
Aug 20 Javascript
layUI的验证码功能及校验实例
Oct 25 Javascript
原生js实现下拉选项卡
Nov 27 Javascript
JavaScript设计模式之代理模式简单实例教程
Jul 03 #Javascript
详解Vue中使用Echarts的两种方式
Jul 03 #Javascript
vue awesome swiper异步加载数据出现的bug问题
Jul 03 #Javascript
JavaScript设计模式之工厂模式简单实例教程
Jul 03 #Javascript
js实现各浏览器全屏代码实例
Jul 03 #Javascript
React Native基础入门之初步使用Flexbox布局
Jul 02 #Javascript
JavaScript设计模式之构造函数模式实例教程
Jul 02 #Javascript
You might like
php获取post中的json数据的实现方法
2011/06/08 PHP
PHP中$_FILES的使用方法及注意事项说明
2014/02/14 PHP
php网页病毒清除类
2014/12/08 PHP
php实现mysql备份恢复分卷处理的方法
2014/12/26 PHP
PHP使用Pthread实现的多线程操作实例
2015/11/14 PHP
PHP使用SOAP调用API操作示例
2018/12/25 PHP
jQuery结合Json提交数据到Webservice,并接收从Webservice返回的Json数据
2011/02/18 Javascript
js获取IFRAME当前的URL的方法
2013/11/13 Javascript
ExtJS4中使用mixins实现多继承示例
2013/12/03 Javascript
JQuery打造省市下拉框联动效果
2014/05/18 Javascript
jQuery实现首页顶部可伸缩广告特效代码
2015/04/15 Javascript
JavaScript中操作字符串之localeCompare()方法的使用
2015/06/06 Javascript
jquery模拟alert的弹窗插件
2015/07/31 Javascript
解决js页面滚动效果scrollTop在FireFox与Chrome浏览器间的兼容问题的方法
2015/12/03 Javascript
easyui validatebox验证
2016/04/29 Javascript
jQuery常见的选择器及用法介绍
2016/12/20 Javascript
BootStrap CSS全局样式和表格样式源码解析
2017/01/20 Javascript
jquery实现表单获取短信验证码代码
2017/03/13 Javascript
vue中keep-alive的用法及问题描述
2018/05/15 Javascript
[01:59][TI9趣味视频] 全明星赛奖励
2019/08/23 DOTA
使用Python神器对付12306变态验证码
2016/01/05 Python
深入理解Django中内置的用户认证
2017/10/06 Python
详解通过API管理或定制开发ECS实例
2018/09/30 Python
python3.7 使用pymssql往sqlserver插入数据的方法
2019/07/08 Python
Django中提供的6种缓存方式详解
2019/08/05 Python
python GUI库图形界面开发之PyQt5多线程中信号与槽的详细使用方法与实例
2020/03/08 Python
Python+unittest+requests+excel实现接口自动化测试框架
2020/12/23 Python
企业管理专业个人求职信范文
2013/09/24 职场文书
年度考核自我鉴定
2014/02/02 职场文书
研发工程师岗位职责
2014/04/28 职场文书
企业三严三实学习心得体会
2014/10/13 职场文书
支行行长竞聘报告
2014/11/06 职场文书
给客户的检讨书
2014/12/21 职场文书
第一军规观后感
2015/06/12 职场文书
2019广播稿怎么写
2019/04/17 职场文书
世界各国短波电台对东亚播送时间频率表(SW)
2021/06/28 无线电