前面我们是将所有的逻辑放到一个App.vue中:
我们来分析一下下面代码的嵌套逻辑,假如我们将所有的代码逻辑都放到一个App.vue组件中:
Header
NavBar
Banner
- 商品列表1
- 商品列表2
- 商品列表3
- 商品列表4
- 商品列表5
Footer
免责声明
我们会发现,将所有的代码逻辑全部放到一个组件中,代码是非常的臃肿和难以维护的。并且在真实开发中,我们会有更多的内容和代码逻辑,对于扩展性和可维护性来说都是非常差的。
所有,在真实的开发中,我们会对组件进行拆分,拆分成一个个功能的小组件。
我们可以按照如下的方式进行拆分:
自定义组件的嵌套逻辑
Header.vue组件:
Header
NavBar
Main.vue组件:
Banner.vue组件:
Banner
ProductList组件:
- 商品列表1
- 商品列表2
- 商品列表3
- 商品列表4
- 商品列表5
Footer.vue组件:
Footer
免责声明
按照如上的拆分方式后,我们开发对应的逻辑只需要去对应的组件编写就可。
上面的嵌套逻辑如下,它们存在如下关系:
在开发过程中,我们会经常遇到需要组件之间相互进行通信:
总之,在一个Vue项目中,组件之间的通信是非常重要的环节,所以接下来我们就具体学习一下组件之间是如何相互之间传递数据的;
在开发中很常见的就是父子组件之间通信,比如父组件有一些数据,需要子组件来进行展示:
什么是Props呢?
Props有两种常见的用法:
封装ShowMessage.vue组件:
组件展示的title:{{title}}
组件展示的content: {{content}}
通过App.vue传递给组件数据:
当然,我们也可以将data中的数据传递给子组件:
当然,我们也可以直接传递一个对象:
数组用法中我们只能说明传入的attribute的名称,并不能对其进行任何形式的限制,接下来我们来看一下对象的写法是如何让我们的props变得更加完善的。
ShowMessage.vue的props对象写法:
组件展示的title:{{title}}
组件展示的content: {{content}}
细节一:那么type的类型都可以是哪些呢?
细节二:对象类型的其他写法
细节三:Prop 的大小写命名(camelCase vs kebab-case)
ShowMessage.vue组件:
{{messageInfo}}
App.vue组件中传入:
重申一次,如果你使用字符串模板,那么这个限制就不存在了。
什么是非Prop的Attribute呢?
Attribute继承
当组件有单个根节点时,非Prop的Attribute将自动添加到根节点的Attribute中:
禁用Attribute继承
如果我们不希望组件的根元素继承attribute,可以在组件中设置 inheritAttrs: false:
我是NotPropAttribue组件
多个根节点的attribute
多个根节点的attribute如果没有显示的绑定,那么会报警告,我们必须手动的指定要绑定到哪一个属性上:
我是NotPropAttribue组件1
我是NotPropAttribue组件2
我是NotPropAttribue组件3
什么情况下子组件需要传递内容到父组件呢?
我们如何完成上面的操作呢?
我们封装一个CounterOperation.vue的组件:
我们可以在App.vue中来监听自定义组件发出的事件:
当前计数: {{counter}}
自定义事件的时候,我们也可以传递一些参数给父组件:
在vue3当中,我们可以对传递的参数进行验证:
我们来做一个相对综合的练习:
综合练习
TabControl.vue的实现代码:
{{ item }}
我们在App中的使用过程如下:
{{contents[currentIndex]}}
在开发中,我们构建了组件树之后,除了父子组件之间的通信之外,还会有非父子组件之间的通信。
这里我们主要讲两种方式:
Provide/Inject用于非父子组件之间共享数据:
对于这种情况下,我们可以使用 Provide 和 Inject :
实际上,你可以将依赖注入看作是“long range props”,除了:
我们开发一个这样的结构:
案例结构
App.vue组件提供数据:
Home.vue是中间的组件:
HomeContent.vue是获取数据的组件:
HomeContent
{{name}}-{{age}}
如果Provide中提供的一些数据是来自data,那么我们可能会想要通过this来获取:
引入data的数据
这个时候会报错:
报错信息
如何解决这个问题呢?
修改为函数的写法
我们先来验证一个结果:如果我们修改了this.names的内容,那么使用length的子组件会不会是响应式的?
我们会发现对应的子组件中是没有反应的:
那么怎么样可以让我们的数据变成响应式的呢?
注意:我们在使用length的时候需要获取其中的value
使用computed
Provide和Inject也可以在Composition API中使用,后续我们会讲到的。
3.2. 全局事件总线
Vue3从实例中移除了 $on、$off 和 $once 方法,所以我们如果希望继续使用全局事件总线,要通过第三方的库:
首先,我们需要先安装这个库:
npm install mitt
其次,我们可以封装一个工具eventbus.js:
import mitt from 'mitt';// 可以创建很多个emitter对象
const emitter = mitt();
export default emitter;
在项目中可以使用它们:
Home.vue组件中监听事件:
App.vue中触发事件:
其他API的补充,如果在某些情况下我们想要取消事件,可以使用下面的API:
// 取消emitter中所有的监听
emitter.all.clear()
// 定义一个函数
function onFoo() {}
// 监听
emitter.on('foo', onFoo)
// 取消监听
emitter.off('foo', onFoo)