什么是组件化
组件化是一种思想,就是拆分的意思,通俗而言,就是大而化小(没有小而化了)、方便管理。比如咱们中国地大物博,人口众多不好管理,所以就拆分成许多省、直辖市、自治区,方便管理。写代码也是一样,如果一个文件写了几万行代码,就会耦合太严重,拆分开来,方便管理。
但是组件化不能过渡使用,不能为了组件化而组件化。合理使用,才为上策
组件化和模块化的区别
- 组件化-ui视图层面的拆分
以vue为例,一个页面有头部、内容区、底部。可以拆分开来,这里的拆分一般都会带着样式css,所以称之为UI视图层面的拆分(当然也会包含js的相关逻辑) - 模块化-js层面的拆分
模块化的拆分主要是js逻辑层面的拆分,二者类似,但不同
组件的分类
- 独立拆分的组件
比如我们把一个页面的头部、内容区、底部分别拆分成三个独立的组件 公共复用的组件
比如在很多的路由页面里,都需要使用到一个弹框、或者使用到一个表格。我们可以封装一个弹框或者封装一个表格,哪里需要引哪里,不同页面的弹框或表格数据不一样,我们可以通过给封装的公共组件传递不同的数据,使其展现不同。其实一个.vue文件就是一个组件,只不过是页面级别的组件罢了
独立拆分的组件之拆分步骤
第一步 组件拆分
本来都写在一个文件中的内容,比如一个.vue文件的结构中包括头部、底部、内容区。我们把头部的html、css、js的内容,单独拎出来成为一个新的.vue文件。当然底部、和内容区的也同样单独拎出来。单独拎出来的就放在components文件夹下吧
第二步 组件引入
import dialogMask from "./components/dialog";
第三步 组件注册
// 是components不是component,要加个s,因为组件可能要注册多个
export default {
// ...
components: {
dialogMask,
},
}
第四步 组件使用
<div class="dialog">
<dialog-mask></dialog-mask>
</div>
公共复用的组件之拆分步骤
复用组件的拆分步骤,最后el-table组件的二次封装会讲解,诸位看官且继续往下看。这里先按下不表。
说道组件的封装,就要与数据传递打交道,所以这里简单说一下vue组件间的数据传递,又因为封装组件大多数的数据传递是以父子组件的传递为主,所以这里提一下vue父子组件间的数据传递。
父子组件间的数据传递之两种方式
方式一(v-bind加v-on)
父传子
- 父组件v-bind绑定自己data中数据传递给子组件
子组件通过props接收到在页面中使用
步骤图如下:子传父
- 子组件通过this.$emit('eventName','参数')触发父组件中的方法
父组件要提前在组件上通过v-on暴露给子组件以便调用
步骤图如下:方式二(使用ref取值赋值)
父传子或子传父
第一步,给子组件打一个ref,就可以看到子组件所有的东西,感兴趣的朋友可以打印一下this.$refs.dialogRef结果一目了然。
<dialogMask ref="dialogRef"></dialogMask>
第二步,在父组件中把父组件的数据赋给子组件(父传子)
this.$refs.dialogRef.子组件的数据 = this.父组件的数据
第三步,在子组件中直接取到拿到子组件的数据赋给父组件
this.父组件的数据 = this.$refs.dialogRef.子组件的数据
父子组件的方法的相互调用
就记住常用的方式吧
- 父组件调用子组件的方法,使用ref
this.$refs.xxx.childMethods()
- 子组件调用父组件的方法,使用this.$emit('eventName','参数')
this.$emit('eventName','参数')
饿了么UI中的el-table组件的二次封装
饿了么UI的组件是饿了么团队基于vue封装的,里面有很多常用的组件,方便我们快速开发项目。不过假设我们的项目中的很多页面都有表格呈现,表格的结构差不多,就是数据不一样,如果我么每个页面都去写el-table一大堆的话,就会比较麻烦,倒不如自己封装一个公共的table组件,那个页面用table的话,那个页面就引进来,传参即可。
第一步,新建组件,注册并在main.js引入
流程图如下:
至此,我们自定义的封装的myTable组件已经注册好了,那个页面需要用,就在那个页面去引入,传对应的参数即可
第二步,根据需求考虑传参
我们先看一下效果图:
需求如下:
- 复选框列和序号列可控制是否展示
- 表头数据动态展示
- 表内容数据也动态展示
实际项目中我们要发请求获取表的数据和表内容数据,这里的话,我们就模拟一下数据即可
封装的myTable组件代码
<template>
<div class="box">
<el-table
:data="tableData"
border
style="width: 100%"
@selection-change="handleSelectionChange"
>
<!-- 复选框列
复选框列和索引列因为有的显示有的不显示,所以我们使用一个v-if去控制它,
v-if的标识取决于父组件(引用这个组件的组件)传递过来的标识。子组件也就是
我们封装的这个myTable组件用props接收一下又因为复选框要有勾选时间所以
@select-change事件不能落下
-->
<el-table-column
v-if="isShowCheckbox == true"
type="selection"
width="48"
fixed
></el-table-column>
<!-- 索引列 -->
<el-table-column
v-if="isShowIndex == true"
label="序号"
type="index"
width="50"
fixed
>
</el-table-column>
<!-- 主内容列
主内容列的表头就是label,表头列对应的数据就是prop,所以父组件可以传递过来
一个数组,里面的每一项就是label的名字和prop对应的值。通过v-for就动态了
-->
<el-table-column
:prop="item.propName"
:label="item.labelName"
v-for="(item, index) in tableHeaderTitle"
:key="index"
>
</el-table-column>
</el-table>
</div>
</template>
<script>
export default {
name: "myTable",
props: {
// 父组件传递过来的表头的数组数据
tableHeaderTitle: {
type: Array,
default: [],
},
// 父组件传递过来的表内容的数组数据
// 注意:表头内容数据和表内容数据有关联的
tableData: {
type: Array,
default: [],
},
// 父组件传递过来的是否展示复选框列的标识
isShowCheckbox: {
type: Boolean,
default: false,
},
// 父组件传递过来的是否展示序号索引列的标识
isShowIndex: {
type: Boolean,
default: false,
},
},
methods: {
// 勾选以后,要把勾选的这一行的数据传递给父组件,以供使用
handleSelectionChange(checked) {
this.$emit("receiveCheckedData", checked);
},
},
};
</script>
引用myTable组件的父组件代码
<template>
<div id="app">
<!-- 因为之前已经vue全局注册了自己封装的组件,所以这里不需要在引入这个组件了
可以直接用即可 -->
<my-table
:tableHeaderTitle="tableHeaderTitle"
:tableData="tableData"
:isShowCheckbox="isShowCheckbox"
:isShowIndex="isShowIndex"
@receiveCheckedData="receiveCheckedData"
></my-table>
</div>
</template>
<script>
export default {
data() {
return {
// 模拟表头数据,实际要发请求获取的
tableHeaderTitle: [
{
propName: "name",
labelName: "姓名",
},
{
propName: "age",
labelName: "年龄",
},
{
propName: "gender",
labelName: "性别",
},
{
propName: "height",
labelName: "身高",
},
{
propName: "weight",
labelName: "体重",
},
{
propName: "like",
labelName: "爱好",
},
{
propName: "address",
labelName: "住址",
},
],
// 模拟表内容数据
tableData: [
{
id:"11111",
name: "孙悟空",
age: 500,
gender: "男",
height: "七尺男儿",
weight: "三百吨",
like: "桃子",
address: "花果山水帘洞",
},
{
id:"22222",
name: "猪八戒",
age: 88,
gender: "男",
height: "七尺男儿",
weight: "八百吨",
like: "肉包子",
address: "高老庄",
},
{
id:"33333",
name: "沙和尚",
age: 1000,
gender: "男",
height: "七尺男儿",
weight: "三百吨",
like: "鱼",
address: "通天河",
},
],
// 是否展示复选框列
isShowCheckbox:true,
// 是否展示序号索引列
isShowIndex:true,
};
},
methods: {
// 接收子组件勾选的行的数据
receiveCheckedData(checked){
console.log('checked',checked);
}
},
};
</script>
<style lang="less" scoped>
#app {
width: 100%;
min-height: 100vh;
box-sizing: border-box;
padding: 50px;
}
</style>
在实际情况中,需要根据产品的需求,去做出对应的封装。组件封装一定要灵活
补充(看饿了么组件的收获)
我们打开node_modules文件夹下,里面有很多的依赖包(库),我们找到element-ui的这个文件夹,里面的packages文件夹存放的就是饿了么团队封装好的组件。如下图:
没事看看也挺好,也能学到不少的东西
**小伙伴们如果觉得文章写的还勉强凑合能看,给鼓励一下点个赞呗。感谢哦**
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。