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>

参考:

vue 为element树形组件el-tree添加虚线,指示线

vue中el-tree增加节点后重新刷新

文章来源:https://blog.csdn.net/zhangruilinmoo/article/details/135122263
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。