在进入这个话题之前,首先我们先来想一下在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)的更多相关文章

  1. 三大前端框架(react、vue、angular2+)父子组件通信总结

    公司业务需要,react.vue.angular都有接触[\无奈脸].虽然说可以拓展知识广度,但是在深度上很让人头疼.最近没事的时候回忆各框架父子组件通信,发现很模糊,于是乎稍微做了一下功课,记录于此 ...

  2. vue 父子组件通信props/emit

    props 1.父组件传递数据给子组件 父组件: <parent> <child :childMsg="msg"></child>//这里必须要 ...

  3. vue 父子组件通信-props

    父组件:引用了ComBack组件 ComBack组件:引用了BasicInfor组件 先使用props获取父组件的headInfo这个对象,这里注意(default)默认返回值要用工厂形式返回 Bas ...

  4. vue 父子组件通信

    算是初学vue,整理一下父子组件通信笔记. 父组件通过 prop 给子组件下发数据,子组件通过事件给父组件发送消息. 一.父组件向子组件下发数据: 1.在子组件中显式地用props选项声明它预期的数据 ...

  5. Vue 非父子组件通信

    组件是Vue核心的一块内容,组件之间的通信也是很基本的开发需求.组件通信又包括父组件向子组件传数据,子组件向父组件传数据,非父子组件间的通信.前两种通信Vue的文档都说的很清楚,但是第三种文档上确只有 ...

  6. Vue 非父子组件通信方案

    Vue 非父子组件通信方案 概述 在 Vue 中模块间的通信很普遍 如果是单纯的父子组件间传递信息,父组件可以使用 props 将数据向下传递到子组件,而在子组件中可以使用 events (父组件需要 ...

  7. vue 父子组件通信详解

    这是一篇详细讲解vue父子组件之间通信的文章,初始学习vue的时候,总是搞不清楚几个情况 通过props在父子组件传值时,v-bind:data="data",props接收的到底 ...

  8. Vue.JS快速上手(组件间的通信)

    前言 Vue采用的是组件化思想,那么这些组件间是如何通信的呢?下面详细介绍一下. 所谓组件间通信,不单单是我们字面上理解的相互传递数据,这里还包括一个组件访问另一个组件的实例方法等,如父组件通过ref ...

  9. 总结Vue第二天:自定义子组件、父子组件通信、插槽

    总结Vue第二天:自定义子组件.父子组件通信.插槽 一.组件: 组件目录 1.注册组件(全局组件.局部组件和小demo) 2.组件数据存放 3.父子组件通信(父级向子级传递数据.子级向父级传递数据) ...

随机推荐

  1. python虚拟环境的配置: virtualenv 和 virtualenvwrapper-win 的用法

    版本:python37, virtualenv==16.7.8, virtualenvwrapper-win==1.2.5 pip37 install virtualenv 安装支持虚拟环境的包,注意 ...

  2. LeetCode 1022. 从根到叶的二进制数之和(Sum of Root To Leaf Binary Numbers)

    1022. 从根到叶的二进制数之和 1022. Sum of Root To Leaf Binary Numbers 题目描述 Given a binary tree, each node has v ...

  3. LeetCode 590. N叉树的后序遍历(N-ary Tree Postorder Traversal)

    590. N叉树的后序遍历 590. N-ary Tree Postorder Traversal 题目描述 给定一个 N 叉树,返回其节点值的后序遍历. LeetCode590. N-ary Tre ...

  4. Struts笔记2

    Struts2-配置文件result元素 作用:为动作指定结果视图 name属性:逻辑视图的名称,对应着动作方法的返回值.默认值是success type属性:结果类型,指的就是用什么方式转到定义的页 ...

  5. Linux基础-09-磁盘分区、挂载及文件系统管理

    1. 硬件设备与文件名的对应关系 1) 在Linux系统中,每个设备都被当初一个文件来对待. 2) 各种设备在Linux中的文件名 2. 硬盘的结构及硬盘分区 1) 为什么要进行硬盘分区: a) 更容 ...

  6. PAT(B) 1082 射击比赛(Java)

    题目链接:1082 射击比赛 (20 point(s)) 题目描述 本题目给出的射击比赛的规则非常简单,谁打的弹洞距离靶心最近,谁就是冠军:谁差得最远,谁就是菜鸟.本题给出一系列弹洞的平面坐标(x,y ...

  7. 1010 Radix:猥琐的测试数据

    谨以此题纪念边界测试数据浪费了我多少时间:https://pintia.cn/problem-sets/994805342720868352/problems/994805507225665536 # ...

  8. 在论坛中出现的比较难的sql问题:30(row_number函数 物料组合问题)

    原文:在论坛中出现的比较难的sql问题:30(row_number函数 物料组合问题) 在论坛中,遇到了不少比较难的sql问题,虽然自己都能解决,但发现过几天后,就记不起来了,也忘记解决的方法了. 所 ...

  9. 多线程使用libcurl

    curl默认情况下有两个地方是线程不安全的, 需要特殊处理, 1是curl_global_init 这个函数必须单线程调用, 2是默认多线程调用https会莫名其妙的挂掉, 以下是网上的解决方案 ht ...

  10. javascript -- 把按钮变成读秒倒计时

    $('#btn').click(function(){ //设置按钮倒计时 $(this).addClass('disabled'); //把按钮变灰 $(this).attr('disabled', ...