前端树形表格展示通过使用umyui组件
参考umyui官网的
一个基于 vue 的 PC 端表格UI库,解决万级数据渲染卡顿问题,过万数据点击全选卡顿等等问题。
博主也查阅过资料,也有使用过elementui中的table来实现,但是最后发现因为我的数据有几千条,使用elementui的table会造成浏览器的卡顿,不论是展示数据还是搜索都会使得页面非常卡顿,经过几次试错后,找到了umyui这个在vue基础上的table组件。
umyui链接
👇官网页面如下:我们可以看到基本的分布,这里我使用的是ux-grid这个组件,因为这边需要涉及到复选框,这个属性对有复选框的需求会比较好。推荐有复选框需求的可以使用这个。
给大家看看最终的效果
👉实现的效果
总的来说,它和elemenyui的table是非常相似的,只需要把elementui的换成就可以了,注意一下里面的属性名称是否一样。
话不多说,来看代码:👇👇👇👇👇👇👇👇👇👇
💞🔥html代码:
要写成树形结构,必须设置row-id=‘id’,这里需要注意,与elementui的table不同,elementui是row-key,
其次,最重要的两个属性是tree-config和checkbox-config
checkbox-config | 复选框配置项 | — | — | — |
---|---|---|---|---|
checkField | 渲染速度更快(建议数据量大时使用,行数据中必须存在该字段,否则无效) | string | — | — |
showHeader | 是否显示全选按钮 | boolean | — | true |
checkAll | 默认勾选所有(只会在初始化时被触发一次) | boolean | — | false |
checkRowKeys | 默认勾选开指定行(只会在初始化时被触发一次,需要有 row-id) | Array | — | — |
checkStrictly | 是否严格的遵循父子不互相关联的做法 | boolean | — | false |
checkMethod | 是否允许勾选的方法,该方法 Function({row}) 的返回值用来决定这一行的 checkbox 是否可以勾选 | Array | — | — |
highlight | 高亮勾选行 | boolean | — | false |
trigger | 触发方式 | string | default(默认), cell(点击单元格触发), row(点击行触发) | default |
tree-config | 树形结构配置项 | — | — | — |
---|---|---|---|---|
children | 树子节点的属性 | string | — | children |
indent | 树节点的缩进 | number | — | 20 |
expandAll | 默认展开所有子孙树节点(只会在初始化时被触发一次) | boolean | — | false |
expandRowKeys | 默认展开指定树节点(只会在初始化时被触发一次,需要有 row-id) | string[] | — | — |
accordion | 对于同一级的节点,每次只能展开一个 | boolean | — | false |
trigger | 触发方式 | string | default(点击展开按钮触发), cell(点击单元格触发), row(点击行触发) | default |
lazy | 是否使用懒加载(启用后只有指定 hasChild 的节点才允许被点击) | boolean | - | false |
hasChild | 只对 lazy 启用后有效,标识是否存在子节点,从而控制是否允许被点 | string | hasChild | |
loadMethod | 该方法 Function({ row }) 用于异步加载子节点, (必须返回 Promise<any[]>对象) | Function | - | - |
reserve | 是否保留展开状态,对于某些场景可能会用到,比如数据被刷新之后还保留之前展开的状态(需要有 row-id) | boolean | - | false |
showIcon | 是否显示图标按钮 | boolean | — | true |
iconOpen | 自定义展开后显示的图标 iconfont图标 | string | — | — |
iconClose | 自定义收起后显示的图标 iconfont图标 | string | — | — |
iconLoaded | 自定义懒加载中显示的图标 iconfont图标 | string | — | — |
line | 树节点的连接线(启用连接线) | boolean | — | false |
<ux-grid ref="plTreeTable" :data="tableData" fixed-columns-roll beautify-table header-drag-style :max-height="height" :checkbox-config="{highlight: false,showHeader:false,checkRowKeys:checkTreeArry,checkField:'courtTypeHidden'}"
@select="handleSelectRow" :tree-config="{ children: 'children',expandAll: false,expandRowKeys:currentExpand}" row-id="id" border :key="keyCode">
<ux-table-column field="name" title="法院名称" :tree-node="true" min-width="15%" type="checkbox">
<template slot-scope="scope">
<span>{{scope.row.name}}</span>
</template>
</ux-table-column>
<ux-table-column field="courtType" title="法院类型" align="center" min-width="15%"></ux-table-column>
<ux-table-column field="courtRelationGood" title="关系很好" align="center" min-width="10%">
<template slot="header" slot-scope="scope">关系很好
<el-checkbox label="智能全选" v-model="checkedGood" style="color: #FF8100;display: block" @change="handleCheckedGood"></el-checkbox>
</template>
<template slot-scope="scope">
<el-checkbox label="" v-if="scope.row.courtType" v-model="scope.row.courtRelationGood" @change="handleCheckedGoodRow(scope.row)"></el-checkbox>
</template>
</ux-table-column>
<ux-table-column field="courtRelationDefalut" title="关系一般" align="center" min-width="10%">
<template slot="header" slot-scope="scope">关系一般
<el-checkbox label="智能全选" v-model="checked" style="color: #FF8100;display: block" @change="handleCheckedDefalut"></el-checkbox>
</template>
<template slot-scope="scope">
<el-checkbox label="" v-if="scope.row.courtType" v-model="scope.row.courtRelationDefalut" @change="handleRelationDef(scope.row)"></el-checkbox>
</template>
</ux-table-column>
<ux-table-column field="courtRelationBad" title="关系很差" align="center" min-width="10%">
<template slot="header" slot-scope="scope">关系很差
<el-checkbox label="智能全选" v-model="checkedBad" style="color: #FF8100;display: block" @change="handleCheckedBad"></el-checkbox>
</template>
<template slot-scope="scope">
<el-checkbox label="" v-if="scope.row.courtType" v-model="scope.row.courtRelationBad" @change="handleRelationBad(scope.row)"></el-checkbox>
</template>
</ux-table-column>
</ux-grid>
🙌💥需要再第一列添加
:tree-node="true"和type=“checkbox”
在表头我们需要设置一个select选择事件,来记录我们选择了哪几行,以便保存到后台,给后台传递一个state是否选中的状态。
这里我是一层层来写的,大家可以写个递归。
handleSelectRow(selection, row){
if(row.children && row.children.length>0){
if(row.children && row.children.length>0){
row.children.forEach(c=>{
if(c.children && c.children.length>0){
c.children.forEach(r=>{
if(r.children && r.children.length>0){
r.children.forEach(_l=>{
if(_l.state==0){
_l.state=1
}else {
_l.state=0
}
})
}else{
if(r.state==0){
r.state=1
}else{
r.state=0
}
}
})
}else{
if(c.state==0){
c.state=1
}else{
c.state=0
}
}
})
}else{
if(v.state==0){
v.state=1
}else{
v.state=0
}
}
}else{
row.state=!row.state
}
selection.forEach(v=>{
this.$set(v,'state',true)
})
this.checkedAllNode=selection
this.$refs.plTreeTable.loadData(this.tableData)
// console.log(selection, row)
},
对了,如果要设置默认展开和默认选中,可以设置expandRowKeys和checkRowKeys属性。
🙆下面来看搜索树形结构的逻辑(需要控制树形的展开和折叠)
input
👉先介绍一下需要用到的一些属性
size | 输入框尺寸 | 只在 type!=“textarea” 时有效 | string | medium / small / mini |
---|---|---|---|---|
prefix-icon | 输入框头部图标 | string | — | — |
placeholder | 输入框占位文本 | string | — | — |
clearable | 是否可清空 | boolean | — | false |
value-key | 输入建议对象中用于显示的键名 | string | — | value |
trigger-on-focus | 是否在输入框 focus 时显示建议列表 | boolean | — | true |
fetch-suggestions | 返回输入建议的方法,仅当你的输入建议数据 resolve 时,通过调用 callback(data:[]) 来返回它 | Function(queryString, callback) | — | — |
select | 点击选中建议项时触发 | 选中建议项 |
👉html代码
<el-autocomplete class="inline-input" v-model.trim="searchForm.queryParam" size="small" value-key="courtName" :fetch-suggestions="querySearchInput" placeholder="请输入法院名称"
:trigger-on-focus="false" @select="handleSelect" suffix-icon="el-icon-search" clearable></el-autocomplete>
👊设置树形展开节点,就必须设置expand-row-keys属性,也必须要设置row-key=“id”,id字段可以自选,但最好可以设置为id
在搜索时,需要展开对应的树形节点,但是有时会出现更新不及时或者说是搜索后表格没有重新渲染,就需要设置 :key=‘’属性
我这里设置了一个:key=“keyCode” 在data中设置了 keyCode:‘keyCode’+new Date().getTime()会实时变化,但对于使用unyui组件的话,也可以使用组件自带的刷新渲染树。
👊刷新表格方法:我使用的是doLayout和loadData,大家根据需求自行设计
doLayout | 重新计算表格,如果传 true 则进行完整计算(对于某些特殊场景可能会用到,比如隐藏的表格、重新计算列宽…等) | — |
---|---|---|
reloadData | 加载数据并清除所有状态(对于表格数据需要重载、局部递增的场景中可能会用到) | data 返回一个Promise |
loadData | 加载数据(对于表格数据需要重载、局部递增场景下可能会用到) | data 返回一个Promise |
reloadColumn | 加载列配置并恢复到初始状态(对于表格列需要重载、局部递增场景下可能会用到) | columns |
loadColumn | 加载列配置(对于表格列需要重载、局部递增场景下可能会用到) | columns |
refreshColumn | 刷新列配置(对于动态修改属性、显示/隐藏列等场景下可能会用到) | — |
reloadRow(rows, record, field) | 局部加载行数据并恢复到初始状态(对于行数据需要局部更改的场景中可能会用到) | rows, record, field |
<el-table :data="tableData" max-height="700" size="small" style="width: 100%" ref="table" :key="keyCode"
header-cell-class-name="table-header-row" row-key="id" :tree-props="{children: 'children', hasChildren: 'hasChildren'}" :expand-row-keys="currentExpand.length>0?currentExpand:currentExpandSearchAyyay" >
👉js代码 实现模糊搜索
/**
* 获取所有的法院信息--所有的搜索数据
* @param $table
*/
querySearch(dataList){
for(let i=0;i<dataList.length;i++){
if(dataList[i].courtName){
this.allData.push(dataList[i])
}
if(dataList[i].children && dataList[i].children.length>0){
for(let j=0;j<dataList[i].children.length;j++){
if(dataList[i].children[j].courtName){
this.allData.push(dataList[i].children[j])
}
if(dataList[i].children[j].children && dataList[i].children[j].children.length>0){
this.querySearch(dataList[i].children[j].children)
}
}
}
}
},
/**
* js搜索模糊查询
* @param queryString
* @param cb
*/
querySearchInput(queryString, cb){
var restaurants = this.allData;
var results = queryString ? restaurants.filter(this.createFilter(queryString)) : restaurants;
// 调用 callback 返回建议列表的数据
cb(results);
},
createFilter(queryString) {
return restaurant => {
return (restaurant.courtName.toLowerCase().indexOf(queryString.toLowerCase())>=0);
};
},
搜索树形结构的展开与折叠以及定位到相应的展开节点
这里我有两个搜索内容,一个是类型一个是名称,搜索前先折叠展开的树节点,使用setTreeExpand方法展开相应的节点,接着计算pagingScrollTopLeft需要滚动的距离,这里我的定位还是不准确的,我觉得使用scrollToRow是最好的,但是不知道为什么我的这个方法没有用,对了,这里需要注意一点,这里重新计算表格使用doLayout的方法,loadData会使定位不起作用。文章来源:https://www.toymoban.com/news/detail-702047.html
search() {
const loading = this.$loading({
lock: true,
text: 'Loading',
spinner: 'el-icon-loading',
background: 'rgba(0, 0, 0, 0.7)'
});
let _this = this
_this.$refs.plTreeTable.clearTreeExpand()
_this.$refs.plTreeTable.pagingScrollTopLeft(0,0)
_this.tableData.forEach(p => {
if ((_this.searchForm.courtType && _this.searchForm.courtType == p.courtType)
&& (_this.searchForm.queryParam && _this.searchForm.queryParam == p.name)) {
// _this.$refs.plTreeTable.setTreeExpansion(p, true)
}
if (p.children && p.children.length > 0) {
p.children.forEach(c => {
if ((_this.searchForm.courtType && _this.searchForm.courtType == c.courtType)
&& (_this.searchForm.queryParam && _this.searchForm.queryParam == c.name)) {
_this.$refs.plTreeTable.setTreeExpand(p, true)
}
if((!_this.searchForm.courtType || _this.searchForm.courtType =='')
&& (_this.searchForm.queryParam && _this.searchForm.queryParam == c.name)){
_this.$refs.plTreeTable.setTreeExpand(p, true)
}
if((_this.searchForm.courtType && _this.searchForm.courtType == c.courtType)
&& (!_this.searchForm.queryParam || _this.searchForm.queryParam == '')){
_this.$refs.plTreeTable.setTreeExpand(p, true)
_
}
if (c.children && c.children.length > 0) {
c.children.forEach(r => {
if ((_this.searchForm.courtType && _this.searchForm.courtType == r.courtType)
&& (_this.searchForm.queryParam && _this.searchForm.queryParam == r.name)) {
_this.$refs.plTreeTable.setTreeExpand(p, true)
_this.$refs.plTreeTable.setTreeExpand(c, true)
}
if ((!_this.searchForm.courtType || _this.searchForm.courtType == '')
&& (_this.searchForm.queryParam && _this.searchForm.queryParam == r.name)) {
_this.$refs.plTreeTable.setTreeExpand(p, true)
_this.$refs.plTreeTable.setTreeExpand(c, true)
}
if ((_this.searchForm.courtType && _this.searchForm.courtType == r.courtType)
&& (!_this.searchForm.queryParam || _this.searchForm.queryParam == '')) {
_this.$refs.plTreeTable.setTreeExpand(p, true)
_this.$refs.plTreeTable.setTreeExpand(c, true)
}
if (r.children && r.children.length > 0) {
r.children.forEach(_c => {
if ((_this.searchForm.courtType && _this.searchForm.courtType == _c.courtType)
&& (_this.searchForm.queryParam && _this.searchForm.queryParam == _c.name)) {
_this.$refs.plTreeTable.setTreeExpand(p, true)
_this.$refs.plTreeTable.setTreeExpand(c, true)
_this.$refs.plTreeTable.setTreeExpand(r, true)
}
if ((!_this.searchForm.courtType || _this.searchForm.courtType == '')
&& (_this.searchForm.queryParam && _this.searchForm.queryParam == _c.name)) {
_this.$refs.plTreeTable.setTreeExpand(p, true)
_this.$refs.plTreeTable.setTreeExpand(c, true)
_this.$refs.plTreeTable.setTreeExpand(r, true)
}
if ((_this.searchForm.courtType && _this.searchForm.courtType == _c.courtType)
&& (!_this.searchForm.queryParam || _this.searchForm.queryParam == '')) {
_this.$refs.plTreeTable.setTreeExpand(p, true)
_this.$refs.plTreeTable.setTreeExpand(c, true)
_this.$refs.plTreeTable.setTreeExpand(r, true)
}
})
}
})
}
})
}
loading.close()
})
_this.tableData.forEach((v,vi)=>{
let n=0
let res=_this.$refs.plTreeTable.isTreeExpandByRow(v)
let resExpand=_this.$refs.plTreeTable.getTreeExpandRecords()
resExpand.forEach(c=>{
if(c.type=='province'){
c.children.forEach((z,x)=>{
// if(z.courtType){
// //高级
// n++
// }
if(z.children && z.children.length>0){
z.children.forEach((r,i)=>{
if(r.courtType){
// 中级
if(r.name==this.searchForm.queryParam){
n+=x
n+=i
}else{
n++
}
}
if(r.children && r.children.length>0){
r.children.forEach((g,y)=>{
if(g.courtType){
if(g.name==this.searchForm.queryParam){
n+=i
n+=x
n++
n+=y
return
}
}
})
}
})
}
})
}
})
console.log(n)
if(resExpand.length==3){
//基层
if(res){
console.log(vi)
// _this.$refs.plTreeTable.scrollToRow(v)
_this.$refs.plTreeTable.pagingScrollTopLeft(vi*60+n*30,0)
}
}else if(resExpand.length==1){
//高级
if(res){
console.log(vi,resExpand)
// _this.$refs.plTreeTable.scrollToRow(v)
_this.$refs.plTreeTable.pagingScrollTopLeft(vi*40+resExpand.length*40,0)
}
}else if(resExpand.length==2){
//中级
if(res){
console.log(vi,resExpand)
// _this.$refs.plTreeTable.scrollToRow(v)
_this.$refs.plTreeTable.pagingScrollTopLeft(vi*60+n*30,0)
}
}
})
// _this.$refs.plTreeTable.loadData(this.tableData)
_this.$refs.plTreeTable.doLayout(true)
},
好了,到这就结束了,感觉代码还是写的有点乱的,做完这个功能后感触最深的是需要提前选择对应的组件,这样可以事半功倍。
再见!🙈🙈🙈🙈🙈文章来源地址https://www.toymoban.com/news/detail-702047.html
到了这里,关于大数据量树形数据表格展示, umy-ui,的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!