vue+element实现树状表格的增删改查;使用el-table树形数据与懒加载实现树状表格增删改查

在这里插入图片描述

以下代码可以直接复制使用

一、情景: 列表是一个树状表格,可以无限添加下级,以及对列表的某一行进行增删改查(目前查没有写)。

原博链接

二、本篇是在原博主的代码基础上添加了部分功能。
功能1: 给树状表格添加虚线部分,可以更清楚树节点层级关系
功能2: 某行数据可以直接输入框编辑,也可以点击编辑按钮打开弹框编辑
功能3: 我这里树状节点一共有三种:
①顶级根节点first: 只会有最外层一个 默认就有的 可以添加下级【夹】、【页】节点
②中间夹节点middle: 通过点击【夹】节点按钮添加来的,可以继续添加下级【夹】、【页】
③末梢页节点last: 不会再有下级。只有它才有数据展示
–总结就是 中间的【夹】可以无限添加下级,【页】就是末梢节点不能添加下级。每行的数据有个字段farOrSon来判断是属于什么节点。然后展示对应的图标。在这里插入图片描述

三、部分代码详解:
–①功能其实还是使用element树形数据与懒加载,不过原博主写的更详细、功能更全,感谢!

–②表格的ref值cimsDictTable是只能给一个表格设置,否则会造成错误

–③树状表格自动展开属性是 default-expand-all ,去掉这个属性就是默认关闭的
–④:tree-props="{children:‘childNode’}" 这个childNode是你自己表格的树节点嵌套的那个字段;我的数据结构就是,childNode数组有值就是有下级,strObj有值就是右边的输入框数字。然后我的数据要求是childNode有值既有下级时候,strObj就是null。相反的strObj有值时候,childNode就是[]。所以你看到我的,【夹】都是没数据,【页】才是有数据的。如果你的要求是【夹】和【页】都有数据,既列表每行都有数据。那么你的strObj就要一直有值。
–⑤我的表格是多级表头,就是在 el-table-column 里面嵌套 el-table-column,具体看这个介绍,无论单级多级,其实数据结构是一样的对象数组,一行数据就是一个对象。
–⑥目前我的添加【夹】、【页】都是直接就加了一行,只有编辑是通过弹框修改。其实添加也可以使用这个弹框来做,逻辑可以参照编辑的。既添加记住是添加在哪个id数据下,点击缺点后,递归遍历找到这个数据将弹框值赋值给它修改既可以。
–⑦目前条件这行是设置了取列表剩余宽度。其实也可以给这列设置自适用撑开的宽度,看这篇自适应展开宽度
–⑧虚线部分是我自己计算写的样式,搜索scope.row.level这个代码就可以看到逻辑。
–⑧①首先是先计算每个行嵌套的层级level,例如【9527】这个就是嵌套了3层,就有三个竖着的虚线,遍历生成三个间距是16px的竖虚线;但是这三条虚线有可能前面的1、2条需要根据delItemFlag删除,然后虚线上移高度一半。这样你看到的一条条很长的竖线,其实是每行的竖线链接在一起形成的。
–⑧②行高时候,当前行的虚线也会多出来一截,故需要给每层嵌套的最后一行多设置个白色竖线,去遮挡多余的一截
–⑧③最后给每行设置横线虚线即可
下图就是设置虚线遇到的问题,不过目前已经解决了在这里插入图片描述

以下代码可直接复制使用

<template><div class="a_tree_box"><div><el-tableref="cimsDictTable"default-expand-all:data="tableData"style="width: 100%"row-key="id"borderstripesize="mini"class="data-table"tooltip-effect="dark"header-row-class-name="data-table-header"lazy:show-overflow-tooltip="true":load="load":tree-props="{children:'childNode'}"@selection-change="handleSelectionChange"@select="select22"@select-all="selectAll"><el-table-column label="条件" min-width="400px"><template slot-scope="scope"><!-- 这部分是设置虚线逻辑 --><template v-for="(item,l) in scope.row.level"><!-- 根据delItemFlag判断 是true或者'true'则对应的竖虚线是多余的 需要删除 --><span v-if="scope.row.delItemFlag[l] == 'false'" :key="l+1" class="l_bor1_box" :style="{'left':`${(l+1)*16 - 6}`+'px'}"></span><!-- 这个是设置横的虚线 --><span v-if="l == (scope.row.level -1)" :key="(l+1)*10000" class="l_bor2_box" :style="{'left':`${(l+1)*16 - 6}`+'px'}"></span></template><!-- 这个是设置每个层级最后的那个节点 多加一个竖线 覆盖多余的行高虚线 --><span v-if="scope.row.moreOneDash" class="more_dash" :style="{'left':`${(scope.row.level)*16 - 6}`+'px'}"></span><span class="showName">{{ scope.row.conditionName }}</span><i v-if="scope.row.farOrSon=='first'|| scope.row.farOrSon=='middle'" style="font-size:18px;margin-left:5px;color:#00ff00;cursor: pointer;" class="el-icon-folder-add" @click="addOneRow(scope.row,scope.$index,'middle')"></i><i v-if="scope.row.farOrSon=='first'|| scope.row.farOrSon=='middle'" style="font-size:18px;margin-left:5px;color:#00ff00;cursor: pointer;" class="el-icon-document-add" @click="addOneRow(scope.row,scope.$index,'last')"></i><i v-if="scope.row.farOrSon=='middle'|| scope.row.farOrSon=='last'" style="font-size:18px;margin-left:5px;color:#f1ff;cursor: pointer;" class="el-icon-edit" @click="editRow(scope.row,scope.$index)"></i><i v-if="scope.row.farOrSon=='middle'|| scope.row.farOrSon=='last'" style="font-size:18px;margin-left:5px;color:#1890FF;cursor: pointer;" type="primary" class="el-icon-close" @click="delRow(scope.row,scope.$index)"></i></template></el-table-column><el-table-column label="交强险(%)"><el-table-column label="上游" width="70px"><template slot-scope="scope"><el-input v-if="scope.row.strObj" v-model="scope.row.strObj.str1" placeholder @input="scope.row.strObj.str1=/^\d+\.?\d{0,2}$/.test(scope.row.strObj.str1)||scope.row.strObj.str1 == '' ? scope.row.strObj.str1 : scope.row.strObj.str1=''"></el-input></template></el-table-column><el-table-column label="基数" width="70px"><template slot-scope="scope"><el-input v-if="scope.row.strObj" v-model="scope.row.strObj.str2" placeholder @input="scope.row.strObj.str2=/^\d+\.?\d{0,2}$/.test(scope.row.strObj.str2)||scope.row.strObj.str2 == '' ? scope.row.strObj.str2 : scope.row.strObj.str2=''"></el-input></template></el-table-column></el-table-column><el-table-column label="车船险(%)"><el-table-column label="上游" width="70px"><template slot-scope="scope"><el-input v-if="scope.row.strObj" v-model="scope.row.strObj.str3" placeholder @input="scope.row.strObj.str3=/^\d+\.?\d{0,2}$/.test(scope.row.strObj.str3)||scope.row.strObj.str3 == '' ? scope.row.strObj.str3 : scope.row.strObj.str3=''"></el-input></template></el-table-column><el-table-column label="基数" width="70px"><template slot-scope="scope"><el-input v-if="scope.row.strObj" v-model="scope.row.strObj.str4" placeholder @input="scope.row.strObj.str4=/^\d+\.?\d{0,2}$/.test(scope.row.strObj.str4)||scope.row.strObj.str4 == '' ? scope.row.strObj.str4 : scope.row.strObj.str4=''"></el-input></template></el-table-column></el-table-column><el-table-column label="商业险(%)"><el-table-column label="上游" width="70px"><template slot-scope="scope"><el-input v-if="scope.row.strObj" v-model="scope.row.strObj.str5" placeholder @input="scope.row.strObj.str5=/^\d+\.?\d{0,2}$/.test(scope.row.strObj.str5)||scope.row.strObj.str5 == '' ? scope.row.strObj.str5 : scope.row.strObj.str5=''"></el-input></template></el-table-column><el-table-column label="基数" width="70px"><template slot-scope="scope"><el-input v-if="scope.row.strObj" v-model="scope.row.strObj.str6" placeholder @input="scope.row.strObj.str6=/^\d+\.?\d{0,2}$/.test(scope.row.strObj.str6)||scope.row.strObj.str6 == '' ? scope.row.strObj.str6 : scope.row.strObj.str6=''"></el-input></template></el-table-column></el-table-column><el-table-column label="操作" width="200px"><template slot-scope="scope"><span v-if="scope.row.farOrSon=='first'|| scope.row.farOrSon=='middle'" style="color:#00ff00;cursor: pointer;" @click="addOneRow(scope.row,scope.$index,'middle')">新增夹</span><span v-if="scope.row.farOrSon=='first'|| scope.row.farOrSon=='middle'" style="color:#00ff00;cursor: pointer;" @click="addOneRow(scope.row,scope.$index,'last')">新增页</span><span v-if="scope.row.farOrSon=='middle'|| scope.row.farOrSon=='last'" style="color:#f1ff;cursor: pointer;" @click="editRow(scope.row,scope.$index)">编辑</span><span v-if="scope.row.farOrSon=='middle'|| scope.row.farOrSon=='last'" style="color:#2593fc;cursor: pointer;" @click="delRow(scope.row,scope.$index)">删除</span></template></el-table-column></el-table><!-- 编辑回显的弹框  其实新增也可以用这个弹框但是没写 --><el-dialog title="提示" class="dia_box" :visible.sync="dialogFlag" width="500px"><el-form :model="formData"><el-form-item label="条件名称:" label-width="128px"><el-input v-model="formData.conditionName" autocomplete="off"></el-input></el-form-item><el-form-item v-if="formData.strObj" label="交强险(%)上游:" label-width="128px"><el-input v-model="formData.strObj.str1" autocomplete="off"></el-input></el-form-item><el-form-item v-if="formData.strObj" label="交强险(%)基数:" label-width="128px"><el-input v-model="formData.strObj.str2" autocomplete="off"></el-input></el-form-item><el-form-item v-if="formData.strObj" label="车船险(%)上游:" label-width="128px"><el-input v-model="formData.strObj.str3" autocomplete="off"></el-input></el-form-item><el-form-item v-if="formData.strObj" label="车船险(%)基数:" label-width="128px"><el-input v-model="formData.strObj.str4" autocomplete="off"></el-input></el-form-item><el-form-item v-if="formData.strObj" label="商业险(%)上游:" label-width="128px"><el-input v-model="formData.strObj.str5" autocomplete="off"></el-input></el-form-item><el-form-item v-if="formData.strObj" label="商业险(%)基数:" label-width="128px"><el-input v-model="formData.strObj.str6" autocomplete="off"></el-input></el-form-item></el-form><span slot="footer" class="dialog-footer"><el-button @click="dialogFlag = false">取 消</el-button><el-button type="primary" @click="changeRow">确 定</el-button></span></el-dialog><el-radio v-model="addOrEdit" :label="false">无数据列表</el-radio><el-radio v-model="addOrEdit" :label="true">有数据列表</el-radio><el-button @click="lookData">点击打印树表数据</el-button></div></div>
</template><script>
export default {name: 'TreeTable',data () {return {addOrEdit: true, // false无数据列表  true是有数据列表ref: 'cimsDictTable',tableData: [], // 这个是真正的展示树状列表selectAddLast: null, // 点击树表的添加  middle是添加中间  last 是添加最后末梢cimsDictTable: [],sourceData: [{id: 3, // 注意数据必须要有id  否则树状数据渲染会出问题 那么我们可以再前端新增时候以时间戳为id 真正保存到数据库后会有真实idconditionName: '顶级条件',strObj: null,parentId: null,childNode: [] // childNode有值 就会形成对应的嵌套下级}],dialogFlag: false,formData: {id: null,conditionName: '',strObj: {str1: '',str2: '',str3: '',str4: '',str5: '',str6: ''}}}},watch: {addOrEdit (val) {if (!this.addOrEdit) {// 打开一个全新的列表this.getNewData()} else {// 根据id找到某个数据列表 回显 假设id是123this.getIdDate(123)}}},mounted () {if (!this.addOrEdit) {// 打开一个全新的列表this.getNewData()} else {// 根据id找到某个数据列表 回显 假设id是123this.getIdDate(123)}},beforeMount () {},methods: {getNewData () {this.$set(this.sourceData[0], 'childNode', [])this.initData()},// 获取页面数据回显getIdDate (id) {// 总数据回显 ---  假设给的数据  这条数据是默认数据的childNodelet dataArr = [{id: 31,conditionName: '条件--【页】--页不可添加下级 是末梢last',strObj: {str1: '11',str2: '22',str3: '1',str4: 2,str5: '2',str6: '2'},parentId: 3,childNode: []},{id: 32,conditionName: '条件--【夹】--夹可以添加下级 是中间middle',strObj: null,parentId: 3,childNode: [{id: 311,conditionName: '机密的任务',strObj: null,parentId: 32,childNode: [{id: 3221,conditionName: '这个条件名字比较长 会自动换行会自动换行会自动换行会自动换行会自动换行会自动换行会自动换行会自动换行',strObj: {str1: '11',str2: '121',str3: '1',str4: 2,str5: '2',str6: '2'},parentId: 311,childNode: []},{id: 3222,conditionName: '9527',strObj: {str1: '11',str2: '1',str3: '1',str4: 2,str5: '2',str6: '2'},parentId: 311,childNode: []},{id: 3223,conditionName: '夹文件',strObj: null,parentId: 311,childNode: []}]},{id: 321,conditionName: '附加条件-日后再说',strObj: {str1: '11',str2: '33',str3: '1',str4: 2,str5: '2',str6: '2'},parentId: 3,childNode: []}]},{id: 33,conditionName: '条件夹',strObj: null,parentId: 3,childNode: []}]// // 设置id---没有id树渲染会报错--// let num = 121210// function setId (arr, pId) {//   for (let j = 0; j < arr.length; j++) {//     const element = arr[j]//     if (element.childNode.length == 0) {//       element['id'] = num//       element['parentId'] = pId//       num++//     } else {//       element['id'] = num//       element['parentId'] = pId//       num++//       setId(element.childNode, element['id'])//     }//   }// }// setId(dataArr, 983873292643)// console.log(dataArr)// 获取数据嵌套的层级function setLevel (arr, levelNum) {for (let j = 0; j < arr.length; j++) {const element = arr[j]if (element.childNode.length == 0) {element['level'] = levelNum} else {element['level'] = levelNumsetLevel(element.childNode, levelNum + 1)}}}setLevel(dataArr, 1)this.$set(this.sourceData[0], 'childNode', dataArr)console.log(this.sourceData)this.initData()},// 在树表每次数据变化时候 新增 删除 编辑  都需要设置出新的状态 判断是中间层 而没有子集checkEveryItem () {// 这一步是找到空的中间层 需要添加页let noChildAndNoRate = []function checkIsNeedChild (arr, ruleName) {for (let j = 0; j < arr.length; j++) {const element = arr[j]if (element.childNode.length == 0) {if (element.strObj == null || element.strObj == 'null') {element['isNeedLast'] = truenoChildAndNoRate.push({ cantName: ruleName.trim() + '/' + element.conditionName.trim() })} else {element['isNeedLast'] = false}} else {element['isNeedLast'] = falsecheckIsNeedChild(element.childNode, ruleName.trim() + '/' + element.conditionName.trim())}}}checkIsNeedChild(this.tableData, '')console.log('中间层的子集为空也就是没末梢', noChildAndNoRate)// 这个是找到每层级最后一个 判断是中间层 且 还有childNode  那么他的childNode就需要删除多余虚线(子集childNode多余的虚线就是父级的的那个嵌套层级 那条虚线)// 第一步先找到 父级(满足最后一层是中间层 且有子集childNode)function set_setLast (arr) {for (let j = 0; j < arr.length; j++) {const element = arr[j]if (element.childNode.length == 0) {if (j == (arr.length - 1)) {// element['isLastZhongjianAndHasChl'] = trueif ((element.strObj == null || element.strObj == 'null') && element.childNode.length > 0) {element['isLastZhongjianAndHasChl'] = true} else {element['isLastZhongjianAndHasChl'] = false}} else {element['isLastZhongjianAndHasChl'] = false}} else {if (j == (arr.length - 1)) {// element['isLastZhongjianAndHasChl'] = trueif ((element.strObj == null || element.strObj == 'null') && element.childNode.length > 0) {element['isLastZhongjianAndHasChl'] = true} else {element['isLastZhongjianAndHasChl'] = false}} else {element['isLastZhongjianAndHasChl'] = false}set_setLast(element.childNode)}}}// console.log(this.tableData[0].childNode)set_setLast(this.tableData[0].childNode)this.tableData[0]['isLastZhongjianAndHasChl'] = true// 第二步 根据isLastZhongjianAndHasChl和所需要删除的层次level 递归遍历 将需要删除虚线的标志为true fasle是不删 将几条虚线删不删的值放在一个数组内function delArrItem (arr, flagDel, num, farArr) {for (let j = 0; j < arr.length; j++) {const element = arr[j]let delItemFlag = JSON.parse(JSON.stringify(farArr)) // 必须深拷贝 将父级的数组继承到子集使用 深拷贝 才不会改变父级数组值for (let h = 0; h < element.level; h++) {if (flagDel == 'true' || flagDel == true) {if ((h + 1) == num) {delItemFlag[h] = 'true'} else {if (delItemFlag[h] == 'true' || delItemFlag[h] == true) { // 针对需要删除的 就不要再赋值} else {delItemFlag[h] = 'false'}}} else {if (delItemFlag[h] == 'true' || delItemFlag[h] == true) {} else {delItemFlag[h] = 'false'}}}element['delItemFlag'] = delItemFlagif (element.childNode.length == 0) {} else {delArrItem(element.childNode, element.isLastZhongjianAndHasChl, element.level, element['delItemFlag'])}}}delArrItem(this.tableData[0].childNode, false, 0, [])// this.tableData[0]['isLastZhongjianAndHasChl'] = true// 这个是找到每层级最后一个 然后标志出来true 最后画虚线时候需要 单独多画一个线用来遮挡多余的当前层虚线(因为行高自适应 当某层的末梢行高超过50px时候 之前设置的top: -24px就不够了 会多出来一部分虚线 故需要遮挡掉)function set_lastMoreDash (arr) {for (let j = 0; j < arr.length; j++) {const element = arr[j]if (element.childNode.length == 0) {if (j == (arr.length - 1)) {element['moreOneDash'] = true} else {element['moreOneDash'] = false}} else {if (j == (arr.length - 1)) {element['moreOneDash'] = true} else {element['moreOneDash'] = false}set_lastMoreDash(element.childNode)}}}set_lastMoreDash(this.tableData[0].childNode)console.log('处理虚线', this.tableData)},lookData () {console.log('tableData--', this.tableData)},Menuclose () {this.dialogVisibleMenu = false},setRowData (row, parentId, farOrSon, val) {let strObj = nullif (farOrSon == 'last') {strObj = {str1: '',str2: '',str3: '',str4: '',str5: '',str6: ''}} else {strObj = null}return {id: new Date().valueOf(),conditionName: val.newName,parentId: parentId || null,strObj: strObj,edit: true,add: true,childNode: [],level: (row.level >= 0) ? (row.level + 1) : 1,farOrSon: farOrSon}},// 手动勾选数据行select22 (selection, row) {// 判断当前行是否选中// 不需要判断 id, 因为引用地址相同const selected = selection.some((item) => item === row)// 处理所有子级this.selectChildren(row, selected)},selectAll (selection) {/** 这里引用别人的代码:* selectAll 只有两种状态: 全选和全不选* 所以我们只需要判断一种状态即可* 而且也不需要判断 id, 因为 selection 和 this.data 中对象引用地址是相同的*/// tableData 第一层只要有在 selection 里面就是全选const isSelect = this.tableData.some((item) => selection.includes(item))if (isSelect) {selection.forEach((item) => {this.selectChildren(item, isSelect)})} else {this.tableData.forEach((item) => {this.selectChildren(item, isSelect)})}},selectChildren (row, selected) {if (row['childNode'] && Array.isArray(row['childNode'])) {row['childNode'].forEach((item) => {this.toggleSelection(item, selected)this.selectChildren(item, selected)})}},selectionChange (selection) {this.debounce(this.tableSelectChange, 100, selection)},toggleSelection (row, select) {row &&this.$nextTick(() => {this.$refs[this.ref] &&this.$refs[this.ref].toggleRowSelection(row, select)})},// 防抖debounce (fun, wait, params) {clearTimeout(this.timeout)this.timeout = setTimeout(fun, wait, params)},getSelectedList () {// 获取选中数据源let list = JSON.parse(JSON.stringify(this.cimsDictTable))list.forEach((e) => (e.childNode = null))return list},addRow (row, id, farOrSon, val) {console.log(row, id)// 去掉这个if和else是 为了达到可以不保存 就继续添加下级// if (!row.add) {// 新增行数据let addrow = this.setRowData(row, row.id, farOrSon, val)// 新增if (row.childNode) {row.childNode.push(addrow)} else {// 添加数据this.$set(row, 'childNode', [addrow])}// 展开行this.$nextTick(() => {// 更新后打开节点this.$refs.cimsDictTable.toggleRowExpansion(row, true)// 刷新树this.refTable()})// } else {//   this.$message({//     message: '请保存后再继续添加子节点!',//     type: 'warning'//   })// }// 每次添加编辑删除树表需要 重新计算出新属性状态this.checkEveryItem()},addOneRow (row, index, farOrSon) {this.selectAddLast = farOrSonlet item = {}let val = { newName: `新的条件${Math.floor(Math.random() * (1 - 1000) + 1000)}` }// 假设这个就是新增是一行的值console.log(1123, val)function findRow (arrA, Id, val) {for (let h = 0; h < arrA.length; h++) {const element = arrA[h]if (element.childNode.length == 0) {if (element.id == Id) {item = element}} else {if (element.id == Id) {item = element}findRow(element.childNode, Id, val)}}}findRow(this.tableData, row.id, val)this.addRow(item, row.id, this.selectAddLast, val)},updateTableTree (parentId, nodes) {// 更新需要先更新上级节点this.$set(this.$refs.cimsDictTable.store.states.lazyTreeNodeMap,parentId,nodes)},refTable () {let _this = thisfunction dg (data) {for (let i in data) {if (data[i].childNode) {_this.updateTableTree(data[i].id, data[i].childNode)dg(data[i].childNode)}}}dg(this.tableData)},// 删除当前条及对应下级数据deleteTable (row, index, arr) {for (let i = 0; i < arr.length; i++) {const element = arr[i]if (element.id == row.id) {arr.splice(i, 1)} else {if (element.childNode.length > 0) {this.deleteTable(row, index, element.childNode)} else {}}}},delRow (row, index) {console.log(row, index)this.$confirm('确认删除该条件及下级条件?', '提示', {confirmButtonText: '确定',cancelButtonText: '取消',type: 'warning'}).then(() => {this.deleteTable(row, index, this.tableData)// 每次添加编辑删除树表需要 重新计算出新属性状态this.checkEveryItem()}).catch(() => {this.$message({type: 'info',message: '已取消删除'})})// 删除行let delArr = []function dg (data) {for (let i in data) {// 过滤当前新增的数据if (!data[i].add) {delArr.push(data[i].id)}if (data[i].childNode) {dg(data[i].childNode)}}}dg([row])// 删除},editRow (row, index) {// 编辑this.$set(row, 'edit', true)// 使用深拷贝 否则会影响改弹框 就直接影响列表数据了 我们要的是改了弹框点击确认才改列表数据 故需要深拷贝this.formData = JSON.parse(JSON.stringify(row))this.dialogFlag = true},// 点击了弹框的确定changeRow () {let val = this.formDatafunction findId (arrA, Id, val) {for (let h = 0; h < arrA.length; h++) {const element = arrA[h]if (element.childNode.length == 0) {if (element.id == Id) {element['conditionName'] = val.conditionNameelement['strObj'] = val.strObjconsole.log(12121, element, val)}} else {if (element.id == Id) {element['conditionName'] = val.conditionNameelement['strObj'] = val.strObjconsole.log(12121, element, val)}findId(element.childNode, Id, val)}}}findId(this.tableData, val.id, val)this.dialogFlag = false// 每次添加编辑删除树表需要 重新计算出新属性状态this.checkEveryItem()},proTableData (data) {let _this = this// 处理数据function dg (data) {for (let i in data) {_this.$set(data[i], 'edit', false)if (data[i].childNode) {// 重要:树状节点数据刷新_this.updateTableTree(data[i].id, data[i].childNode)dg(data[i].childNode)}}}dg(data)// 给数据判断添加父子节点标识function setFarSon (data) {for (let index = 0; index < data.length; index++) {const element = data[index]// console.log(element.parentId, element.parentId == undefined)if (element.parentId == undefined || element.parentId == null) {element['farOrSon'] = 'first'setFarSon(element.childNode)} else {if (element.strObj == null || element.strObj == 'null') {element['farOrSon'] = 'middle'setFarSon(element.childNode)} else {element['farOrSon'] = 'last'}}}}setFarSon(data)},initData () {// 数据加载   模仿数据请求let res = JSON.parse(JSON.stringify(this.sourceData))// 数据处理 添加编辑标识this.proTableData(res)this.tableData = res// 每次添加编辑删除树表需要 重新计算出新属性状态this.checkEveryItem()},load (tree, treeNode, resolve) {// 节点加载setTimeout(() => {resolve(tree.childNode)}, 1000)},handleSelectionChange (val) {// 全选this.cimsDictTable = val}}
}
</script><style lang="less" scoped>
// 树状表格样式
.a_tree_box {width: calc(100vw - 300px);height: 100%;margin-bottom: 20px;padding: 40px;.cd-tool {display: flex;flex-direction: row;}.data-table {/deep/ .cell {display: flex;align-items: center;}// 固定表格高度/deep/td {height: 50px;padding: 0;}/deep/tbody {tr {overflow: hidden;td {// width: 40px !important;// background-color: #1fff!important;// background-color: rgba(255, 255, 255, 0); //必须设置为透明色  否则 warning-row 显示不出来.cell {padding: 0 !important;// background-color: #1fff;height: 100%;position: relative;overflow: visible !important;.l_bor1_box {top: -24px;display: inline-block;width: 1px;height: 100%;border-left: 1px dashed #ccc;position: absolute;}.l_bor2_box {display: inline-block;width: 30px;height: 1px;border-top: 1px dashed #ccc;position: absolute;}.more_dash {display: inline-block;width: 1px;height: 50%;border-top: 1px dashed #ccc;position: absolute;top: calc(50% - 1px);// background-color: rgba(248, 250, 252, 1);background-color: rgb(255, 253, 253);}.el-table__expand-icon {//这个是将所有的条件前面的图标 固定掉display: inline-block;width: 20px !important;min-width: 20px !important;position: relative;z-index: 999;// background-color: #1fff;}.el-table__placeholder {//这个是将所有的条件前面的空白 固定成20px   这样才会有间隔层级视觉效果 如果不做固定 会导致 条件文字多的时候 有的是20xp 有的不是 就导致看起来没层级一样display: inline-block;width: 25px !important;max-width: 25px !important;min-width: 25px !important;}.l_bor3_box {display: inline-block;width: 1px;height: 15px;border-left: 1px dashed #ccc;top: 15px;left: -13px;position: relative;}}}td:nth-child(n + 2) {.cell {span {// background-color: #1fff;display: inline-block;width: 100%;text-align: center;}}}}}}.showName {display: inline-block;// max-width: 100px;// white-space: nowrap;white-space: wrap;overflow: hidden;text-overflow: ellipsis;}.one_two {width: 20px;height: 20px;margin-right: 3px;}.isML10 {margin-left: 10px; //判断有无数据 没数据就需要左偏移对齐}.abcd {width: 20px;height: 20px;cursor: pointer;margin-left: 3px;}.tip_icon {width: 20px;height: 20px;cursor: pointer;position: relative;top: -1px;left: 30px;}.tip_box {display: inline-block;width: fit-content !important;min-width: 105px;color: red;font-weight: 700;position: relative;top: 1px;margin-left: 33px;font-size: 17px;}/deep/ .el-input__inner {margin-left: 3px !important;padding: 0 !important;width: 44px !important;height: 25px !important;text-align: center !important;}.dia_box {/deep/.el-input {text-align: left;.el-input__inner {width: 300px !important;height: 35px !important;text-align: left !important;}}}
}
</style>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/403253.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ISCSI 1-由零开始

iSCSI的概念 iSCSI&#xff0c;即Internet SCSI&#xff0c;是IETF制订的一项标准&#xff0c;用于将SCSI数据块映射为以太网数据包。从根本上说&#xff0c;它是一种基于IP Storage理论的新型存储技术&#xff0c;该技术将存储行业广泛应用的SCSI接口技术与IP网络技术相结合&a…

存储技术与iSCSI

本章主要介绍基于IP SAN的网络存储iSCSI。iSCSI技术以其低廉的构建成本和优秀的存储性能&#xff0c;博得了很多CIO和存储管理员的喜爱&#xff0c;目前陆续进入企业应用领域&#xff0c;推动了企业的存储环境向集中式转变。虽然&#xff0c;目前对于iSCSI应该在什么样的环境中…

lvs和HA的高可用性

Heartbeat实现Lvs高可用和HA高可用效果图如下1、heartbeat的介绍Heartbeat 项目是 Linux-HA 工程的一个组成部分&#xff0c;它实现了一个高可用集群系统。心跳服务和集群通信是高可用集群的两个关键组件&#xff0c;在 Heartbeat 项目里&#xff0c;由 heartbeat 模块实现了这…

输入框限制只能输入数字,正数、负数、0,最多两位小数;数字输入框可以输入负数,并最多保留两位小数;el-number-input去掉四舍五入和自动补齐小数;

场景&#xff1a; –要求1&#xff1a;输入框只能输入数字&#xff0c;可以使正数、负数、0&#xff0c;小数点最多保留两位。 –要求2&#xff1a;不需要自动补齐小数点&#xff0c;也不需要自动四舍五入。 element-ui的数字输入框el-input-number只能满足要求1&#xff0c;所…

【工具】Win 7/8/10 下使用 VC++6.0

Microsoft Visual C&#xff08;也就是 MSVC或者VC&#xff09;&#xff0c;是大部分计算机专业学生接触的第一款编译器。它具有轻量&#xff0c;界面简洁等优点&#xff0c;也是许多计算机考试的指定工具。VC6.0已经推出近20年&#xff0c;仍旧深受许多编程人员的喜爱&#xf…

【maven3学习之一】window7下maven环境搭建

2019独角兽企业重金招聘Python工程师标准>>> 软件准备&#xff1a; jdk-7u10-windows-i586 apache-maven-3.0.4-bin maven介绍&#xff1a; 按照一般的套路老说应该要说明一下maven&#xff0c;觉得maven就是一个项目管理的框架&#xff0c;因为之前的一个项目对mav…

解决去除“请输入有效值。两个最接近的有效值分别为1和2“提示

场景&#xff1a;el-input输入框&#xff0c;hover上去会有"请输入有效值。两个最接近的有效值分别为1和2"提示。 只需要给el-input加上属性 :step“0.01” 即可&#xff0c;注意精确度与你的小数点位数有关。也就是说如果你是三位小数点&#xff0c;那就是:step“0.…

【贪心】Vijos P1615 旅行

题目链接&#xff1a; https://vijos.org/p/1615 题目大意&#xff1a; N条路&#xff0c;路的高度给你&#xff0c;走一条路的耗费体力是从上一条路的高度到当前路高度的绝对值差。 可以改变一条路的高度&#xff0c;耗费的体力等于改变前后的路高度差。求最小耗费体力。 题目…

向 Web 开发人员推荐35款 JavaScript 图形图表库

From: http://www.cnblogs.com/lhb25/p/35-javascript-chart-and-graph-libraries.html 图表是数据图形化的表示&#xff0c;通过形象的图表来展示数据&#xff0c;比如条形图&#xff0c;折线图&#xff0c;饼图等等。可视化图表可以帮助开发者更容易理解复杂的数据&#xff…

解决列表某项文字过度过多 需要自适应撑开高度展示 其他项目按照行高居中

解决列表某项文字过度过多 需要自适应撑开高度展示 其他项目按照行高居中 以下代码可直接复制&#xff1a; 两种方法&#xff1a;分别是方法1&#xff1a;bfc配合浮动撑高 其他项目子绝父相 方法二&#xff1a;第一项也是相对定位&#xff08;不推荐&#xff09; <templat…

uni-app更新某个组件版本;uni-app更新插件版本;uni-app更新uni_modules插件;uni-app小程序更新某一个组件的版本库

uni-app官方介绍的更新某一个组件的uni_modules方法 注意&#xff1a;本篇只是记录更新uni-app的组件库下某一个组件的版本。不是更新微信小程序版本。 场景原因&#xff1a;项目最初是去年开发的&#xff0c;当时下载了uni-app的自带组件库。但是时间筛选器uni-datetime-picke…

课文《小站》

小站 --作者&#xff1a;袁鹰 这是一个铁路线上的小站&#xff0c;只有慢车才停两三分钟。快车疾驰而过&#xff0c;旅客们甚至连站名还来不及看清楚。 就在这一刹那&#xff0c;你也许看到一间红瓦灰墙的小屋&#xff0c;一排漆成白色的小栅栏&#xff0c;或者还有三五个人影…

wordpress在新窗口打开留言者链接

为什么80%的码农都做不了架构师&#xff1f;>>> 没有什么技术含量可言&#xff0c;网上早有高手支招&#xff0c;但其方法在我现在使用的inove主题下不行&#xff0c;于是自己研究了下代码&#xff0c;完美解决&#xff0c;分享一下&#xff1a; 一般主题都可以这…

vue上传图片加水印;js上传图片添加水印;vue给图片添加水印;canvas图片添加水印;canvas画布导出图片

uni-app微信小程序图片加水印&#xff0c;点击看这篇 需求场景&#xff1a; 要求上传图片&#xff0c;并给图片添加水印。传给后端的也是有水印的图片。 逻辑步骤&#xff1a; 通过input上传图片&#xff0c;拿到图片的信息和base64&#xff0c;将图片绘制到画布上&#xff0c;…

The path is not a valid path to the xx-generic kernel headers

如果在安装 VMware Tools 的过程中弹出该选项&#xff0c;按照以下步骤进行操作&#xff1a; 1. 检查系统内是否已经安装好相应的 kernel headers&#xff0c;比如我的系统&#xff1a; 如果没有该目录的话&#xff0c;那么需要安装以下资源&#xff1a; sudo apt-get instal…

库-libuv:概述

From&#xff1a; http://blog.chinaunix.net/uid-28458801-id-4464173.html libuv 是 Node 的新跨平台抽象层&#xff0c;用于抽象 Windows 的 IOCP 及 Unix 的 libev。作者打算在这个库的包含所有平台的差异性。特性&#xff1a;非阻塞 TCP 套接字非阻塞命名管道UDP定时器子进…

input上传图片;input上传file;vue上传图片。js读取文件的base64;通过File文件读取base64;

本篇是通过File文件来获取base64的&#xff1b;如果需要 通过文件url获取base64看这篇 需求&#xff1a;上传图片并获取base&#xff0c;用的是input file功能上传 注意点&#xff1a;input上传相同文件不触发的原因。需要将inputDOM.value null (不过置空后 29行的打印 就看不…

C#WinForm WebBrowser (二) 实用方法总结

实用方法1&#xff1a;获取状态栏信息 void webBrowser1_StatusTextChanged(object sender, EventArgs e){ label1.Text webBrowser1.StatusText;} 实用方法2&#xff1a;页面跳转后改变地址栏地址//在Navigated事件处理函数中改变地址栏地址是最恰当的&#xff1a;private…

虚拟机找不到/mnt/hgfs挂载目录

如果在安装好 VMware Tools 并在设置里面设定好共享目录之后仍然找不到 /mnt/hgfs 默认挂载目录&#xff0c;那么尝试以下步骤&#xff1a;1. 确认VMware Tools 和共享目录设定已经完成&#xff1a;2. 如果操作结果如上所示&#xff0c;那么表示前提条件准备充足啦&#xff0c;…

pdf上传及预览;file上传pdf文件及预览;vue上传pdf文件及预览;vue-pdf预览pdf文件

需求&#xff1a;上传pdf文件&#xff0c;并点击可以打开预览。使用input的file功能即可完成&#xff0c;预览只需要跳转到pdf的url地址即可。 1.使用iframe直接预览 2.vue-pdf参考 3.vue-pdf报错解决 以下代码可直接复制使用&#xff01;&#xff01;&#xff01;有效的可以点…