vue實現 可展開 且 可多選table 元件封裝
基於 網上程式碼進行優化, 實現 實際開發功能
效果如圖:
在父元件可以拿到 當前點選所有行陣列:就可以愉快的 把 id 傳給後端了!
建立 TreeTable 元件:
<template>
<el-table
ref="multipleTable"
:data="formatData"
:row-style="showRow"
v-bind="$attrs"
>
<!-- @header-click="chooseall" -->
<el-table-column :render-header="renderHeader" width="50" align="center">
<template slot-scope="scope">
<el-checkbox
v-model="scope.row.checks"
@change="toselect(scope.row)"
></el-checkbox>
</template>
</el-table-column>
<el-table-column v-if="columns.length === 0" width="150">
<template slot-scope="scope">
<span
v-for="space in scope.row._level"
:key="space"
class="ms-tree-space"
/>
<span
v-if="iconShow(0, scope.row)"
class="tree-ctrl"
@click="toggleExpanded(scope.$index)"
>
<i v-if="!scope.row._expanded" class="el-icon-plus" />
<i v-else class="el-icon-minus" />
</span>
{{ scope.$index }}
</template>
</el-table-column>
<el-table-column
v-for="(column, index) in columns"
v-else
:key="column.value"
:label="column.text"
:width="column.width"
>
<template slot-scope="scope">
<!-- Todo -->
<!-- eslint-disable-next-line vue/no-confusing-v-for-v-if -->
<span
v-for="space in scope.row._level"
v-if="index === 0"
:key="space"
class="ms-tree-space"
/>
<span
v-if="iconShow(index, scope.row)"
class="tree-ctrl"
@click="toggleExpanded(scope.$index)"
>
<i v-if="!scope.row._expanded" class="el-icon-plus" />
<i v-else class="el-icon-minus" />
</span>
{{ scope.row[column.value] }}
</template>
</el-table-column>
<slot />
</el-table>
</template>
<script>
import treeToArray from "./eval";
export default {
name: "TreeTable",
data() {
return {
chooseson: true, //全選
key: true, //單個點選直到全部選中
tableChcekedList: [],
};
},
props: {
/* eslint-disable */
data: {
type: [Array, Object],
required: true,
},
columns: {
type: Array,
default: () => [],
},
evalFunc: Function,
evalArgs: Array,
expandAll: {
type: Boolean,
default: false,
},
},
computed: {
// 格式化資料來源
formatData: function () {
let tmp;
if (!Array.isArray(this.data)) {
tmp = [this.data];
} else {
tmp = this.data;
}
const func = this.evalFunc || treeToArray;
const args = this.evalArgs
? [tmp, this.expandAll].concat(this.evalArgs)
: [tmp, this.expandAll];
return func.apply(null, args);
},
},
methods: {
showRow: function (row) {
const show = row.row.parent
? row.row.parent._expanded && row.row.parent._show
: true;
row.row._show = show;
return show
? "animation:treeTableShow 0s;-webkit-animation:treeTableShow 0s;"
: "display:none;";
},
// 切換下級是否展開
toggleExpanded: function (trIndex) {
const record = this.formatData[trIndex];
record._expanded = !record._expanded;
},
// 圖示顯示
iconShow(index, record) {
return index === 0 && record.child && record.child.length > 0;
},
//設定表頭全選
renderHeader(h, data) {
return h(
"span",
{
attrs: {
style: "display:flex;align-items: center; justify-content: center;",
},
},
[
h("input", {
attrs: {
id: "chooseall",
type: "checkbox",
},
}),
]
);
},
//功能函式:選中部分子集
setchildtobeselect(arr, key) {
arr.forEach((v, i) => {
// v.checks = key;
this.$set(v, "checks", key);
// v._expanded = key;//選中後展開子項
if (v.child) {
this.setchildtobeselect(v.child, v.checks);
}
});
arr.forEach((item, index) => {
if (item.checks) {
if (item._level === 2) {
let flag = false;
this.tableChcekedList.forEach((tableItem, tableIndex) => {
if (item._level === 2) {
if (item.checks) {
if (item.id === tableItem.id) {
flag = true;
}
} else {
if (item.id === tableItem.id) {
flag = true;
this.tableChcekedList.splice(tableIndex, 1);
}
}
}
});
if (!flag) {
this.tableChcekedList.push(item);
}
}
} else {
this.tableChcekedList.splice(index, 1);
}
this.$emit("getCheckedRow", this.tableChcekedList);
});
},
//是否所有的都被選中
isallchecked(arr) {
arr.forEach((v, i) => {
if (!v.checks) {
this.key = false;
this.$set(this, "key", false);
}
if (v.child) {
this.isallchecked(v.child);
}
});
},
//設定父級為 未選中狀態(父級的父級沒改變-有bug)
setparentfalse(arr, id, level) {
arr.forEach((v, i) => {
if (v._level == level - 1 && v.child) {
v.child.forEach((val, ind) => {
if (val.id == id) {
v.checks = false;
return false; //終止此次迴圈,減少迴圈次數
}
});
}
if (v.child) {
this.setparentfalse(v.child, id, level);
}
});
},
//設定父級為 選中狀態
setparenttrue(arr, id, level) {
arr.forEach((v, i) => {
if (v._level == level - 1 && v.child) {
let key = true;
let sameidkey = false;
v.child.forEach((val, ind) => {
if (val.id == id) {
//確保當前點選的在該父級內
sameidkey = true;
}
if (!val.checks) {
key = false;
}
});
if (key && sameidkey) {
// v.checks = true;
this.$set(v, "checks", true);
}
}
if (v.child) {
this.setparentfalse(v.child, id, level);
}
});
},
//某個核取方塊被點選時
toselect(row) {
// row._expanded = row.checks;//選中後是否展開
//1、若有子集先讓子選中
if (row.child) {
this.setchildtobeselect(row.child, row.checks);
}
//2、然後判斷是否全選中
this.key = true; //重置為true,防止上次已經是false的狀態
this.isallchecked(this.formatData);
//3、設定多選框的狀態
if (!row.checks) {
this.setparentfalse(this.formatData, row.id, row._level); //設定父級選中的狀態為false
document.getElementById("chooseall").checked = false; //設定全選框的狀態
} else {
this.setparenttrue(this.formatData, row.id, row._level); //設定父級選中的狀態為true
}
if (this.key) {
document.getElementById("chooseall").checked = true; //設定全選框的狀態
}
if (
this.tableChcekedList.length === 0 &&
row._level === 2 &&
row.checks
) {
// console.log("陣列長度為0的時候 觸發");
this.tableChcekedList.push(row);
} else {
var flag = false;
this.tableChcekedList.forEach((item, index) => {
if (row._level === 2) {
if (row.checks) {
flag = true;
// this.tableChcekedList.push(row);
} else {
if (item.id === row.id) {
this.tableChcekedList.splice(index, 1);
}
}
}
});
if (flag) {
// console.log("單選行觸發");
this.tableChcekedList.push(row);
}
}
this.$emit("getCheckedRow", this.tableChcekedList);
// console.log(this.tableChcekedList, "this.tableChcekedList");
},
},
mounted() {
this.$nextTick(() => {
var that = this;
const all = document.getElementById("chooseall");
all.onchange = function (e) {
if (all.checked == true) {
that.setchildtobeselect(that.formatData, true);
} else {
that.setchildtobeselect(that.formatData, false);
}
};
});
},
};
</script>
<style rel="stylesheet/css">
@keyframes treeTableShow {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
@-webkit-keyframes treeTableShow {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
</style>
<style>
#chooseall:checked {
background: #1673ff !important;
border: solid 1px #1673ff !important;
}
#chooseall {
background-color: #ffffff;
border-radius: 50%;
font-size: 0.8rem;
margin: 0;
padding: 0;
position: relative;
display: inline-block;
vertical-align: top;
cursor: default;
-webkit-appearance: none;
-webkit-user-select: none;
user-select: none;
-webkit-transition: background-color ease 0.6s;
transition: background-color ease 0.6s;
border: 1px solid #dcdfe6;
border-radius: 2px;
box-sizing: border-box;
width: 14px;
height: 14px;
cursor: pointer;
}
#chooseall:checked::after {
content: "";
top: 2px;
left: 2px;
position: absolute;
background: transparent;
border: #fff solid 1px;
border-top: none;
border-right: none;
height: 4px;
width: 9px;
-webkit-transform: rotate(-45deg);
transform: rotate(-45deg);
}
.ms-tree-space {
position: relative;
top: 1px;
display: inline-block;
font-style: normal;
font-weight: 400;
line-height: 1;
width: 18px;
height: 14px;
}
.ms-tree-space::before {
content: "";
}
.processContainer {
width: 100%;
height: 100%;
}
table td {
line-height: 26px;
}
.tree-ctrl {
position: relative;
cursor: pointer;
color: #2196f3;
margin-left: -18px;
}
</style>
在 .vue 父元件呼叫:
<template>
<div>
<tree-table
:data="data"
:columns="columns"
:expandAll="true"
border
@getCheckedRow="getCheckedRow"
/>
</div>
</template>
<script>
import treeTable from "../../components/TreeTable";
export default {
name: "courseProgress",
components: {
treeTable,
},
data() {
return {
rowArrList: [],
columns: [
{
text: "事件",
value: "event",
width: 200,
},
{
text: "ID",
value: "id",
},
],
data: [
{
id: 0,
event: "區域1",
child: [
{
id: 1,
event: "裝置11",
},
{
id: 2,
event: "裝置12",
},
],
},
{
id: 1,
event: "區域2",
child: [
{
id: 3,
event: "裝置21",
},
{
id: 4,
event: "裝置22",
},
],
},
],
};
},
methods: {
getCheckedRow(arr) {
this.rowArrList = arr;
console.log(arr, "父元件拿到 點選行陣列");
},
},
};
</script>
<style scoped>
</style>
建立 eval.js
import Vue from "vue";
export default function treeToArray(
data,
expandAll,
parent = null,
level = null
) {
let tmp = [];
Array.from(data).forEach(function(record) {
if (record._expanded === undefined) {
Vue.set(record, "_expanded", expandAll);
}
let _level = 1;
if (level !== undefined && level !== null) {
_level = level + 1;
}
Vue.set(record, "_level", _level);
// 如果有父元素
if (parent) {
Vue.set(record, "parent", parent);
}
tmp.push(record);
if (record.child && record.child.length > 0) {
const child = treeToArray(record.child, expandAll, record, _level);
tmp = tmp.concat(child);
}
});
return tmp;
}
相關文章
- 封裝Vue Element的可編輯table表格元件封裝Vue元件
- 封裝Vue Element的table表格元件封裝Vue元件
- vue使用element元件實現選單的摺疊與展開Vue元件
- 最近封裝的table ui元件封裝UI元件
- vue元件封裝指南Vue元件封裝
- 基於vue和elementUI封裝框選表格元件VueUI封裝元件
- 封裝react antd的表格table元件封裝React元件
- 從零實現Vue的元件庫(十二)- Table 實現Vue元件
- Vue 封裝動態元件Vue封裝元件
- 封裝Vue 的 SVG 元件封裝VueSVG元件
- Vue實現跑馬燈效果以及封裝為元件釋出Vue封裝元件
- 元件化頁面:封裝el-table元件化封裝
- 小程式如何封裝提示元件並且使用封裝元件
- Vue3.0實現原生高度可自定義選單元件vue3-menusVue元件
- vue3 echart元件封裝Vue元件封裝
- Android ListView收縮與展開的封裝實現AndroidView封裝
- element封裝可編輯表格元件封裝元件
- element對上傳元件二次封裝,vue上傳下載元件的實現元件封裝Vue
- 如何優雅的封裝vue元件封裝Vue元件
- VUE封裝的元件庫上傳Vue封裝元件
- vue - antd UI table表格展開行+展開多行共存VueUI
- 手把手實現圖片懶載入+封裝vue懶載入元件封裝Vue元件
- Android元件化開發實戰:封裝許可權管理請求框架Android元件化封裝框架
- Vue封裝Swiper實現圖片輪播Vue封裝
- vue 多時間段範圍選擇及回顯 元件封裝Vue元件封裝
- 【Vue】el-table 簡易表格可篩選列Vue
- 封裝Vue Element的form表單元件封裝VueORM元件
- 封裝Vue元件的一些技巧封裝Vue元件
- vue實現展開全部,收起全部Vue
- vue元件封裝及父子元件傳值,事件處理Vue元件封裝事件
- jquery 封裝 bootstrap tablejQuery封裝boot
- 封裝Vue Element的upload上傳元件封裝Vue元件
- 封裝Vue Element的dialog彈窗元件封裝Vue元件
- vue 將echarts封裝為元件一鍵使用VueEcharts封裝元件
- 更好的封裝Vue3元件封裝Vue元件
- vue+webpack+amaze-vue實現省市區聯動選擇元件VueWeb元件
- 封裝Vue縱向表頭左右結構的table表格封裝Vue
- 基於Vue+element-ui 的Table二次封裝VueUI封裝