vue多功能表格封裝___動态展示表格列、多條件查詢
以下代碼有部分是看開源eladmin-web項目改寫的,不足之處請大家多多指教,共同學習。
eladmin-web項目位址:https://github.com/elunez/eladmin
1、 index.vue
<template>
<div class="app-container">
<!-- 多條件查詢元件 -->
<queryForm ref="queryForm" />
<!-- 篩選元件 -->
<buttonGroup :table-columns="tableColumns" @initCol="initCol" @toQuery="toQuery" @refresh="refresh"/>
<!--表格元件-->
<tables ref="table" :loading="loading" :data="data" :table-columns="tableColumns" :height="height" @clickRow="clickRow" @selectData="selectData" @edit="edit" />
<!--分頁元件-->
<el-pagination
:total="total"
:current-page="page + 1"
:page-sizes="[20, 40, 80, 100]"
:page-size="size"
style="margin-top: 8px;"
layout="total, prev, pager, next, sizes"
@size-change="sizeChange"
@current-change="pageChange"/>
</div>
</template>
<script>
import tables from '@/components/ViewComponents/table'// 引入元件
import buttonGroup from '@/components/ViewComponents/buttonGroup' // 篩選元件
import queryForm from './multiQuery' // 多條件查詢元件
import initData from '@/mixins/requestInit'
export default {
// 注冊元件
components: { tables, buttonGroup, queryForm },
mixins: [initData],
data() {
return {
height: 625,
columns: this.obColumns(),
tableColumns: [{
hasSort: false,
isShow: true,
prop: 'number',
label: '數量',
align: 'center',
mwidth: 100
}, {
hasSort: false,
isShow: true,
prop: 'number1',
label: '數量',
align: 'center',
mwidth: 100
}, {
hasSort: false,
isShow: true,
prop: 'failureCause',
label: '原因',
align: 'center',
mwidth: 100
}, {
hasSort: false,
isShow: true,
prop: 'number2',
label: '數量',
align: 'center',
mwidth: 100
}]
}
},
created() {
this.$nextTick(() => {
this.height = document.documentElement.clientHeight - 240
})
this.init()
},
methods: {
beforeInit() {
this.url = 'api/repairRequest'
const sort = 'id,desc'
this.params = { page: this.page, size: this.size, sort: sort }
return true
},
// 輕按兩下編輯
edit() {
console.log(arguments[0], '表格編輯資料')
},
// 表格多選
selectData(arr) {
console.log(arr, '表格元件傳回值')
},
// 表格單選
clickRow(row, event, column) {
console.log('單擊表格行資料')
},
// 條件查詢
toQuery() {
this.$refs.queryForm.dialog = true
},
// 重新整理
refresh() {
this.init()
},
initCol() {
const that = this.$refs.table
that.initCol(arguments[0])
},
obColumns(columns) {
return {
visible(col) {
return !columns || !columns[col] ? true : columns[col].visible
}
}
}
}
}
</script>
2、表格元件(table.vue)

<template>
<div style="padding-top:30px;">
<el-table
v-loading="loading"
ref="table"
:data="data"
:height="height"
:span-method="arraySpanMethod"
:row-class-name="tableRowClassName"
resizable
border
style="width: 100%"
@filter-change="handleFilterChange"
@row-click="clickRow"
@row-dblclick="edit"
@selection-change = "selectData">
<!-- 明細 -->
<el-table-column
type="selection"
width="40"/>
<!--資料源-->
<el-table-column
v-for="(column, index) in tableColumns"
v-if="columns.visible(`${column.prop}`)"
:sortable="column.hasSort"
:key="index"
:prop="column.prop"
:label="column.label"
:align="column.align"
:width="column.width"
:min-width="column.mwidth"
header-align="center">
<template slot-scope="scope">
<span v-if="column.prop === 'returnDate'" >{{ parseTime1(scope.row.returnDate) }}</span>
<span v-else-if="column.prop === 'demandTime'" >{{ parseTime1(scope.row.demandTime) }}</span>
<template v-else>
<span>{{ scope.row[column.prop] }}</span>
</template>
</template>
</el-table-column>
</el-table>
</div>
</template>
<script>
import { parseTime1 } from '@/utils/index'
import Vue from 'vue'
export default {
//過濾器
filters: {
getStatus(val) {
switch (val) {
case 0:
return '不知道'
case 1:
return '了解'
case 2:
return '熟悉'
}
}
},
props: {
loading: {
type: Boolean,
default: () => false
},
data: {// 表格資料源 預設為空數組
type: Array,
default: () => []
},
tableColumns: {// 表格的字段展示 預設為空數組
type: Array,
default: () => []
},
height: {// 表格高度
type: Number,
default: () => 625
},
formatter: {// 單據資訊行資料顯示
type: Function,
default: () => {
return
}
}
},
data() {
return {
columns: this.obColumns(),
listLoading: false,
visible: false,
delLoading: false,
rowIds: [],
deleteIds: [],
detailIds: [],
isAdd: true,
multipleSelection: []
}
},
created() {
this.$nextTick(() => {
this.initColData()
})
},
methods: {
parseTime1,
initColData() {
const columns = {}
this.$refs.table.columns.forEach(e => {
if (!e.property || e.type !== 'default') {
return
}
columns[e.property] = {
label: e.label,
visible: true
}
})
this.columns = this.obColumns(columns)
this.updateProp('tableColumns', columns)
},
initCol(columns) {
this.columns = this.obColumns(columns)
this.updateProp('tableColumns', columns)
},
handleCurrentChange(row) {
this.currentRow = JSON.parse(JSON.stringify(row))
},
// 選擇改變
selectionChangeHandler(val) {
this.selections = val
},
obColumns(columns) {
return {
visible(col) {
return !columns || !columns[col] ? true : columns[col].visible
}
}
},
// Vue.set( target, key, value )
// 在對象上設定一個屬性。如果屬性還不存在,則添加新屬性并觸發更改通知
// target:要更改的資料源(可以是對象或者數組)
// key:要更改的具體資料
// value :重新賦的值
updateProp(name, value) {
console.log(name === 'tableColumns', 'name名字', value)
// const table = this.$refs.table
Vue.set(this.tableColumns, name, value)
},
// 表頭點選
handleFilterChange() {
console.log(arguments, '表頭點選')
},
// 輕按兩下編輯
edit() {
this.$emit('edit', arguments[0])
},
// 單擊行時觸發方法
clickRow(row, event, column) {
// this.$emit('clickRow', row, event, column)
this.$refs.table.clearSelection()
const index = this.rowIds.indexOf(row.id)
if (index === -1) {
this.$refs.table.toggleRowSelection(row, true)
} else {
this.rowIds = []
this.$refs.table.toggleRowSelection(row, false)
}
},
// 多選改變時觸發方法
selectData(arr) {
this.multipleSelection = arr
this.$emit('selectData', arr)
},
// 合并表格行
arraySpanMethod({ row, column, rowIndex, columnIndex }) {
const length = this.tableColumns.length + 2
if (columnIndex === 0 && this.dataSource[rowIndex].isShow) {
return [1, length]
}
for (let i = 1; i < length; i++) {
if (columnIndex === i && this.dataSource[rowIndex].isShow) {
return [1, 0]
}
}
},
// 斑馬紋表格樣式
tableRowClassName({ row, rowIndex }) {
let color = ''
if (rowIndex % 2 === 0) {
color = 'warning-row'
} else {
color = 'success-row'
}
if (row.isShow) {
color = 'table-row'
}
for (let i = 0; i < this.multipleSelection.length; i++) {
if (row === this.multipleSelection[i]) {
color = 'select-row'
}
}
return color
}
}
}
</script>
<style lang="scss">
@import "@/styles/table.scss";
</style>
3、篩選列、重新整理、查詢按鈕元件(multiQuery.vue)
<template>
<div class="buttonGroup-box">
<el-button-group class="crud-opts-right">
<el-button size="mini" icon="el-icon-search" @click="toQuery"/>
<el-button size="mini" icon="el-icon-refresh" @click="refresh"/>
<el-popover placement="bottom-end" width="150" trigger="click">
<el-button slot="reference" size="mini" icon="el-icon-s-grid">
<i class="fa fa-caret-down" aria-hidden="true"/>
</el-button>
<el-checkbox v-model="allColumnsSelected" :indeterminate="allColumnsSelectedIndeterminate" @change="handleCheckAllChange">全選</el-checkbox>
<el-checkbox v-for="(item,index) in tableColumns" :key="index" v-model="item.visible" @change="handleCheckedTableColumnsChange(item)"> {{ item.label }}</el-checkbox>
</el-popover>
</el-button-group>
</div>
</template>
<script>
export default {
props: {
tableColumns: {// 表格資料源 預設為空數組
type: Array,
default: () => []
}
},
data() {
return {
allColumnsSelected: true,
allColumnsSelectedIndeterminate: false
}
},
methods: {
handleCheckAllChange(val) {
if (val === false) {
this.allColumnsSelected = true
return
}
for (const key in this.tableColumns) {
this.tableColumns[key].visible = val
}
this.allColumnsSelected = val
this.allColumnsSelectedIndeterminate = false
},
handleCheckedTableColumnsChange(item) {
let totalCount = 0
let selectedCount = 0
for (const key in this.tableColumns) {
++totalCount
selectedCount += this.tableColumns[key].visible ? 1 : 0
}
if (selectedCount === 0) {
this.$notify({
title: '請至少選擇一列',
type: 'warning',
duration: 2500
})
this.$nextTick(function() {
item.visible = true
})
return
}
this.allColumnsSelected = selectedCount === totalCount
this.allColumnsSelectedIndeterminate = selectedCount !== totalCount && selectedCount !== 0
const columns = {}
this.tableColumns.forEach(e => {
columns[e.prop] = {
label: e.label,
visible: e.visible === true
}
})
this.$emit('initCol', columns)
},
toQuery() {
this.$emit('toQuery')
},
refresh() {
this.$emit('refresh')
}
}
}
</script>
<style scoped>
.el-button--mini {
padding: 7px 15px;
font-size: 14px;
border-radius: 3px;
}
.buttonGroup-box{
float: right;
}
</style>
4、多條件查詢元件(queryForm.vue)
<template>
<!-- <div class="app-container" style="height:800px"> -->
<el-dialog :append-to-body="true" :close-on-click-modal="false" :before-close="cancel" :visible.sync="dialog" :title="form.table" center width="800px" @open="getCondition">
<div sclass="button-row" style="margin-top:10px">
<template>
<el-button size="mini" type="primary" icon="el-icon-plus" @click="insertEvent">添加查詢條件</el-button>
<el-button size="mini" type="success" icon="el-icon-search" @click="doSubmit" >查詢</el-button>
<el-button size="mini" type="primary" @click="reset" >重置</el-button>
<el-button type="text" @click="cancel">關閉</el-button>
</template>
</div>
<!-- 表格 -->
<vxe-table
ref="queryTable"
:data="form.conditionVoList"
:edit-config="{trigger: 'click', mode: 'cell'}"
show-overflow
resizable
max-height="400"
@edit-actived="editActivedEvent"
@cell-click="increase">
<vxe-table-column name="icon" fixed="left" width="60" title="删除" >
<template slot-scope="scope" >
<svg-icon icon-class="delete" @click.native="deleteRow(scope.row)" />
</template>
</vxe-table-column>
<vxe-table-column :edit-render="{name: 'input', attrs: {disabled: false}}" width="140" field="associate" title="條件間聯系" >
<template v-if="form.conditionVoList.indexOf(scope.row)!==0 " slot-scope="scope" >
<el-select v-model="scope.row.associate" placeholder="請選擇" @change="autoAdd(scope.row)">
<el-option
v-for="item in associates"
:disabled="form.conditionVoList.indexOf(scope.row)===0"
:key="item.value"
:label="item.label"
:value="item.value"/>
</el-select>
</template>
</vxe-table-column>
<vxe-table-column :edit-render="{name: 'input', attrs: {disabled: false}}" min-width="140" field="column" title="查詢條件"/>
<vxe-table-column :edit-render="{name: 'input', attrs: {disabled: false}}" width="140" field="type" title="條件值關系" >
<template slot-scope="scope">
<el-select v-model="scope.row.type" placeholder="請選擇">
<el-option
v-for="item in types"
:key="item.value"
:label="item.label"
:value="item.value"/>
</el-select>
</template>
</vxe-table-column>
<vxe-table-column :edit-render="{name: 'input', attrs: {disabled: false}}" min-width="140" field="value" title="查詢值" />
</vxe-table>
<template>
<!-- 查詢傳回清單 -->
<el-table
v-loading="listLoading"
v-if="query"
ref="refTable"
:data="columns"
height="200px"
resizable
border
style="width: 100%">
<!-- 單據 -->
<el-table-column prop="name" width="350px" label="姓名" />
<el-table-column prop="age" width="350px" label="年齡" />
</el-table>
</template>
</el-dialog>
<!-- </div> -->
</template>
<script>
import pSelect from '@/components/ViewComponents/select'
import personSelect from '@/components/ViewComponents/select'
import request from '@/utils/request'
export default {
components: { pSelect, personSelect },
props: {
},
data() {
return {
query: false,
loading: false,
dialog: false,
columns: [],
form: {
table: 'test',
conditionVoList: []
},
types: [
{
label: '大于',
value: 'gt'
},
{
label: '等于',
value: 'eq'
},
{
label: '小于',
value: 'lt'
}, {
label: '包含',
value: 'like'
}
],
associates: [
{
label: '并且',
value: 'and'
},
{
label: '或者',
value: 'or'
}
]
}
},
// created() {
// this.insertEvent()
// },
mounted() {
this.insertEvent()
this.insertEvent()
},
methods: {
// 打開dialog的回調方法
getCondition() {
this.form.conditionVoList = [{
column: 'name',
type: 'like',
value: '小',
associate: ''
}]
},
// 增加行
insertEvent() {
this.form.conditionVoList.push({
column: '',
type: '',
value: '',
associate: ''
})
},
// vxe表格 單元格點選事件
increase(data) {
const index = this.form.conditionVoList.indexOf(data.row)
const length = this.form.conditionVoList.length
if ((index === length - 1) && data.row.value !== '') {
this.insertEvent()
}
},
// 條件聯系選擇後就自動增加行
autoAdd() {
const index = this.form.conditionVoList.indexOf(arguments[0])
const length = this.form.conditionVoList.length
if (index === length - 1) {
this.insertEvent()
}
},
// vxe表格 控制單元格禁用狀态
editActivedEvent({ row }) {
const qTable = this.$refs.queryTable
const aColumn = qTable.getColumnByField('associate') // 條件之間的聯系
if (this.form.conditionVoList.indexOf(row) === 0) {
aColumn.editRender.attrs.disabled = true
}
},
// 點選查詢按鈕
doSubmit() {
console.log(this.form)
var arr = []
for (let i = 0; i < this.form.conditionVoList.length; i++) {
if (!this.form.conditionVoList[i].value) {
this.form.conditionVoList.splice(i, 1)
}
}
request({
method: 'post',
url: 'api/testQuery',
data: this.form
}).then(res => {
this.query = true
this.columns = res
console.log(res, '資料')
})
// this.columns = arr
},
// 删除行
deleteRow() {
const index = this.form.conditionVoList.indexOf(arguments[0])
this.form.conditionVoList.splice(index, 1)
},
// 點選重置按鈕 Multiconditional
reset() {
this.query = false
this.form.conditionVoList = [
{
column: '',
type: '',
value: '',
associate: ''
},
{
column: '',
type: '',
value: '',
associate: ''
}
]
},
// 關閉查詢表單
cancel() {
this.resetForm()
},
resetForm() {
this.dialog = false //
this.reset()
}
}
}
</script>
<style lang="scss">
@import "@/styles/form.scss";
</style>