赞
踩
公司业务可能需要进行一些组件的封装,基于第三方elementPlus框架,进行符合UI设计原型的组件封装,这篇主要讲解Table表格的封装,目的主要是梳理封装的思路,下面的代码并不是提供完整的源码,因此不包含样式代码。
webpack+vue3+elementPlus
官方地址:https://element-plus.gitee.io/zh-CN/component/table.html
- <el-table
- ref="table"
- :data="tableData"
- :height="height"
- :style="{ fontSize: fontSize, fontFamily: fontFamily }"
- :border="border"
- :stripe="stripe"
- :row-key="
- (row) => {
- return row.id;
- }
- "
- :header-cell-style="{ 'text-align': headerCellStyle }"
- :cell-style="cellStyle"
- @selection-change="handleSelectionChange"
- >
- <!-- checkbox列 -->
- <el-table-column
- v-if="selection"
- type="selection"
- width="56"
- align="center"
- :fixed="fixed"
- >
- </el-table-column>
- <!-- 序号列 -->
- <el-table-column
- v-if="index"
- type="index"
- width="56"
- label="序号"
- :fixed="fixed"
- ></el-table-column>
- <!-- columnData属性列 -->
- <template v-for="item in columnData" :key="item.id">
- <el-table-column
- v-if="item.type === 'link'"
- :label="item.label"
- :prop="item.prop"
- :width="item.width"
- :align="item.align"
- :fixed="item.fixed"
- :sortable="item.sort"
- :formatter="item.formatter"
- >
- <template #default="scope">
- <slot :name="item.prop" v-bind="scope"></slot>
- </template>
- </el-table-column>
- <el-table-column
- v-else-if="item.type === 'tag'"
- :label="item.label"
- :prop="item.prop"
- :width="item.width"
- :align="item.align"
- :fixed="item.fixed"
- :sortable="item.sort"
- :filters="item.filters"
- :filter-method="filterTag"
- :formatter="item.formatter"
- >
- <template #default="scope">
- <slot :name="item.prop" v-bind="scope"></slot>
- </template>
- </el-table-column>
- <el-table-column
- v-else
- :label="item.label"
- :prop="item.prop"
- :width="item.width"
- :align="item.align"
- :fixed="item.fixed"
- :sortable="item.sort"
- :formatter="item.formatter"
- >
- </el-table-column>
- </template>
- </el-table>
- <!--摘自elementPlus表格(基础用法)-->
- <template>
- <el-table :data="tableData" style="width: 100%">
- <el-table-column prop="date" label="Date" width="180" />
- <el-table-column prop="name" label="Name" width="180" />
- <el-table-column prop="address" label="Address" />
- </el-table>
- </template>
原因:我们来分析一下上面的代码,首先我们需要用组件封装的思想思考。el-table标签上的属性都可以通过父子传值的方式传进组件。但是el-table-column到底有几个我们不确定,那我们很自然的就会想到组件内部需要用到v-for循环,循环的数据也是通过外部传进来。
所以子组件内部发展为:
- <el-table
- ref="table"
- :data="tableData"
- >
- <!-- columnData属性列 -->
- <template v-for="item in columnData" :key="item.id">
- <el-table-column
- :label="item.label" //每列标题内容,参考elemengPlus
- :prop="item.prop" //每列字段名称,参考elemengPlus
- :width="item.width" //每列宽度,参考elemengPlus
- :align="item.align" //每列对齐方式,参考elemengPlus
- :fixed="item.fixed" //首列和标题固定,参考elemengPlus
- :sortable="item.sort" //排序,参考elemengPlus
- :formatter="item.formatter" //支持内容自定义方法,参考elemengPlus
- >
- </el-table-column>
- </template>
- </el-table>
- <script setup>
- import {defineProps} from 'vue'
- defineProps({
- tableData:{
- type:Array
- },
- columnData:{
- type:Array
- }
- })
- </script>
父页面传入的数据发展为:
- const columnData = ref([
- {
- id: 0,
- prop: "contractName",
- // width: "140",
- align: "left",
- label: "常规名称长字段",
- },
- {
- id: 1,
- prop: "contractDate",
- // width: "200",
- align: "left",
- label: "合同日期",
- },
- {
- id: 2,
- prop: "contractAmout",
- // width: "130",
- align: "right",
- label: "合同金额",
- sort: true,
- formatter: (row) => {
- return <div>{row.contractAmout}万</div>;
- },
- },
- {
- id: 3,
- prop: "contractNum",
- // width: "100",
- align: "left",
- label: "合同编号",
- },
- {
- id: 4,
- prop: "operation",
- width: "150",
- align: "left",
- label: "操作",
- type: "slot",
- formatter: (row,column,cellValue,index) => {
- //编辑按钮事件
- const handleEdit = (val) => {
- console.log('row',row);
- console.log('column',column);
- console.log('cellValue',cellValue);
- console.log('index',index);
- // console.log('val',val);
- alert(val.contractName);
- };
- //删除按钮事件
- const handleDelete = (val) => {
- console.log('row',row);
- console.log('column',column);
- console.log('cellValue',cellValue);
- console.log('index',index);
- console.log('row',row);
- // console.log('val',val);
- alert(val.contractName);
- };
- return (
- <div>
- <el-button
- type="primary"
- size="small"
- onClick={() => {
- handleEdit(row,column,cellValue,index);
- }}
- >
- 编辑
- </el-button>
- <el-button
- type="danger"
- size="small"
- onClick={() => {
- handleDelete(row,column,cellValue,index);
- }}
- >
- 删除
- </el-button>
- </div>
- );
- },
- },
- ]);
- //表格数据的key键名要和columnData中的prop保持一致
- const tableData = ref([
- {
- "id": "1",
- "contractName": "医院设备1",
- "contractDate": "2023-01-30 14:44:19",
- "contractAmout": "50000",
- "contractNum": "1",
- },
- {
- "id": "2",
- "contractName": "医院设备2",
- "contractDate": "2023-01-29 14:44:19",
- "contractAmout": "30000",
- "contractNum": "2",
- },
- {
- "id": "3",
- "contractName": "医院设备3",
- "contractDate": "2023-01-28 15:44:19",
- "contractAmout": "75000",
- "contractNum": "3",
- },
- {
- "id": "4",
- "contractName": "医院设备4",
- "contractDate": "2023-01-27 15:44:19",
- "contractAmout": "80000",
- "contractNum": "4",
- },
- {
- "id": "5",
- "contractName": "医院设备5",
- "contractDate": "2023-01-26 15:44:19",
- "contractAmout": "80000",
- "contractNum": "5",
- },
- {
- "id": "6",
- "contractName": "医院设备6",
- "contractDate": "2023-01-25 15:44:19",
- "contractAmout": "80000",
- "contractNum": "6",
- },
- {
- "id": "7",
- "contractName": "医院设备7",
- "contractDate": "2023-01-24 15:44:19",
- "contractAmout": "80000",
- "contractNum": "7",
- },
- {
- "id": "8",
- "contractName": "医院设备8",
- "contractDate": "2023-01-23 15:44:19",
- "contractAmout": "80000",
- "contractNum": "8",
- },
- {
- "id": "9",
- "contractName": "医院设备9",
- "contractDate": "2023-01-22 15:44:19",
- "contractAmout": "80000",
- "contractNum": "9",
- },
- {
- "id": "10",
- "contractName": "医院设备10",
- "contractDate": "2023-01-21 15:44:19",
- "contractAmout": "80000",
- "contractNum": "10",
- }
- ]);
注意:表格数据的key键名必须和columnData中的prop保持一致;
也就是外部传入个布尔值去控制是否渲染这两列即可,所以子组件再前面的基础上再加上:
- <!-- checkbox列 -->
- <el-table-column
- v-if="selection"
- type="selection"
- width="56"
- align="center"
- :fixed="fixed"
- >
- </el-table-column>
-
- <!-- 序号列 -->
- <el-table-column
- v-if="index"
- type="index"
- width="56"
- label="序号"
- :fixed="fixed"
- ></el-table-column>
-
- <script setup>
- import {defineProps} from 'vue'
- defineProps({
- tableData:{
- type:Array
- },
- columnData:{
- type:Array
- },
- selection: Boolean,
- index: Boolean,
- })
- </script>
如果需要渲染这两列,父页面使用的时候直接传入相应的布尔值即可,如下示例:
- <flex-table
- ref="flexTable"
- :columnData="columnData"
- :tableData="tableData"
- selection
- index
- >
由于formatter的方法内部是react写法,不支持template标签。如果自定义的内容包含el-tag标签或其他可扩展内容时,可以通过插槽实现;
子组件内部就变成了:
- <!-- columnData属性列 -->
- <template v-for="item in columnData" :key="item.id">
- <!-- 扩展列 -->
- <el-table-column
- v-if="item.type === 'link'"
- :label="item.label"
- :prop="item.prop"
- :width="item.width"
- :align="item.align"
- :fixed="item.fixed"
- :sortable="item.sort"
- :formatter="item.formatter"
- >
- <template #default="scope">
- <slot :name="item.prop" v-bind="scope"></slot>
- </template>
- </el-table-column>
- <!-- 标签列 -->
- <el-table-column
- v-else-if="item.type === 'tag'"
- :label="item.label"
- :prop="item.prop"
- :width="item.width"
- :align="item.align"
- :fixed="item.fixed"
- :sortable="item.sort"
- :filters="item.filters"
- :filter-method="filterTag"
- :formatter="item.formatter"
- >
- <template #default="scope">
- <slot :name="item.prop" v-bind="scope"></slot>
- </template>
- </el-table-column>
- <!-- 其他正常列 -->
- <el-table-column
- v-else
- :label="item.label"
- :prop="item.prop"
- :width="item.width"
- :align="item.align"
- :fixed="item.fixed"
- :sortable="item.sort"
- :formatter="item.formatter"
- >
- </el-table-column>
- </template>
父页面使用的时候就可以通过插槽的名称来实现内容的自定义:
tag标签插槽:
- <template #state="{ row }">
- <el-tag v-if="row.state === '进行中'" type="primary">{{
- row.state
- }}</el-tag>
- <el-tag v-if="row.state === '已完成'" type="success">{{
- row.state
- }}</el-tag>
- <el-tag v-if="row.state === '已终止'" type="danger">{{
- row.state
- }}</el-tag>
- <el-tag v-if="row.state === '已中止'" type="warning">{{
- row.state
- }}</el-tag>
- <el-tag v-if="row.state === '已取消'" type="info">{{
- row.state
- }}</el-tag>
- </template>
link扩展链接插槽:
- <template #link="{ row }">
- <ul class="linkMenu">
- <li>
- <el-link type="primary" v-if="row.link === 1">催填</el-link>
- <el-link type="primary" v-if="row.link === 2">汇总</el-link>
- <el-link type="primary" v-if="row.link === 3">重新汇总</el-link>
- <el-link type="primary" v-if="row.link === 4">重新确认</el-link>
- <el-link type="primary" v-if="row.link === 5">调整</el-link>
- </li>
- </ul>
- </template>
- <!--labelWidth和labelPosition是el-form的属性,参考elementPlus-->
- <el-form :label-width="labelWidth" :label-position="labelPosition">
- <slot name="search"></slot>
- </el-form>
在el-table标签上方加上如上代码,使用插槽支持自定义;
在父页面使用的时候:
- <!-- 搜索插槽 -->
- <template v-slot:search>
- <div class="ipt-btn">
- <!-- 输入框 -->
- <el-row gutter="0">
- <!-- 第一行 -->
- <el-col :span="8">
- <el-form-item label="标题标题">
- <el-input
- placeholder="请输入"
- v-model="form.value1"
- @keyup.enter="handleFilter(form)"
- />
- </el-form-item>
- </el-col>
- <el-col :span="8">
- <el-form-item label="标题标题">
- <el-input
- placeholder="请输入"
- v-model="form.value2"
- @keyup.enter="handleFilter(form)"
- />
- </el-form-item>
- </el-col>
- <el-col :span="8">
- <el-form-item label="标题标题">
- <el-input
- placeholder="请输入"
- v-model="form.value3"
- @keyup.enter="handleFilter(form)"
- />
- </el-form-item>
- </el-col>
- <!-- 第二行 -->
- <el-col :span="8">
- <el-form-item label="标题标题" v-show="isShow">
- <el-select v-model="form.value5" @change="handleFilter(form)">
- <el-option label="选项一" value="选项一">选项一</el-option>
- <el-option label="选项二" value="选项二">选项二</el-option>
- </el-select>
- </el-form-item>
- </el-col>
- <el-col :span="8">
- <el-form-item label="标题标题" v-show="isShow">
- <el-date-picker
- value-format="YYYY-MM-DD"
- placeholder="请选择"
- v-model="form.value6"
- @change="handleFilter(form)"
- ></el-date-picker>
- </el-form-item>
- </el-col>
- <el-col :span="8">
- <el-form-item label="标题标题" v-show="isShow">
- <el-date-picker
- type="datetime"
- placeholder="请选择"
- v-model="form.value7"
- value-format="YYYY-MM-DD HH:mm:ss"
- @change="handleFilter(form)"
- ></el-date-picker>
- </el-form-item>
- </el-col>
- </el-row>
- <!-- 按钮 -->
- <div class="btn">
- <el-form-item class="btns">
- <el-button
- class="arrow"
- :icon="isShow ? ArrowUp : ArrowDown"
- @click="isShow = !isShow"
- ></el-button>
- <el-button
- class="reset"
- @click="resetForm"
- >重置</el-button
- >
- <el-button
- class="confirm"
- type="primary"
- @click="onSubmit"
- >确定</el-button
- >
- </el-form-item>
- </div>
- </div>
- </template>
- <script setup>
- import {ref, reactive} from 'vue'
- const isShow = ref(false);
- const form = reactive({
- value1: "张三",
- value2: "10",
- value3: "",
- value4: "",
- value5: "",
- value6: "",
- value7: "",
- });
- </script>
展开效果图:
隐藏效果图:
效果图:
直接运用el-pagination,html代码示例:
- <div class="bottom_box">
- <!-- 左侧统计checkbox选中状态 -->
- <ul class="flex-ul">
- <li>
- 已选择<span style="color: #3480fb" v-if="checkNumber > 0">{{
- checkNumber
- }}</span
- >项
- </li>
- <li>|</li>
- <li class="cancelCheckBox" @click="toggleSelection">
- <span style="color: #3480fb">取消</span>
- </li>
- </ul>
- <!-- 右侧分页器组件 -->
- <el-pagination
- :small="small" //是否启用小型分页器,字号12px
- :background="background" //页码选中是否有背景色
- layout="total, prev, pager, next, sizes, jumper" //分页器各组件
- :total="total" //总条数
- :pager-count="4" //设置最大按钮数
- :page-size="pageSize" //每页显示条数
- :page-sizes="pageSizes" //每页显示个数选择器的选项设置
- @size-change="sizeChange" //page-size 改变时触发
- @current-change="handleCurrentChange" //页码发生变化触发事件
- />
- </div>
参考elementPlus的方法,结合vue3的写法,js代码示例:
- //checkbox点击事件
- const instance = getCurrentInstance();
- const table = ref(null);
- const multipleSelection = ref([]);
- const checkNumber = ref(null);
- //取消勾选事件
- const toggleSelection = () => {
- var ultipleTabInstance = toRefs(instance.refs.table);
- ultipleTabInstance.clearSelection.value();
- };
- //勾选checkbox事件
- const handleSelectionChange = (val) => {
- console.log("val", val);
- multipleSelection.value = val;
- checkNumber.value = multipleSelection.value.length;
- };
- <flex-table
- ref="flexTable"
- size="large"
- disabled
- background
- prevIcon="ArrowLeft"
- nextIcon="ArrowRight"
- :url="apiUrl.tableList2"
- :requestData="request_data"
- :columnData="columnData"
- :pageSizes="pageSizes"
- fontSize="14px"
- fontFamily="PingFangSC-Regular"
- labelWidth="110"
- selection
- border
- fixed
- >
- <!-- 链接插槽 -->
- <template #link="{ row }">
- <ul class="linkMenu">
- <li>
- <el-link type="primary" v-if="row.link === 1">催填</el-link>
- <el-link type="primary" v-if="row.link === 2">汇总</el-link>
- <el-link type="primary" v-if="row.link === 3">重新汇总</el-link>
- <el-link type="primary" v-if="row.link === 4">重新确认</el-link>
- <el-link type="primary" v-if="row.link === 5">调整</el-link>
- </li>
- <li>|</li>
- <li v-if="row.link === 1">
- <el-dropdown>
- <span class="el-dropdown-link">
- 二级配置
- <el-icon class="el-icon--right">
- <arrow-down />
- </el-icon>
- </span>
- <template #dropdown>
- <el-dropdown-menu>
- <el-dropdown-item>更多菜单一</el-dropdown-item>
- <el-dropdown-item>更多菜单二</el-dropdown-item>
- <el-dropdown-item>更多菜单三</el-dropdown-item>
- <el-dropdown-item>更多菜单四</el-dropdown-item>
- </el-dropdown-menu>
- </template>
- </el-dropdown>
- </li>
- <li v-if="row.link === 2">
- <el-dropdown>
- <span class="el-dropdown-link">
- 上会结束
- <el-icon class="el-icon--right">
- <arrow-down />
- </el-icon>
- </span>
- <template #dropdown>
- <el-dropdown-menu>
- <el-dropdown-item>更多菜单一</el-dropdown-item>
- <el-dropdown-item>更多菜单二</el-dropdown-item>
- <el-dropdown-item>更多菜单三</el-dropdown-item>
- <el-dropdown-item>更多菜单四</el-dropdown-item>
- </el-dropdown-menu>
- </template>
- </el-dropdown>
- </li>
- <li v-if="row.link === 3">
- <el-dropdown>
- <span class="el-dropdown-link">
- 二级配置
- <el-icon class="el-icon--right">
- <arrow-down />
- </el-icon>
- </span>
- <template #dropdown>
- <el-dropdown-menu>
- <el-dropdown-item>更多菜单一</el-dropdown-item>
- <el-dropdown-item>更多菜单二</el-dropdown-item>
- <el-dropdown-item>更多菜单三</el-dropdown-item>
- <el-dropdown-item>更多菜单四</el-dropdown-item>
- </el-dropdown-menu>
- </template>
- </el-dropdown>
- </li>
- <li v-if="row.link === 4">
- <el-dropdown>
- <span class="el-dropdown-link">
- 上会结束
- <el-icon class="el-icon--right">
- <arrow-down />
- </el-icon>
- </span>
- <template #dropdown>
- <el-dropdown-menu>
- <el-dropdown-item>更多菜单一</el-dropdown-item>
- <el-dropdown-item>更多菜单二</el-dropdown-item>
- <el-dropdown-item>更多菜单三</el-dropdown-item>
- <el-dropdown-item>更多菜单四</el-dropdown-item>
- </el-dropdown-menu>
- </template>
- </el-dropdown>
- </li>
- <li v-if="row.link === 5">
- <el-dropdown>
- <span class="el-dropdown-link">
- 二级配置
- <el-icon class="el-icon--right">
- <arrow-down />
- </el-icon>
- </span>
- <template #dropdown>
- <el-dropdown-menu>
- <el-dropdown-item>更多菜单一</el-dropdown-item>
- <el-dropdown-item>更多菜单二</el-dropdown-item>
- <el-dropdown-item>更多菜单三</el-dropdown-item>
- <el-dropdown-item>更多菜单四</el-dropdown-item>
- </el-dropdown-menu>
- </template>
- </el-dropdown>
- </li>
- </ul>
- </template>
- <!-- 标签插槽 -->
- <template #state="{ row }">
- <el-tag v-if="row.state === '进行中'">{{ row.state }}</el-tag>
- <el-tag v-if="row.state === '已完成'" type="success">{{
- row.state
- }}</el-tag>
- <el-tag v-if="row.state === '已终止'" type="danger">{{
- row.state
- }}</el-tag>
- <el-tag v-if="row.state === '已中止'" type="warning">{{
- row.state
- }}</el-tag>
- <el-tag v-if="row.state === '已取消'" type="info">{{
- row.state
- }}</el-tag>
- </template>
- <!-- 搜索插槽 -->
- <template v-slot:search>
- <div class="ipt-btn">
- <!-- 输入框 -->
- <el-row gutter="0">
- <!-- 第一行 -->
- <el-col :span="8">
- <el-form-item label="标题标题">
- <el-input
- placeholder="请输入"
- v-model="form.value1"
- @keyup.enter="handleFilter(form)"
- />
- </el-form-item>
- </el-col>
- <el-col :span="8">
- <el-form-item label="标题标题">
- <el-input
- placeholder="请输入"
- v-model="form.value2"
- @keyup.enter="handleFilter(form)"
- />
- </el-form-item>
- </el-col>
- <el-col :span="8">
- <el-form-item label="标题标题">
- <el-input
- placeholder="请输入"
- v-model="form.value3"
- @keyup.enter="handleFilter(form)"
- />
- </el-form-item>
- </el-col>
- <!-- <el-col :span="6">
- <el-form-item label="标题标题">
- <el-input
- v-model="form.value4"
- placeholder="请输入"
- @keyup.enter="handleFilter(form)"
- ></el-input>
- </el-form-item>
- </el-col> -->
- <!-- 第二行 -->
- <el-col :span="8">
- <el-form-item label="标题标题" v-show="isShow">
- <el-select v-model="form.value5" @change="handleFilter(form)">
- <el-option label="选项一" value="选项一">选项一</el-option>
- <el-option label="选项二" value="选项二">选项二</el-option>
- </el-select>
- </el-form-item>
- </el-col>
- <el-col :span="8">
- <el-form-item label="标题标题" v-show="isShow">
- <el-date-picker
- value-format="YYYY-MM-DD"
- placeholder="请选择"
- v-model="form.value6"
- @change="handleFilter(form)"
- ></el-date-picker>
- </el-form-item>
- </el-col>
- <el-col :span="8">
- <el-form-item label="标题标题" v-show="isShow">
- <el-date-picker
- type="datetime"
- placeholder="请选择"
- v-model="form.value7"
- value-format="YYYY-MM-DD HH:mm:ss"
- @change="handleFilter(form)"
- ></el-date-picker>
- </el-form-item>
- </el-col>
- </el-row>
- <!-- 按钮 -->
- <div class="btn">
- <el-form-item class="btns">
- <el-button
- style="
- width: 30px;
- height: 34px;
- background: #eef1f5;
- borderradius: 4px;
- "
- class="arrow"
- :icon="isShow ? ArrowUp : ArrowDown"
- @click="isShow = !isShow"
- ></el-button>
- <el-button
- class="reset"
- @click="resetForm"
- style="
- width: 50px;
- height: 34px;
- border: 1px solid rgba(0, 0, 0, 0.2);
- border-radius: 4px;
- "
- >重置</el-button
- >
- <el-button
- class="confirm"
- type="primary"
- @click="onSubmit"
- style="
- width: 50px;
- height: 34px;
- background: #3480FB;
- border-radius: 4px;
- "
- >确定</el-button
- >
- </el-form-item>
- </div>
- </div>
- </template>
- </flex-table>
- </div>
如果业务要求直接传入url就可以实现数据渲染的话,就需要在组件内部去进行数据请求,下面主要进行axios请求mock数据模拟,先测试可行性,再根据真实数据对接即可。
yarn add mockjs / npm i mockjs
yarn add axios/ npm i axios
在scr文件夹下新建mock文件夹,新建index.js文件,和mockData文件夹;
在mockData文件里新建table.json文件,写上tableData的数据
{ "totalElements":10, //总条数 "page":1, //当前页码 "rows":5, //每行显示条数 "content":[ { "id": "1", "contractName": "医院设备1", "contractDate": "2023-01-30 14:44:19", "contractAmout": "50000", "contractNum": "1", }, { "id": "2", "contractName": "医院设备2", "contractDate": "2023-01-29 14:44:19", "contractAmout": "30000", "contractNum": "2", }, { "id": "3", "contractName": "医院设备3", "contractDate": "2023-01-28 15:44:19", "contractAmout": "75000", "contractNum": "3", }, { "id": "4", "contractName": "医院设备4", "contractDate": "2023-01-27 15:44:19", "contractAmout": "80000", "contractNum": "4", }, { "id": "5", "contractName": "医院设备5", "contractDate": "2023-01-26 15:44:19", "contractAmout": "80000", "contractNum": "5", }, { "id": "6", "contractName": "医院设备6", "contractDate": "2023-01-25 15:44:19", "contractAmout": "80000", "contractNum": "6", }, { "id": "7", "contractName": "医院设备7", "contractDate": "2023-01-24 15:44:19", "contractAmout": "80000", "contractNum": "7", }, { "id": "8", "contractName": "医院设备8", "contractDate": "2023-01-23 15:44:19", "contractAmout": "80000", "contractNum": "8", }, { "id": "9", "contractName": "医院设备9", "contractDate": "2023-01-22 15:44:19", "contractAmout": "80000", "contractNum": "9", }, { "id": "10", "contractName": "医院设备10", "contractDate": "2023-01-21 15:44:19", "contractAmout": "80000", "contractNum": "10", } ] } ] }
另外在index.js文件中配置mock数据请求地址:
- import Mock from 'mockjs';
- import tableData from './mockData/tableData.json';
- Mock.mock("/getData",(config)=>{
- let params = Json.parse(config.body) //这里是请求的参数
- return {
- success:true,
- data:tableData
- }
- })
最后一定要记得在main.js文件中引入mock文件夹下的index.js文件
import './mock/index'
- import axios from 'axios';
- import {ElMessage} from 'element-plus';
- //请求表格数据
- const getTableData = (url, data)=>{
- console.log('post请求参数',data);
- return axios({
- method:'post',
- url:url,
- data:data
- }).then(
- res => {
- return res.data
- },
- error => {
- ElMessage({
- type:'error',
- message:error.message,
- showClose: true
- })
- }
- )
- }
- export default getTableData
组件代码:
- import getTableData from "../api/table";
- props: {
- //外部传入url,但也需要给个默认值
- url: {
- type: String,
- require: true,
- default: "/getData",
- },
- }
- //get请求数据方法
- const getTableList = (url, options) => {
- //判断url不存在不继续进行请求
- if (!url) {
- console.log("请求地址不存在!");
- return false;
- }
- getTableData(url, options).then((res) => {
- console.log("res", res);
- const { data } = res;
- //处理请求数据内容渲染表格
- tableData.value = data.content;
- });
- };
- onMounted(() => {
- getTableList(props.url, props.requestData);
- });
使用父页面:
- <flex-table
- url="/getData"
- :columnData="columnData"
- ></flex-table>
阶段总结:基本上表格的数据已经可以渲染出来了,至于请求request拦截器,需要和后端配合去完善。这里主要是前端先负责渲染出数据和调整效果样式等。
- "totalElements":10, //总条数
- "page":1, //当前页码
- "rows":5, //每行显示条数
- <el-pagination
- :small="small" //是否启用小型分页器,字号12px
- :background="background" //页码选中是否有背景色
- layout="total, prev, pager, next, sizes, jumper" //分页器各组件
- :total="total" //总条数
- :pager-count="4" //设置最大按钮数
- :page-size="pageSize" //每页显示条数
- :page-sizes="pageSizes" //每页显示个数选择器的选项设置
- @size-change="sizeChange" //page-size 改变时触发
- @current-change="handleCurrentChange" //页码发生变化触发事件
- />
- const total = ref(10); //总条数,可以给个默认值
- const pageSize = ref(10); //每页条数,可以给个默认值
- const currentPage = ref(1); //当前页码,可以给个默认值
-
- //get请求数据方法
- const getTableList = (url, options) => {
- //判断url不存在不继续进行请求
- if (!url) {
- console.log("请求地址不存在!");
- return false;
- }
- getTableData(url, options).then((res) => {
- console.log("res", res);
- const { data } = res;
- //处理请求数据内容渲染表格
- tableData.value = data.content;
- //处理请求数据总条数 ---后端给的
- total.value = data.totalElements;
- //处理请求每页显示条数 ---后端给的
- pageSize.value = data.rows;
- //处理请求当前显示页码 ---后端给的
- currentPage.value = data.page;
- });
- };
父组件传入请求分页器参数
- <flex-table
- url="/getData"
- :columnData="columnData"
- :requestData="request_data"
- ></flex-table>
- <script>
- const request_data = reactive({
- page: 1, //当前页码
- rows: 10, //每页显示条数
- searchVal: {}, //搜索框输入的值
- });
- </script>
- import {
- ref,
- computed,
- onMounted,
- getCurrentInstance,
- toRefs,
- defineExpose,
- defineEmits,
- } from "vue";
-
- props: {
- //分页器请求参数
- requestData: {
- type: Object,
- default: () => ({
- page: 1, //当前页数
- rows: 10, //显示条数
- searchVal: {}, //搜索框的值
- }),
- },
- }
-
- //处理props值可以重新赋值
- const emits = defineEmits();
- const pageParams = computed({
- get: () => {
- return props.requestData;
- },
- set: (val) => {
- emits("update:requestData", val);
- },
- });
-
- //当前页码变化事件
- const handleCurrentChange = (val) => {
- //把当前页码赋值给请求参数
- pageParams.value.page = val;
- //请求数据
- getTableList(props.url, pageParams.value);
- };
- //每页显示条数变化事件
- const sizeChange = (val) => {
- //把变化的每页显示条数赋值给请求参数
- pageParams.value.rows = val;
- //请求数据
- getTableList(props.url, pageParams.value)
- };
- //上一页点击事件
- const handlePreClick = (val) => {
- console.log(`handlePreClick,点击了上一页,当前第${val}页`);
- };
- //下一页点击事件
- const handleNextClick = (val) => {
- console.log(`handleNextClick,点击了下一页,当前第${val}页`);
- };
注意:这里为什么需要用外部传入的requestData?
因为外部使用的时候需要用到searchVal,也就是搜索栏输入框的值;也有可能从刚开始请求表格初始数据的时候,需要传入特定页码和特定关键词的数据,所以暴露在外面可以提高组件的灵活性。
- import Mock from 'mockjs';
- import tableData from './mockData/tableData.json';
- Mock.mock("/getData",(config)=>{
- let params = Json.parse(config.body)
- console.log(params) //这里打印验证是否更新参数
- return {
- success:true,
- data:tableData
- }
- })
目前分页器和搜索框的值就暴露到了请求数据的参数中。但是在mock中想要实现有切换数据的效果,我们需要根据返回的参数自己模拟mock返回的数据。
- import tableData1 from './mockData/tableData1.json'
- import tableData2 from './mockData/tableData2.json'
-
- Mock.mock("/getData",(config)=>{
- let params = JSON.parse(config.body)
- //如果当前页码 = 2,返回第二页数据
- if(params.page == 2){
- return {
- success: true,
- data: tableData1,
- }
- }else if(params.page == 1){
- //如果当前页码 = 1,返回第一页数据
- return {
- success: true,
- data: tableData2,
- };
- }
- })
这样简单的数据切换的效果就实现了,方便去调试传给后端的参数;
因为搜索表单内容是插槽,外部自己写搜索表单的样式和布局,所以包括表单提交事件也是在组件外去操作的,那这个时候就需求去调用内部的请求去重新请求数据。vue3的话可以通过ref来实现。
<flex-table ref="flexTable"></flex-table>
- const flexTable = ref(null)
- //搜索表单v-model的值
- const form = reactive({
- value1: "张三",
- value2: "10",
- value3: "",
- value4: "",
- value5: "",
- value6: "",
- value7: "",
- });
- //重置按钮
- const resetForm = () => {
- Object.keys(form).forEach((key) => (form[key] = ""));
- flexTable.value.reload(form);
- };
- //提交按钮
- const onSubmit = () => {
- flexTable.value.reload(form);
- };
- //输入框enter事件
- const handleFilter = (val) => {
- flexTable.value.reload(val);
- };
- //reload请求方法
- const reload = (val) => {
- pageParams.value.searchVal = val;
- getTableList(props.url, pageParams.value);
- };
- defineExpose({
- reload,
- });
因为之前开发组件的时候需要用到name,所以用的写法是vue3的,没有用到setup语法糖。后面在完善的时候发现可以实现setup语法,也可以保留name。亲测有效。
- <sctipt>
- export default{
- name:"组件名"
- }
- </script>
- <sctipt setup>
- //正常业务代码
- </script>
这里主要讲解了一些重要的常用的属性,至于其他控制样式的属性可以参考elementPlus的组件属性表。
这个之前也是慢慢研究的,但是还没有整理,整理之后再单独更新吧。
上面主要展示的是mock数据的对接模拟,至于真实数据需要对接自己的后端给的字段或者要求等;情况不一。但是大概的思路都可以参考的,大家可以根据自己的真实接口去灵活应用的。
不同业务或许有不同的组件封装需求,以上主要是提供一些需求的一种解决方案,大家可以灵活参考。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。