一、概述

以脚手架搭建的Vue项目为笔记背景。

如果将所有的代码逻辑全部放到一个组件中,代码是非常的臃肿和难以维护的。

并且在真实开发中,可能会有更多的内容和代码逻辑,对于扩展性和可维护性来说都是非常不友好的。

所以开发者,我们会把一个大功能进行拆分,拆分成一个个功能的小组件。

那组件多了,就必然涉及到组件之间的数据传递。

二、组件通信-父传子

2.1 props属性的作用和使用场景

父组件有一些数据,需要子组件来进行展示。这种情况可以通过props组合式API来完成组件之间的通信。

props可以在当前组件上注册一些自定义的attribute(属性)。

父组件给这些attribute赋值,子组件通过attribute的名称获取到对应的值。

2.2 props有两种常见的用法

  • 字符串数组,数组中的字符串就是attribute的名称

    props: ['name', 'age']
    
  • 对象类型,对象类型可以在指定attribute名称时,指定它的类型、是否是必须的、默认值等等

    props: {name: {type: String,                // 需要传递的数据类型required: true,             // 是否必须传递,不传递的话报错default: "张三"            // 属性默认值 },                              // 一般required和default只选其一配置即可// 对象类型的默认值,必须是一个函数,使用函数返回值来确定默认值   friend: {type: Object,default() {return { name: "james" }}},hobbies: {type: Array,default: () => ["篮球", "rap", "唱跳"]},
    }
    

如何选择?

数组类型它对传入的attribute的名称,并不能对其进行任何限制吗,而对象的写法则让props变得更加完善。

当使用对象语法的时候,我们可以对传入的内容作出很多限制:

  • 指定传入的attribute的类型;
  • 指定传入的attribute是否是必传的;
  • 指定没有传入时,attribute的默认值;

这些限制可以让程序更加严谨。通常都会选用这种方式去定义props的相关属性。

注意点:

  • 一般requireddefault只选其一配置即可
  • 对象类型的默认值,必须是一个函数,使用函数返回值来确定默认值

2.3 props属性的type类型支持

  • String
  • Number
  • Boolean
  • Array
  • Object
  • Date
  • Function
  • Symbol

2.5 props属性命名问题

由于HTML 中的 attribute 名是大小写不敏感的,所以浏览器会把所有大写字符解释为小写字符。

因此使用 DOM 模板时,驼峰命名法的 prop 名可以使用其等价的 短横线分隔命名方式来使用。

也可以直接使用驼峰命名法来使用。

定义时:

props: {showMessage: {type: String,default: "默认showMessage的值"}
}

使用时:

<show-info :age="100" showMessage="我的个人信息"/><show-info :age="100" show-message="我的个人信息"/>

更推荐使用时,用短横线分隔的方式来使用。

2.6 关于非Prop的Attribute

当我传递给一个组件某个属性,该属性并没有定义对应的props或者emits时,就称之为 非propsAttribute

常见的包括classstyleid等属性 。

这时有两种情况:

  • 当组件有单个根节点时,非propsAttribute将自动添加到根节点的标签属性中。

  • 如果组件有多个根节点,那么会报警告,必须手动的指定要绑定到哪一个属性上。

    • 手动指定的方式是使用$attrs来获取非propsAttribute

      <template><div class="infos"><h2 :class="$attrs.class">姓名: {{ name }}</h2><h2>年龄: {{ age }}</h2></div>
      </template>
      

上面的情况就叫做属性继承。

如果不希望组件的根元素继承attribute,可以在组件中设置 :

export default {inheritAttrs: false
}

上面设置可以禁用Attribute继承和多根节点的方式。

2.7 代码示例

1)父组件

<template><!-- 展示个人信息的组件 --><!-- 如果当前的属性是一个非prop的attribute, 那么该属性会默认添加到子组件的根元素上 --><show-info name="jack" :age="25" :height="1.78" address="广州市" abc="cba" class="active" /></template><script>// 导入子组件import ShowInfo from './ShowInfo.vue'export default {// 局部注册子组件components: {ShowInfo}}
</script><style scoped>
</style>

2)子组件

<template><div class="infos"><!-- 获取继承而来的class属性 --><h2 :class="$attrs.class">姓名: {{ name }}</h2><h2>年龄: {{ age }}</h2><h2>身高: {{ height }}</h2><h2>Message: {{ showMessage }}</h2></div><!-- v-bind="$attrs 一次性把所有继承而来的属性全部绑定到当前元素上面 --><div class="others" v-bind="$attrs"></div>
</template><script>export default {//inheritAttrs: false,       // 设置不允许属性继承props: {                    // props对象语法定义属性name: {type: String,default: "我是默认name"},age: {type: Number,required: true},height: {type: Number,default: 1.75},// 对象类型写默认值时, 需要编写default的函数, 函数返回默认值friend: {type: Object,default() {return { name: "james" }}},hobbies: {type: Array,default: () => ["篮球", "rap", "唱跳"]},showMessage: {type: String,default: "我是showMessage"}}}
</script><style scoped>
</style>

三、组件通信-子传父

3.1 使用场景

  • 当子组件有一些事件被触发时,比如在组件中发生了点击,父组件需要作出一定的响应;

  • 子组件有一些内容想要传递给父组件的时候;

3.2 操作步骤

  • 在子组件中定义好在某些情况下触发的事件名称(自定义事件);

  • 在父组件中以v-on的方式传入要监听的事件名称,并且绑定到对应的方法中;

  • 在子组件中发生某个事件的时候,根据事件名称触发对应的事件;

3.3 自定义事件实现子向父传递

子组件:

<template><div class="add"><button @click="btnClick(1)">+1</button><button @click="btnClick(5)">+5</button><button @click="btnClick(10)">+10</button></div>
</template><script>export default {methods: {btnClick(count) {// 当btnClick方法被调用时,子组件会发出去一个自定义事件// 第一个参数自定义的事件名称// 第二个参数是传递的参数this.$emit("add", count)}}}
</script>

父组件:

<template><div class="app"><h2>当前计数: {{ counter }}</h2><!-- 并且监听组件add-counter内部的add事件 --><add-counter @add="addBtnClick"></add-counter></div>
</template><script>//导入组件import AddCounter from './AddCounter.vue'export default {// 注册组件components: {AddCounter,},data() {return {counter: 0}},methods: {// 子组件中add事件触发时,将调用此方法addBtnClick(count) {this.counter += count},}}
</script>

简单来说:

  • 父组件内, 在子组件标签上添加 @自定义事件="父methods函数"

  • 子组件内, 恰当时机this.$emit('自定义事件名', 值)

4.3 关于Vue3.x对上面方式传值的优化

假设开发父组件和子组件的是两个人,那么开发父组件的人在使用子组件时。

一时是找不到子组件中发出的自定义事件在哪里的。

因为这都是写在业务逻辑里,代码量比较多的时候确实比较难找。而且这些事件也缺乏有效的管理。

因此Vue3.x提供了emits组合式API的写法去优化上面的内容。

1)数组写法对发出的事件进行注册说明

<template><div class="add"><button @click="btnClick(1)">+1</button><button @click="btnClick(5)">+5</button><button @click="btnClick(10)">+10</button></div>
</template><script>export default {// emits数组语法(把发出的自定义事件全部写到这里面)// 相当于把发出的事件进行注册说明一下,这个写法是非必须的emits: ["add"],methods: {btnClick(count) {this.$emit("add", count)}}}
</script>
  • emits数组写法有两个好处

    • 让调用者更清晰子组件中发出了什么事件
    • 使用vscode开发的话,还可以获得事件提示,对开发更加友好,如果不写则没有事件提示

2)对象写法对发出的事件参数进行参数验证

<template><div class="add"><button @click="btnClick(1)">+1</button><button @click="btnClick(5)">+5</button><button @click="btnClick(10)">+10</button></div>
</template><script>export default {// emmits对象语法,对参数count进行验证emits: {add: function(count) {if (count <= 10) {return true}return false}},methods: {btnClick(count) {console.log("btnClick:", count)this.$emit("add", 100)}}}
</script>

对象语法在写业务逻辑的时候用的可能会少一些,一般只用数组语法来进行优化就可以了。

除非是封装一些严格的组件库的时候,可以对事件参数作出相应的验证。

四、组件通信-非父子组件

4.1 Vue3中的Provide/Inject(依赖注入)方式

1)概念和使用场景

Provide/Inject用于非父子组件之间共享数据。这也是Vue3新提供的一些特性。

如果有些深度嵌套的组件,子组件想要获取父组件的部分内容。

在这种情况下,如果仍然将props沿着组件链逐级传递下去,就会非常的麻烦。

此时可以使用 ProvideInject ,无论层级结构有多深,父组件都可以作为其所有子组件的依赖 提供者。

父组件有一个 provide 选项来提供数据,子组件有一个 inject 选项来开始使用这些数据。

父组件不需要知道哪些子组件使用它使用了它提供的属性。 子组件也不需要知道 注入的属性来自哪里。

2)代码示例

A组件:

<template><div class="app"></div>
</template><script>import Home from './B.vue'export default {components: {B},// provide一般都是写成函数provide() {return {name: "张三",age: 25}}}
</script>

父组件提供一个对象数据。

B组件:

<template><div class="app"></div>
</template><script>import Home from './C.vue'export default {components: {C},}
</script>

C组件:

<template><div class="banner"><h2> {{ name }} - {{ age }}</h2></div>
</template><script>export default {inject: ["name", "age"]}
</script>

C组件并不是A组件的直接子组件。但是可以使用inject的方式接收到。

今后开发Vue3项目,可能这种方式用的不多,因为可以使用Vuex或者pinia去共享数据。

4.2 Vue3中的事件总线方式

Vue3从实例中移除了 $on$off$once 方法。

也就是说我们无法像Vue2中那种方式去使用事件总线。也不能直接把公共Vue

所以我们如果希望继续使用全局事件总线,可以通过 Vue3官方有推荐一些库。

mitt或者tiny-emitter。 这里就以mitt为例。

1)npm安装

num install mitt -s

2)新建一个event-bus.js作为事件总线

import mitt from 'mitt'
const emitter = mitt()
export default emitter

3)A组件触发自定义事件

<template><div><h1>A组件</h1><button @click>按钮</button></div>
</template>
<script>import emitter from '../plugins/event-bus.js'export default {      created(){emitter.emit("fn",{name:'张三',age:19})}}
</script>

4)B组件监听和移除自定义事件

<template><div><h1>B组件</h1>{{ str }}</div></template>
<script >import emitter from '../plugins/event-bus.js'export default {      created(){// 监听fn事件emitter.on("fn",msg=>{console.log(msg);});},methods: {eventHandler() {console.log("已经终止事件监听")}},unmounted() {// 取消监听fn函数eventBus.off("fn", this.eventHandler)}}
</script>

按照更加严谨的做法,组件中需要监听的同时也要取消监听。

这种方式不要乱用,如果在代码中大量的使用事件总线代码,其实是不便于管理和维护的

Vue组件化开发--组件通信方式-父传子、子传父、非父子组件传值相关推荐

  1. Thymeleaf + Vue组件化开发

    Thymeleaf 搭配 Vue 完成组件化开发 前言 一.vue2 1.引入静态文件 2.声明组件 二.语法搭配 使用vue方法调用th数据 前言 提示:thymeleaf 固然好,但是 vue 也 ...

  2. vue组件间传值: 父传子、子传父、非父子组件传值

    父组件向子组件传值 // 父组件通过属性将值传递给子组件 <template><div><closePopup :optionsID="optionsID&qu ...

  3. 【组件化开发】前端进阶篇之如何编写可维护可升级的代码

    前言 我还在携程的做业务的时候,每个看似简单的移动页面背后往往会隐藏5个以上的数据请求,其中最过复杂的当属机票与酒店的订单填写业务代码 这里先看看比较"简单"的机票代码: 然后看看 ...

  4. 前端笔记:使用Web Components进行原生组件化开发

    文章目录 目的 基础说明 技术点介绍 Custom elements Shadow DOM HTML templates 整合成独立组件文件 示例演示与说明 示例一 示例二 es6-string-ht ...

  5. 组件化开发与资源管理

    前端,是一种GUI软件 现如今前端可谓包罗万象,产品形态五花八门,涉猎极广,什么高大上的基础库/框架,拽炫酷的宣传页面,还有屌炸天的小游戏--不过这些一两个文件的小项目并非是前端技术的主要应用场景,更 ...

  6. iOS 的组件化开发

    2019独角兽企业重金招聘Python工程师标准>>> 在一个APP开发过程中,如果项目较小且团队人数较少,使用最基本的MVC.MVVM开发就已经足够了,因为维护成本比较低. 但是当 ...

  7. Android之组件化开发

    转载请标明出处:[顾林海的博客] 个人开发的微信小程序,目前功能是书籍推荐,后续会完善一些新功能,希望大家多多支持! ##前言 在以前的项目中都是建一个基础库,项目依赖基础库,主项目中集成了所有的功能 ...

  8. 我的react组件化开发道路(二) 分页 组件开发

    2019独角兽企业重金招聘Python工程师标准>>> 上一篇文章主要写了关于react组件化开发的一些基本配置,慢慢的深入到每个组件的详细介绍中,今天我们就来分享react的分页组 ...

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

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

最新文章

  1. python 数字循环
  2. 凤凰网广告包装的js
  3. getopt函数—分析命令行参数
  4. MySQL返回多行错误怎么处理_结果包含多个行错误mysql
  5. C#获取和设置环境变量
  6. 1.1 算法编译与调试
  7. 【数据结构与算法】字符串匹配 BM算法
  8. C#(asp.net)实现目录(无扩展名)重写
  9. RK3288_Android7.1的gpio按键驱动浅析
  10. Struts2理解--动态方法和method属性及通配符_默认Action
  11. JavaScript/JS闭包理解
  12. 如何自定义TCP通信协议
  13. 依赖注入:语法糖胜于功能组合
  14. 安卓手机怎么运行java?如何在Android手机上运行jAVA程序?
  15. html怎么用css文件怎么打开,css文件用什么打开?
  16. http 阮一峰_JavaScript 标准参考教程(alpha) 阮一峰
  17. 全国高校恋爱关系图谱:北大受宠爱,浙大最孤独
  18. 二维离散型随机变量及其分布
  19. 三级管集电极开路电路工作原理详细分析
  20. ABAP bgRFC 实例

热门文章

  1. 滨州医学院做计算机作业的网站,滨州医学院教务网(点击进入)
  2. 抽奖模块代码分享(数据库sql + java业务代码)
  3. 【王喆-推荐系统】线上服务篇-(task3)召回层
  4. vue路由传参的三种方式
  5. pipenv介绍和简单使用
  6. Ubuntu c++ 删除文件夹或者文件
  7. ios自建服务器降级,开发者发布苹果iOS 64位设备降级工具:支持恢复到关闭验证固件...
  8. anaconda遇到“An unexpected error has occurred”问题
  9. android 百度地图 黑屏,百度地图 Fragment之间切换黑屏现象解决方案
  10. sqli-labs/Less-2