系列文章目录
【Vue3+Vite+Ts+element-plus】
超级详细 最新 vite4+vue3+ts+element-plus+eslint-prettier 项目搭建流程
【Vue3+Vite+Ts+element-plus】使用tsx实现左侧栏菜单无限层级封装
【Ts 系列】
TypeScript 从入门到进阶之基础篇(一) ts类型篇
文章目录
- 系列文章目录
- 前言
- 一、必要插件安装
- 1.安装
- 2.配置
- 二、table 封装实现步骤
- 1.创建
- 2.封装
- 3、使用
前言
在我们日常开发中 会经常用到表格 特别是后台管理系统 几乎大部分页面都涉及到表格,使用好的表格封装能为我们节省很多开发时间,也能让代码清晰易懂,接下来我们将从零使用tsx 二次封装一下element-plus的表格。
一、必要插件安装
我们需要创建一个vue3项目 我用的是vite去创建vue3+ts 项目的 ,这里就不多讲项目的创建了 ,如果要详细的项目搭建流程可参考:超级详细 最新 vite4+vue3+ts+element-plus+eslint-prettier 项目搭建流程
在使用tsx之前 我们要安装一些插件 使我们的项目支持tsx
1.安装
//下面3种安装方式选择一种 推荐pnpm
yarn add @vitejs/plugin-vue-jsx
//or
npm install @vitejs/plugin-vue-jsx -D
//or
pnpm install @vitejs/plugin-vue-jsx -D
2.配置
在 vite.config.ts 文件中挂载
import vueJsx from '@vitejs/plugin-vue-jsx'
export default defineConfig({plugins: [ vueJsx()]
})
tsconfig.json 文件中
{// include 需要包含tsx
"include": ["src/*", "src/**/*.vue", "src/**/*.tsx", "src/**/*.jsx", "src/**/*.ts", "src/**/*.js"],"compilerOptions": {// 在.tsx文件里支持JSX"jsx": "preserve",}
}
二、table 封装实现步骤
1.创建
首先我们在项目的 components 文件夹下 新建 DynamicTable 文件夹, 并在DynamicTable* 文件夹下新建 DynamicTable.vue文件
2.封装
在封装表格之前 我们要了解 在通常的表格中 有哪些情况会出现 例如: 表格可能涉及到分页 、可能涉及到接口的请求、也可能表格中的每一行 可内容自定义 等情况 。首先我们先将表格和分页写出来先 代码如下
<script lang="tsx">
import { ElTable } from 'element-plus'
export default {props: {//表格数据tableData: {type: Array,default: () => [],},//表格列数据tableColumns: {type: Array,default: () => [],},//表格配置项configuration: {type: Object,default: () => ({}),},//分页下拉选择pageSizes: {type: Array,default: () => [10, 20, 50, 100],},//分页组件的样式paginationLayout: {type: String,default: () => 'total,sizes,prev, pager, next,jumper',},//是否为分页按钮添加背景色background: {type: Boolean,default: true,},//请求函数request: {type: Function,default: () => {return Function},},//是否开启单选highlightCurrentRow: {type: Boolean,default: () => {return false},},//是否在打开页面时默认加载表格请求 默认为 trueisLoadRequest: {type: Boolean,default: () => {return true},},//表格勾选的数据selectedList: {type: Array,default: () => {return []},},//获取表格勾选的行数据getAllSelectedList: {type: Array,default: () => {return []},},//表格行禁用tableDisable: {type: Function,default: () => {return Function},},//分页是否只有一页时隐藏hideOnSinglePage: {type: Boolean,default: () => {return false},},//是否自定义转换isCustomConversion: {type: Boolean,default: () => {return false},},//返回转换好的数据customConversion: {type: Function,default: () => {return Function},},//是否自定义分页isCustomPage: {type: Boolean,default: () => {return false},},// 接收自定义分页返回的参数customPage: {type: Function,default: () => {return Function},},},emits: ['handleSelectionChange','update:selectedList','update:getAllSelectedList','update:tableData','getResultData','selectable',],setup(props, { slots, expose, emit }) {const singleTableRef = ref<InstanceType<typeof ElTable>>()//表格加载const loading = ref(false)const clientWidth = ref(document.documentElement.clientWidth)onMounted(() => {window.onresize = () => {return (() => {clientWidth.value = document.documentElement.clientWidth})()}})const getWidth = (width: string) => {return `${clientWidth.value * (parseInt(width) / 1440.0)}px`}//设置表格 Column/const setTableColumn = () => {return props.tableColumns.map((item: any) => {if (!item.slot) {return (<el-table-column{...item}width={item.type === 'selection' ? getWidth(item.width) : item.width}selectable={selectable}></el-table-column>)} else {return (<el-table-column{...item}selectable={selectable}width={item.slotName === 'operation'? getWidth(item.width): item.width}>{{default: (scope: any) => slots[item.slotName]?.(scope),}}</el-table-column>)}})}/*** 分页相关配置*///表格数据const tableData = ref(props.tableData as any[])//第几页const currentPage = ref(1)//每页的数量const pageSize = ref(10)//总数量const total = ref(props.tableData.length)const getData = ref({})watch(props.tableData,(nel) => {tableData.value = nel},{ deep: true },)//数据请求const refreshTable = async (datas: any = {}, reset = true) => {if (reset) {currentPage.value = 1}loading.value = truegetData.value = datastry {const { result }: any = await props.request({...datas,pageNo: props.isCustomPage ? 1 : currentPage.value,pageSize: pageSize.value,})const { totalPage }: any = result.pageInfo//判断要跳转的页是否没有了 是的话回到接口返回的最后一页if (!reset && totalPage < currentPage.value && currentPage.value > 1) {currentPage.value = totalPagerefreshTable(datas, reset)}//表格数据转换赋值tableData.value = resultemit('getResultData', result, tableData.value)//总条数赋值total.value = props.isCustomPage? props.customPage(): result.pageInfo && result.pageInfo.totalSize? Number(result.pageInfo.totalSize): 0loading.value = false} catch (err) {tableData.value = []loading.value = false}}//是否默认开启请求props.isLoadRequest ? refreshTable(getData.value) : ''onMounted(() => {getData.value = {}})//page-size 改变时触发const handleSizeChange = (val: number) => {console.log(`${val} items per page`)refreshTable(getData.value, false)}//current-page 改变时触发const handleCurrentChange = (val: number) => {console.log(`current page: ${val}`)refreshTable(getData.value, false)}//勾选事件const selectedList = ref<string[]>([])const handleSelectionChange = (val: any) => {selectedList.value = val.map((item: any) => item.id)emit('update:getAllSelectedList', val)emit('update:selectedList', selectedList.value)}const selectable = (row: any) => {return props.tableDisable(row)}//选中项高亮const tableRowClassName = ({ row }: { row: any }) => {return selectedList.value.indexOf(row.id) ? 'warning-row' : 'success-row'}/**获取页数 和每页数量 */const getPageSizeAndCurrentPage = () => {return {currentPage: currentPage.value,pageSize: pageSize.value,}}/**设置页数 和每页数量 */const setCurrentPage = (current: any) => {currentPage.value = current}const tableRowStype = () => {return {borderRadius: '15px',overflow: 'hidden',}}// 使用 expose 暴露组件内部的方法expose({refreshTable,getPageSizeAndCurrentPage,setCurrentPage,})return () => (<div class="table-style table"><el-tablemax-height="800px"ref="singleTableRef"class="custom-table"row-key="id"v-loading={loading.value}data={tableData.value}row-class-name={tableRowClassName}row-style={tableRowStype}cell-style={{ textAlign: 'center' }}onSelectionChange={handleSelectionChange}{...props.configuration}>{setTableColumn()}</el-table><el-paginationsmallv-model:current-page={currentPage.value}v-model:page-size={pageSize.value}total={total.value}highlightCurrentRow={props.highlightCurrentRow}background={props.background}layout={props.paginationLayout}onCurrentChange={handleCurrentChange}onSizeChange={handleSizeChange}popper-class="popperClass"hideOnSinglePage={props.hideOnSinglePage}></el-pagination></div>)},
}
</script>
3、使用
在需要使用的引入使用 并 创建一个ts文件用于存放列的配置即可
<dynamic-tableref="dynamicTableRef"class="dynamic-table":request="request.listPagesBrand":tableColumns="tableColumns":isLoadRequest="false":tableDisable="selectable"><template #internal="scope">{{ scope.row.internal === 1 ? '是' : '否' }}</template><template #operation="scope"><el-buttontype="primary"link@click="editbrand(scope.row.id)":disabled="!!Number(scope.row.internal)">编辑</el-button><el-divider direction="vertical" /><delete-button:data="[scope.row.id]":request="request.delBatchBrand"@requestCallback="() => submitSearch(false)":disabled="!!Number(scope.row.internal)"type="primary"link></delete-button></template></dynamic-table>
//Table 表头定义
const tableColumns: any = [{type: 'selection',width: '70px',},{prop: 'brandName',label: '品牌',showOverflowTooltip: true,},{prop: 'englishLogo',label: '英文标识',showOverflowTooltip: true,},{slot: true,slotName: 'internal',label: '内置',showOverflowTooltip: true,},{slot: true,slotName: 'operation',width: '200px',label: '操作',},
]export default tableColumns