位置: IT常识 - 正文

二次封装 el-table(二次封装机)

发布时间:2024-01-15
二次封装 el-table

推荐整理分享二次封装 el-table(二次封装机),希望有所帮助,仅作参考,欢迎阅读内容。

文章相关热门搜索词:二次封装eltable,二次封装机,二次封装eltable,二次封装axios,二次封装axios,二次封装axios,二次封装点光源,二次封装axios,内容如对您有帮助,希望把文章链接给更多的朋友!

很多中后台业务的系统中,表格是最高频的组件之一,其中一般包括搜索条件、表格展示、表格操作列、分页等。那么我们二次封装的这个表格组件就需要包含以下几个功能点:

1、数据自动获取和刷新

2、自定义列配置

3、分页功能

4、根据搜索条件进行搜索功能

5、加载中状态和空数据状态

一、先上页面最终效果

二、创建目录yxt-table如下图

index.vue为父级页面

yxt-table.vue为表格组件

二、数据自动获取和刷新

因为表格的数据一般都比较简单,就是根据搜索条件,调用接口请求一个到列表,然后将列表数据一一展示到表格上,再对特定的列进行一些过滤转化等个性化操作。但是万变不离其宗,这个步骤基本每个表格都要进行一遍,所以考虑到通用性(其实是为了偷懒),将请求接口获取数据这一步放在组件里面实现。

created () { this.getData() }, methods: { getData () { const fun = this.apiUrl fun().then(res => { this.tableData = res[this.otherConfig.list] || [] this.tableTotal = res.pageInfo?.total || 0 }) } }

三、自定义列配置

组件接收一个数组作为自定义列

tableColumn: [ { prop: 'name', label: '名称' }, { prop: 'code', label: '编码' }, { prop: 'status', label: '状态' }]

 index.vue

<!-- index.vue --><template> <div> <yxt-table :apiUrl="yxtTableList" :tableColumn="tableColumn"></yxt-table> </div></template><!-- index.vue --><script>import yxtTable from './yxt-table.vue'import { yxtTableList } from 'https/yxtDemo.js'export default { name: 'yxtDemoTable', components: { yxtTable }, data () { return { yxtTableList, tableColumn: [ { prop: 'name', label: '名称' }, { prop: 'code', label: '编码' }, { prop: 'status', label: '状态' } ] } }}</script>

 yxt-table.vue

<!-- yxt-table.vue --><template> <div> <el-table :data="tableData"> <el-table-column v-for="item in tableColumn" :key="item.prop" :prop="item.prop" :label="item.label"></el-table-column> </el-table> </div></template><!-- yxt-table.vue --><script>export default { name: 'yxtTable', props: { apiUrl: { // 列表接口(必填) type: Function, required: true }, tableColumn: { // 自定义列配置 type: Array, default: () => [] }, otherConfig: { // type: Object, default: () => { return { list: 'list' } } } }, data () { return { tableData: [] } }, created () { this.getData() }, methods: { getData () { const fun = this.apiUrl fun().then(res => { this.tableData = res[this.otherConfig.list] || [] this.tableTotal = res.pageInfo?.total || 0 }) } }}</script>

至此,一个表格可以实现了

1、otherConfig说明

由于我们的接口请求放在组件里面了,但是我们对接的接口可能由于业务的不同项目组的不同开发人员的不同,而导致接口返回的列表的字段名不同,这里通过传参的形式做一下兼容

2、上面这样只能实现简单的展示功能,还有些数据比如 状态1 需要转化为打卡成功,状态0 需要转化为打卡失败进行显示,这类需求可以通过filter进行转化

<!-- yxt-table.vue --> <el-table-column v-for="item in tableColumn" :key="item.prop" :prop="item.prop" :label="item.label"> <template v-slot:default="scope"> <div v-if="item.dictCode"> {{ scope.row[item.prop] | filterStatus(dict[item.dictCode]) }} </div> <div v-else> {{ scope.row[item.prop] }} </div> </template> </el-table-column> props: { dict: { // 全部字典 type: Object, default: () => {} } }, filters: { filterStatus (value, array, code = 'code', name = 'name') { if (!value && value !== 0) { // 要把0摘出来,一般0都是正常的数据,所以不能只用 !value return '' } const find = array.find(e => (e[code] === value.toString()) || (e[code] === +value)) // 字符型数值型都得匹配 if (find) { return find[name] } else { // 没有匹配的就原样返回 return value } } },<!-- index.vue --> <yxt-table :apiUrl="yxtTableList" :tableColumn="tableColumn" :dict="dict"></yxt-table> data () { return { tableColumn: [ { prop: 'name', label: '名称' }, { prop: 'code', label: '编码' }, { prop: 'status', label: '状态', dictCode: 'status' } ], dict: { status: [ { code: 0, name: '打卡失败' }, { code: 1, name: '打卡成功' } ] } } }

这里dict设置为对象的原因是为了装进更多字典

二次封装 el-table(二次封装机)

3、思考一下,如果要在表格中展示这样的自定义图标怎么办? 

使用插槽slot,在tableColumn里面设置某行属性的slot为true,改造el-table-column如下:

<!-- yxt-table.vue --> <el-table-column v-for="(item, index) in tableColumn" :key="index" :prop="item.prop" :label="item.label"> <template v-if="item.slot" v-slot:default="scope"> <slot :name="item.prop" :row="scope.row" :index="scope.$index"></slot> </template> <template v-else v-slot:default="scope"> <div v-if="item.dictCode"> {{ scope.row[item.prop] | filterStatus(dict[item.dictCode]) }} </div> <div v-else> {{ scope.row[item.prop] }} </div> </template> </el-table-column><!-- index.vue --> <yxt-table :apiUrl="yxtTableList" :tableColumn="tableColumn" :otherConfig="otherConfig" :dict="dict"> <template v-slot:icon="{row, index}"> <i :class="row.status ? 'el-icon-circle-check' : 'el-icon-circle-close'"></i> </template> </yxt-table> data () { return { tableColumn: [ { prop: 'name', label: '名称' }, { prop: 'code', label: '编码' }, { prop: 'status', label: '状态', dictCode: 'status' }, { prop: 'icon', label: '图标', slot: true } ] } }

 4、在实际项目中,除了字典转化,还有一些比较定制化的展示需求,这个可以通过传入一个函数format进行计算,然后在这个方法里面将最后的计算结果return

<!-- yxt-table.vue --> <el-table-column v-for="(item, index) in tableColumn" :key="index" :prop="item.prop" :label="item.label"> <template v-if="item.slot" v-slot:default="scope"> <slot :name="item.prop" :row="scope.row" :index="scope.$index"></slot> </template> <template v-else v-slot:default="scope"> <div v-if="item.dictCode"> {{ scope.row[item.prop] | filterStatus(dict[item.dictCode]) }} </div> <div v-else-if="item.format"> {{ item.format(scope.row) }} </div> <div v-else> {{ scope.row[item.prop] }} </div> </template> </el-table-column><!-- index.vue --> data () { return { tableColumn: [ { prop: 'name', label: '名称' }, { prop: 'code', label: '编码' }, { prop: 'status', label: '状态', dictCode: 'status' }, { prop: 'icon', label: '图标', slot: true }, { prop: 'phone', label: '电话号码', format: (row) => { return `${row.name}-${row.code}(${row.phone})` } } ] } }

5、表格一般还有批量操作,所以需要多选和单选以及针对特定场景设置禁选

 yxt-table.vue

<!-- yxt-table.vue --><template> <div class="yxt-table"> <!-- 批量操作按钮,因为每个需求不同,批量操作的功能也不同,所以这里只放一个插槽,不设置默认内容,所有按钮均在父级设置 --> <div class="multiple-operation"> <slot name="multiple-operation" :selectionData="selectionData"></slot> </div> <!-- 页面主表格 --> <el-table :data="tableData" :row-key="rowKey" @selection-change="selectionChange"> <!-- 可选框(多选) --> <el-table-column v-if="selection === 'multiple'" type="selection" align="center" width="55" :reserve-selection="rowKey ? true : false" :selectable="selectable"/> <!-- 可选框(单选) --> <el-table-column v-else-if="selection === 'single'" align="center" width="30"> <template v-slot:default="scope"> <el-radio v-model="selectionRadio" :label="scope.$index" :disabled="selectable ? !selectable(scope.row) : false" @change="selectionChangeSingle(scope.row)"> {{ '' }} </el-radio> </template> </el-table-column> <el-table-column v-for="(item, index) in tableColumn" :key="index" :prop="item.prop" :label="item.label"> <template v-if="item.slot" v-slot:default="scope"> <slot :name="item.prop" :row="scope.row" :index="scope.$index"></slot> </template> <template v-else v-slot:default="scope"> <div v-if="item.dictCode"> {{ scope.row[item.prop] | filterStatus(dict[item.dictCode]) }} </div> <div v-else-if="item.format"> {{ item.format(scope.row) }} </div> <div v-else> {{ scope.row[item.prop] }} </div> </template> </el-table-column> </el-table> </div></template><!-- yxt-table.vue --><script>export default { name: 'yxtTable', props: { apiUrl: { // 列表接口(必填) type: Function, required: true }, tableColumn: { // 自定义列配置 type: Array, default: () => [] }, otherConfig: { // 其他配置 type: Object, default: () => { return { list: 'list' // 接口返回数据的列表字段的字段名(因为在组件里面调接口,可能不同业务不同项目组不同一个开发者返回给前端的参数名不一致,这里进行兼容) } } }, dict: { // 全部字典 type: [Array, Object], default: () => [] }, selection: { // 是否显示可选框(多选-multiple 、单选-single ) type: String }, selectable: { // 当前行是否可选择 type: Function }, rowKey: { // 表格唯一key(适用于分页多选表格,保留之前的选择,不传则为单页选择) type: [Number, String, Function], default: '' } }, filters: { filterStatus (value, array, code = 'code', name = 'name') { if (!value && value !== 0) { // 要把0摘出来,一般0都是正常的数据,所以不能只用 !value return '' } const find = array.find(e => (e[code] === value.toString()) || (e[code] === +value)) // 字符型数值型都得匹配 if (find) { return find[name] } else { // 没有匹配的就原样返回 return value } } }, data () { return { tableData: [], tableTotal: 0, selectionRadio: '', selectionData: [] } }, created () { this.getData() }, methods: { getData () { const fun = this.apiUrl fun().then(res => { this.tableData = res[this.otherConfig.list] || [] this.tableTotal = res.pageInfo?.total || 0 }) }, // 多选,选择行数据change selectionChange (selection) { this.selectionData = selection }, // 单选,选择行数据change selectionChangeSingle (selection) { this.selectionData = [selection] } }}</script><style scoped lang="scss">.yxt-table { margin: 30px; .multiple-operation { margin-bottom: 10px; }}</style>

 index.vue

<!-- index.vue --><template> <div> <yxt-table :apiUrl="yxtTableList" :tableColumn="tableColumn" :otherConfig="otherConfig" :dict="dict" selection="multiple" :selectable="isSelectable"> <!-- 图标插槽 --> <template v-slot:icon="{row, index}"> <i :class="row.status ? 'el-icon-circle-check' : 'el-icon-circle-close'"></i> </template> <!-- 批量操作按钮插槽 --> <template v-slot:multiple-operation="{selectionData}"> <el-button type="primary" size="small" @click="handleClick1(selectionData)">批量操作1</el-button> <el-button type="success" size="small" @click="handleClick2(selectionData)">批量操作2</el-button> </template> </yxt-table> <yxt-table :apiUrl="yxtTableList" :tableColumn="tableColumn" :otherConfig="otherConfig" :dict="dict" selection="single" :selectable="isSelectable"> <!-- 图标插槽 --> <template v-slot:icon="{row, index}"> <i :class="row.status ? 'el-icon-circle-check' : 'el-icon-circle-close'"></i> </template> <!-- 批量操作按钮插槽 --> <template v-slot:multiple-operation="{selectionData}"> <el-button type="primary" size="small" @click="handleClick1(selectionData)">单选操作</el-button> </template> </yxt-table> </div></template><!-- index.vue --><script>import yxtTable from './yxt-table.vue'import { yxtTableList } from 'https/yxtDemo.js'export default { name: 'yxtDemoTable', components: { yxtTable }, data () { return { yxtTableList, tableColumn: [ { prop: 'name', label: '名称' }, { prop: 'code', label: '编码' }, { prop: 'status', label: '状态', dictCode: 'status' }, { prop: 'icon', label: '图标', slot: true }, { prop: 'phone', label: '电话号码', format: (row) => { return `${row.name}-${row.code}(${row.phone})` } } ], tableConfig: { stripe: 'stripe', border: 'border', height: '200', maxHeight: '200', showHeader: true }, otherConfig: { list: 'tasks' }, dict: { status: [ { code: 0, name: '打卡失败' }, { code: 1, name: '打卡成功' } ] } } }, methods: { handleClick1 (selectionData) { console.log('1', selectionData) }, handleClick2 (selectionData) { console.log('2', selectionData) }, isSelectable (row) { return row.selectable !== 0 } }}</script><style scoped lang="scss">.el-icon-circle-check { font-size: 28px; color: #67C23A;}.el-icon-circle-close { font-size: 28px; color: #F00;}</style>

6、操作列

根据业务需求,可以在操作列设置几个默认按钮,通过setupConfig设置开关,如果有除了默认按钮之外的操作需求,再通过插槽slot进行插入

<!-- yxt-table.vue --> <!-- 操作列 --> <el-table-column v-if="setupConfig.width !== 0" :fixed="setupConfig.fixed" :width="setupConfig.width" label="操作"> <template v-slot:default="scope"> <slot name="setup" :row="scope.row" :index="scope.$index"></slot> <!-- 查看 --> <el-button v-if="setupConfig.view" type="text" @click="setupEvents('view', scope.row)">查看</el-button> <!-- 编辑 --> <el-button v-if="setupConfig.edit" type="text" @click="setupEvents('edit', scope.row)">编辑</el-button> <!-- 删除 --> <el-button v-if="setupConfig.del" type="text" @click="setupEvents('del', scope.row)">删除</el-button> <!-- 操作日志 --> <el-button v-if="setupConfig.log" type="text" @click="setupEvents('log', scope.row)">操作日志</el-button> </template> </el-table-column> props: { setupConfig: { type: Object, default: () => { return { width: 'auto' } } } }, methods: { setupEvents (setupType, row) { // 操作列方法 查看/编辑/删除/操作日志 this.$emit(setupType, row) } }

 index.vue做相应的处理,这里不贴代码了

7、分页 

pagination控制是否需要分页组件,如果不需要分页则设置为false。根据业务需求,可传入pageSizes控制条数下拉框的条数选项

<!-- yxt-table.vue --> <!-- 分页 --> <el-pagination v-if="pagination" class="pagination tablePage" :pager-count="5" :page-sizes="pageSizes || [10, 20, 50, 100]" :total="tableTotal || 0" :page-size="pageInfo.pageSize || 10" :current-page="pageInfo.startPage || 1" layout="total, sizes, prev, pager, next, jumper" @size-change="sizeChange" @current-change="pageChange"></el-pagination> props: { pagination: { // 是否需要分页,默认需要 type: Boolean, default: true }, pageSizes: { type: Array } }, methods: { getData () { const fun = this.apiUrl const pageInfo = { // 分页信息 pageSize: this.pageInfo.pageSize, startPage: this.pageInfo.startPage } let param = { // 其他的搜素条件 } if (this.pagination) { // 如果需要分页,则传分页信息 param = { ...param, ...pageInfo } } fun(param).then(res => { this.tableData = res[this.otherConfig.list] || [] this.tableTotal = res.pageInfo?.total || 0 }) }, // 条数变化 sizeChange (size) { this.pageInfo.startPage = 1 this.pageInfo.pageSize = size this.getData() }, // 页码变化 pageChange (page) { this.pageInfo.startPage = page this.getData() } }

 8、el-table还有一个展开行功能expand,根据业务需求,也可以加进组件里

<!-- yxt-table.vue --> <!-- 展开行 --> <el-table-column v-if="expand" type="expand"> <template v-slot:default="scope"> <slot name="expand" :row="scope.row" :index="scope.$index"></slot> </template> </el-table-column> props: { expand: { // 是否展开行 type: Boolean, default: false } }<!-- index.vue --> <yxt-table :apiUrl="yxtTableList" :tableColumn="tableColumn" :expand="true"> <template v-slot:expand="{row, index}"> <div> <p>序号:{{index}}</p> <p>内容:{{row}}</p> </div> </template> </yxt-table>

四、根据搜索条件进行搜索更新表格数据

新增一个yxt-search.vue

<!-- yxt-search.vue --><template> <div class="yxt-search"> <div v-for="(item,index) in searchConfig" :key="index" class="yxt-search-item"> <el-input v-if="item.type==='input'" v-model="searchModel[item.key]" size="medium" :clearable="item.clearable || true" :placeholder="item.placeholder || '请输入'" :maxlength="item.maxlength"></el-input> <el-select v-if="item.type==='select'" v-model="searchModel[item.key]" size="medium" style="width: 100%" :clearable="item.clearable || true" :filterable="item.filterable || true" :disabled="item.disabled || false" :multiple="item.multiple || false" :allow-create="item.allowCreate" :placeholder="item.placeholder || '请选择'"> <el-option v-for="(selectItem, selectIndex) in item.selectList" :key="selectIndex" :label="selectItem[item.listLabel]" :value="selectItem[item.listValue]"></el-option> </el-select> </div> <div v-if="searchConfig.length" class="yxt-search-button"> <el-button size="medium" type="primary" @click="search">搜索</el-button> <el-button size="medium" type="primary" plain @click="reset">重置</el-button> <!-- 其他的按钮需求通过插槽传入 --> <slot name="searchBtn" :searchData="searchModel"></slot> </div> </div></template><!-- yxt-search.vue --><script>export default { name: 'yxtSearch', props: { searchConfig: { // 搜索条件配置项 type: Array, required: true, default () { return [] } }, searchModel: { // 搜索条件绑定值 type: Object, required: true, default () { return {} } }, searchReset: { // 搜索条件默认值重置值 type: Object } }, data () { return { } }, methods: { search () { this.$emit('search', this.searchModel) }, reset () { if (this.searchReset) { // 如果传入有默认值,则重置后为默认值 Object.keys(this.searchModel).forEach((item) => { this.searchModel[item] = this.searchReset[item] }) } else { Object.keys(this.searchModel).forEach((item) => { this.searchModel[item] = '' }) } } }}</script><style scoped lang="scss">.yxt-search { display: flex; flex-direction: row; flex-wrap: wrap; justify-content: flex-start; .yxt-search-item { flex: 1; margin: 0 10px 10px 0; width: calc((100% - 30px) / 4); // 这里的30px = (分布个数4-1)*间隙1px, 可以根据实际的分布个数和间隙区调整 min-width: calc((100% - 30px) / 4); max-width: calc((100% - 30px) / 4); &:nth-child(4n) { // 去除每行最后一个(第4n个)的margin-right margin-right: 0; } } .yxt-search-button { margin: 0 0 10px 0; width: 100%; text-align: right; }}</style><!-- yxt-table.vue --> <yxt-search :searchConfig="searchConfig" :searchModel="searchModel" :searchReset="searchReset" @search="getData(1)"> <template v-slot:searchBtn="{searchData}"> <!-- 其他的按钮需求通过插槽传入 --> <slot name="searchBtn" :searchData="searchData"></slot> </template> </yxt-search> props: { searchConfig: { // 搜索条件配置项 type: Array, default () { return [] } }, searchReset: { // 搜索条件默认值重置值 type: Object } }, data () { return { searchModel: this.searchReset ? JSON.parse(JSON.stringify(this.searchReset)) : {} } }, methods: { getData (startPage) { if (startPage) { // 如果传入值,则从改值的页码数开始 this.pageInfo.startPage = startPage } let param = { // 其他的搜素条件 ...this.searchModel } ... } }<!-- index.vue --> <yxt-table :apiUrl="yxtTableList" :tableColumn="tableColumn" :searchConfig="searchConfig" :searchReset="searchReset"> <template v-slot:searchBtn="{searchData}"> <el-button size="medium" type="success" @click="handleClickExport(searchData)">导出</el-button> </template> </yxt-table> data () { return { searchConfig: [ { type: 'input', key: 'name' }, { type: 'input', key: 'code' }, { type: 'select', key: 'status', selectList: [ { code: 0, name: '打卡失败' }, { code: 1, name: '打卡成功' } ], listLabel: 'name', listValue: 'code' } ], searchReset: { name: '张三', code: '', status: 1 } } }, methods: { handleClickExport (data) { console.log(data) } }

五、加载中状态和空数据状态

加载中:el-table 添加 v-loading="loading",getData里面,发送请求之前设置为true,获得数据后设置为false

空数据:通过插槽empty设置

 六、完整代码:

index.vue<!-- index.vue --><template> <div> <yxt-table :apiUrl="yxtTableList" :tableColumn="tableColumn" :otherConfig="otherConfig" :dict="dict" selection="multiple" :selectable="isSelectable" :setupConfig="setupConfig" :searchConfig="searchConfig" :searchReset="searchReset" @view="view" @log="log"> <!-- 图标插槽 --> <template v-slot:icon="{row, index}"> <i :class="row.status ? 'el-icon-circle-check' : 'el-icon-circle-close'"></i> </template> <!-- 批量操作按钮插槽 --> <template v-slot:multiple-operation="{selectionData}"> <el-button type="primary" size="small" @click="handleClick1(selectionData)">批量操作1</el-button> <el-button type="success" size="small" @click="handleClick2(selectionData)">批量操作2</el-button> </template> <template v-slot:searchBtn="{searchData}"> <el-button size="medium" type="success" @click="handleClickExport(searchData)">导出</el-button> </template> </yxt-table> <yxt-table :apiUrl="yxtTableList" :tableColumn="tableColumn" :otherConfig="otherConfig" :dict="dict" selection="single" :selectable="isSelectable" :setupConfig="setupConfig2" :pagination="false" :expand="true" :emptyText="'没有数据的展示文字'"> <!-- 图标插槽 --> <template v-slot:icon="{row, index}"> <i :class="row.status ? 'el-icon-circle-check' : 'el-icon-circle-close'"></i> </template> <!-- 批量操作按钮插槽 --> <template v-slot:multiple-operation="{selectionData}"> <el-button type="primary" size="small" @click="handleClick1(selectionData)">单选操作</el-button> </template> <template v-slot:expand="{row, index}"> <div> <p>序号:{{index}}</p> <p>内容:{{row}}</p> </div> </template> </yxt-table> </div></template><!-- index.vue --><script>import yxtTable from './yxt-table.vue'import { yxtTableList } from 'https/yxtDemo.js'export default { name: 'yxtDemoTable', components: { yxtTable }, data () { return { yxtTableList, tableColumn: [ { prop: 'name', label: '名称' }, { prop: 'code', label: '编码' }, { prop: 'status', label: '状态', dictCode: 'status' }, { prop: 'icon', label: '图标', slot: true }, { prop: 'phone', label: '电话号码', format: (row) => { return `${row.name}-${row.code}(${row.phone})` } } ], tableConfig: { stripe: 'stripe', border: 'border', height: '200', maxHeight: '200', showHeader: true }, otherConfig: { list: 'tasks' }, setupConfig: { width: 100, view: true, log: true }, setupConfig2: { edit: true, del: true, log: true }, dict: { status: [ { code: 0, name: '打卡失败' }, { code: 1, name: '打卡成功' } ] }, searchConfig: [ { type: 'input', key: 'name' }, { type: 'input', key: 'code' }, { type: 'select', key: 'status', selectList: [ { code: 0, name: '打卡失败' }, { code: 1, name: '打卡成功' } ], listLabel: 'name', listValue: 'code' } ], searchReset: { name: '张三', code: '', status: 1 } } }, methods: { handleClick1 (selectionData) { console.log('1', selectionData) }, handleClick2 (selectionData) { console.log('2', selectionData) }, handleClickExport (data) { console.log(data) }, isSelectable (row) { return row.selectable !== 0 }, view (row) { console.log('view', row) }, log (row) { console.log('log', row) } }}</script><style scoped lang="scss">.el-icon-circle-check { font-size: 28px; color: #67C23A;}.el-icon-circle-close { font-size: 28px; color: #F00;}</style>yxt-table.vue<!-- yxt-table.vue --><template> <div class="yxt-table"> <yxt-search :searchConfig="searchConfig" :searchModel="searchModel" :searchReset="searchReset" @search="getData(1)"> <template v-slot:searchBtn="{searchData}"> <!-- 其他的按钮需求通过插槽传入 --> <slot name="searchBtn" :searchData="searchData"></slot> </template> </yxt-search> <!-- 批量操作按钮,因为每个需求不同,批量操作的功能也不同,所以这里只放一个插槽,不设置默认内容,所有按钮均在父级设置 --> <div class="multiple-operation"> <slot name="multiple-operation" :selectionData="selectionData"></slot> </div> <!-- 页面主表格 --> <el-table :data="tableData" :row-key="rowKey" v-loading="loading" @selection-change="selectionChange"> <!-- 可选框(多选) --> <el-table-column v-if="selection === 'multiple'" type="selection" align="center" width="55" :reserve-selection="rowKey ? true : false" :selectable="selectable"/> <!-- 可选框(单选) --> <el-table-column v-else-if="selection === 'single'" align="center" width="30"> <template v-slot:default="scope"> <el-radio v-model="selectionRadio" :label="scope.$index" :disabled="selectable ? !selectable(scope.row) : false" @change="selectionChangeSingle(scope.row)"> {{ '' }} </el-radio> </template> </el-table-column> <!-- 展开行 --> <el-table-column v-if="expand" type="expand"> <template v-slot:default="scope"> <slot name="expand" :row="scope.row" :index="scope.$index"></slot> </template> </el-table-column> <el-table-column v-for="(item, index) in tableColumn" :key="index" :prop="item.prop" :label="item.label"> <template v-if="item.slot" v-slot:default="scope"> <slot :name="item.prop" :row="scope.row" :index="scope.$index"></slot> </template> <template v-else v-slot:default="scope"> <div v-if="item.dictCode"> {{ scope.row[item.prop] | filterStatus(dict[item.dictCode]) }} </div> <div v-else-if="item.format"> {{ item.format(scope.row) }} </div> <div v-else> {{ scope.row[item.prop] }} </div> </template> </el-table-column> <!-- 操作列 --> <el-table-column v-if="setupConfig.width !== 0" :fixed="setupConfig.fixed" :width="setupConfig.width" label="操作"> <template v-slot:default="scope"> <slot name="setup" :row="scope.row" :index="scope.$index"></slot> <!-- 查看 --> <el-button v-if="setupConfig.view" type="text" @click="setupEvents('view', scope.row)">查看</el-button> <!-- 编辑 --> <el-button v-if="setupConfig.edit" type="text" @click="setupEvents('edit', scope.row)">编辑</el-button> <!-- 删除 --> <el-button v-if="setupConfig.del" type="text" @click="setupEvents('del', scope.row)">删除</el-button> <!-- 操作日志 --> <el-button v-if="setupConfig.log" type="text" @click="setupEvents('log', scope.row)">操作日志</el-button> </template> </el-table-column> <!-- 空状态 --> <template slot="empty"> <p>{{ emptyText }}</p> </template> </el-table> <!-- 分页 --> <el-pagination v-if="pagination" class="pagination tablePage" :pager-count="5" :page-sizes="pageSizes || [10, 20, 50, 100]" :total="tableTotal || 0" :page-size="pageInfo.pageSize || 10" :current-page="pageInfo.startPage || 1" layout="total, sizes, prev, pager, next, jumper" @size-change="sizeChange" @current-change="pageChange"></el-pagination> </div></template><!-- yxt-table.vue --><script>import yxtSearch from './yxt-search'export default { name: 'yxtTable', components: { yxtSearch }, props: { apiUrl: { // 列表接口(必填) type: Function, required: true }, tableColumn: { // 自定义列配置 type: Array, default: () => [] }, otherConfig: { // 其他配置 type: Object, default: () => { return { list: 'list' // 接口返回数据的列表字段的字段名(因为在组件里面调接口,可能不同业务不同项目组不同一个开发者返回给前端的参数名不一致,这里进行兼容) } } }, dict: { // 全部字典 type: [Array, Object], default: () => [] }, selection: { // 是否显示可选框(多选-multiple 、单选-single ) type: String }, selectable: { // 当前行是否可选择 type: Function }, rowKey: { // 表格唯一key(适用于分页多选表格,保留之前的选择,不传则为单页选择) type: [Number, String, Function], default: '' }, setupConfig: { type: Object, default: () => { return { width: 'auto' } } }, pagination: { // 是否需要分页,默认需要 type: Boolean, default: true }, pageSizes: { // 分页的下拉框选项 type: Array }, expand: { // 是否展开行 type: Boolean, default: false }, searchConfig: { // 搜索条件配置项 type: Array, default () { return [] } }, searchReset: { // 搜索条件默认值重置值 type: Object }, emptyText: { type: String } }, filters: { filterStatus (value, array, code = 'code', name = 'name') { if (!value && value !== 0) { // 要把0摘出来,一般0都是正常的数据,所以不能只用 !value return '' } const find = array.find(e => (e[code] === value.toString()) || (e[code] === +value)) // 字符型数值型都得匹配 if (find) { return find[name] } else { // 没有匹配的就原样返回 return value } } }, data () { return { loading: true, tableData: [], tableTotal: 0, pageInfo: { pageSize: 10, startPage: 1 }, selectionRadio: '', selectionData: [], searchModel: this.searchReset ? JSON.parse(JSON.stringify(this.searchReset)) : {} } }, created () { this.getData() }, methods: { getData (startPage) { if (startPage) { // 如果传入值,则从改值的页码数开始 this.pageInfo.startPage = startPage } this.loading = true const fun = this.apiUrl const pageInfo = { // 分页信息 pageSize: this.pageInfo.pageSize, startPage: this.pageInfo.startPage } let param = { // 其他的搜素条件 ...this.searchModel } if (this.pagination) { // 如果需要分页,则传分页信息 param = { ...param, ...pageInfo } } fun(param).then(res => { setTimeout(() => { this.tableData = res[this.otherConfig.list] || [] this.tableTotal = res.pageInfo?.total || 0 this.loading = false }, 2000) }) }, // 多选,选择行数据change selectionChange (selection) { this.selectionData = selection }, // 单选,选择行数据change selectionChangeSingle (selection) { this.selectionData = [selection] }, // 操作列方法 查看/编辑/删除/操作日志 setupEvents (setupType, row) { this.$emit(setupType, row) }, // 条数变化 sizeChange (size) { this.pageInfo.startPage = 1 this.pageInfo.pageSize = size this.getData() }, // 页码变化 pageChange (page) { this.pageInfo.startPage = page this.getData() } }}</script><style scoped lang="scss">.yxt-table { margin: 30px; .multiple-operation { margin-bottom: 10px; }}</style>yxt-search.vue<!-- yxt-search.vue --><template> <div class="yxt-search"> <div v-for="(item,index) in searchConfig" :key="index" class="yxt-search-item"> <el-input v-if="item.type==='input'" v-model="searchModel[item.key]" size="medium" :clearable="item.clearable || true" :placeholder="item.placeholder || '请输入'" :maxlength="item.maxlength"></el-input> <el-select v-if="item.type==='select'" v-model="searchModel[item.key]" size="medium" style="width: 100%" :clearable="item.clearable || true" :filterable="item.filterable || true" :disabled="item.disabled || false" :multiple="item.multiple || false" :allow-create="item.allowCreate" :placeholder="item.placeholder || '请选择'"> <el-option v-for="(selectItem, selectIndex) in item.selectList" :key="selectIndex" :label="selectItem[item.listLabel]" :value="selectItem[item.listValue]"></el-option> </el-select> </div> <div v-if="searchConfig.length" class="yxt-search-button"> <el-button size="medium" type="primary" @click="search">搜索</el-button> <el-button size="medium" type="primary" plain @click="reset">重置</el-button> <!-- 其他的按钮需求通过插槽传入 --> <slot name="searchBtn" :searchData="searchModel"></slot> </div> </div></template><!-- yxt-search.vue --><script>export default { name: 'yxtSearch', props: { searchConfig: { // 搜索条件配置项 type: Array, required: true, default () { return [] } }, searchModel: { // 搜索条件绑定值 type: Object, required: true, default () { return {} } }, searchReset: { // 搜索条件默认值重置值 type: Object } }, data () { return { } }, methods: { search () { this.$emit('search', this.searchModel) }, reset () { if (this.searchReset) { // 如果传入有默认值,则重置后为默认值 Object.keys(this.searchModel).forEach((item) => { this.searchModel[item] = this.searchReset[item] }) } else { Object.keys(this.searchModel).forEach((item) => { this.searchModel[item] = '' }) } } }}</script><style scoped lang="scss">.yxt-search { display: flex; flex-direction: row; flex-wrap: wrap; justify-content: flex-start; .yxt-search-item { flex: 1; margin: 0 10px 10px 0; width: calc((100% - 30px) / 4); // 这里的30px = (分布个数4-1)*间隙1px, 可以根据实际的分布个数和间隙区调整 min-width: calc((100% - 30px) / 4); max-width: calc((100% - 30px) / 4); &:nth-child(4n) { // 去除每行最后一个(第4n个)的margin-right margin-right: 0; } } .yxt-search-button { margin: 0 0 10px 0; width: 100%; text-align: right; }}</style>

yxtTable.json

{ "retCode": "0", "retMsg": "success", "pageInfo": { "total": 300 }, "tasks": [ { "name": "张三", "code": "zhangSan", "status": 1, "icon": true, "phone": "17801010101", "selectable": 1 }, { "name": "李四", "code": "liSi", "status": 0, "icon": false, "phone": "17802020202", "selectable": 2 }, { "name": "王五", "code": "wangWu", "status": 2, "icon": true, "phone": "17803030303", "selectable": 0 }, { "name": "马六", "code": "maLiu", "status": 1, "icon": false, "phone": "17804040404", "selectable": 2 } ]}

最后效果

本文链接地址:https://www.jiuchutong.com/zhishi/295935.html 转载请保留说明!

上一篇:uniapp页面跳转的几种方式(uniapp跳转页面没反应)

下一篇:怎么安装离线vue环境(怎么安装离线导航)

  • 华为p40pro尺寸长宽高分别是多少(华为p40pro尺寸长宽高厘米)

    华为p40pro尺寸长宽高分别是多少(华为p40pro尺寸长宽高厘米)

  • 华为手机怎么发信息给别人(华为手机怎么发送信息)

    华为手机怎么发信息给别人(华为手机怎么发送信息)

  • 京东退货商家审核多久(京东退货商家审核超时需要再次申请吗)

    京东退货商家审核多久(京东退货商家审核超时需要再次申请吗)

  • 哈罗单车还不了车怎么办(哈罗单车还不了车怎么办客服电话)

    哈罗单车还不了车怎么办(哈罗单车还不了车怎么办客服电话)

  • app连接服务器失败是什么原因(app连接服务器失败原因)

    app连接服务器失败是什么原因(app连接服务器失败原因)

  • 笔记本的键盘灯怎么打开(笔记本的键盘灯光怎么开)

    笔记本的键盘灯怎么打开(笔记本的键盘灯光怎么开)

  • 华为FlG-TL10什么型号(华为fla–tl10)

    华为FlG-TL10什么型号(华为fla–tl10)

  • 苹果手机天气为什么显示不出来(苹果手机天气为什么是北京)

    苹果手机天气为什么显示不出来(苹果手机天气为什么是北京)

  • 苹果8p有原彩显示吗(8p的原彩)

    苹果8p有原彩显示吗(8p的原彩)

  • 为什么人脸识别多次失败(为什么人脸识别突然不能用了)

    为什么人脸识别多次失败(为什么人脸识别突然不能用了)

  • 电池健康多少该换了(电池健康度多少需要换电池)

    电池健康多少该换了(电池健康度多少需要换电池)

  • ipad新机充电注意事项(新买的ipad 充电)

    ipad新机充电注意事项(新买的ipad 充电)

  • 企鹅电竞看直播老黑屏(企鹅电竞直播app下载安装)

    企鹅电竞看直播老黑屏(企鹅电竞直播app下载安装)

  • 手机充电器是多少w(手机充电器是多少w的)

    手机充电器是多少w(手机充电器是多少w的)

  • 快手改名上限怎么解除(快手改名字上限了怎么办)

    快手改名上限怎么解除(快手改名字上限了怎么办)

  • 苹果5怎么打开录屏功能(苹果5怎么打开悬浮球)

    苹果5怎么打开录屏功能(苹果5怎么打开悬浮球)

  • 移动路由器怎么改密码(移动路由器怎么连接另一个路由器)

    移动路由器怎么改密码(移动路由器怎么连接另一个路由器)

  • 美图秀秀萌趣贴纸在哪(美图秀秀萌拍素材已下载)

    美图秀秀萌趣贴纸在哪(美图秀秀萌拍素材已下载)

  • 荣耀10快充多少w(荣耀10快充功率)

    荣耀10快充多少w(荣耀10快充功率)

  • 文件上的横线怎么去掉(文件上的横线怎么去掉图片)

    文件上的横线怎么去掉(文件上的横线怎么去掉图片)

  • 陌陌和探探有什么区别(陌陌跟探探的区别)

    陌陌和探探有什么区别(陌陌跟探探的区别)

  • 小米手环4怎么刷公交卡(小米手环4怎么解绑)

    小米手环4怎么刷公交卡(小米手环4怎么解绑)

  • 电脑屏幕黑了(电脑屏幕黑了按什么键恢复)

    电脑屏幕黑了(电脑屏幕黑了按什么键恢复)

  • 为什么电脑时间不同步(为什么电脑时间不能自动更新)

    为什么电脑时间不同步(为什么电脑时间不能自动更新)

  • dedecms 5.7首页文章下面的评论框不显示的解决办法(网站的首页文件名是什么)

    dedecms 5.7首页文章下面的评论框不显示的解决办法(网站的首页文件名是什么)

  • 公司租赁个人车辆税率是多少
  • 小规模纳税人怎么变成一般纳税人
  • 原材料入库汇总单
  • 法人转入公司的资金怎么做账
  • 行政事业单位会计制度
  • 增值税包括哪些税种
  • 固定资产抵债要交税吗怎么交
  • 一般纳税人普通发票免税吗
  • 部分红冲的发票无法勾选怎么办
  • 材料采购发生的合理损耗计入
  • 建筑工程公司是什么意思
  • 搬运费计入
  • 存款取款业务记入那个日记账?
  • 合同期限3年
  • 开进来的发票冲红怎么处理?
  • 公司租车税务处理办法
  • 文化用品利润怎么样
  • 2018劳务费个人所得税税率表
  • 主营业务税金及附加包括印花税吗
  • 代扣款怎么做账
  • 汇票和本票之间在使用上有什么差别
  • 企业发给员工的福利要交税吗
  • 总账会计就是内外账合并吗
  • 同期对比和同比增长
  • 股票质押期间收益归谁
  • 公司内部领用库存商品
  • 应付工资和实付工资的差额叫什么
  • 筹建期的工资
  • 已计提月份的公式
  • 腾讯电脑管家中蓝牙在哪
  • linux查看du
  • 事假扣款进什么科目
  • 转出未交增值税怎么算
  • 融资性售后回租是什么意思
  • 调整以前年度亏损
  • 没报关的货物还需要开发票嘛
  • 承担客户车辆维修责任
  • html里面有什么
  • vue项目部署后白屏
  • 自动驾驶决策规划技术理论与实践电子版
  • php框架自动加载
  • 人力为主的公司名称
  • 出口退税率和进项税额
  • wordpress文章保存在哪里
  • 预提管理费用怎么计算
  • 残保金滞纳金可以税前扣除吗
  • 绿化养护合同交不交印花税
  • 分批发货分批付款
  • 《中华人民共和国治安管理处罚法》
  • 哪些税种影响当期损益
  • 建筑业增值税税负率
  • 产品不符合要求
  • 固定资产报废电费怎么算
  • 所有者权益的确认依赖于资产和负债的确认
  • 应付账款预付账款期末余额怎么算
  • 如何制作u盘系统win7
  • window系统怎么用
  • 联想e430安装win10
  • 系统技巧 制作流程
  • win7和xp文件共享
  • linux常用命令查看
  • win7怎么查看电池信息
  • win8如何输入命令
  • linux常用命令查询
  • Setver、Share、Subst命令的使用方法
  • 压缩的linux命令
  • 谈一谈js中的执行者是谁
  • 简述javascript
  • jquery iframe
  • JAVAscript字符串类型单引号和双引号意一样吗
  • 教你学python
  • js图片轮播和点击切换
  • jQuery 获取跨域XML(RSS)数据的相关总结分析
  • 在python程序中变量名不能用
  • 高速公路过路费一公里多少钱
  • 大米可以抵扣增值税吗
  • 德勤 税务
  • 文化传媒公司能卖多少钱
  • 城镇土地使用税优惠政策
  • 将购进农产品用于生产销售或委托加工货物的税率多少
  • 免责声明:网站部分图片文字素材来源于网络,如有侵权,请及时告知,我们会第一时间删除,谢谢! 邮箱:opceo@qq.com

    鄂ICP备2023003026号