从“心”认识Vue(五):父组件与子组件

  • 前言
  • 一、父组件与子组件的关系
  • 二、注册组件语法糖
  • 三、模板与组件的分离写法
  • 四、组件可以访问vue实例数据吗?
  • 五、为什么组件的data必须是一个函数?
  • 六、父子之间通信
    • 1.父传子
    • 2.子传父
  • 七、父访问子/子访问父
    • 1.父访问子
      • 一、ref方法
      • 二、children方法
    • 2.子访问父:
  • 八、非父子通信(以后再讲)
    • 1.中央事件总线
    • 2.vuex状态管理
  • 总结

前言

学习vue的时候学完模板语法,上来就开始了脚手架,虽然上手快了点,但是感觉还是少了一点衔接,知识遇到了断层,于是自己就再补了一点,理解起来比较顺畅一些。

  • 上篇文章:从“心”认识Vue(四):组件的基本使用

一、父组件与子组件的关系

我们将某段代码封装成一个组件,而这个组件又在另一个组件中引入,而引入该封装的组件的文件叫做父组件,被引入的组件叫做子组件。

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body>
<div id="app">
<!--  4.使用父组件2--><comp2></comp2>
</div><script src="node_modules/vue/dist/vue.min.js"></script>
<script>//1.注册组件构造器对象const comp1 = Vue.extend({template: `<div><h2>我是标题1</h2><p>我是内容,哈哈哈哈</p></div>`})const comp2 = Vue.extend({template: `<div><h2>我是标题2</h2><p>我是内容,嘻嘻嘻嘻</p><comp1></comp1></div>`,//3.注册子组件1,并在comp2里面使用组件1components: {comp1:comp1}})new Vue({el: "#app",data: {msg: "haha"},//2.注册父组件2components:{comp2:comp2}})
</script>
</body>
</html>

二、注册组件语法糖

语法糖,也称糖衣语法,指的是计算机语言中添加的某种语法,这种语法对语言的功能并没有影响,但是更方便程序员使用。即在功能实现上与原代码一模一样,但是用法很简洁方便,提高程序员工作效率。

例子1中的注册组件比较管繁琐,vue提供了注册组件的语法糖,即省略了注册组件的步骤,直接用一个对象来代替:

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body>
<div id="app"><comp1></comp1><comp2></comp2>
</div><script src="node_modules/vue/dist/vue.min.js"></script>
<script>//1.全局组件注册的语法糖// const comp1 = Vue.extend()//2。注册组件Vue.component("comp1",{template: `<div><h2>我是标题1</h2><p>我是内容,哈哈哈哈</p></div>`})new Vue({el: "#app",data: {msg: "haha"},//局部组件语法糖components: {"comp2": {template: `<div><h2>我是标题2</h2><p>我是内容,xixix</p></div>`}}})
</script>
</body>
</html>

三、模板与组件的分离写法

将模板与组件分离开来写,将使代码变得更加清晰。

vue提供了两种方案定义html内容:

  • 一是使用script标签
  • 二是使用templete标签
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body>
<div id="app"><comp1></comp1>
</div><!--  1.script标签写法,注意类型必须是text/x-template-->
<!--<script type="text/x-template" id="comp1">-->
<!--  <div>-->
<!--    <h2>我是标题1</h2>-->
<!--    <p>我是内容,哈哈哈哈</p>-->
<!--  </div>-->
<!--</script>--><!--2.template标签-->
<template id="comp1"><div><h2>我是标题1</h2><p>我是内容,哈哈哈哈</p></div>
</template>
<script src="node_modules/vue/dist/vue.min.js"></script>
<script>//1。注册一个全局组件Vue.component("comp1", {template: "#comp1"})new Vue({el: "#app",data: {msg: "haha"}})
</script>
</body>
</html>

四、组件可以访问vue实例数据吗?

先测试一下:

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body>
<div id="app"><comp></comp>
</div><template id="comp1"><div><h2>{{title}}</h2><p>我是内容,哈哈哈哈</p></div>
</template><script src="node_modules/vue/dist/vue.min.js"></script><script>//1.注册全局组件Vue.component("comp",{template:"#comp1",})new Vue({el: "#app",data: {msg: "haha",title: "我是标题"}})
</script>
</body>
</html>

结果:vue报错,title未定义,那么说明组件不可以访问vue实例数据。

  • 组件是一个单独功能模块的封装,有自己的html模板,也应该有自己的数据data;
  • 组件里也有一个自己的data属性
  • 组件的data是一个函数, 而且这个函数返回一个对象,对象内保存着数据

五、为什么组件的data必须是一个函数?

  • 首先来看如果不是一个函数会是怎样,按照vue实例里的写法:
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body>
<div id="app">
<!--  创建组件实例--><comp></comp><comp></comp><comp></comp>
</div><template id="comp"><div><h3>当前计数:{{count}}</h3><button @click="increment">+</button><button @click="decrement">-</button></div>
</template><script src="node_modules/vue/dist/vue.min.js"></script>
<script>//1.注册全局组件Vue.component("comp",{template:"#comp",data:{count:0},//报错,如果这样不同组件会共享同一个数据,造成相互影响methods:{increment(){this.count++},decrement(){this.count--}}})new Vue({el: "#app",data: {msg: "haha"}})
</script></body>
</html>

结果:报错.

  • 我们再给它传入一个对象试试:
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body>
<div id="app">
<!--  创建组件实例--><comp></comp><comp></comp><comp></comp>
</div><template id="comp"><div><h3>当前计数:{{count}}</h3><button @click="increment">+</button><button @click="decrement">-</button></div>
</template><script src="node_modules/vue/dist/vue.min.js"></script>
<script>const obj1 = {count:0}//1.注册全局组件Vue.component("comp",{template:"#comp",// data:{//   count:0// },//报错,如果这样不同组件会共享同一个数据,造成相互影响data(){return obj1;//不同组件获取到同一个对象,数据相互影响},methods:{increment(){this.count++},decrement(){this.count--}}})new Vue({el: "#app",data: {msg: "haha"}})
</script></body>
</html>

再来看一下结果:

结果发现三个组件之间的数据被相互影响了,这是我们不愿意看到的。因为我们需要组件之间数据相互独立。

接着我们将它改为正确的写法:

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body>
<div id="app">
<!--  创建组件实例--><comp></comp><comp></comp><comp></comp>
</div><template id="comp"><div><h3>当前计数:{{count}}</h3><button @click="increment">+</button><button @click="decrement">-</button></div>
</template><script src="node_modules/vue/dist/vue.min.js"></script>
<script>//const obj1 = {//  count:0//}//1.注册全局组件Vue.component("comp",{template:"#comp",//data数据相互独立data(){return {count:0}},// data数据相互影响// data:{//   count:0// },//报错,如果这样不同组件会共享同一个数据,造成相互影响// data(){//   return obj1;//不同组件获取到同一个对象,数据相互影响// },methods:{increment(){this.count++},decrement(){this.count--}}})new Vue({el: "#app",data: {msg: "haha"}})
</script></body>
</html>

结果正确了:

到这里我们可以得出结论:

  • 1.组件data如果不是一个函数,vue会报错;
  • 2.组件data需要每个组件之间都保持数据的独立,每个组件调用data时都会返回一个新的对象,这就确保了组件之间数据不会相互影响。

六、父子之间通信

1.父传子

步骤:

  • 1.在父级添加上数据
  • 2.在子级添加props声明需要传递的数据变量
  • 3.在组件实例中传递数据
  • 4.在子组件中使用数据
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body>
<div id="app"><!--      2.carr是子组件的属性,接收到来自父级的数据--><comp :carr="arr" :cmsg="msg"></comp><!--    <comp :carr="arr" ></comp> 当cmsg为required时这里会报错-->
</div><template id="comp"><div><ul><!--        3.在子组件内可以使用到来自父级的数据--><li v-for="(v,i) in carr">{{v}}</li></ul>{{cmsg}}</div>
</template>
<!--  使用生产版本一些错误会被忽略,而开发版本则不会-->
<script src="node_modules/vue/dist/vue.js"></script>
<script>//子组件const comp = {template: "#comp",//1.props声明需要从父级接收到的数据// props:["carr","cmsg"]//1.props验证props: {// 1.1限制类型// carr:Array,// cmsg:String// 1.2提供默认值cmsg: {type: String,default: "abcabc",required: true  //该属性必须传值},carr: {type: Array,//在高版本中数组默认值必须是一个函数default() {return []}}}}//root组件new Vue({el: "#app",data: {//0.父级里的数据msg: "haha",arr: ["xixi", "haha", "heiehie"]},components: {comp}})
// 总结步骤:
//   1.在父级添加上数据
//   2.在子级添加props声明需要传递的数据变量
//   3.在组件实例中传递数据
//   4.在子组件中使用数据
</script>
</body>
</html>

2.子传父

步骤:

  • 1.子组件里添加数据
  • 2.子组件模板添加点击事件
  • 3.添加点击事件方法,使用$emit进行数据传递,第一个参数是自定义事件名称,第二个参数是需要传递的数据
  • 4.在父组件模板里添加自定义事件,添加方法,注意方法名称后面不加括号,vue默认传递数据
  • 5.父组件里添加自定义事件处理函数
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body>
<!--父组件模板-->
<div id="app">
<!--  4.在父组件模板里添加自定义事件,添加方法,注意方法名称后面不加括号--><comp @item-click="comClick"></comp><h2>你点击的是:{{item.name}}</h2>
</div><!--子组件模板-->
<template id="comp"><div>
<!--    2.子组件模板添加点击事件--><button v-for="items in categories" @click="btnClick(items)">{{items.name}}</button></div>
</template><script src="node_modules/vue/dist/vue.js"></script>
<script>//子组件const comp = {template: "#comp",//1.子组件里添加数据data() {return {categories:[{id:"1",name:"推荐"},{id:"2",name:"手机"},{id:"3",name:"电脑"},{id:"4",name:"箱包"},]}},methods:{btnClick(item){//3.添加点击事件方法,使用$emit进行数据传递,第一个参数是自定义事件名称,第二个参数是需要传递的数据this.$emit("item-click",item)}}}//父组件new Vue({el: "#app",data: {msg: "haha",item:""},components: {comp},methods:{// 5.父组件里添加自定义事件处理函数comClick(item){console.log(item)this.item = item}}})// 总结:// 1.子组件里添加数据// 2.子组件模板添加点击事件// 3.添加点击事件方法,使用$emit进行数据传递,第一个参数是自定义事件名称,第二个参数是需要传递的数据// 4.在父组件模板里添加自定义事件,添加方法,注意方法名称后面不加括号,vue默认传递数据// 5.父组件里添加自定义事件处理函数
</script>
</body>
</html>

七、父访问子/子访问父

有时我们不想传递数据了,直接拿到父或子级的数据:(不常用)

  • 父访问子:$children 或者 $refs方法
  • 子访问父:$parent方法

1.父访问子

一、ref方法

  • 1.给组件添加ref属性xxx
  • 2.父级方法调用this.$refs.xxx.子级数据

二、children方法

  • 1.父级方法中直接通过children索引取值,this.$children[索引].子级数据

2.子访问父:

  • 1.父级定义数据
  • 2.子级方法里直接调用this.$parent.父级数据
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body>
<div id="app">
<!--  2.添加ref属性--><comp ref="xixi"></comp><button @click="btnClick()">点击访问子组件</button><h2>拿到子组件的数据是:{{sonName}}</h2>
</div><template id="comp"><div>{{name}}<br><button @click="showMsg()">点击访问父组件</button><h2>拿到父组件的数据是:{{parentData}}</h2></div>
</template><script src="node_modules/vue/dist/vue.min.js"></script>
<script>const comp = {template:"#comp",data(){return {name:"我是子组件的name",parentData:""}},methods:{showMsg(){this.parentData = this.$parent.parentMsg}}}new Vue({el: "#app",data: {parentMsg: "我是父组件的haha",sonName:""},components: {comp},methods:{btnClick(){// 1.$children 用的少 因为不容易确定组件的索引值// console.log(this.$children[0].name);// 2.$refs 常用 对象类型,默认为空,必须在组件上添加ref属性后生效console.log(this.$refs.xixi.name)this.sonName = this.$refs.xixi.name}}})
</script>
</body>
</html>


八、非父子通信(以后再讲)

1.中央事件总线

2.vuex状态管理


总结

  • 1.父组件与子组件的关系:将某段代码封装成一个组件,而这个组件又在另一个组件中引入,而引入该封装的组件的文件叫做父组件,被引入的组件叫做子组件。
  • 2.注册组件语法糖:将注册组件的步骤用一个对象代替;
  • 3.vue提供两种方法分享模板与组件:script标签与template标签
  • 4.组件不能访问vue实例数据,组件有自己存放数据的地方;
  • 5.组件data必须要是一个函数,不然vue会报错,而且为了不同组件之间必须保证数据的独立,每个组件的data函数要返回一个新的对象。
  • 6.父传子用props
    • 1)在父级添加上数据
    • 2)在子级添加props声明需要传递的数据变量
    • 3)在组件实例中传递数据
    • 4)在子组件中使用数据
  • 7.子传父用自定义事件$emit
    • 1)子组件里添加数据
    • 2)子组件模板添加点击事件
    • 3)添加点击事件方法,使用$emit进行数据传递,第一个参数是自定义事件名称,第二个参数是需要传递的数据
    • 4)在父组件模板里添加自定义事件,添加方法,注意方法名称后面不加括号,vue默认传递数据
    • 5)父组件里添加自定义事件处理函数
  • 8.父访问子数据用$children或者 $refs, $children不常用 ,因为常常不能准确知道索引值
  • 9.子访问父数据用$parent,而这两种访问方式都不建议使用,因为代码耦合度太高,不利于代码的利用。

从“心”认识Vue(五):父组件与子组件相关推荐

  1. 三、Vue组件化开发学习笔记——组件化的基本步骤、全局组件和局部组件、父组件和子组件、注册组件的语法糖、模板分离写法、组件的数据存放

    一.什么是组件化? 人面对复杂问题的处理方式: 任何一个人处理信息的逻辑能力都是有限的 所以,当面对一个非常复杂的问题时,我们不太可能一次性搞定一大堆的内容. 但是,我们人有一种天生的能力,就是将问题 ...

  2. vue请求数据传给子组件_vue.js基础,父组件如何向子组件传递数据「607」

    本文只有一个学习点. 父组件如何向子组件传递数据. 一起学习,更多文章请关注我的头条号,我是落笔承冰. 一.先创建一张空白网页index.html,在head标签里设置好vue的链接库. 二.写一个绑 ...

  3. 【vue】父组件与子组件之间的数据交互

    一.前端项目目录结构 二.vue单文件组件格式 注意1: scoped表示对当前组件生效 <style scoped> </style> 这个是设置组件中html样式(css) ...

  4. Vue父组件调用子组件的方法并传参的两种方式(用$refs.refName.functionName、window.function)

    如需了解儿子怎么控制老子的,传送门:https://s-z-q.blog.csdn.net/article/details/120094689 父组件father.vue <template&g ...

  5. vue父组件调用子组件的方法

    vue组件与组件通信有如下几种情况: 平行组件 父组件与子组件 子组件与父组件 它们之间通信有几种方法有: props 自定义事件 vuex 今天我们聊一下父组件调用子组件的一种方法 parent.v ...

  6. Vue父组件和子组件之间传递数据

    Vue父组件和子组件之间传递数据 klmhly 已关注 2018.05.19 19:56* 字数 367 阅读 23评论 0喜欢 0 一.概念解析 挂载点: Vue实例的el属性对应的id,vue只会 ...

  7. Vue中父组件调用子组件的方法

    场景 SpringBoot+Vue+Echarts实现选择时间范围内数据加载显示柱状图: SpringBoot+Vue+Echarts实现选择时间范围内数据加载显示柱状图_BADAO_LIUMANG_ ...

  8. 042——VUE中组件之子组件使用$on与$emit事件触发父组件实现购物车功能

    <!DOCTYPE html> <html lang="en"><head><meta charset="UTF-8" ...

  9. vue父组件使用子组件函数,vue子组件使用父组件函数

    (1)vue中父组件调用子组件函数 用法: 子组件上定义ref="refName", 父组件的方法中用 this.$refs.refName.method 去调用子组件方法 详解: ...

最新文章

  1. Python学习笔记十 IO编程
  2. Eclipse中Java文件图标由实心J变成空心J的问题
  3. 看一遍就理解,图解单链表反转
  4. 服务端 https和SSL
  5. mysql 定义XML字段_MyBatis之基于XML的属性与列名映射
  6. 一个显示器分两个屏幕_桌面改造计划2.0:一个显示器不够那就两个,桌面好物分享...
  7. 如何获取codeforces的完整数据
  8. asp.net asp:TextBox控件绑定值后,获取不到新值问题解决方法
  9. 中国AI英雄风云榜十位领军人揭晓 | 网易2018中国年度AI领域人物评选
  10. 关于单细胞批次矫正那些事(一)
  11. 作为一个程序员需要学多少技能?
  12. wojilu系统的ORM代码解析-[源代码结构分析,用特性和反射来感知属性-特性介绍篇]...
  13. 统计学原理 实验方法
  14. 利用WebMatrix安装drupal7 基于IID+SqlExpress
  15. 电机系列(1) - foc最基本原理、clark变换 、park变换、附代码
  16. 三维人脸表情识别综述学习笔记
  17. 多值逻辑与计算机科学,多值逻辑
  18. PostgreSQL表增加一列或删除一列
  19. 【统计分析系统--SAS介绍】
  20. 商业web 漏洞扫描神器———AWVS篇基础

热门文章

  1. 累涨超200%成华尔街新宠 Fastly借边缘云有望冲上“云”霄?
  2. 平均值的标准误差(SEM)
  3. 余淼杰老师 经济学原理复习笔记(宏观1) 2020-12-14
  4. 大神们都是如何在时间序列中进行特征提取的?看完就懂了!
  5. h5的开源播放器组件
  6. DDD为什么能火起来?和微服务有啥关系?
  7. 腾讯ui测试机实时预览软件,腾讯ISUX终端设备实时预览Photoshop的设计稿的神器Ps Play...
  8. 聚合物钽电容和普通钽电容的区别
  9. mtk9652和mt9638选哪个好
  10. 推动加密硬件性能改进的六项创新