详细讲解vue.js里的父子组件通信(props和$emit)
在进入这个话题之前,首先我们先来想一下在vue里,如何写一个父子组件。为了简单起见,下面的代码我都没用脚手架来构建项目,直接在html文件里引入vue.js来作为例子。父子组件的写法如下:
<div id="app">
<parent></parent>
</div>
<script src="node_modules/vue/dist/vue.js"></script>
<script>
let childNode = {
template: `<div>childNode</div>`
}
let parentNode = {
template: `
<div>
<child></child>
</div>
`,
components: {
child: childNode
}
}
new Vue({
el: '#app',
components: {
parent: parentNode
}
})
</script>
在这个代码里,template表示的是模板,components表示的是组件。子组件先要在父组件里显示就要通过components把组件对应的模板引擎(childNode对象)给挂载到父组件的components上去。然后子组件就会在父组件上得以显示。
在父子组件中,如果想要父组件的变量传递到子组件中,则需要通过props属性来进行传递。props有静态的也有动态的,下面来介绍静态的写法:
<script>
let childNode = {
template: `<div>{{message}}</div>`,
props: ['message']
}
let parentNode = {
template: `
<div>
<child message="child"></child>
</div>
`,
components: {
child: childNode
}
}
new Vue({
el: '#app',
components: {
parent: parentNode
}
})
</script>
在这里,子组件通过在props里写入想要获取的父组件的某个属性值,在父组件里,通过父组件在子组件里的占位符添加属性的方式来传值。在这里有一个命名规范,在子组件里,如果props里的参数由多个词组成则应该用驼峰命名的写法;而在父组件中则用横线做分隔符的写法。如:
<script>
let childNode = {
template: `<div>{{myMessage}}</div>`,
props: ['myMessage']
}
let parentNode = {
template: `
<div>
<child my-message="child"></child>
</div>
`,
components: {
child: childNode
}
}
new Vue({
el: '#app',
components: {
parent: parentNode
}
})
</script>
而动态props的用法是将占位符进行绑定,将父组件的数据绑定到子组件的props中,可以实现父组件的数据发生改变的时候子组件的数据也会发生改变的动态效果。如:
<script>
let childNode = {
template: `<div>{{myMessage}}</div>`,
props: ['myMessage']
}
let parentNode = {
template: `
<div>
<input type="text" v-model="myData">
<div>
<child :my-message="child"></child>
</div>
</div>
`,
components: {
child: childNode
},
data(){
return {
child: '',
myData: ''
}
},
watch: {
myData(newValue, oldValue){
this.child = newValue
}
}
}
new Vue({
el: '#app',
components: {
parent: parentNode
}
})
</script>
在这里,我通过利用v-model和watch来实现输入框发生变化的时候父组件数据动态修改后子组件的数据跟着改变。为什么这里不用computed而用watch呢?这里其实也涉及到watch和computed的区别,在vue里,这两个方法都能监听数据的变化,不同的是computed是只能读取不能写入,而watch可以读取也可以写入。当父组件的myData这个值发生改变的时候就将myData的值不断赋值给child,由于对占位符进行了绑定,所以子组件能够接收到父组件的改变。
动态props和静态props除了上面的区别以外还有一个区别,就是传递参数的时候数据类型发生变化。如下面的静态props里
<script>
let childNode = {
template: `<div>{{myMessage}}的类型是{{type}}</div>`,
props: ['myMessage'],
computed: {
type() {
return typeof this.myMessage
}
}
}
let parentNode = {
template: `
<div>
<div>
<child my-message="1"></child>
</div>
</div>
`,
components: {
child: childNode
}
}
new Vue({
el: '#app',
components: {
parent: parentNode
}
})
</script>
我们传的1在子组件里却是string类型,而如果是加入了绑定变成动态props:
<div>
<child :my-message="1"></child>
</div>
则会变成nunber,这种情况除了在数字类型发生以外,其他类型也会发生,需要注意。
在props里,我们可以验证父组件传过来的参数是否有问题,下面的例子主要是验证父组件传过来的数据是否是Number类型,如果不是的话则会在控制台里看到报错。在用这个方法的时候不要引用vue.min.js而要引用vue.js,因为vue.min.js会省略掉相应的报错提示,不利于开发的时候查看:
<script>
let childNode = {
template: `<div>{{myMessage}}</div>`,
props: {
myMessage: Number
}
}
let parentNode = {
template: `
<div>
<input type="text" v-model="myData">
<div>
<child :my-message="child"></child>
</div>
</div>
`,
components: {
child: childNode
},
data() {
return {
child: 123,
myData: ''
}
},
watch: {
myData(newValue, oldValue) {
if (/^[0-9]*$/.test(newValue)) {
this.child = parseInt(newValue)
} else {
this.child = '输入的数据不是number类型'
}
}
}
}
new Vue({
el: '#app',
components: {
parent: parentNode
}
})
</script>
可以看到我是在props里添加了一个对象,该对象里的myMessage属性里有属性值Number,表示验证数字类型,当myMessage的值不是数字类型的时候就会报错。除了Number的验证规则以外还有String、Boolean、Function、Object、Array和Symbol等验证规则,同时也可以写成这样来验证多种类型:
props: {
myMessage: [Number, String]
}
或者可以通过一个自定义一个工厂函数来进行匹配,如:
props: {
myMessage: {
validator: function (value) {
return value > 10
}
}
}
当然,在props对象里面,还有另外三个属性,一个是default属性,表示的是父组件传入值的时候子组件默认的值,另一个是require,表示的是该值是否要传入,而type则表示的是验证规则。如:
<script>
let childNode = {
template: `<div>{{myMessage}}</div>`,
props: {
myMessage: {
type: Number,
// required: true,
default: 321
}
}
};
let parentNode = {
template: `
<div>
<div>
<child></child>
</div>
</div>
`,
components: {
child: childNode
},
data() {
return {
child: 123
}
}
};
new Vue({
el: '#app',
components: {
parent: parentNode
}
})
</script>
一般来说,当props里的require表示为true的时候,则父组件要加上占位符,因为父组件有传值过来,所以default的值被覆盖了,如:
<script>
let childNode = {
template: `<div>{{myMessage}}</div>`,
props: {
myMessage: {
type: Number,
required: true,
default: 321
}
}
};
let parentNode = {
template: `
<div>
<div>
<child :my-message="child"></child>
</div>
</div>
`,
components: {
child: childNode
},
data() {
return {
child: 123
}
}
};
new Vue({
el: '#app',
components: {
parent: parentNode
}
})
</script>
由于props是单向数据流,所以父组件传过来的数据子组件修改了也不会修改到父组件的数据,而父组件一修改了则会修改到子组件的数据。所以想要反过来将子组件的数据传到给父组件则要换一种方法。用的比较多的是自定义一个事件,如:
<script>
let childNode = {
template: `
<div>
<button @click="toParent">子传父</button>
</div>
`,
methods: {
toParent() {
this.$emit('myParent', 'hello')
}
}
};
let parentNode = {
template: `
<child @myParent="change" :message="message"></child>
`,
components: {
'child': childNode
},
methods: {
change(data) {
console.log(data)
}
}
};
new Vue({
el: '#app',
components: {
parent: parentNode
}
})
</script>
在这里,子组件通过比如点击事件来触发一个自定义事件,该事件里有this.$emit的处理函数,第一个参数表示的是父组件里负责监听的函数名,第二个参数表示的传递的数值。在父组件里,通过在子组件占位符绑定一个子组件this.$emit定义的方法名即可监听得到传入的参数。
详细讲解vue.js里的父子组件通信(props和$emit)的更多相关文章
- 三大前端框架(react、vue、angular2+)父子组件通信总结
公司业务需要,react.vue.angular都有接触[\无奈脸].虽然说可以拓展知识广度,但是在深度上很让人头疼.最近没事的时候回忆各框架父子组件通信,发现很模糊,于是乎稍微做了一下功课,记录于此 ...
- vue 父子组件通信props/emit
props 1.父组件传递数据给子组件 父组件: <parent> <child :childMsg="msg"></child>//这里必须要 ...
- vue 父子组件通信-props
父组件:引用了ComBack组件 ComBack组件:引用了BasicInfor组件 先使用props获取父组件的headInfo这个对象,这里注意(default)默认返回值要用工厂形式返回 Bas ...
- vue 父子组件通信
算是初学vue,整理一下父子组件通信笔记. 父组件通过 prop 给子组件下发数据,子组件通过事件给父组件发送消息. 一.父组件向子组件下发数据: 1.在子组件中显式地用props选项声明它预期的数据 ...
- Vue 非父子组件通信
组件是Vue核心的一块内容,组件之间的通信也是很基本的开发需求.组件通信又包括父组件向子组件传数据,子组件向父组件传数据,非父子组件间的通信.前两种通信Vue的文档都说的很清楚,但是第三种文档上确只有 ...
- Vue 非父子组件通信方案
Vue 非父子组件通信方案 概述 在 Vue 中模块间的通信很普遍 如果是单纯的父子组件间传递信息,父组件可以使用 props 将数据向下传递到子组件,而在子组件中可以使用 events (父组件需要 ...
- vue 父子组件通信详解
这是一篇详细讲解vue父子组件之间通信的文章,初始学习vue的时候,总是搞不清楚几个情况 通过props在父子组件传值时,v-bind:data="data",props接收的到底 ...
- Vue.JS快速上手(组件间的通信)
前言 Vue采用的是组件化思想,那么这些组件间是如何通信的呢?下面详细介绍一下. 所谓组件间通信,不单单是我们字面上理解的相互传递数据,这里还包括一个组件访问另一个组件的实例方法等,如父组件通过ref ...
- 总结Vue第二天:自定义子组件、父子组件通信、插槽
总结Vue第二天:自定义子组件.父子组件通信.插槽 一.组件: 组件目录 1.注册组件(全局组件.局部组件和小demo) 2.组件数据存放 3.父子组件通信(父级向子级传递数据.子级向父级传递数据) ...
随机推荐
- kubectl exec 执行 容器命令
格式如下: kubectl exec -it podName -c containerName -n namespace -- shell comand 1 创建目录 kubectl exec -it ...
- union all 关键字的应用(合并两个查询结果集到同一个结果集)
在此对于数据库中 union all 关键字的功能和用法进行简单的使用介绍. 这是我工作中的一个需求: 有两个 A表 和B表. A表的数据: B表的数据: 现在有这样一个需求,让他一次性的全部查出来. ...
- mysql查看和设置最大连接数
.查看最大连接数 SHOW VARIABLES LIKE '%max_connections%'; .修改最大连接数 ;
- mysql You can't specify target table for update in FROM clause解决方法
mysql You can't specify target table for update in FROM clause解决方法出现这个错误的原因是不能在同一个sql语句中,先select同一个表 ...
- Python 环境搭建(Win 安装以及Mac OS 安装)
千里之行始于足下,今天我们先来学习 Python 环境搭建. 注意:本系列教程基于 Python 3.X Python 环境搭建 Win 安装 打开 Python 官网 https://www.pyt ...
- Deepin安装JavaFX
1.环境:JDK1.8(目前国内好用的版本里比较流行的是这个版本),deepin 15.11(linux内核是5.2.9,安装了大黄蜂驱动): 2.由于是用的JDK1.8,所以没法用最新的openjf ...
- php高级研发或架构师必了解---面试题系列
近接连面试了几家公司,有些重要问题记录一下,督促自己学习提高,同时希望给朋友们一些帮助. 内容很多,一点点完善,一步步学习.. 有些是面试被问,有些是招聘要求,有些是自己整理加的. 一.mysql相关 ...
- Spring之25:SingletonBeanRegistry&DefaultSingletonBeanRegistry
此接口是针对Spring中的单例Bean设计的.提供了统一访问单例Bean的功能,BeanFactory可实现此接口以提供访问内部单例Bean的能力. //将对象(singletonObject)注册 ...
- PAT(B) 1069 微博转发抽奖(Java)
题目链接:1069 微博转发抽奖 (20 point(s)) 题目描述 小明 PAT 考了满分,高兴之余决定发起微博转发抽奖活动,从转发的网友中按顺序每隔 N 个人就发出一个红包.请你编写程序帮助他确 ...
- Android去评分,分享
去评分: 跳到手机中已安装的市场评分页面 Uri uri = Uri.parse("market://details?id="+getPackageName()); Intent ...