效果
需要环境
需配置属性
属性 | 数据类型 | 是否必填 | 默认值 | 描述 |
---|
data | Array | 是 | [] | 表格的行数据 |
columns | Array | 是 | [] | 表格的列数据,详细数据格式看上面 |
setColumn | Boolean | 否 | false | 是否可以设置显示列 |
tableKey | String | 否 | '' | tableKey 唯一, 设置后可以缓存列表的列 |
示例
<HTable
:columns="columns"
:data="list"
:setColumn="true"
tableKey="CategoriesList"
style="width: 100%"
border
>
<template slot="create_time" slot-scope="scope">
{{ scope.column.label + scope.item.prop }}
</template>
<template slot="action" slot-scope="scope">
<el-button type="primary" @click="handleEdit(scope.row)" size="small">
编辑
</el-button>
<el-button @click="handleDelete(scope.row)" type="danger" size="small">
删除
</el-button>
</template>
</HTable>
import HTable from "@/components/HTable";
export default {
components: { HTable },
data() {
return {
list: [],
columns: [
{
label: "ID",
prop: "_id",
checked: true
...
},
{
label: "分类名称",
prop: "name",
checked: true
},
{
label: "上级分类",
prop: "parent.name",
checked: true
},
{
label: "状态",
prop: "status",
width: "100",
checked: true
},
{
label: "创建时间",
prop: "create_time",
slotHeaderName: "create_time",
checked: true
},
{
label: "操作",
prop: "action",
fixed: "right",
"min-width": "100",
slotName: "action",
checked: true,
disabled: true
}
]
};
}
};
有用到的话给我点个赞!附组件代码
<template>
<div class="HTable">
<div class="settingBox" v-if="setColumn">
<el-popover
placement="bottom-end"
trigger="click"
popper-class="settingPopper"
>
<el-checkbox-group
v-model="selectCol"
@change="handleChangeSelectColumn"
>
<el-checkbox
v-for="item in col"
:key="item.prop"
:label="item.prop"
:disabled="item.disabled"
style="display:block;line-height:2;margin-right:0;"
>{{ item.label }}</el-checkbox
>
</el-checkbox-group>
<i class="icon el-icon-setting" slot="reference"></i>
</el-popover>
</div>
<el-table
v-bind="$attrs"
:data="tableData"
v-on="$listeners"
:key="JSON.stringify(checkedCol)"
>
<el-table-column
v-for="(item, index) in checkedCol"
:key="item.prop"
v-bind="item"
:index="index"
:column-key="item.prop"
>
<template v-if="item.slotHeaderName" v-slot:header="scope">
<slot :name="item.slotHeaderName" v-bind="scope" :item="item"></slot>
</template>
<template v-if="item.slotName" v-slot:default="scope">
<slot :name="item.slotName" v-bind="scope"></slot>
</template>
</el-table-column>
</el-table>
</div>
</template>
<script>
import Sortable from "sortablejs"
export default {
name: "HTable",
props: {
tableKey: String,
columns: {
type: Array,
default() {
return []
}
},
data: {
type: Array,
default() {
return []
}
},
setColumn: {
type: Boolean,
default: false
}
},
watch: {
columns: {
handler(newVal) {
let localVal = this.getStorageCol()
let hotVal = []
if (localVal) {
hotVal = this.dataDiff(newVal, localVal)
} else {
hotVal = [...newVal]
}
this.col = hotVal.map(
(item, index) =>
(item = { ...item, index, checked: item.checked || false })
)
this.checkedCol = this.checkedColFun(this.col)
this.selectCol = this.checkedCol.map(item => (item = item.prop))
},
immediate: true
},
data: {
handler(newVal) {
this.tableData = [...newVal]
},
immediate: true
},
col: {
handler(newVal) {
this.setStorageCol(newVal)
},
deep: true,
immediate: true
}
},
data() {
return {
tableData: [],
col: [],
checkedCol: [],
selectCol: []
}
},
mounted() {
document.body.ondrop = function(event) {
event.preventDefault()
event.stopPropagation()
}
this.$nextTick(() => {
this.rowDrop()
this.columnDrop()
})
},
methods: {
drap() {
this.$nextTick(() => {
this.rowDrop()
this.columnDrop()
})
},
handleChangeSelectColumn() {
this.col.forEach(item => {
if (this.selectCol.includes(item.prop)) {
item.checked = true
} else {
item.checked = false
}
})
this.checkedCol = this.checkedColFun(this.col)
this.drap()
},
rowDrop() {
const tbody = document.querySelector(".el-table__body-wrapper tbody")
Sortable.create(tbody, {
onEnd: ({ newIndex, oldIndex }) => {
[this.tableData[newIndex], this.tableData[oldIndex]] = [
this.tableData[oldIndex],
this.tableData[newIndex]
]
this.drap()
this.$emit("dropRow", {
drapRow: this.tableData[oldIndex],
targetRow: this.tableData[newIndex],
drapRowIndex: oldIndex,
targetRowIndex: newIndex,
data: this.tableData
})
}
})
},
columnDrop() {
const wrapperTr = document.querySelector(".el-table__header-wrapper tr")
Sortable.create(wrapperTr, {
animation: 180,
delay: 0,
onEnd: ({ newIndex, oldIndex }) => {
const oldItem = this.checkedCol[oldIndex]
const newItem = this.checkedCol[newIndex]
[this.col[newItem.index].index, this.col[oldItem.index].index] = [
oldItem.index,
newItem.index
]
this.col.sort((a, b) => {
return a.index - b.index
})
this.checkedCol = this.checkedColFun(this.col)
this.tableData = this.tableData.slice(0, this.tableData.length)
this.drap()
this.$emit("dropCol", {
colItem: oldItem,
newIndex: newIndex,
oldIndex: oldIndex,
column: this.checkedCol
})
}
})
},
checkedColFun(arr) {
return arr.filter(item => item.checked)
},
setStorageCol(data) {
if (this.tableKey && data && data.length > 0) {
localStorage.setItem("HTable-" + this.tableKey, JSON.stringify(data))
}
},
getStorageCol() {
let datajson = localStorage.getItem("HTable-" + this.tableKey)
return datajson ? JSON.parse(datajson) : ""
},
dataDiff(newVal, localVal) {
let nl = newVal.length
let ll = localVal.length
if (nl != ll) {
return newVal
} else {
let np = newVal.map(item => item.prop).sort()
let lp = localVal.map(item => item.prop).sort()
if (np.join() != lp.join()) {
return newVal
} else {
let nnl = []
for (let i = 0
const item_l = localVal[i]
for (let j = 0
const item_n = newVal[j]
if (item_l.prop === item_n.prop) {
nnl.push({
...item_n,
index: item_l.index
})
}
}
}
return nnl
}
}
}
}
}
</script>
<style lang="less" scoped>
.HTable {
position: relative
.settingBox {
width: 36px
height: 36px
border-radius: 2px
border: 1px solid
border-bottom: 0
margin-left: auto
position: relative
.icon {
position: absolute
top: 0
left: 0
z-index: 1
width: 36px
height: 36px
text-align: center
font-size: 20px
line-height: 36px
color:
cursor: pointer
}
}
}
</style>
<style lang="less">
.settingPopper {
min-width: 100px !important
}
</style>