什么是组件?
在 Vue 中,组件就好像是可以拼装的小零件一样。就像我们用积木一块块搭建出一个房子一样,Vue 中的组件也可以用来拼装出一个完整的网页。每一个组件都是独立存在的,就像每一个积木一样。
每个组件都可以包括一些自己的特性,例如按钮、输入框、图片轮播和弹出框等等。我们可以把这些组件一个个拼起来,搭建成一个完整的网页。而像Vue这样的框架,更是方便我们将一个大的网页拆分成一个个小的组件,让我们的代码更加清晰易懂。
所以说,组件就好像积木一样,可以拼装成很多不同的形状,而在 Vue 中,它们可以帮我们建造出很多不同的网页。
组件命名规范
驼峰命名-大写开头 GoodsItems
横线链接 goods-items
组件特点
解决高度耦合的问题
测试不独立的问题
设计模式冲突的问题
优点
1, 组件之间相互独立, 节约编译时间 , 降低耦合性
2, 复用性
3, 节约测试和开发的时间
组件的划分
1, 基础组件 : 基础配置, 工具类 网络封装
2, 功能性组件: 控件(弹幕,轮播图 , 选项卡), 功能(断电续传 音视频处理)
3, 业务组件 各个业务线
组件之间的关系
1 , 基础组件 和功能性组件 是同层的 不能产生依赖关系
2 , 同类组件内部 之间 不能产生依赖关系
3 , 业务组件依赖于基础组件和功能组件
在vue中 组件分为全局组件和局部组件
组件又有 动态组件 递归组件 缓存组件
如何创建组件?
在项目目录 src/components
下创建 .vue
文件。
如下图,创建一个文件名为GoodsItem
的商品列表组件。
建议通过 vsCode
开发,安装 vue 语法插件 Vue Language Features (Volar)
后,输入 vue 回车,可快速生成页面模板
商品列表组件内容如下:
<template> <div class="goods-items"> <!-- {{ this.$parent }} --> <div class="right-des"> <!-- 商品标题 --> <h3> {{ title }} </h3> <!-- 商品价格 --> <h3>{{ price }}</h3> </div> <!-- 商品图片 --> <img :src="img" class="left-img" /> </div> </template> <script> export default { name: 'WebCodeGoodsItem', // 组件的配置项,数据的入口 props:{ title:{ type:String, // 定义字段类型 default:'商品标题' // 定义默认数据 }, img:{ type:String, default:'https://v2.cn.vuejs.org/images/logo.svg' }, price:{ type:Number, default:99 } }, data() { return { }; } }; </script> <style scoped> .goods-items{ width: 100%; display: flex; justify-content: space-between; } .goods-items img{ width: 100px; height: 100px; margin: 10px; } </style>
如何使用组件?
局部组件:
当前页面引入组件
<script> // 【局部引入组件】 import GoodsItem from './components/GoodsItem.vue'; export default { name: 'WebCodeApp', // 页面实例中的components中注册组件 components:{ GoodsItem }, data() { return { }; } }; </script>
全局组件:
在 main.js 中注册组件
import GoodsItem from "@/components/GoodsItem.vue" Vue.component('goods-car',GoodsItem)
组件通信
什么是组件通信
咱们应该知道网页是由很多小部件组成的吧?
比如按钮、输入框、图片等等,这些小部件可以组合在一起,形成一个大大的网页,就像搭积木一样。有时候,这些小部件之间需要传递信息,才能完成各种酷炫的功能,比如你在网上购物,需要把选好的商品放到购物车里面去。这个过程就需要用到组件通信。。
组件通信的场景
比如,在一个在线聊天的应用中,你输入聊天内容后,需要把这个内容发送给对方,这时需要用到组件通信。
再比如,你在一个电商网站中看到一件喜欢的衣服,想要加入购物车,这个加入购物车的过程也需要用到组件通信。
比如,在网上上传头像时,需要在上传按钮和图片预览区之间进行通信,才能让你选择了一张图片之后,立刻在预览区域看到它的效果。
组件通信的分类
- 父子组件通信:通过“props”属性向下传递数据,通过“$emit”事件向上传递数据。
- 兄弟组件通信:通过在共同的父组件中定义数据并通过“props”和“$emit”将数据传递给需要的两个兄弟组件。
- 祖先组件通信:通过“provide”和“inject”来传递数据,祖先组件用“provide”提供数据,后代组件通过“inject”来获取数据。
- 后代组件通信:通过“$ref”引入组件对象,并直接访问其数据和方法。
- 任意两个组件通信:可以通过事件总线或Vuex来实现。事件总线相当于给组件之间建立了一座桥梁,任何一个组件都可以向事件总线发出事件,其他组件收到事件后可以做出相应的处理。Vuex是一个全局状态管理器,通过统一管理组件共享的状态,从而实现组件之间的数据共享
1, 父子通信 父传子
在子组件中配置props
组件参数,定义组件属性
type
:字段类型
defalut
:默认值
props:{ title:{ type:String, // 定义字段类型 default:'商品标题' // 定义默认数据 } }
子组件:
<template> <div class="goods-items"> <img :src="img" class="left-img" /> <div class="right-des"> <h3> {{ title }} </h3> <h3>{{ price }}</h3> </div> </div> </template> <script> export default { name: 'WebCodeGoodsItem', // 组件的配置项,数据的入口【可配置字段类型校验】 props:{ title:{ type:String, // 定义字段类型 default:'商品标题' // 定义默认数据 }, img:{ type:String, default:'https://v2.cn.vuejs.org/images/logo.svg' }, price:{ type:Number, default:99 } } }; </script>
父组件:
在组件中,使用 v-bind
、或者:
给组件内部传值
<GoodsItem :key="key" :img="item.img" :price="item.price" :title="item.title"></GoodsItem> export default { name: 'WebCodeApp', // 页面实例中的components中注册组件 components:{ GoodsItem }, data() { return { goodList:[] ,// 后台返回的总数据 }; },}
2, 子传父
通过Vue实例的$emit 派发自定义事件,然后在父组件监听自定义事件 通过callback来获取子组件传递过来的数据
子组件
carClick(){ // $emit this.$emit('carClick',this.title) }
父组件
<GoodsItem @carClick="carClick" :key="key" :img="item.img" :price="item.price" :title="item.title"></GoodsItem> // methods中的函数 carLick(data){ // alert(data) Toast('子组件发送的自定义事件:'+data) }
3、$parent、$chidren
$parent、$chidren 都是获取vue实例对象属性
1、$parent 获取父组件的实例对象
2、$chidren 获取子组件的实例对象
!!注意
parent/chidren 只能获取最近的一级组件,如果组件嵌套,需要链式调用获取内部实例数据方法
如下页面,使用了一个嵌套组件,我们在 GoodsItem 组件内部,调用父页面的alertBox方法,如何实现?
<template> <div id="app"> <van-list v-model="loadding" :finished="finished" finished-text="没有更多了" @load="onLoad" > <GoodsItem v-for="(item,key) in currentList" @carClick="carLick1" :key="key" :img="item.img" :price="item.price" :title="item.title"></GoodsItem> </van-list> </div> </template> // methods中方法 alertBox(){ // vant 对话框 Dialog.alert({ title: '警告标题', message: '是否清空数据', }).then(() => { console.log('this',this.$children) // on close }); }
需在goodsItem 内部中 通过$parant 获取实例
this.$parent.$parent.alertBox()
缺点:子组件可能有很多个,导致代码不够整洁,嵌套层级过多,需要手动遍历
4、$refs
作用:1、操作获取dom;2、操作组件实例方法和数据
操作dom节点传统写法:document.querySelector(".input1")
使用 refs 调用即可,同时可以获取组件内部数据/方法。
5、跨组件通信
eventBus 是一种在任何组件之间进行通信的机制,常用于兄弟组件传值。
基于发布/订阅模式,使组件可以将事件发送到事件总线(EventBus)并订阅来自事件总线的事件
不必通过祖先或子孙的耦合关系的情况下相互通信,
使用方式:
一、手动创建一个发布订阅者js插件
二、【快捷方式】
结合 Vue 实例中的 监听订阅特性,在main.js 中 向Vue 原型中 添加一个 vue实例对象,作为 eventBus
// main.js 代码 Vue.prototype.$eventBus = new Vue();
注意!!
事件订阅越多消耗内存越大。需及时销毁,否则造成内测泄漏
destroyed() { // 销毁 this.$eventBus.$off('xxx'); }
建议在页面销毁生命周期中,移除事件监听