Vue+ElementUi 基于Tree实现动态节点添加,节点自定义为输入框列
2023-12-21 09:30:02
Vue+ElementUi 基于Tree实现动态节点手动添加,节点自定义为输入框列
代码
<el-steps :active="active" finish-status="success" align-center>
<el-step title="test1"/>
<el-step title="test2"/>
<el-step title="test3"/>
</el-steps>
<el-row style="margin-top:15px">
<el-row v-if="active == 0">
.....
</el-row>
<el-row v-if="active == 1">
<el-tree
v-if="reloadStatus"
ref="tree"
:data="chargebackData"
:render-content="renderContent"
:render-after-expand=true
:expand-on-click-node=false
:default-expand-all=true
icon-class="el-icon-circle-plus-outline"
class="tree-line"
node-key="id"
>
</el-tree>
</el-row>
<el-row v-if="active == 2">
....
</el-row>
</el-row>
<el-row style="text-align: right;">
<el-button style="margin-top: 12px;" @click="next">{{this.active == 2 ? '确认' : '下一步'}}</el-button>
</el-row>
</el-row>
数据以及树节点自定义内容
<script>
export default {
data(){
return {
//步骤条 当前选择的下标(从0开始)
active: 0,
//步骤条第一步所需的数据
stepsOneData: {},
//步骤条第二步所需的数据
stepsTwoData: [],
//tree数据 重新加载使用
reloadStatus: true,
//tree数据
chargebackData:[
{
createItemCount:0,//只针对一级节点
chargebackItemId:undefined,
amount: undefined,
children:[]
}
],
//步骤条的下一步是否可以通过
isNext: true,
}
},
methods:{
/*
步骤条点击 下一步 按钮 触发
*/
next() {
this.dialogContentLoading = true
if(this.active == 0){
//这里可以查询后端结果返回丰富
this.stepsTwoData = [...]
}else if(this.active == 1){
//2.清除无效数据
let handleData = JSON.parse(JSON.stringify(this.chargebackData))
//2.1请求一级节点的数据
let arr = handleData.filter(item => item.itemName != undefined || item.itemName != null || item.itemName == '')
//2.2处理二级节点的数据
for(let i=0; i< arr.length ; i++){
arr[i].children = arr[i].children.filter(item => item.key != undefined || item.key != null || item.key == '')
}
this.showChargebackData = arr
}else if(this.active = 2){//确认按钮触发
let list = JSON.parse(JSON.stringify(this.showChargebackData))
let arr = this.showChargebackData
let data = []
for(let i = 0; i < arr.length; i++){
let obj = {}
obj.orderId = this.form.id
obj.userId = this.form.userId
obj.chargebackItemId = arr[i].chargebackItemId
obj.amount = arr[i].amount
if(arr[i].children.length > 0){
obj.detail = JSON.parse(JSON.stringify(arr[i].children))
}
data.push(obj)
}
console.log("data",data)
this.active = 0
this.stepsOneData = {}
this.stepsTwoData = []
this.chargebackData = [
{
createItemCount:0,//只针对一级节点
chargebackItemId:undefined,
amount: undefined,
children:[]
}
]
this.dialogContentLoading = false
this.open = false
return
}
if (this.active++ > 1) this.active = 0;
},
/*
tree 树节点处理
@param node 当前节点对象
@param data 当前节点数据对象
*/
renderContent(h, { node, data, store }){
return (
<el-row style="width:100%">
{node.level == 1 ? (
<el-row class="row-col-title">
<el-col span={2} class="col-title">
<span>扣款项:</span>
</el-col>
<el-col span={6}>
<el-select placeholder="请求选择扣款项" v-model={data.itemName} onChange={(val) => this.selectChangeHandle(val,node,data)} clearable>
{
this.stepsTwoData.map((item,index) => {
return (
<el-option key={index} value={item.itemName}>{item.itemName}</el-option>
)
})
}
</el-select>
</el-col>
<el-col span={3} class="col-title">
<span>退款项总金额:</span>
</el-col>
<el-col span={6}>
<el-input placeholder="请输入退款项总金额" v-model={data.amount}>
<template slot="append">元</template>
</el-input>
</el-col>
<el-col span={5} style="margin-left:20px">
<el-button type="primary" onClick={() => this.addChangeHandle(node, data, true)}>
<i class="el-icon-circle-plus-outline"></i>
</el-button>
<el-button type="primary" onClick={() => this.reduceChangeHandle(node, data, true)}>
<i class="el-icon-remove-outline"></i>
</el-button>
</el-col>
</el-row>
) : ''}
{
node.level != 1 ? (
<el-row gutter={20}>
<el-col span={10}>
<el-input placeholder="退款项明细" v-model={data.key}/>
</el-col>
<el-col span={10}>
<el-input placeholder="退款项明细金额" v-model={data.value} onInput={(value) => this.computeItem(value,node)}/>
</el-col>
<el-col span={4}>
<el-button type="primary" onClick={() => this.addChangeHandle(node, data, false)}>
<i class="el-icon-circle-plus-outline"></i>
</el-button>
<el-button type="primary" onClick={() => this.reduceChangeHandle(node, data, false)}>
<i class="el-icon-remove-outline"></i>
</el-button>
</el-col>
</el-row>
) : ''
}
</el-row>
)
},
/*
步骤条-扣除项-扣除项下拉列表选择option时触发
@param val 当前选中的option key值
@param node 当前节点对象
@param data 当前节点数据对象
*/
selectChangeHandle(val,node,data){
if(val){//选中时
if(node.level == 1){//扣除项
let target = this.stepsTwoData.filter(item => item.itemName == val)[0]
//以下参数不会导致tree自动重新渲染tree组件,但数据是存在的,如果需要重新渲染,手动调用 treeRefresh()
data.itemName = target.itemName
data.chargebackItemId = target.id
//添加一个子节点(一个一级节点一次添加)
if(data.createItemCount == 0){
let children = {
key:undefined,
value: undefined
}
data.createItemCount += 1
data.children.push(children)
this.treeRefresh()
}
}
}else{//清除选择时
//清空扣款项的扣款明细列表
data.createItemCount = 0
data.amount = undefined
data.children = []
this.treeRefresh()
}
},
/*
点击添加按钮触发
@param node 当前节点对象
@param data 当前节点数据对象
@param isOneLevel 当前节点是否为一级节点
*/
addChangeHandle(node, data, isOneLevel){
if(isOneLevel){//一级节点的添加
let obj = {
createItemCount:0,//只针对一级节点
chargebackItemId:undefined,
amount: undefined,
children:[]
}
this.chargebackData.push(obj)
this.treeRefresh()
}else{//非一级节点(二级)的添加
let children = {
key:undefined,
value: undefined
}
node.parent.data.children.push(children)
this.treeRefresh()
}
},
/*
点击减号按钮触发
@param node 当前节点对象
@param data 当前节点数据对象
@param isOneLevel 当前节点是否为一级节点
*/
reduceChangeHandle(node, data, isOneLevel){
if(isOneLevel){//一级节点
if(this.chargebackData.length == 1){
this.$modal.msgError("扣款项已达最低条数限制,无法删除");
return
}
let delIndex = this.chargebackData.indexOf(data)
if(delIndex > -1){
this.chargebackData.splice(delIndex, 1)
this.treeRefresh()
}
}else{//非一级(二级)节点
let arr = node.parent.data.children
if(arr.length == 1){
this.$modal.msgError("当前扣款项明细已达最低条数限制,无法删除");
return
}
let delIndex = arr.indexOf(data)
if(delIndex > -1){
arr.splice(delIndex, 1)
this.treeRefresh()
}
}
},
//输入扣款项明细时计算金额并自动填充扣款项总金额中
computeItem(value,node){
let val = Number(value)
if(isNaN(val)){
this.isNext = false
this.$modal.msgError("金额格式错误");
return
}
this.isNext = true
//计算价格
let parentData = node.parent.data
let sonData = JSON.parse(JSON.stringify(parentData.children))
let sum = 0
for(let i = 0; i < sonData.length; i++){
//排除值为空的情况
if(sonData[i].value){
sum += Number(sonData[i].value)
}
}
parentData.amount = sum + ''
},
/*
扣除项树节点手动刷新
*/
treeRefresh(){
this.reloadStatus = false;
this.$nextTick(() => {
this.reloadStatus = true;
})
}
}
}
</script>
相关样式:
<style lang="scss">
.tree-line{
.el-tree-node__content {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
height: 50px;
cursor: default;
}
.row-col-title{
display: flex;
}
.row-col-title > .el-col {
margin: auto 0;
}
.col-title{
text-align: right;
}
/* 以下全是分支相关样式 start */
.el-tree-node {
position: relative;
padding-left: 16px; /*缩进量*/
}
.el-tree-node__children {
padding-left: 16px; /*缩进量*/
}
/* 竖线 */
.el-tree-node::before {
content: "";
height: 100%;
width: 1px;
position: absolute;
left: -3px;
top: -12px;
border-width: 1px;
border-left: 1px solid #52627C;
}
/* 当前层最后一个节点的竖线高度固定 */
.el-tree-node:last-child::before {
height: 38px; /* 可以自己调节到合适数值 */
}
/* 横线 */
.el-tree-node::after {
content: "";
width: 45px;
height: 20px;
position: absolute;
left: -3px;
top: 25px;
border-width: 1px;
border-top: 1px solid #52627C;
}
/* 去掉最顶层的虚线,放最下面样式才不会被上面的覆盖了 */
& > .el-tree-node::after {
border-top: none;
}
& > .el-tree-node::before {
border-left: none;
}
/* 展开关闭的icon */
.el-tree-node__expand-icon{
font-size: 16px;
/* 叶子节点(无子节点) */
&.is-leaf{
color: transparent;
/*display: none;*/ /* 也可以去掉 */
}
}
/* 以上全是分支相关样式 end */
}
</style>
参考:
文章来源:https://blog.csdn.net/zhangruilinmoo/article/details/135122263
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!