bmTable使用方法
<BmTable url="/project/list":columns="columns":formItem="formItem":formConfig="formConfig":isPagination="true"@postData="postData"@preData="preData"ref="bmTable"><template #bmSuffix><div><el-button type="success">新增</el-button></div></template></BmTable>
export default {mixins: [IndexMixin],setup() {const bmTable = ref()const postData = (data)=> { return data; }const preData = (data)=> { return data; }return {postData,preData,bmTable}}
}
export default {data() {return {columns: [{prop: 'creatTime',label: '创建时间',},{prop: 'datas',label: '操作',labelWidth: 180,render: (item)=> {return <><el-button link type="success" onClick={()=> { this.deletes(item); }}>删除</el-button></>}}],formItem: [{prop: 'created',label: '创建时间',el: 'el-input',placeholder: '123',defaultValue: 'test'},{prop: 'crea',label: '创建',el: 'el-select',data: [{label: '123', value: '1'}, {label: '3', value: '2'}],elOpt: 'el-option',placeholder: '123',defaultValue: '1'},],formConfig: { }}},
}
参数
- columns 表格列参数
- formItem 页面搜索条件参数
- formConfig 页面搜索内容配置参数
- isPagination 是否前端分页
- bmSuffix 插槽 页面操作按钮位置,如新增、批量下载、批量删除等操作
事件
- postData 请求完成后对返回的数据处理事件
- preData 请求前对请求参数处理事件
实现方案
原理:当我们存在多个组件中的数据或者功能很相近时,我们就可以利用 mixins 将公共部分提取出来,通过 mixins 封装函数,组件调用他们是不会改变函数作用域外部的。
注意事项
- 接口返回数据
接口返回参数若后端分页时数据放入data.data.result, 前端分页时数据放入data.data
if (!isPagination) {tableData.list = onPostData ? onPostData(data.data) : data.data;tableData.data = tableData.list.slice((tableData.pagination.page - 1) * tableData.pagination.pageSize,tableData.pagination.page * tableData.pagination.pageSize);tableData.pagination.total = tableData.list.length;return;}tableData.data = onPostData? onPostData(data.data.result): data.data.result;tableData.pagination.total = data.data.total;});
组件封装源码
index.vue
<template><div class="bm-content"><BmForm:formConfig="formConfig":initData="searchData":formItem="formItem":inline="true"@search="search"v-if="formItem?.length"></BmForm><slot name="bmSuffix"></slot><el-table:data="tableData.data"style="width: 100%"stripev-bind="$attrs"header-row-class-name="bm-table-header"row-class-name="bm-table-body"><el-table-columnv-for="(item, index) in columns":key="item.label":width="item.labelWidth"v-bind="item"><template #default="scope"><span v-if="!item.render">{{ scope.row[item.prop] }}</span><render v-else :render="item.render" :data="scope.row" /></template></el-table-column></el-table><div class="bm-pagination"><el-paginationv-model:current-page="tableData.pagination.page"v-model:page-size="tableData.pagination.pageSize"@current-change="currentChange":page-sizes="[10, 20, 50]"smalllayout="total, sizes, prev, pager, next, jumper":total="tableData.pagination.total"background/></div></div>
</template><script lang="ts" setup>
import render from "./render.jsx";
interface propsType {method?: string; // 方法url?: string; // 地址columns?: {label?: string;props?: string;labelWidth?: number;render?: any;};isPagination?: boolean; // 是否前端分页onPostData?: Function; // 后置数据处理formConfig?: Object; // 表单配置formItem?: any[]; // 表单item配置onPreData?: Function; // 参数前置处理
}
import { getCurrentInstance, onMounted, reactive, useAttrs, ref } from "vue";const Instance = getCurrentInstance();
const http = Instance?.appContext.config.globalProperties.$http;
const attrs = useAttrs();const {method = "get",url,columns,isPagination = true,onPostData,formConfig,formItem,onPreData,
}: propsType = attrs;
const searchData = reactive({});const tableData: any = reactive({data: [],list: [],pagination: {total: 0,pageSize: 10,page: 1,},
});const getList = () => {// 请求参数 queryconst query: any = { ...searchData };if (isPagination) {query.page = tableData.pagination.page;query.pageSize = tableData.pagination.pageSize;}// 前置调用onPreData && onPreData(query);http({method: method,url: url,data: query,}).then((data: any) => {// 后置调用// result.dataif (!isPagination) {tableData.list = onPostData ? onPostData(data.data) : data.data;tableData.data = tableData.list.slice((tableData.pagination.page - 1) * tableData.pagination.pageSize,tableData.pagination.page * tableData.pagination.pageSize);tableData.pagination.total = tableData.list.length;return;}tableData.data = onPostData? onPostData(data.data.result): data.data.result;tableData.pagination.total = data.data.total;});
};const currentChange = (e: any) => {if (!isPagination) {tableData.data = tableData.list.slice((e - 1) * tableData.pagination.pageSize,e * tableData.pagination.pageSize);return;}getList();
};const search = (data, formData) => {data.validate((valid) => {if (valid) {Object.keys(searchData).map((item) => {searchData[item] = formData[item];});getList();} else {return false;}});
};onMounted(() => {formItem?.map((item) => {searchData[item.prop] = item.defaultValue ? item.defaultValue : "";});getList();
});defineExpose({getList,
});
</script>
<style lang="less" scoped>
:deep(.bm-table-header) {height: 60px;
}
:deep(.bm-table-body) {height: 50px;.cell {font-size: 13px;}
}
.bm-pagination {display: flex;justify-content: flex-end;height: 50px;background-color: #ffff;
}
.bm-content {border-radius: 3px;overflow: hidden;// height: calc(100vh - 100px);// background-color: white;
}
</style>
render.jsx
export default {render(context) {return (<>{context.$attrs.render(context.$attrs.data)}</>);}
}
bmform.vue
<template><el-form v-bind="$attrs" :model="formData" ref="formRef"><el-form-item v-for="(item, ind) in formItem" :key="ind" v-bind="item"><component :is="item.el" v-bind="item" v-model="formData[item.prop]" v-if="!item.types"><component :is="item.elOpt"v-for="(option, index) in item.data":key="index"v-bind="option"v-if="item.data"></component></component><el-buttontype="primary"v-elsev-for="(opt, key) in item.options":key="key"v-bind="opt"@click="opt.click(formRef)">{{ opt.value }}</el-button></el-form-item><el-form-item v-if="$attrs.inline"><el-button type="primary" :icon="Search" @click="submitForm(formRef)" style="width: 0px;">搜索</el-button></el-form-item></el-form>
</template>
<script setup lang="ts">
import { useAttrs, reactive, ref } from "vue";
import { Search } from '@element-plus/icons-vue';const emit = defineEmits(['search'])
const attr = useAttrs();
const formRef = ref()const { formConfig, formItem, initData }: any = attr;
const formData = reactive(initData);// 数据向外暴露
const submitForm = (data)=> {emit('search', data, formData)
}</script>