Vue 笔记
本人是一个web前端开发工程师,主要是vue框架,整理了一些Vue常用的技术,一方面是分享,一方面是做总结,今后也会一直更新,有好建议的同学欢迎评论区分享 ;-)
Vue专栏:点击此处
Vue组件库专栏:点击此处
Vue2 vs Vue3 专栏:点击此处
Typescript专栏:点击此处
组件库开发流程
Vue组件库专栏会按顺序执行一下流程,不断完善组件库开发流程
- Vue3+element-plus+vite 组件的二次封装,封装了头部的搜索条件栏,tabel栏,分页栏,form表单,都设置成了通过json可配置项,方便复用;
- 封装好了就开始打包,并且进行本地测试;
- 组件库发布到npm;
- 添加vitest单元测试框架;
- 添加vuepress文档。
文章目录
前言
环境状态
vue版本:vue3
是否使用 ts:是
后台管理系统的网站,一个页面无非就是4个常用业务块
- 头部的搜索栏
- table表格
- 页脚
- 新增编辑弹框
那咋们是不是可以将其进行封装成组件呢?
只需要传入一个配置文件就可以了~
项目解构如下:
封装后的展示图如下:
效果图如下:
如果能做成这样,是不是页面就会整洁很多?
el-table表格的二次封装
原理:
- 通过tableData 传递进表格里面的数据,后台返回的数据
- 通过columnConfig 传递进去表格需要展示的效果,是个对象数组,每个对象都是一个列,里面有列名以及对应的tableData.props 属性,比如 typeName
- 通过hasOpr 传递看看需不需要操作列,因为有些角色是不是操作权限的,做兼容处理了
- 添加作用域插槽,让父组件可以获取子组件的数据,比如row.id,然后就可以在父组件中执行删除操作。
1. 效果图
2. 父组件
2.1 父组件 template 中的调用
<!-- 表格 -->
<PenkTable :table-data="tableData" :column-config="columnConfig" hasOpr>
<template #default="{ scope }">
<el-button
type="danger"
:icon="Delete"
@click="handleForceDeleteItem(scope.$index, scope.row)"
>
</el-button>
</template>
</PenkTable>
可以看到:
如果,只是简单的表格查看的话,只需要传递tableData数据,以及columnConfig配置项;
如果,需要有操作栏,就可以添加hasOpr 属性,并且使用作用域插槽。
2.2. 父组件 script 中的调用
2.2.1 将数据更新到组件上
由于双向绑定,直接修改tableData即可
// 表格数据
let tableData = reactive([]);
// 查找数据
async function getList() {
// 清空数据
tableData.length = 0;
console.log("tableData1:", tableData);
// 判断是否有对象,没有的话就自动弄
let res = await http.getList({
//...
});
// @ts-ignore
tableData.push(...res.rows);
paginationData.total = res.count;
console.log("tableData:", tableData);
}
tips:这边要注意reactive 创建的tabelData,不能使用直接赋值,因为是个proxy对象~
2.2.2 配置项
这边有的配置是可填可不填的,具体的配置项可以看封装组件里面的参数,这边大概看一下
props:每一列对应对象的属性名,方便通过索引的方式获得键值
render:渲染函数,比如后端给你返回了0 代表 禁止, 1 代表启用
- label:在UI组件前面的label
- width:列的宽度,无设置就是自适应
- hidden:是否隐藏,有些业务需求是根据不同角色,一些是不展示的
const columnConfig = [
{
label: "父级类型名",
prop: "parentTypeFk.typeName",
render: (value) => {
if (value) return "父-"+value;
},
},
{
label: "类型名",
prop: "typeName",
},
{
label: "创建时间",
prop: "createdAt",
},
{
label: "更新时间",
prop: "updatedAt",
},
{
label: "删除时间",
prop: "deletedAt",
},
];
3. 组件的封装
3.1 封装组件template
代码太长了,将显示部分代码…
3.1.1 el-table的配置
这边统一的样式以及配置,就只用了父组件props上的tableData,用于将表格数据传递给elementUI组件 el-table
<el-table
:data="props.tableData"
table-layout="fixed"
border
highlight-current-row
size="large"
empty-text="-"
stripe
>
<!-- el-table 没数据插槽 -->
<template #empty>
<h1>没数据</h1>
</template>
<!-- 选择框,通过props.isSelection 来判断是否需要展示 -->
<el-table-column v-if="props.isSelection" type="selection" width="55" />
<!-- 索引,默认展示索引 -->
<el-table-column type="index" width="50" />
...
...
...
3.1.2 el-table-column 的配置
- props.columnConfig:数组,用于每一列的配置。
- 通过作用域插槽,可以获取每一条数据row,通过配置中columnConfig.prop 实现字符串索引,可以得到每一项的值。
- 配合columnConfig中的render函数,可以渲染出自己想要的数据,比如 0 => 禁用,1=> 启用…
<template v-for="item in props.columnConfig" :key="item.label">
<el-table-column
v-if="item.hidden != true"
:fixed="item.fixed"
:prop="item.prop"
:label="item.label"
:width="item.width || 'auto'"
>
<template #default="{ row, column, $index }">
<span style="white-space: nowrap" v-if="item.render">{{
item.render(row[item.prop]) || item.emptyStr || "--"
}}</span>
<span style="white-space: nowrap" v-else>{{
row[item.prop] || item.emptyStr || "--"
}}</span>
</template>
</el-table-column>
</template>
3.2 封装组件script
由于使用了TS来编码,咋们可以在组件中interface中写清楚一些配置,方便使用者知道有什么配置 :)
这边用的是typescript写的,不懂得同学可能要先学习一下,或者去我的ts专栏看看~
3.2.1 props属性
interface props {
// 表格数据
tableData: {
[index: number]: dataItemObj;
};
// 列数据
columnConfig: columnItemObj[];
// 判断表格有无列操作
hasOpr?: boolean;
// 判断是否有checkbox
isSelection?: boolean;
}
3.2.2 tableData后台返回数据
// tableData的item对象,是一个不确定的对象
interface dataItemObj {
[index: string]: any;
}
3.2.3 columnConfig配置文件
// 渲染函数,比如后端给你返回了0 代表 禁止, 1 代表启用
// 这个时候就需要渲染函数了...
interface render {
(v: any): string;
}
// 每一列的配置对象
interface columnItemObj {
// 判断是否隐藏,一些业务需求,比如不同的权限可能就不展示了
hidden?:boolean
// 列无数据占位符
emptyStr?: string;
// el-table fixed 属性 左右固定布局
fixed?: string;
// el-table width 属性 宽度
width?: number;
// el-table prop 属性 字段名
prop: string;
// el-table label 属性 列名
label: string;
// 自定义渲染
render?: render;
}
总结
这边只是将只是用作展示数据,并没有什么数据交互,所以封装的组件并没有什么事件,唯一需要获取的数据可能就是通过作用域插槽了~
组件源码
<!--
* @Author: Penk
* @LastEditors: Penk
* @LastEditTime: 2022-11-29 18:23:25
* @FilePath: \front-master\src\components\public\PenkTable.vue
* @email: 492934056@qq.com
-->
<template>
<el-table
:data="props.tableData"
table-layout="fixed"
border
highlight-current-row
size="large"
empty-text="-"
stripe
>
<!-- el-table 没数据插槽 -->
<template #empty>
<h1>没数据</h1>
</template>
<!-- 选择框,通过props.isSelection 来判断是否需要展示 -->
<el-table-column v-if="props.isSelection" type="selection" width="55" />
<!-- 索引,默认展示索引 -->
<el-table-column type="index" width="50" />
<template v-for="item in props.columnConfig" :key="item.label">
<el-table-column
v-if="item.hidden != true"
:fixed="item.fixed"
:prop="item.prop"
:label="item.label"
:width="item.width || 'auto'"
>
<template #default="{ row, column, $index }">
<span style="white-space: nowrap" v-if="item.render">{{
item.render(row[item.prop]) || item.emptyStr || "--"
}}</span>
<span style="white-space: nowrap" v-else>{{
row[item.prop] || item.emptyStr || "--"
}}</span>
</template>
</el-table-column>
</template>
<!-- 操作列 -->
<el-table-column v-if="hasOpr" fixed="right" label="操作" width="200">
<!-- 这边是插槽组件,外部无法访问到里面的数据,比如每一列的item -->
<!-- 使用作用域插槽,将数据从element组件拿下来,
再通过 自定义插槽属性scope 传递到父组件,
使父组件可以调用子组件的数据 -->
<template #default="{ row, column, $index }">
<slot :scope="{ row, column, $index }"></slot>
</template>
</el-table-column>
</el-table>
</template>
<script setup lang="ts">
// 渲染函数,比如后端给你返回了0 代表 禁止, 1 代表启用
// 这个时候就需要渲染函数了...
interface render {
(v: any): string;
}
// columnConfig 是一个columnItemObj对象的数组
interface columnConfig {
[index: string]: columnItemObj;
}
// 每一列的配置对象
interface columnItemObj {
// 必填
// el-table prop 属性 字段名
prop: string;
// el-table label 属性 列名
label: string;
// 选填
// 判断是否隐藏,一些业务需求,比如不同的权限可能就不展示了
hidden?: boolean;
// 列无数据占位符
emptyStr?: string;
// el-table fixed 属性 左右固定布局 只能在头尾的配置中存在
fixed?: string;
// el-table width 属性 宽度
width?: number;
// 自定义渲染
render?: render;
}
// tableData的item对象,是一个不确定的对象
interface dataItemObj {
[index: string]: any;
}
interface props {
// 表格数据
tableData: {
[index: number]: dataItemObj;
};
// 列数据
columnConfig: columnConfig;
// 判断表格有无列操作
hasOpr?: boolean;
// 判断是否有checkbox
isSelection?: boolean;
}
let props = defineProps<props>();
console.log("props:", props.columnConfig);
</script>
<style lang="less" scoped>
.el-table-border {
border: 1px #eee solid;
}
// :deep(.el-scrollbar__view) {
// width: 100%;
// }
</style>
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/66357.html