Vue2向Vue3过度核心技术组件通信 浅浅的花香味﹌ 2024-03-24 21:37 89阅读 0赞 #### 目录 #### * * 1 组件基础知识scoped解决样式冲突 * * 1.1 默认情况: * 1.2 代码演示 * 1.3 scoped原理 * 1.4 总结 * 2 组件基础知识data必须是一个函数 * * 2.1 data为什么要写成函数 * 2.2 代码演示 * 2.3 总结 * 3 组件通信 * * 3.1 什么是组件通信? * 3.2 组件之间如何通信 * 3.3 组件关系分类 * 3.4 通信解决方案 * 3.5 父子通信流程 * 3.6 父向子通信代码示例 * 3.7 子向父通信代码示例 * 3.8 总结 * 4 什么是props * * 4.1.Props 定义 * 4.2.Props 作用 * 4.3.特点 * 4.4.代码演示 * 5 props校验 * * 5.1.思考 * 5.2.作用 * 5.3.语法 * 5.4.代码演示 * 6 props校验完整写法 * * 6.1.语法 * 6.2.代码实例 * 6.3.注意 * 7 props&data、单向数据流 * * 7.1.共同点 * 7.2.区别 * 7.3.单向数据流: * 7.4.代码演示 * 7.5.口诀 * 8 综合案例-组件拆分 * * 8.1.需求说明 * 8.2.拆分基础组件 * 9 综合案例-列表渲染 * 10 综合案例-添加功能 * 11 综合案例-删除功能 * 12 综合案例-底部功能及持久化存储 * 13 非父子通信-event bus 事件总线 * * 13.1.作用 * 13.2.步骤 * 13.3.代码示例 * 13.4.总结 * 14 非父子通信-provide&inject * * 14.1.作用 * 14.2.场景 * 14.3.语法 * 14.4.注意 -------------------- ### 1 组件基础知识scoped解决样式冲突 ### ![在这里插入图片描述][4102ecdd08c845478ef53f0224af8014.png] #### 1.1 默认情况: #### 写在组件中的样式会 **全局生效** → 因此很容易造成多个组件之间的样式冲突问题。 1. **全局样式**: 默认组件中的样式会作用到全局,任何一个组件中都会受到此样式的影响 2. **局部样式**: 可以给组件加上**scoped** 属性,可以**让样式只作用于当前组件** #### 1.2 代码演示 #### BaseOne.vue <template> <div class="base-one"> BaseOne </div> </template> <script> export default { } </script> <style scoped> </style> BaseTwo.vue <template> <div class="base-one"> BaseTwo </div> </template> <script> export default { } </script> <style scoped> </style> App.vue <template> <div id="app"> <BaseOne></BaseOne> <BaseTwo></BaseTwo> </div> </template> <script> import BaseOne from './components/BaseOne' import BaseTwo from './components/BaseTwo' export default { name: 'App', components: { BaseOne, BaseTwo } } </script> #### 1.3 scoped原理 #### 1. 当前组件内标签都被添加**data-v-hash值** 的属性 2. css选择器都被添加 \[**data-v-hash值**\] 的属性选择器 最终效果: **必须是当前组件的元素**, 才会有这个自定义属性, 才会被这个样式作用到 ![在这里插入图片描述][06b787cccea746dd94f29f48ab12fe9e.png] #### 1.4 总结 #### 1. style的默认样式是作用到哪里的? 2. scoped的作用是什么? 3. style中推不推荐加scoped? ### 2 组件基础知识data必须是一个函数 ### #### 2.1 data为什么要写成函数 #### 一个组件的 **data** 选项必须**是一个函数**。目的是为了:保证每个组件实例,维护**独立**的一份**数据**对象。 每次创建新的组件实例,都会新**执行一次data 函数**,得到一个新对象。 ![在这里插入图片描述][bcede011bb1f4d8dba2d22113866ce42.png] #### 2.2 代码演示 #### BaseCount.vue <template> <div class="base-count"> <button @click="count--">-</button> <span>{ { count }}</span> <button @click="count++">+</button> </div> </template> <script> export default { data: function () { return { count: 100, } }, } </script> <style> .base-count { margin: 20px; } </style> App.vue <template> <div class="app"> <BaseCount></BaseCount> </div> </template> <script> import BaseCount from './components/BaseCount' export default { components: { BaseCount, }, } </script> <style> </style> #### 2.3 总结 #### data写成函数的目的是什么? ### 3 组件通信 ### #### 3.1 什么是组件通信? #### 组件通信,就是指**组件与组件**之间的**数据传递** * 组件的数据是独立的,无法直接访问其他组件的数据。 * 想使用其他组件的数据,就需要组件通信 #### 3.2 组件之间如何通信 #### ![在这里插入图片描述][0ce1410321f14183a35b103267b686f0.png] 思考: 1. 组件之间有哪些关系? 2. 对应的组件通信方案有哪几类? #### 3.3 组件关系分类 #### 1. 父子关系 2. 非父子关系 ![在这里插入图片描述][92ee14be28bc469ebad886641f636a67.png] #### 3.4 通信解决方案 #### ![在这里插入图片描述][bf6a145272054b4b938e556570189bc8.png] #### 3.5 父子通信流程 #### 1. 父组件通过 **props** 将数据传递给子组件 2. 子组件利用 **$emit** 通知父组件修改更新 ![在这里插入图片描述][2a287fb4a15c4038b54afe793d19616e.png] #### 3.6 父向子通信代码示例 #### 父组件通过**props**将数据传递给子组件 父组件App.vue <template> <div class="app" style="border: 3px solid #000; margin: 10px"> 我是APP组件 <Son></Son> </div> </template> <script> import Son from './components/Son.vue' export default { name: 'App', data() { return { myTitle: '学前端,就来黑马程序员', } }, components: { Son, }, } </script> <style> </style> 子组件Son.vue <template> <div class="son" style="border:3px solid #000;margin:10px"> 我是Son组件 </div> </template> <script> export default { name: 'Son-Child', } </script> <style> </style> ![在这里插入图片描述][8b42792ccd944345813bcf33e2e530e3.png] 父向子传值步骤 1. 给子组件以添加属性的方式传值 2. 子组件内部通过props接收 3. 模板中直接使用 props接收的值 #### 3.7 子向父通信代码示例 #### 子组件利用 **$emit** 通知父组件,进行修改更新 ![在这里插入图片描述][80902b88081946f78fef9c83f70dd3dc.png] 子向父传值步骤 1. $emit触发事件,给父组件发送消息通知 2. 父组件监听$emit触发的事件 3. 提供处理函数,在函数的性参中获取传过来的参数 #### 3.8 总结 #### 1. 组件关系分类有哪两种 2. 父子组件通信的流程是什么? 1. 父向子 2. 子向父 ### 4 什么是props ### #### 4.1.Props 定义 #### 组件上 注册的一些 自定义属性 #### 4.2.Props 作用 #### 向子组件传递数据 #### 4.3.特点 #### 1. 可以 传递 **任意数量** 的prop 2. 可以 传递 **任意类型** 的prop ![在这里插入图片描述][6d12d44f697a4939888576985b81e7fd.png] #### 4.4.代码演示 #### 父组件App.vue <template> <div class="app"> <UserInfo :username="username" :age="age" :isSingle="isSingle" :car="car" :hobby="hobby" ></UserInfo> </div> </template> <script> import UserInfo from './components/UserInfo.vue' export default { data() { return { username: '小帅', age: 28, isSingle: true, car: { brand: '宝马', }, hobby: ['篮球', '足球', '羽毛球'], } }, components: { UserInfo, }, } </script> <style> </style> 子组件UserInfo.vue <template> <div class="userinfo"> <h3>我是个人信息组件</h3> <div>姓名:</div> <div>年龄:</div> <div>是否单身:</div> <div>座驾:</div> <div>兴趣爱好:</div> </div> </template> <script> export default { } </script> <style> .userinfo { width: 300px; border: 3px solid #000; padding: 20px; } .userinfo > div { margin: 20px 10px; } </style> ### 5 props校验 ### #### 5.1.思考 #### 组件的props可以乱传吗 #### 5.2.作用 #### 为组件的 prop 指定**验证要求**,不符合要求,控制台就会有**错误提示** → 帮助开发者,快速发现错误 #### 5.3.语法 #### * **类型校验** * 非空校验 * 默认值 * 自定义校验 ![在这里插入图片描述][74556ffa61e24885a918c35860d438b9.png] #### 5.4.代码演示 #### App.vue <template> <div class="app"> <BaseProgress :w="width"></BaseProgress> </div> </template> <script> import BaseProgress from './components/BaseProgress.vue' export default { data() { return { width: 30, } }, components: { BaseProgress, }, } </script> <style> </style> BaseProgress.vue <template> <div class="base-progress"> <div class="inner" :style="{ width: w + '%' }"> <span>{ { w }}%</span> </div> </div> </template> <script> export default { props: ['w'], } </script> <style scoped> .base-progress { height: 26px; width: 400px; border-radius: 15px; background-color: #272425; border: 3px solid #272425; box-sizing: border-box; margin-bottom: 30px; } .inner { position: relative; background: #379bff; border-radius: 15px; height: 25px; box-sizing: border-box; left: -3px; top: -2px; } .inner span { position: absolute; right: 0; top: 26px; } </style> ### 6 props校验完整写法 ### #### 6.1.语法 #### props: { 校验的属性名: { type: 类型, // Number String Boolean ... required: true, // 是否必填 default: 默认值, // 默认值 validator (value) { // 自定义校验逻辑 return 是否通过校验 } } }, #### 6.2.代码实例 #### <script> export default { // 完整写法(类型、默认值、非空、自定义校验) props: { w: { type: Number, //required: true, default: 0, validator(val) { // console.log(val) if (val >= 100 || val <= 0) { console.error('传入的范围必须是0-100之间') return false } else { return true } }, }, }, } </script> #### 6.3.注意 #### 1.default和required一般不同时写(因为当时必填项时,肯定是有值的) 2.default后面如果是简单类型的值,可以直接写默认。如果是复杂类型的值,则需要以函数的形式return一个默认值 ### 7 props&data、单向数据流 ### #### 7.1.共同点 #### 都可以给组件提供数据 #### 7.2.区别 #### * data 的数据是**自己**的 → 随便改 * prop 的数据是**外部**的 → 不能直接改,要遵循 **单向数据流** #### 7.3.单向数据流: #### 父级props 的数据更新,会向下流动,影响子组件。这个数据流动是单向的 #### 7.4.代码演示 #### App.vue <template> <div class="app"> <BaseCount></BaseCount> </div> </template> <script> import BaseCount from './components/BaseCount.vue' export default { components:{ BaseCount }, data(){ }, } </script> <style> </style> BaseCount.vue <template> <div class="base-count"> <button @click="count--">-</button> <span>{ { count }}</span> <button @click="count++">+</button> </div> </template> <script> export default { // 1.自己的数据随便修改 (谁的数据 谁负责) data () { return { count: 100, } }, // 2.外部传过来的数据 不能随便修改 //props: { // count: { // type: Number, // }, //} } </script> <style> .base-count { margin: 20px; } </style> ![在这里插入图片描述][fe128184e55f4b75aff7f72430206866.png] #### 7.5.口诀 #### **谁的数据谁负责** ### 8 综合案例-组件拆分 ### #### 8.1.需求说明 #### * 拆分基础组件 * 渲染待办任务 * 添加任务 * 删除任务 * 底部合计 和 清空功能 * 持久化存储 #### 8.2.拆分基础组件 #### 咱们可以把小黑记事本原有的结构拆成三部分内容:头部(TodoHeader)、列表(TodoMain)、底部(TodoFooter) ![在这里插入图片描述][b8ce92b6270d4104bc66f5d6a247e00d.png] ### 9 综合案例-列表渲染 ### 思路分析: 1. 提供数据:提供在公共的父组件 App.vue 2. 通过父传子,将数据传递给TodoMain 3. 利用v-for进行渲染 ### 10 综合案例-添加功能 ### 思路分析: 1. 收集表单数据 v-model 2. 监听时间 (回车+点击 都要进行添加) 3. 子传父,将任务名称传递给父组件App.vue 4. 父组件接受到数据后 进行添加 **unshift**(自己的数据自己负责) ### 11 综合案例-删除功能 ### 思路分析: 1. 监听时间(监听删除的点击)携带id 2. 子传父,将删除的id传递给父组件App.vue 3. 进行删除 **filter** (自己的数据自己负责) ### 12 综合案例-底部功能及持久化存储 ### 思路分析: 1. 底部合计:父组件传递list到底部组件 —>展示合计 2. 清空功能:监听事件 —> **子组件**通知父组件 —>父组件清空 3. 持久化存储:watch监听数据变化,持久化到本地 ### 13 非父子通信-event bus 事件总线 ### #### 13.1.作用 #### 非父子组件之间,进行简易消息传递。(复杂场景→ Vuex) #### 13.2.步骤 #### 1. 创建一个都能访问的事件总线 (空Vue实例) import Vue from 'vue' const Bus = new Vue() export default Bus 2. A组件(接受方),监听Bus的 $on事件 created () { Bus.$on('sendMsg', (msg) => { this.msg = msg }) } 3. B组件(发送方),触发Bus的$emit事件 Bus.$emit('sendMsg', '这是一个消息') ![在这里插入图片描述][a2e97474f66f470e933e9cf39acb633c.png] #### 13.3.代码示例 #### EventBus.js import Vue from 'vue' const Bus = new Vue() export default Bus BaseA.vue(接受方) <template> <div class="base-a"> 我是A组件(接收方) <p>{ {msg}}</p> </div> </template> <script> import Bus from '../utils/EventBus' export default { data() { return { msg: '', } }, } </script> <style scoped> .base-a { width: 200px; height: 200px; border: 3px solid #000; border-radius: 3px; margin: 10px; } </style> BaseB.vue(发送方) <template> <div class="base-b"> <div>我是B组件(发布方)</div> <button>发送消息</button> </div> </template> <script> import Bus from '../utils/EventBus' export default { } </script> <style scoped> .base-b { width: 200px; height: 200px; border: 3px solid #000; border-radius: 3px; margin: 10px; } </style> App.vue <template> <div class="app"> <BaseA></BaseA> <BaseB></BaseB> </div> </template> <script> import BaseA from './components/BaseA.vue' import BaseB from './components/BaseB.vue' export default { components:{ BaseA, BaseB } } </script> <style> </style> #### 13.4.总结 #### 1.非父子组件传值借助什么? 2.什么是事件总线 3.发送方应该调用事件总线的哪个方法 4.接收方应该调用事件总线的哪个方法 5.一个组件发送数据,可不可以被多个组件接收 ### 14 非父子通信-provide&inject ### #### 14.1.作用 #### 跨层级共享数据 #### 14.2.场景 #### ![在这里插入图片描述][9eb1056ae8374ac98eecbf028d404b45.png] #### 14.3.语法 #### 1. 父组件 provide提供数据 export default { provide () { return { // 普通类型【非响应式】 color: this.color, // 复杂类型【响应式】 userInfo: this.userInfo, } } } 2.子/孙组件 inject获取数据 export default { inject: ['color','userInfo'], created () { console.log(this.color, this.userInfo) } } #### 14.4.注意 #### * provide提供的简单类型的数据不是响应式的,复杂类型数据是响应式。(推荐提供复杂类型数据) * 子/孙组件通过inject获取的数据,不能在自身组件内修改 [4102ecdd08c845478ef53f0224af8014.png]: https://image.dandelioncloud.cn/pgy_files/images/2024/03/13/cca339344ee04a1cb7d9680dda65d819.png [06b787cccea746dd94f29f48ab12fe9e.png]: https://image.dandelioncloud.cn/pgy_files/images/2024/03/13/f08e1367cdc14cda9800bf5db0a8d954.png [bcede011bb1f4d8dba2d22113866ce42.png]: https://image.dandelioncloud.cn/pgy_files/images/2024/03/13/2b0b8d53e8384df3be416f36f65fa094.png [0ce1410321f14183a35b103267b686f0.png]: https://image.dandelioncloud.cn/pgy_files/images/2024/03/13/3ddb389bfca84b6e86067105e916d044.png [92ee14be28bc469ebad886641f636a67.png]: https://image.dandelioncloud.cn/pgy_files/images/2024/03/13/2a36e1f9f3a8421e85a7e0bf4e93c1cd.png [bf6a145272054b4b938e556570189bc8.png]: https://image.dandelioncloud.cn/pgy_files/images/2024/03/13/037bba4bfe954069ac9807754f62e587.png [2a287fb4a15c4038b54afe793d19616e.png]: https://image.dandelioncloud.cn/pgy_files/images/2024/03/13/b8ae7a83017a4b899dbdfad966f15b93.png [8b42792ccd944345813bcf33e2e530e3.png]: https://image.dandelioncloud.cn/pgy_files/images/2024/03/13/a1c9699d84e746ac8c75a1861f8a025f.png [80902b88081946f78fef9c83f70dd3dc.png]: https://image.dandelioncloud.cn/pgy_files/images/2024/03/13/ca43c1dda4d74f1ea9c34a356edfdaad.png [6d12d44f697a4939888576985b81e7fd.png]: https://image.dandelioncloud.cn/pgy_files/images/2024/03/13/7ce94891c2f2401a85ab252d0fe8b0b3.png [74556ffa61e24885a918c35860d438b9.png]: https://image.dandelioncloud.cn/pgy_files/images/2024/03/13/9c91be3d61c948089974074bdbc164db.png [fe128184e55f4b75aff7f72430206866.png]: https://image.dandelioncloud.cn/pgy_files/images/2024/03/13/b71bfe77e8944e01a5a2c545b2a16f17.png [b8ce92b6270d4104bc66f5d6a247e00d.png]: https://image.dandelioncloud.cn/pgy_files/images/2024/03/13/54d171cee1ad47f3a31915bdf9db2003.png [a2e97474f66f470e933e9cf39acb633c.png]: https://image.dandelioncloud.cn/pgy_files/images/2024/03/13/a6f985e8a9c64e9caa4a9250209fc583.png [9eb1056ae8374ac98eecbf028d404b45.png]: https://image.dandelioncloud.cn/pgy_files/images/2024/03/13/5b07bfb868fc470e9ad14949f9a5aeab.png
相关 Vue2向Vue3过度核心技术综合案例 目录 1 面经基础版-案例效果分析 1.面经效果演示 2.功能分析 3.实现思路分析:配置路由 曾经终败给现在/ 2024年03月24日 21:50/ 0 赞/ 94 阅读
相关 Vue2向Vue3过度核心技术声明式导航 目录 1 声明式导航-导航链接 1.需求 2.解决方案 3.通过router-link自带的两 本是古典 何须时尚/ 2024年03月24日 21:49/ 0 赞/ 84 阅读
相关 Vue2向Vue3过度核心技术插槽 目录 1 插槽-默认插槽 1.作用 2.需求 3.问题 4.插槽的基本语 Love The Way You Lie/ 2024年03月24日 21:48/ 0 赞/ 84 阅读
相关 Vue2向Vue3过度核心技术组件通信 目录 1 组件基础知识scoped解决样式冲突 1.1 默认情况: 1.2 代码演示 1.3 浅浅的花香味﹌/ 2024年03月24日 21:37/ 0 赞/ 90 阅读
相关 Vue2向Vue3过度核心技术生命周期 目录 1 Vue生命周期 2 Vue生命周期钩子 3 生命周期钩子小案例 1.1 在created中发送数据 小灰灰/ 2024年03月24日 21:35/ 0 赞/ 82 阅读
相关 Vue2向Vue3过度核心技术watch侦听器 目录 1 watch侦听器 1.1 作用: 1.2 语法: 1.3 侦听器代码准备 以你之姓@/ 2024年03月24日 21:33/ 0 赞/ 59 阅读
还没有评论,来说两句吧...