vue学习记录⑤(组件通信-父与子)
今天我们看一下组件通信。
经过前面几篇文章,我们已经可以构建出完整的单个组件,并利用路由使其串联起来访问了。
但这明显还是不够的。一个页面不可能就是个单组件,一般是由多个组件合成的。正因为如此,组件之间肯定是有相互关系的,我们就称这种现象叫组件通信。
比如父组件发生了某项改变,子组件会跟着相应发生变化;反过来,子组件有了某种改变,父组件有时也会随之做出调整。那么这种现象我们称之为双向数据流动。
然而,vue的作者敏锐的认识到,双向数据流带来便捷的同时,也存在着极大的安全隐患。
父组件将变化传递给子组件(父影响子),这是没问题的,在我们日常生活中也是极为普遍的现象(老子教训儿子是天经地义的),然而反过来子影响父的话,这就变得不可理喻了(儿子教训老子?)
子组件修改父组件,增大了组件之间的耦合度。有时开发者根本没有意识到这种修改,这犹如埋下一颗定时炸弹,随着日后项目代码的膨胀,一旦引爆,问题排查难度也会呈指数级的徒增。
为了斩断这种安全隐患,vue提倡的是单向数据流动——也就是只能父影响子,而反过来则不成立。
父传子,我们利用props作为桥梁。下面看一个例子。
首先我将目录调整一下:
其中,helloworld.vue组件,我们设定其为父组件;而children目录下的child.vue,我们设定为其子组件。
Helloworld.vue代码如下:
<!--模板部分-->
<template>
<div class="container">
<h1>我是父亲</h1>
<!--绑定父组件的某个变量myMsg-->
<div>
<!--注意子组件接受变量时,需要变为驼峰命令法sendMessage-->
<child v-bind:send-message="myMsg"></child>
</div> </div>
</template>
<!--js部分-->
<script>
//引入子组件,需要设定子组件的name为child
import child from './children/child.vue'
export default {
name:'helloworld',
data(){
return {
myMsg:'hello,my son!'
};
},
components:{child}//局部注册子组件
}
</script>
<!--样式部分-->
<style>
.container{
background: #ccc;
color:greenyellow;
} </style>
大家注意下别把组件和路由的概念搞混了,二者之间一毛钱关系都没有。要使用组件,需做局部或者全局注册。我这里只做局部注册,大家仔细看一下写法。
我们在父组件定义了一个myMsg这个变量,然后通过v-bind绑定到了child组件中。这时,child组件就可以通过props来接收这个变量了。
child.vue代码如下:
<!--模板部分-->
<template>
<div class="sub-container">
<h3>我是儿子</h3> <div>我从父亲那边接收过来的信息:</div>
<div>{{sendMessage}}</div>
</div>
</template>
<!--js部分-->
<script>
//子组件
export default {
name:'child',//必须设定name,否则无法在父组件import
props:['sendMessage'],
data(){
return { };
}
}
</script>
<!--样式部分-->
<style>
.sub-container{
background: blue;
color:red;
}
</style>
一个简单的父子通信案例就完成了,看一下路由router/index.js,代码如下:
import Vue from 'vue'
import Router from 'vue-router'
import Hello from '@/components/Hello'
import HelloWorld from '@/components/Helloworld' //我们新定义的组件 Vue.use(Router) export default new Router({
routes: [{
path: '/',
name: 'Hello',
component: Hello
},
{ //新路由
path: '/helloworld/:id',
name: 'HelloWorld',
component: HelloWorld,
}
]
})
运行一下npm run dev,看一下结果:
可以看到,子组件顺利接收到了父组件传来的信息。
那么,到底子组件能否影响父组件呢?我们将以上代码做一下调整。
调整后的Helloworld.vue
<!--模板部分-->
<template>
<div class="container">
<h1>我是父亲</h1> <input type="text" v-model="myMsg">
<br>
<!--绑定父组件的某个变量myMsg-->
<div>
<!--注意子组件接受变量时,需要变为驼峰命令法sendMessage-->
<child v-bind:send-message="myMsg"></child>
</div> </div>
</template>
<!--js部分-->
<script>
//引入子组件,需要设定子组件的name为child
import child from './children/child.vue'
export default {
name:'helloworld',
data(){
return {
myMsg:'hello,my son!'
};
},
components:{child}//局部注册子组件
}
</script>
<!--样式部分-->
<style>
.container{
background: #ccc;
color:greenyellow;
} </style>
调整后的child.vue
<!--模板部分-->
<template>
<div class="sub-container">
<h3>我是儿子</h3> <div>我从父亲那边接收过来的信息:</div>
<div>{{sendMessage}}</div>
<div>是否可以子影响父呢?</div>
<input type="text" v-model="sendMessage">
</div>
</template>
<!--js部分-->
<script>
//子组件
export default {
name:'child',//必须设定name,否则无法在父组件import
props:['sendMessage'],
data(){
return { };
}
}
</script>
<!--样式部分-->
<style>
.sub-container{
background: blue;
color:red;
}
</style>
运行一下npm run dev,看一下结果:
可以看出,子组件是无法影响父组件的,这样父组件就成功解耦了。
大家要注意一个问题——传递的数据类型问题。
传递的是值类型肯定没问题,假如是对象或者数组这样的引用类型,变量共用同一内存,所以父子会出现双向影响,这个问题一定要注意。
为了杜绝隐患,提高安全性,我们在子组件将prop接收的类型做一下强制检测,假如传入的数据类型并不是我需要的,可以抛出异常。
Helloworld.vue
<!--模板部分-->
<template>
<div class="container">
<h1>我是父亲</h1> <input type="text" v-model="myMsg">
<!--<input type="text" v-model="myNum">-->
<ul v-for="item of myObj">
<li>{{item.name}}</li>
</ul>
<br>
<!--绑定父组件的某个变量myMsg-->
<div>
<!--注意子组件接受变量时,需要变为驼峰命令法sendMessage-->
<child :send-message="myMsg" :send-num="myNum" :send-obj="myObj"></child>
</div> </div>
</template>
<!--js部分-->
<script>
//引入子组件,需要设定子组件的name为child
import child from './children/child.vue'
export default {
name:'helloworld',
data(){
return {
myMsg:'hello,my son!',
myNum:'123',
myObj:[{id:1,name:'Tom_Lo'},{id:2,name:'tom'}]
};
},
components:{child}//局部注册子组件
}
</script>
<!--样式部分-->
<style>
.container{
background: #ccc;
color:green;
}
</style>
父组件这次传了三个不同类型的信息,分别是字符串、数字和json对象。其中,数字类型我故意写错了,看一下子组件是否会检测出来。
child.vue
<!--模板部分-->
<template>
<div class="sub-container">
<h3>我是儿子</h3> <div>我从父亲那边接收过来的信息:</div>
<div>字符串:{{sendMessage}}</div>
<div>数字:{{sendNum}}</div>
<div>
<ul v-for="item of list">
<li>{{item.name}}</li>
</ul>
</div> </div>
</template>
<!--js部分-->
<script>
//子组件
export default {
name:'child',//必须设定name,否则无法在父组件import
props:{
sendMessage:{
type:String,//传入类型必须是字符串
required:true//必传
},
sendNum:{
type:Number,//传入类型必须是数字
required:true
},
//如果是数组或对象
sendObj:{
validator:function(val){ if(Object.prototype.toString.call(val) === '[object Array]' || Object.prototype.toString.call(val) === '[object Object]'){
return true;
}
}
}
},//声明验证类型
data(){
var parentObj = this.sendObj;//获取父组件传来的json
var childObj =JSON.parse(JSON.stringify(parentObj));//复制一份,避免污染父组件的数据
childObj.push({id:3,name:'mike'});//追加一个对象
return {
list:childObj
};
}
}
</script>
<!--样式部分-->
<style>
.sub-container{
background: blue;
color:red;
}
</style>
大家需要注意下子组件props的验证规则。
那么对于容易引发错误的引用类型,大家应该如何避免呢?
当我们接收过来这个对象数据后,先将其拷贝一份副本,然后用副本做增加修改等操作,这样便不会影响到父组件的数据了。
我们运行一下看看:
看起来验证规则生效了哈~~
那么以上都是同步的情况,那么异步呢?
假设父组件的数据是异步ajax获取的,然后渲染页面。那么此时,子组件如何跟着更新视图呢?
这就得有个监听机制。当子组件监听到父组件的数据到位后,将本地数据更新即可。
vue提供的watch可以达到此目的,我们看一下例子。
Helloworld.vue
<!--模板部分-->
<template>
<div class="container">
<h1>我是父亲</h1>
<input type="text" v-model="myMsg">
<!--<input type="text" v-model="myNum">-->
<ul v-for="item of myObj">
<li>{{item.name}}</li>
</ul>
<br>
<!--绑定父组件的某个变量myMsg-->
<div>
<!--注意子组件接受变量时,需要变为驼峰命令法sendMessage-->
<child :send-message="myMsg" :send-num="myNum" :send-obj="myObj"></child>
</div> </div>
</template>
<!--js部分-->
<script>
//引入子组件,需要设定子组件的name为child
import child from './children/child.vue'
export default {
name:'helloworld',
data(){
//初始化obj
var obj = {
myMsg:'hello,my son!',
myNum:123,
myObj:[]
};
//延时返回myObj,模拟ajax的延时情况
setTimeout(function(){
obj['myObj'] = [{id:1,name:'jack'},{id:2,name:'tom'}]; },2000);
return obj;
},
components:{child}//局部注册子组件
}
</script>
<!--样式部分-->
<style>
.container{
background: #ccc;
color:green;
}
</style>
child.vue
<!--模板部分-->
<template>
<div class="sub-container">
<h3>我是儿子</h3> <div>我从父亲那边接收过来的信息:</div>
<div>字符串:{{sendMessage}}</div>
<div>数字:{{sendNum}}</div>
<div>
<ul v-for="item of list">
<li>{{item.name}}</li>
</ul>
</div> </div>
</template>
<!--js部分-->
<script>
//子组件
export default {
name:'child',//必须设定name,否则无法在父组件import
props:{
sendMessage:{
type:String,//传入类型必须是字符串
required:true//必传
},
sendNum:{
type:Number,//传入类型必须是数字
required:true
},
//如果是数组或对象
sendObj:{
validator:function(val){ if(Object.prototype.toString.call(val) === '[object Array]' || Object.prototype.toString.call(val) === '[object Object]'){
return true;
}
}
}
},//声明验证类型
data(){ return {
list:null
};
},
watch:{//监控父组件sendObj的变化
sendObj(newval,oldval){ if(newval !== oldval){ var newobj =JSON.parse(JSON.stringify(newval));//复制一份,避免污染父组件的数据
newobj.push({id:3,name:'mike'});//追加一个对象
this.list = newobj;//将新值赋予data的list
} }
}
}
</script>
<!--样式部分-->
<style>
.sub-container{
background: blue;
color:red;
}
</style>
watch的函数名称,就是要监听的值,这里我们监听父组件传来的prop;而newval和oldval参数,分别代表了新值和旧值。
在父组件未更新之前,子组件监听到的sendObj,新值和旧值都是空数组,二者是相等的;而当监听到二者发生不等时,就说明父组件传来的信息发生了改变。我们取新值,并将拷贝后的数据传给data里面的list,然后更新到视图。
看一下运行情况:
父组件与子组件的交互就实现了。
参考文章:http://mp.weixin.qq.com/s/rrKGRPTIt-aiZXijIli3ww
参考文章:http://www.cnblogs.com/ghostwu/p/7518002.html
vue学习记录⑤(组件通信-父与子)的更多相关文章
- Vue学习笔记-组件通信-父传子(props中的驼峰标识)
在组件中,使用选项props来声明需要从父级接收到的数据.props的值有两种方式:方式一:字符串数组,数组中的字符串就是传递时的名称.方式二:对象,对象可以设置传递时的类型,也可以设置默认值等. & ...
- 浅谈vue学习之组件通信
vue用组件化简化了我们编写代码的复杂度,组件之间经常会出现数据传递的情况,那么组件之间是怎样通信的呢? 使用props传递数据 组件实例的作用域是孤立的.这意味着不能 (也不应该) 在子组件的模板内 ...
- Vue学习笔记-组件通信-子传父(自定义事件)
props用于父组件向子组件传递数据,还有一种比较常见的是子组件传递数据或事件到父组件中.我们应该如何处理呢?这个时候,我们需要使用自定义事件来完成.什么时候需要自定义事件呢?当子组件需要向父组件传递 ...
- Vue学习记录-接口通信(数据请求)
这一篇,把前两天实践的“数据请求”部分总结一下.从最终的结果来看,配置非常的简单,使用非常的简单,也非常的灵活,同时也存在一个很头疼的问题,这个问题可以解决,但是解释不了(功力尚浅). 选型 可选项: ...
- 45.VUE学习之--组件之父组件使用scope定义子组件模板样式结构实例讲解
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- vue单文件组件形成父子(子父)组件之间通信(vue父组件传递数据给子组件,子组件传递数据给父组件)
看了很多文章,官网文档也有看,对父子组件通信说的不是很明白:决定自己总结一下: vue一般都使用构建工具构建项目:这样每个组件都是单文件组件:而网上很多文章都是script标签方式映入vue,组件通信 ...
- Vue 非父子组件通信方案
Vue 非父子组件通信方案 概述 在 Vue 中模块间的通信很普遍 如果是单纯的父子组件间传递信息,父组件可以使用 props 将数据向下传递到子组件,而在子组件中可以使用 events (父组件需要 ...
- 【VUE】7.组件通信(二)子组件修改父组件
1. 前提&知识点 1./components/Father.vue 是父组件, Son.vue 是子组件 2.子组件修改父组件 emit 2. 组件通信 1. 首先对子组件绑定一个事件 ch ...
- 【VUE】6.组件通信(一)父组件向子组件传值
1. 前提&知识点 1./components/Father.vue 是父组件, Son.vue 是子组件 2.父组件像子组件通信 props 2.组件通信 1. 新增一个路由入口 /fath ...
随机推荐
- sql中关于存在就不做操作的代码块
前言: 在开发中,经常会对数据库表进行新增修改操作,那么如果表中的属性信息已然存在啦!就没必要去做重复的操作了... 代码块 BEGIN SELECT "COUNT"(*) int ...
- java多线程对CountDownLatch的使用实例
介绍 CountDownLatch是一个同步辅助类,它允许一个或多个线程一直等待直到其他线程执行完毕才开始执行. 用给定的计数初始化CountDownLatch,其含义是要被等待执行完的线程个数. 每 ...
- PAT1115:Counting Nodes in a BST
1115. Counting Nodes in a BST (30) 时间限制 400 ms 内存限制 65536 kB 代码长度限制 16000 B 判题程序 Standard 作者 CHEN, Y ...
- cas 4.1.4单点登录实战
使用工具 maven-3.3.9 cas-4.1.4 Tomcat-7.0.57-win-x64 cas-sample-Java-webapp 一.Hello cas 1.下载Tomcat,解压:修改 ...
- .Net Core微服务系列--理论篇
微服务的由来 微服务最早由Martin Fowler与James Lewis于2014年共同提出来的,但是微服务也不是一个全新的概念,它是由一系列在实践中获得成功并流行起来的概念中总结出来的一种模式, ...
- 对混合数值,字符,null的字段进行排序
今天有个需求是进行排序. 这一列值是字符串类型的, 但是里面有数值型 比如"1" 和null类型的. 实现效果是需要 数值型的先按照数值的方式先排,然后字符串按照字符传排,最后 ...
- ORACLE 快速启动监听及相关服务程序
windows7 系统下,鼠标移至任务栏右键启动任务管理器->选择服务->点击右下角服务选项 ->选中名称,键盘输入O(大写),快速找到ORACLE相关服务进程 ->将所有的O ...
- margin-塌陷问题
塌陷问题 当两个盒子在垂直方向上设置margin值时,会出现一个有趣的塌陷现象. ①垂直并列(少见) 首先设置两个DIV,并为其制定宽高 /*HTML部分*/ <body> <div ...
- 34.如何获取app(apk和ipa)中的资源
移动互联网中,主要的两个平台是android和ios,android上文件的安装包是后缀名为apk的文件,ios上文件的安装包是后缀名为ipa的文件,在本文分析一下这两种文件的特点,以及如何用程序去解 ...
- java处理图片--图片的缩放,旋转和马赛克化
这是我自己结合网上的一些资料封装的java图片处理类,支持图片的缩放,旋转,马赛克化.(转载请注明出处:http://blog.csdn.net/u012116457) 不多说,上代码: packag ...