vue小总结

建立本地分支并关联远程分支 git checkout -b feature-Task202

从远程分支拉取代码   git pull develop【关联的远程源】 develop【远程指定分支】
本地推送   git push develop【关联的远程源】 feature-Task202【本地分支名】
添加远程源   git remote add origin【远程源】 xxxxxxx.git
设置远程源   git remote set-url origin URL
代码暂存   git stash
代码还原  git stash pop
代码合并(合并指定分支到当前分支)   git merge dev
合并单一提交   git cherry-pick commit-id
删除分支   git branch -d dev
查看本地分支   git branch
查看本地分支和远程分支  git branch -a

创建vue-cli项目遇到上下选择失效问题

winpty vue.cmd create 项目名称

和git创建关联

 git remote add origin +远程的http(建立他们之间的连接)
 git push origin master  推上去
 git remote -v 查看是否链接成功

vue中v-bind:class

<div v-bind:class="[isActive ? activeClass : '', errorClass]"></div>(绑定一个三元运算符)

自定义指令

 <div class="tab-title"
      v-nav-current="{
      	cur,
    	className:'allstyle',
      	activeClass:'activestyle'
      }"
 >
 //把自定义指令写在父亲的div中  这里的v-nav-current就是我们起的那个js的名字  navCurrent.js
  <span class="allstyle" v-for="items,index in tj" :key='index'  @click="changeNum(index)">{{items}}</span>


</div>
export default{
  bind(el,binding,vnode){
    console.log(el)
    console.log(binding.value.className)
    const _a = el.getElementsByClassName(binding.value.className)
    const _b = binding.value
    _a[_b.cur].className += ` ${_b.activeClass}`
  },
  update(el,binding,vnode){
    const _a = el.getElementsByClassName(binding.value.className)
    const _b = binding.value
    const _oldb = binding.oldValue
    _a[_oldb.cur].className = ` ${_b.className}`
    _a[_b.cur].className += ` ${_b.activeClass}`
  }
}

vue组件之间的通信

1.父组件向子组件传值
父组件中把父组件的值 通过props传给子组件 然后再父组件中展示出来
父组件:  <zujian1 :users="users"></zujian1>  第一个users是自定义的名称  第二个是我们想要传的值
子组件 在data下面写一个  
	props:["users"], (当为数组或是值的时候)
	props:{ //当为对象时
		users:{
			type:Object,
			default(){
				return {}
			}
		},
	}
2.子组件像父组件传值
子组件中 首先是触发子组件的一个事件 
 <div v-on:click="chuanzhi">我是儿子组件</div>
 然后再methods中通过this.$rmit第一个参数为自定义的一个事件  第二个是传递的值
 chuanzhi(){
    this.$emit("sonChanged",this.msg)
  }
在父组件中接受这个值
  <zujian1 v-on:sonChanged='update'></zujian1>
  update就是当触发自定义事件后触发的父组件的事件
  update(e){
      // this.title = e;
      this.mrr = e;
    }

然后在遍历就可以取到子组件传过来的值

vuex

1.在page下面单独创一个store文件夹 在其下面创建一个index.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({

**this.$store.state.count**

  state:{
    name:'小明',
    phone:'13366733350',
    str:[]
  },
 // 相当于vuex的计算属性
  getters:{
    phoneShow:state => {
      return state.phone.substring(0,3)
    }
  },
  mutations:{
	
	**this.$store.commit('incerent')**

    strPush(state,mm){
      state.str = mm
    }
  },
  actions: {
  // 异步操作
  
	**this.$store.dispatch('incerent')**
	
	  async actionA ({ commit }) {
	    commit('gotData', await getData())
	  },
	  async actionB ({ dispatch, commit }) {
	    await dispatch('actionA') // 等待 actionA 完成
	    commit('gotOtherData', await getOtherData())
	  }
	}
  modules:{

  }
})
2.在组建中引用vuex中的值
import {mapState,mapGetters,mapMutations} from 'vuex'
	computed:{
     ...mapState(['name','str']),
     ...mapGetters(['phoneShow']),
  },
  methods:{
  	//引入strPush修改str的值
    ...mapMutations(['strPush']),	   
    jiazai(){
      this.strPush([123,123,123,456,789,456,752,863,96963])
    },	 
  },
  mounted() {
    this.jiazai()
  }

路由传参

(这是导航栏点击跳转时)
 1.<div v-for="items,index in arr" :key='index'>
 	//跳转一个参数对应的路由  用v-bind: 也就是:绑定to
  	**<router-link :to="'/blog/' + index">**
      <div>{{items.txt}}</div>
    </router-link>
    </div>
   (这是点击跳转时)
 1.<div v-for="items,index in arr" :key='index'>
      <div @click="hhhh(index)">{{items.txt}}</div>
	</div>
  	methods:{
		 hhhh(index){
	      **this.$router.push**({
	        path:'/blog/' + index
	      })
	    }
	  }
  2.既然要跳转路由此时需要注册路由
  	{
  	//:id 接收了我们点击时传过来的值也就是 index
      path: '/blog/:id',
      name: 'singblod',
      component: singblod
    },
   3.当要跳转到我们那个页面时需要创建这个页面也就是 singleblod.vue
   export default{
    data(){
      return{
      //这个就是我们通过路由传过来的参数id值
        id:this.$route.params.id
      }
    }
  }

跨域

在proxyTable中配置一下 
	'/v1': {
    target: 'http://*********.com', // 接口的域名
    // secure: false,  // 如果是https接口,需要配置这个参数
    changeOrigin: true, // 如果接口跨域,需要进行这个参数配置
    pathRewrite: {
      // '^/v1': 'app.php' //像接口 http://localhost:8081/v1?c=cross&a=gdzh_list 最终请求时是这样的 都会有一个叫做v1的  我这里把他重写成了app.php
      '^/v1': ''
   }
	  }
	 配置完成之后切记要重启项目!!!

filter过滤器

在src下面创建一个filter。js
export default {
  setOrders(status){
    switch(status){
      case 1:
        return '待付款';
      case 2:
        return '待发货';
      case 3:
        return '待收货';
      case 4:
        return '待评价';
    }
  },
  setOrdersStyle(status){
    switch(status){
      case '待付款':
        return 'red';
      case '待发货':
        return 'blue';
      case '待收货':
        return 'yellow';
      case '待评价':
        return 'orange';
    }
  },
}
在组件中引用这个js然后在
import filterMy from '../filter/filter.js'
data(){},
filters:filterMy, 
methods:{}
在div中  //每个  |   前面的都是我们filter下的参数
 <td :class="items.status | setOrders | setOrdersStyle">{{items.status | setOrders}}</td>

router-view 和 keep-alive

匹配最近的router-link
我在app.vue中写了一个 全局的
<router-link to="/">组件1</router-link>
<router-link to="/zujian1">组件2</router-link>
<router-view />  //他会把组件一盒组件二渲染出来

我在组件二下面又写了两个切换的组件他是组件二的两个儿子组件

<router-link to="/zujian1/tongxin">组件3</router-link>
<router-link to="/zujian1/tongxin1">组件4</router-link>
 
 //当需要缓存时 我们可以给router-view加一个keep-alive
 //当keepAlive为true时被keep-alive包裹着的是需要被缓存的 反之亦然
 
<keep-alive>
 	<router-view  v-if="$route.meta.keepAlive"/>
</keep-alive>
<router-view  v-if="!$route.meta.keepAlive"/>

路由的配置
routes: [
    {
      path: '/',
      name: 'HelloWorld',
      component: HelloWorld,
    },
    {
      path: '/zujian1',
      name: 'Zujian1',
      component: zujian1,
      children: [
           {
             path: 'tongxin',
             component: tongxin,
              meta: {
                keepAlive: true // 需要缓存
              }
           },
           {
             path: 'tongxin1',
             component: tongxin1,
              meta: {
                keepAlive: false // 需要缓存
              }
           }
      ]
    },
  ]

全局首位钩子函数

vue-router
他里面的两个钩子函数  beforeEach  afterEach
用法 在 main.js里直接写(适应于如果还没有登陆时 我们要是访问权限的路由需要登录才可)
里面有三个参数  to(到哪个组件)  from(离开的路由) next(是一个方法)
 router.beforeEach((to,from,next) => {
		   var login = false;
		   //若果没登录还要访问我们的权限组件的路由时
		   // if(!login && to.path == '/zujian1'){
		   //   next('/');
		   // }
			//若果没登录还要访问我们的权限组件的路由时  并且在访问时退出了登录 此时需要退出我们的权限页面时
		   if(!login && to.matched.some((item) => {
		     return item.path == '/zujian1'
		   })){
		     next('/');
		   }
		   else{
		      next();
		   }
  })

.v-on监听多个方法

<a style="cursor:default" v-on='{click:DoSomething,mouseleave:MouseLeave}'>doSomething</a>

在method方法里面分别写两个时事件;

<button @click="a(),b()">点我ab</button>

绑定class的数组用法

1.对象方法v-bind:class="{'orange':isRipe, 'green':isNotRipe}”
2.数组方法v-bind:class="[class1,class2]"
3.行内v-bind:style="{color:color,fontSize:fontSize+'px'}”

ant design vue

form表单

// :form="pwdform"
 <a-form abelAlign="right" :form="pwdform" :label-col="{ span: 6 }" :wrapper-col="{ span: 16 }">
    <a-form-item label="新密码">
      <a-input-password
        allowClear
        placeholder="请输入新密码"
        v-decorator="[
          'password',
          {
            rules: [
              //设置表单域的值
              {initialValue:''},
              { required: true, message: '密码不能为空' },
              { max: 16, min: 1, message: '密码长度应在4至16位之间' },
              { pattern: '^.*(?=.*\\d)(?=.*[A-Z]{1,})(?=.*[a-z]{1,}).*$', message: '密码必须包含大小写字母和数字' },
              //自定义校验
              { validator: this.chongzhimima },
            ],
          },
        ]"
      />
    </a-form-item>
	return{
		pwdform: this.$form.createForm(this, { password: '' }),
	}
	//用来获取表单的所有值
	const formData = this.pwdform.getFieldsValue()

	//用来进行所有表单的验证 只有通过才能执行里面的操作
	this.pwdform.validateFields((err, values) => {
    if (!err) {
      resetPassword({ id: this.selectRow.id, password: formData.password })
        .then((res) => {
          if (res.status === '00000') {
            this.$message.success('重置成功')
          } else {
            this.$message.success(res.message)
          }
          this.pwdform.resetFields()
          this.visible = false
        })
        .catch((rres) => {
          console.log(rres)
          this.$message.error('重置失败')
        })
    }
  })

//相当于v-model    this.form.setFieldsValue设置值
this.$nextTick(() => {
	//为表单设置值
    this.form.setFieldsValue({
      displayName: record.displayName,
      username: record.username,
      phoneNo: record.phoneNo,
      passwordExpiryDate: record.passwordExpiryDate == null ? null : moment(record.passwordExpiryDate),
      expiryDate: record.expiryDate == null ? null : moment(record.expiryDate),
      orgId: [...new Set(this.getParentId(data, record.orgId, []))],
      serialIndex: record.serialIndex,
      accountState: record.accountState + '',
    })
  })

表单下一些参数的含义以及用法

labelCol 是label所占的百分比,wrapperCol 是label后面的内容所占的百分比
labelCol: { // 24格栅格系统,label所占为 a
    xxl: 5, // ≥1600px 响应式栅格
    xl: 8, // ≥1200px 响应式栅格
    lg: 10, // ≥992px 响应式栅格
    md: 12 // ≥768px 响应式栅格
  },
  wrapperCol: { // 24格栅格系统,label后面内容所占为 24-a
    xxl: 19,
    xl: 16,
    lg: 14,
    md: 12
  },

antdesign的上传文件功能

<a-upload
    name="file"
    :multiple="true"
    :customRequrst = 'uploadFnc'
    :headers="headers"
    @change="handleChange"
  >
    <a-button> <a-icon type="upload" /> Click to Upload </a-button>
 </a-upload>
uploadFnc(file){
	console.log(file)
	const fileName = file.file.name
	const formData = new FormData()
	formData.append("file",file.file,fileName)
	//uploads 是我写的接口
	uploads(formData).then((res) =>{
		file.onsuccess(res.data,file)})
	},

下载功能

export function exportData (param) {
  return axios({
    url: `/detect/sample/exportSample`,
    data: param,
    method: 'post',
    responseType: 'blob'
  })
}
 downloadFile1 () {
      var that = this
      exportData(
        { client: that.queryParam.client,
          entrustNo: that.queryParam.entrustNo,
          name: that.queryParam.name,
          testSampleNo: that.queryParam.testSampleNo
        }
      ).then(res => {
        const blob = new Blob([res])
        //这里的名字是后台传值过来的
        const fileName = '样品清单.xls'
        const link = document.createElement('a')
        link.download = fileName
        link.style.display = 'none'
        link.href = URL.createObjectURL(blob)
        document.body.appendChild(link)
        link.click()
        URL.revokeObjectURL(link.href)
        document.body.removeChild(link)
      })
    },

实现element + vue的单选功能图表的

<el-table ref="multipleTable" :data="dialogTables" @select-all="dialogCheck" @select="dialogCheck" @selection-change="dialogCheckChange">
    <el-table-column type="selection" width="55"></el-table-column>
    <el-table-column property="ANAME" label="模块名称"></el-table-column>
</el-table>

	data(){
		selectioned:''
	}


	/**
   *    单选操作,全选按钮失效操作
   */
dialogCheck: function(selection, row) {
  this.$refs.multipleTable.clearSelection()
  if (selection.length === 0) { // 判断selection是否有值存在
    return
  }
  if (row) {
    this.selectioned = row
    this.$refs.multipleTable.toggleRowSelection(row, true)
  }
},

  /**
   *  取消单选的checkbox
   */
dialogCheckChange(row) {
  if (row.length === 0) {
    this.selectioned = null
  }
}

echarts 柱状图设置滚动条

dataZoom: [
//1.横向使用滚动条
{
    type: 'slider',//有单独的滑动条,用户在滑动条上进行缩放或漫游。inside是直接可以是在内部拖动显示
    show: true,//是否显示 组件。如果设置为 false,不会显示,但是数据过滤的功能还存在。
    start: 0,//数据窗口范围的起始百分比0-100
    end: 50,//数据窗口范围的结束百分比0-100
    xAxisIndex: [0],// 此处表示控制第一个xAxis,设置 dataZoom-slider 组件控制的 x轴 可是已数组[0,2]表示控制第一,三个;xAxisIndex: 2 ,表示控制第二个。yAxisIndex属性同理
    bottom: -10 //距离底部的距离
},
//2.在内部可以横向拖动
{
    type: 'inside',// 内置于坐标系中
    start: 0,
    end: 30,
    xAxisIndex: [0]
},
//3.纵向使用滚动条
{
    type: 'slider',
    show: true,
    yAxisIndex: [0],//设置组件控制的y轴
    left: '93%',//距离左侧的距离 可以使百分比,也可以是像素 left: '30'(30像素)
    start: 29,
    end: 36
},
//4.在内部可以纵向拖动
{
    type: 'inside',
    yAxisIndex: [0],
    start: 29,
    end: 36
}]

echarts设置提示消息的函数

formatter: function(params, i) {
        if(params.data.label !== undefined){
             if(params.data.label.position === 'left' || params.data.label.position === 'right' ){
                return 
            }
        }else{
           return `<span style='color:rgba(0, 255, 252, 1)'>${params.data.target} </span>的 
              <span style="color:rgba(0, 255, 252, 1)">${params.data.source}</span> 碳排放总量为
              <span style="color:rgba(0, 255, 252, 1)">${params.data.value.toFixed(2)}</span>`
   			},
        }

element-ui 中el-select 嵌套 tree树形控件 (多选)

 <el-select v-model="mineStatus" placeholder="请选择" multiple collapse-tags @change="selectChange">
  <el-option  :value="mineStatusValue" :disabled="true" style="height: auto; width: 100%;background: white">/
   	<el-tree :data="data" show-checkbox node-key="id" ref="tree" highlight-current :props="defaultProps" @check-change="handleCheckChange"></el-tree>
  </el-option>
</el-select>

js部分

<script>
export default {
  data() {
    return {
      mineStatus: "",
      mineStatusValue: [],
      data: [
        {
          id: 1,
          label: "一级 1",
          children: [
            {
              id: 4,
              label: "二级 1-1"
            }
          ]
        },
        {
          id: 2,
          label: "一级 2",
          children: [
            {
              id: 5,
              label: "二级 2-1"
            },
            {
              id: 6,
              label: "二级 2-2"
            }
          ]
        },
        {
          id: 3,
          label: "一级 3",
          children: [
            {
              id: 7,
              label: "二级 3-1"
            },
            {
              id: 8,
              label: "二级 3-2"
            }
          ]
        }
      ],
      defaultProps: {
        children: "children",
        label: "label"
      }
    };
  },
  methods: {
//select框值改变时候触发的事件
selectChange(e){
	  var arrNew = [];
      var dataLength = this.mineStatusValue.length;
      var eleng = e.length;
      for(let i = 0; i< dataLength ;i++){
        for(let j = 0; j < eleng; j++){
          if(e[j] === this.mineStatusValue[i].label){
            arrNew.push(this.mineStatusValue[i])
          }
        }
      }
      this.$refs.tree.setCheckedNodes(arrNew);//设置勾选的值
},
 handleCheckChange() {
      let res = this.$refs.tree.getCheckedNodes(true, true); //这里两个true,1. 是否只是叶子节点 2. 是否包含半选节点(就是使得选择的时候不包含父节点)
      let arrLabel = [];
      let arr = [];
      res.forEach(item => {
        arrLabel.push(item.label);
        arr.push(item);
      });
      this.mineStatusValue = arr;
      this.mineStatus = arrLabel;
      console.log('arr:'+JSON.stringify(arr))
      console.log('arrLabel:'+arrLabel)
    }
  }
};
</script>>

把对象中的属性名字更换

JSON.parse(JSON.stringify(arrayData).replace(/oldName/g, 'newName'))
//arrayData为数组,oldName为json内现有的,newName为想要更改的名字

根据id查对应的对象 递归实现

this.editTree = this.digui(this.dataTree, data.parent_id)
console.log(this.editTree)
digui (data, id) {
      for (let i = 0; i < data.length; i++) {
        let item = data[i]
        if (item.object_id === id) {
          return item
        } else {
          // item.children 不等于 undefined && item.children.length 大于 0 时
          if (item.children && item.children.length > 0) {
            let res = this.digui(item.children, id)
            if (res) {
              return res
            }
          }
        }
      }
    },

element的多选table表格变成单选

    <t-table
      ref="multipleTable"
      :data="paramDataPg"
      :row-key="rowKey"
      highlight-current-row
      line
      size="sm"
      @selection-change="handleSelectionChange" @row-click="handleRowClick">
      <t-table-column :reserve-selection="true" width="60" type="selection"></t-table-column>
      <template v-for="(item, index) in columnsOther">
        <t-table-column :prop="item.prop" :label="item.label" :key="index" show-overflow-tooltip></t-table-column>
      </template>
    </t-table>
    <div class="paginationCss">
      <t-pager :current.sync="tableDataOtherPage.current" :sizer-range="[10,30,60]" :page-size.sync="tableDataOtherPage.pageSize" :total="tableDataOtherPage.total" size="sm" show-elevator style="float: right;margin-top: 10px;" show-sizer @on-size-change="handleSizeChangeOther" @on-change="handleCurrentChangeOther">
      </t-pager>
    </div>
	
	//data
	paramDataPg: [
        {users: '1', name: '张三'},
        {users: '2', name: '李四'},
        {users: '3', name: '王五'},
        {users: '4', name: '学3'},
        {users: '5', name: '阿达'},
        {users: '6', name: '而且额'},
        {users: '7', name: '沙发'}
     ],
     multipleTable: [],
     columnsOther: [
        { label: '用户名', prop: 'users' },
        { label: '昵称', prop: 'name' }
      ],

	// methods
	handleSelectionChange (val) {
      if (val.length > 1) {
        this.$refs.multipleTable.clearSelection()
        this.$refs.multipleTable.toggleRowSelection(val.pop())
      } else {
        var obj = val.pop()
        if (obj) {
          this.multipleTable[0] = obj
          this.pgInform.pgPeople = this.multipleTable[0].name
          this.pgInform.pgPeopleId = this.multipleTable[0].users
          // this.multipleTable 就是单选过后的对象
        }
      }
    },
    handleRowClick(row) {
      this.$refs.multipleTable.toggleRowSelection(row)
    },
    rowKey (row) {
      return row.users
    },

element-ui 中el-select 嵌套 tree树形控件 (单选)

	<el-select v-model="zhuanDanInform.parentNodeLabel" style="width: 100%;" placeholder="请选择转单人员">
        <el-option :value="zhuanDanInform.parentNodeLabelid " style="height: auto; width: 100%;background: white">
          <el-tree
            ref="treeFormZhuandan"
            :data="dataTreeZhuandanTrue"
            node-key="object_id"
            show-checkbox
            check-strictly
            default-expand-all
            @check-change="handleNodeClick">
            <span slot-scope="{ data }" class="custom-tree-node">
              <span>{{ data.object_name }}</span>
            </span>
          </el-tree>
        </el-option>
      </el-select>

	//data
	zhuanDanInform: {
        parentNodeLabel: '',
        parentNodeLabelid: '',
        content: ''
    },
    dataTreeZhuandan: [{
        object_id: '1',
        object_name: '转单1',
        children: [
          {
            object_id: '2',
            object_name: '转单2'
          },
          {
            object_id: '3',
            object_name: '转单3'
          }
        ]
      },
      {
        object_id: '4',
        object_name: '转单4',
        children: [
          {
            object_id: '5',
            object_name: '转单5'
          },
          {
            object_id: '6',
            object_name: '转单6'
          }
        ]
      }]
    dataTreeZhuandanTrue: [],
    
	//mounted
	// 为了让其不选择有children的父集
	this.defaultShow(this.dataTreeZhuandan)
    this.dataTreeZhuandanTrue = this.dataTreeZhuandan

	//methods
	handleNodeClick (data, checked) {
      if (checked === true) {
        this.checkedId = data.object_id
        this.$refs.treeFormZhuandan.setCheckedKeys([data.object_id])
        this.zhuanDanInform.parentNodeLabel = this.$refs.treeFormZhuandan.getCheckedNodes()[0].object_name
        // 用id传参数 用label显示东西
        this.zhuanDanInform.parentNodeLabelid = this.$refs.treeFormZhuandan.getCheckedNodes()[0].object_id
      } else {
        if (this.checkedId === data.object_id) {
          this.$refs.treeFormZhuandan.setCheckedKeys([data.object_id])
        }
      }
    },
    defaultShow (arr) {
      arr.map(item => {
        item.disabled = false
        if (item.children) {
          item.disabled = true
          this.defaultShow(item.children)
        }
  })
}

把一个树中本地菜单和接口返回的菜单通过一个key(displayNameKey)来做对比 留下满足权限接口的前端的本地菜单

   this.jisuo(this.data[0]) // 这是接口返回的菜单
   this.newViews = JSON.parse(JSON.stringify(views))   //  这是本地存储的菜单
   this.IterationDelateMenuChildren(this.newViews)
   var arrs = []  // 消除为empty的数组
   this.newViews.map(item => {  // 消除为empty的数组
     arrs.push(item)  // 消除为empty的数组
   })  // 消除为empty的数组
     this.shuxing(arrs) // 去除这个single属性
   jisuo (previousList) {
      previousList.map(item => {
    		this.digui(this.newViews, item)
    		if (item.children) {
    			this.jisuo(item.children)
    		}
    	})
    },
    digui(data, id) {
     for (let i = 0; i < data.length; i++) {
       let item = data[i]
       if (item.displayNameKey === id.resources_name) {
    		  item.single = true
          item.idSelf = id.resources_id
       } else {
    	 if (item.children && item.children.length > 0) {
    	   this.digui(item.children, id)
    	 }
       }
     }
     },
     // 去除single不为true的  因为我把所有name能够匹配的到的 新加了一个属性为true
     IterationDelateMenuChildren (arr) {
      if (arr) {
        for (let i in arr) {
          if (arr[i].single && arr[i].children) {
            this.IterationDelateMenuChildren(arr[i].children)
          } else if (!arr[i].single) {
            delete arr[i]
          }
        }
      }
    },
     shuxing (tableData) {
      tableData.map(item => {
        delete item.single
        if (item.children) {
          this.shuxing(item.children)
        }
      })
    },

JS删除两个数组中相同的某个对象值

var arr1=[{id:1},{id:2},{id:3},{id:4},{id:5}]
var arr2=[{id:1},{id:2},{id:3}]
var set=arr2.map(item=>item.id)
console.log(set)
var resArr=arr1.filter(item=>!set.includes(item.id))
console.log(resArr)

vue+element实现table表格的编辑删除保存取消

<el-button
        type="primary"
        icon="plus-outline"
        @click="xinzengs"
        >新增</el-button>
      <el-tabs>
        <el-tab-pane label="参数名">
          <!-- 参数名的新增编辑删除保存取消 -->
          <el-table 
            :data="tableData" 
            size="small"
            line
            all-show-tooltip-when-overflow
            highlight-current-row>
            <el-table-column
              :index="indexMethod"
              type="index"
              label="序号"
              width="60"
            ></el-table-column>
            <el-table-column prop="codes" label="参数编码">
              <template slot-scope="scope">
                <el-input size="small" type="text" v-model="scope.row.codes" v-show="scope.row.iseditor" />
                <span v-show="!scope.row.iseditor">{{scope.row.codes}}</span>
              </template>
            </el-table-column>
            <el-table-column prop="names" label="参数名称">
              <template slot-scope="scope">
                <el-input size="small" type="text" v-model="scope.row.names" v-show="scope.row.iseditor" />
                <span v-show="!scope.row.iseditor">{{scope.row.names}}</span>
              </template>
            </el-table-column>
            <el-table-column label="操作">
              <template slot-scope="scope">
                <a
                  v-show="!scope.row.iseditor"
                  href="javascript:void(0)"
                  size="small"
                  @click="edit(scope.row)"
                  style="color: #147bd1"
                  >编辑</a
                >
                <span  v-show="!scope.row.iseditor" style="color: #bbbec1">&nbsp;|&nbsp;</span>
                <a
                  v-show="!scope.row.iseditor"
                  href="javascript:void(0)"
                  size="small"
                  @click="deletes()"
                  style="color: #ff5f5f"
                  >删除</a
                >
                <a
                  v-show="scope.row.iseditor"
                  href="javascript:void(0)"
                  size="small"
                  style="color: #147bd1"
                  @click="save(scope.row)"
                  >保存</a
                >
                <span v-show="scope.row.iseditor" style="color: #bbbec1">&nbsp;|&nbsp;</span>
                <a
                  v-show="scope.row.iseditor"
                  href="javascript:void(0)"
                  size="small"
                  style="color: #ff5f5f"
                  @click="() => cancels(scope.row, scope.$index)"
                  >取消</a
                >
              </template>
            </el-table-column>
          </el-table>
        </el-tab-pane>
      </el-tabs>
      export default ({
data () {
    return {
      tableData: [
        {
          codes: "aaa",
          names: "testcode",
          iseditor: false
        },
        {
          codes: "bbb",
          names: "testcode",
          iseditor: false
        },
        {
          codes: "ccc",
          names: "testcode",
          iseditor: false
        }
      ],
      arr: {}
    }
},
methods: {
  edit(row) {
    row.iseditor = true;
    this.arr = {}
    this.arr = JSON.parse(JSON.stringify(row))
  },
  save(row) {
    if (row.codes && row.names) {
      row.iseditor = false;
    } else {
      this.$message.warning("参数编码或参数名称不能为空!");
    }
  },
  deletes () {
    this.$confirm("确认删除该参数吗?", "提示", {
      confirmButtonText: "确定",
      cancelButtonText: "取消",
      type: "warning",
    }).then(() => {});
  },
  cancels (row, index) {
    if (index === (this.tableData.length - 1)) {
       if (Object.keys(this.arr).length) {
         row.codes = this.arr.codes
         row.names = this.arr.names
         row.iseditor = false;
       } else {
         this.tableData.splice(index, 1);
       }
    } else {
      row.codes = this.arr.codes
      row.names = this.arr.names
      row.iseditor = false;
    }
  },
  xinzengs () {
    let single = true
    this.tableData.map(item => {
      if (!item.codes || !item.names) {
        this.$message.warning("请先保存参数,在进行新增!");
        single = false
      }
    })
    if (single) {
      this.arr = {}
      this.tableData.push({
        codes: '',
        names: '',
        iseditor: true
      })
    }
  }
}
})

js 递归 更改数组的key值

   var tree=[
      {
        tename:'一级',
        teList:[
          {
            tename:'二级',
            teList:[
                {
                tename:'三级',
                teList:[
                  
                ]
              }
            ]
          },
          
        ]
      },
      {
        tename:'一yi级',
        teList:[
      {
        tename:'二级',
        teList:[
            {
            tename:'三级',
            teList:[
              
            ]
          }
        ]
      },
      
    ]
  }
]
var key = 'children'
var keyname = 'name'
function parseJson(arr) {
  arr = arr.slice()
  function toParse(arr) {
      arr.forEach(function (item) {
          if (item.teList && Array.isArray(item.teList)) {
              item[key] = item.teList
              item[keyname] = item.tename
              toParse(item[key])
          }
          delete item.teList
          delete item.tename
      })
      return arr
    
  }
  return toParse(arr)
}

console.log(parseJson(tree))

JS根据子节点数据获取所有父节点

const cities = [
  {
    "value": "13",
    "text": "河北省",
    "children": [
      {
        "value": "1306",
        "text": "保定市",
        "children": [
          {
            "value": "130602",
            "text": "竞秀区"
          },
          {
            "value": "130606",
            "text": "莲池区"
          },
          {
            "value": "130607",
            "text": "满城区"
          },
          {
            "value": "130608",
            "text": "清苑区"
          },
          {
            "value": "130609",
            "text": "徐水区"
          },
          {
            "value": "130628",
            "text": "高阳县"
          },
          {
            "value": "130636",
            "text": "顺平县"
          }
        ]
      }
    ]
  }
]


function treeFindPath(tree, func, field = "", path = []) {
  if (!tree) return []
  for (const data of tree) {
    field === "" ? path.push(data) : path.push(data[field]);
    if (func(data)) return path
    if (data.children) {
      const findChildren = treeFindPath(data.children, func, field, path)
      if (findChildren.length) return findChildren
    }
    path.pop()
  }
  return []
  
  	const cId = "130628";
	let arr = this.treeFindPath(cities, data => data.value === cId, "text");
	console.log(arr);
	// ["河北省", "保定市", "高阳县"]
// 注意在递归时在vue中函数加this    (treeFindPath这个函数不用动,只修改传参就好)

js根据对象数组中某一属性值,合并相同项,并对某一属性累加处理

  let data = [{ code: 1001, name: '苹果', sl: 11 },
	{ code: 1001, name: '苹果', sl: 11 },
	{ code: 1001, name: '苹果', sl: 11 },
	{ code: 1001, name: '苹果', sl: 11 },
	{ code: 1002, name: '西瓜', sl: 11 },
	{ code: 1002, name: '西瓜', sl: 15 },
	{ code: 1003, name: '梨', sl: 15 },
	{ code: 1003, name: '梨', sl: 15 }]
	
	第一种:根据对象key的唯一性,累加sl值
	let item = {}
	for (let i = 0; i < data.length; i++) {
	  item[data[i].code] = ~~item[data[i].code] + data[i].sl
	}
	console.log(item)
	// 结果: {1001: 44, 1002: 26, 1003: 30}
	第二种:根据reduce遍历累加,得到数组
	let newArray = data.reduce((total, cur, index) => {
	  let hasValue = total.findIndex(current => { return current.code === cur.code})
	  hasValue === -1 && total.push(cur)
	  hasValue !== -1 && (total[hasValue].sl = total[hasValue].sl + cur.sl)
	  return total
	}, [])
	console.log(newArray)
	// 结果: 
	[{code: 1001, name: "苹果", sl: 44},
	 {code: 1002, name: "西瓜", sl: 26}, 
	 {code: 1003, name: "梨", sl: 30}]

动态图表

  <template>
	  <div>
	    <div id="main"></div>
	  </div>
	</template>
	<script>
	// import moment from "moment";
	
	export default {
	  data () {
	    return {}
	  },
	  mounted () {
	    this.getZXT()
	  },
	  methods: {
	    getZXT () {
	      var myChart = this.$echarts.init(document.getElementById("main"));
	      var KSMC = [100, 82, 80, 70, 65, 66, 60, 54, 50, 42];
	      var option = {
	        color: ["#3398DB"],
	        tooltip: {
	          trigger: "axis",
	          axisPointer: {
	            // 坐标轴指示器,坐标轴触发有效
	            type: "shadow", // 默认为直线,可选为:'line' | 'shadow'
	          },
	        },
	        grid: {
	          left: "3%",
	          right: "4%",
	          bottom: "3%",
	          containLabel: true,
	        },
	        xAxis: [
	          {
	            type: "category",
	            data: [
	              "1",
	              "2",
	              "3",
	              "4",
	              "5",
	              "6",
	              "7",
	              "8",
	              "9",
	              "10",
	            ],
	            axisLabel: {
	              interval: 0,
	              fontSize: 18,
	              formatter: function (value) {//横坐标数据竖着显示
	                var str = value.split("");
	                return str.join("\n");
	              },
	            },
	          },
	        ],
	        dataZoom: [
	          //滑动条
	          {
	            xAxisIndex: 0, //这里是从X轴的0刻度开始
	            show: false, //是否显示滑动条,不影响使用
	            type: "slider", // 这个 dataZoom 组件是 slider 型 dataZoom 组件
	            startValue: 0, // 从头开始。
	            endValue: 6, // 一次性展示6个。
	          },
	        ],
	        yAxis: [
	          {
	            type: "value",
	            inverse: false, //是否是反向坐标轴
	          },
	        ],
	        series: [
	          {
	            name: "直接访问",
	            type: "line",
	            barWidth: "60%",
	            data: KSMC,
	            smooth: true,
	            areaStyle: {},
	          },
	        ],
	      };
	      myChart.setOption(option);
	      setInterval(function () {
	        // 每次向后滚动一个,最后一个从头开始。
	        // console.log(option.dataZoom[0].endValue);
	        // console.log("---"+KSMC.length);
	
	        if (option.dataZoom[0].endValue == KSMC.length) {
	          option.dataZoom[0].endValue = 6;
	          option.dataZoom[0].startValue = 0;
	        } else {
	          option.dataZoom[0].endValue = option.dataZoom[0].endValue + 1;
	          option.dataZoom[0].startValue = option.dataZoom[0].startValue + 1;
	        }
	        myChart.setOption(option);
	      }, 2000);
	    },
	  },
	};
	</script>
	<style scoped>
	#main {
	  width: 800px;
	  height: 600px;
	}
	</style>

多选下拉树,并且子节点全部选中只展示父节点

   <template>
  <el-tooltip
    :content="valueTranslate.toString()"
    placement="top"
    effect="light"
  >
    <el-select
      class="main-select-tree"
      ref="selectTree"
      v-model="value"
      multiple
      @change="selectchange"
      collapse-tags
    >
      <template slot="prefix">
        {{ (options1.find((item) => item.value === value) || {}).label }}
      </template>
      <el-option
        v-for="(item, index) in options1"
        :key="index"
        :label="item.label"
        :value="item.value"
        style="display: none"
      />
      <el-tree
        class="main-select-el-tree"
        ref="selecteltree"
        :data="datas"
        node-key="id"
        highlight-current
        show-checkbox
        :props="defaultProps"
        @check-change="handleNodeClick"
        :current-node-key="value"
        :expand-on-click-node="expandOnClickNode"
        default-expand-all
      />
    </el-select>
  </el-tooltip>
</template>

<script>
export default {
  data () {
    return {
      value: [5, 11],
      expandOnClickNode: true,
      datas: [
        {
          id: 1,
          label: '云南',
          children: [{
            id: 2,
            label: '昆明',
            children: []
          }]
        },
        {
          id: 3,
          label: '五华区',
          children: [{
            id: 8,
            label: '北辰小区',
            children: [{
              id: 9,
              label: '我是你吧'
            }]
          }]
        },
        {
          id: 4,
          label: '盘龙区'
        },
        {
          id: 5,
          label: '湖南',
          children: [
            { id: 6, label: '长沙' },
            { id: 7, label: '永州' }
          ]
        },
        {
          id: 10,
          label: '10区'
        },
        {
          id: 11,
          label: '11区'
        }],
      defaultProps: {
        children: 'children',
        label: 'label'
      },
      options1: [],
      valueTranslate: []
    }
  },
  mounted () {
    this.options1 = []
    this.formatData(this.datas)
    this.selectchange()
  },
  methods: {
    // 处理value转成中文
    changeValue () {
      this.valueTranslate = []
      this.options1.map(item => {
        this.value.map(item1 => {
          if (item.value == item1) {
            this.valueTranslate.push(item.label)
          }
        })
      })

      console.log(this.valueTranslate)
    },
    // 回调处理数据
    formatData (data) {
      data.forEach((item, key) => {
        this.options1.push({ label: item.label, value: item.id });
        if (item.children && item.children.length) {
          item.children.forEach((items, keys) => {
            this.options1.push({ label: items.label, value: items.id });
          })
          this.formatData(item.children)
        }
      });
    },
    handleNodeClick (node) {
      this.value = []
      // this.$refs.selecteltree.getCheckedNodes().map(item => {
      //   if (item.children) {
      //     this.value.push(item.id)
      //   }
      // })
      let newArr = this.getSimpleCheckedNodes(this.$refs.selecteltree.store)
      console.log(newArr)
      newArr.map(item => {
        this.value.push(item.id)
      })
      this.changeValue()
    },
    // 子节点全部选中只输出父节点
    getSimpleCheckedNodes (store) {
      const checkedNodes = [];
      const traverse = function (node) {
        const childNodes = node.root ? node.root.childNodes : node.childNodes;
        childNodes.forEach(child => {
          if (child.checked) {
            checkedNodes.push(child.data);
          }
          if (child.indeterminate) {
            traverse(child);
          }
        });
      };
      traverse(store)
      return checkedNodes;
    },
    selectchange () {
      this.$refs.selecteltree.setCheckedKeys(this.value);
      this.changeValue()
    },
  }
}
</script>
<style lang="scss">
.main-select-tree {
  min-width: 300px;
  // height: 40px;
  // max-width: 500px;
  // .el-select__tags {
  //   max-width: 500px !important;
  // }
}
.main-select-el-tree .el-tree-node .is-current > .el-tree-node__content {
  font-weight: bold;
  color: #409eff;
}
.main-select-el-tree .el-tree-node.is-current > .el-tree-node__content {
  font-weight: bold;
  color: #409eff;
}
.el-tag.el-tag--info {
  background-color: #bbd5f0;
  border-color: #cde0f4;
  color: #184794;
  height: 30px;
}
.el-tag.el-tag--info .el-tag__close {
  color: #184794;
}
.el-select .el-tag__close.el-icon-close {
  background: none;
}
</style>

MOCK.js总结

开始 & 安装

# 安装
npm install mockjs
// 使用 Mock
var Mock = require('mockjs')
var data = Mock.mock({
    // 属性 list 的值是一个数组,其中含有 1 到 10 个元素
    'list|1-10': [{
        // 属性 id 是一个自增数,起始值为 1,每次增 1
        'id|+1': 1
    }]
})
// 输出结果
console.log(JSON.stringify(data, null, 4))

element的树形table 增加 删除

请添加图片描述

<template>
  <div>
    <el-button type="primary" @click="addBigParent">增加子集</el-button>
    <el-table
      :data="tableData"
      style="width: 100%; margin-bottom: 20px"
      row-key="id"
      border
      default-expand-all
      line
      all-show-tooltip-when-overflow
      highlight-current-row
      :tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
      :row-class-name="rowClassName"
    >
      <el-table-column prop="index" label="序号" width="150"></el-table-column>
      <el-table-column prop="date" label="检查内容" sortable width="180">
      </el-table-column>
      <el-table-column prop="name" label="标准值" sortable width="180">
      </el-table-column>
      <el-table-column prop="address" label="是否拍照"> </el-table-column>
      <el-table-column prop="operate" label="操作" fixed="right">
        <template slot-scope="scope">
          <a
            href="javascript:void(0);"
            style="color: #147bd1"
            @click="addBig(scope.row, scope.$index)"
            >增加子集</a
          >
          <span style="color: #bbbec1">&nbsp;|&nbsp;</span>
          <a
            href="javascript:void(0);"
            class="delete"
            @click="remove(scope.row, scope.$index)"
            >删除</a
          >
        </template>
      </el-table-column>
      <div slot="empty">
        <emptyContent></emptyContent>
      </div>
    </el-table>
  </div>
</template>
<script>
export default {
  data () {
    return {
      tableData: [{
        id: 1,
        date: '工具检查',
        name: '',
        address: '',
        children: [{
          id: 2,
          date: '工具检查',
          name: '',
          address: '',
          children: [{
            id: 3,
            date: '工具检查1',
            name: '100',
            address: '是'
          }]
        }, {
          id: 4,
          date: '工具检查2',
          name: '100',
          address: '是'
        }]
      }, {
        id: 5,
        date: '电梯、爬梯',
        name: '',
        address: '',
        children: [{
          id: 6,
          date: '电梯、爬梯1',
          name: '100',
          address: '是'
        }, {
          id: 7,
          date: '电梯、爬梯2',
          name: '100',
          address: '是'
        }]
      }],
      number: 100,
      numberParent: 10000
    }
  },
  mounted () {
    this.tableData = this.addChildren(this.tableData)
    console.log(this.tableData)
    this.indexData(this.tableData)
  },
  methods: {
    //子序列增加
    indexData (val) {
      val.forEach((item, index) => {
        item.index = index + 1 + '';
        if (item.children?.length > 0) {
          this._indexData(item, item.index);
        }
      })
      // this._indexData(item, oldIndex)
      return val;
    },
    _indexData (item, oldIndex) {
      if (item.children?.length < 0) return;
      if (item.children?.length > 0) {
        item.children.forEach((Item, i) => {
          Item.index = oldIndex + '.' + (i + 1);
          this._indexData(Item, Item.index);
        });
      }
    },
    addBig (row, index) {
      this.number++
      row.children.push({
        id: this.number,
        date: 'xxx',
        name: '100',
        address: '是',
        children: []
      })
      this.indexData(this.tableData)
    },
    remove (row, index) {
      this.deleteTable(row, index, this.tableData)
      this.indexData(this.tableData)
    },
    rowClassName ({ row, columnIndex }) {
      if (row.children && row.children.length) {
        return "rowName"
      }
    },
    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.children.length > 0) {
            this.deleteTable(row, index, element.children)
          } else {

          }
        }
      }
    },
    addChildren (treeData) {
      for (let i = 0; i < treeData.length; i++) {
        const node = treeData[i];
        if (node.children?.length > 0) {
          this.addChildren(node.children);
        } else {
          this.$set(node, 'children', [])
        }
      }
      return treeData;
    },
    addBigParent () {
      this.tableData.push({
        id: this.numberParent++,
        date: 'xxx',
        name: '',
        address: '',
        children: []
      })
      this.indexData(this.tableData)
    }
  },
}
</script>
<style>
.el-icon-arrow-right:before {
  content: none;
}
.el-table__expand-icon {
  width: 0px !important;
  margin-right: 0px !important;
}
.el-table__indent {
  /* padding-left: 0px !important; */
}
.el-table__placeholder {
  width: 0px !important;
}
.rowName {
  background: #d4d4d4 !important;
  font-size: 19px;
  font-weight: 650;
  color: #000;
}
.el-table__body tr.hover-row > td.el-table__cell {
  background: none;
}
/* .el-table__expand-icon {
  display: none !important;
} */
/* .el-table__expand-column {
  display: none;
}
.el-table__row--level-1 td:first-child {
  padding-left: 40px;
}
.el-table__row--level-2 td:first-child {
  padding-left: 80px;
} */
/* 根据层级嵌套,设置不同的padding-left值 */
</style>
<template>
  <div>
    <el-button type="primary" @click="addBigParent">增加子集</el-button>
    <el-table
      class="table"
      :data="table"
      :key="key"
      style="width: 100%; margin-bottom: 20px"
      row-key="id"
      border
      default-expand-all
      line
      all-show-tooltip-when-overflow
      highlight-current-row
      :tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
      :row-class-name="rowClassName"
    >
      <el-table-column prop="index" label="序号" width="150"></el-table-column>
      <el-table-column prop="date" label="检查内容" sortable width="180">
      </el-table-column>
      <el-table-column prop="name" label="标准值" sortable width="180">
      </el-table-column>
      <el-table-column prop="address" label="是否拍照"> </el-table-column>
      <el-table-column prop="operate" label="操作" fixed="right">
        <template slot-scope="scope">
          <a
            href="javascript:void(0);"
            style="color: #147bd1"
            @click="addBig(scope.row, scope.$index)"
            >增加子集</a
          >
          <span style="color: #bbbec1">&nbsp;|&nbsp;</span>
          <a
            href="javascript:void(0);"
            class="delete"
            @click="remove(scope.row, scope.$index)"
            >删除</a
          >
        </template>
      </el-table-column>
      <div slot="empty">
        <emptyContent></emptyContent>
      </div>
    </el-table>
  </div>
</template>
<script>
import Sortable from 'sortablejs'
// 支持拖动的包含父级的拖动插件引入
export default {
  data () {
    return {
      table: [{
        id: 1,
        date: '工具检查',
        name: '',
        address: '',
        children: [{
          id: 2,
          date: '工具检查',
          name: '',
          address: '',
          children: [{
            id: 3,
            date: '工具检查1',
            name: '100',
            address: '是'
          }]
        }, {
          id: 4,
          date: '工具检查2',
          name: '100',
          address: '是'
        }]
      }, {
        id: 5,
        date: '电梯、爬梯',
        name: '',
        address: '',
        children: [{
          id: 6,
          date: '电梯、爬梯1',
          name: '100',
          address: '是'
        }, {
          id: 7,
          date: '电梯、爬梯2',
          name: '100',
          address: '是'
        }]
      }
      ],
      number: 100,
      numberParent: 10000,
      activeRows: [], // 转换为列表的数据扁平化
      numberNew: null,
      key: null,
      tbody: null
    }
  },
  mounted () {
    this.table = this.addChildren(this.table)
    this.indexData(this.table)
    this.treeParent(this.table)
    this.rowDrop()
    console.log(this.table)
  },
  watch: {
    table () {
      this.rowDrop()
    }
  },
  methods: {
    //子序列增加
    indexData (val) {
      val.forEach((item, index) => {
        item.index = index + 1 + '';
        if (item.children?.length > 0) {
          this._indexData(item, item.index);
        }
      })
      // this._indexData(item, oldIndex)
      return val;
    },
    _indexData (item, oldIndex) {
      if (item.children?.length < 0) return;
      if (item.children?.length > 0) {
        item.children.forEach((Item, i) => {
          Item.index = oldIndex + '.' + (i + 1);
          this._indexData(Item, Item.index);
        });
      }
    },
    addBig (row, index) {
      this.number++
      row.children.push({
        id: this.number,
        date: 'xxx',
        name: '100',
        address: '是',
        children: []
      })
      this.indexData(this.table)
      this.treeParent(this.table)
    },
    remove (row, index) {
      this.deleteTable(row, index, this.table)
      this.indexData(this.table)
    },
    rowClassName ({ row, columnIndex }) {
      if (row.children && row.children.length) {
        return "rowName"
      }
    },
    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.children.length > 0) {
            this.deleteTable(row, index, element.children)
          }
        }
      }
    },
    addChildren (treeData) {
      for (let i = 0; i < treeData.length; i++) {
        const node = treeData[i];
        if (node.children && node.children.length > 0) {
          this.addChildren(node.children);
        } else {
          this.$set(node, 'children', [])
        }
      }
      return treeData;
    },
    addBigParent () {
      this.table.push({
        id: this.numberParent++,
        date: 'xxx',
        name: '',
        address: '',
        children: []
      })
      this.indexData(this.table)
      this.treeParent(this.table)
    },
    rowDrop () {
      this.key = Symbol(new Date().toString())
      this.$nextTick(() => {
        this.tbody = document.querySelector('.table .el-table__body-wrapper tbody')
        Sortable.create(this.tbody, {
          animation: 200, // 定义排序动画的时间
          forceFallback: true, // boolean 如果设置为true时,将不使用原生的html5的拖放,可以修改一些拖放中元素的样式等;
          onMove: ({ dragged, related }) => {
            const oldRow = this.activeRows[dragged.rowIndex] // 移动的那个元素
            const newRow = this.activeRows[related.rowIndex] // 新的元素
            if (oldRow.parentId !== newRow.parentId) { // 移动的元素与新元素父级id不相同
              return false // 不允许跨级拖动
            }
          },
          onStart: () => { // 开始拖拽前把树形结构数据扁平化
            this.activeRows = this.treeToTile(this.table) // 把树形的结构转为列表再进行拖拽
          },
          onEnd: e => {
            const oldRow = this.activeRows[e.oldIndex] // 移动的那个元素
            const newRow = this.activeRows[e.newIndex] // 新的元素
            if (e.oldIndex === e.newIndex || oldRow.parentId !== newRow.parentId) return
            const index = this.activeRows.indexOf(oldRow)
            if (index < 0) return
            const changeIndex = e.newIndex - e.oldIndex
            this.activeRows.splice(index, 1)
            this.activeRows.splice(index + changeIndex, 0, oldRow)
            this.table = this.listToTree(this.activeRows)
            this.activeRows = this.treeToTile(this.table)
            this.indexData(this.table)
          }
        })
      })
    },
    /**
  * 将树数据转化为平铺数据
  * @param <Array> treeData当前要转的id
  * @param <String> childKey 子级字段
  * @return <Array> 返回数据
  */
    treeToTile (treeData, childKey = 'children') {
      const arr = []
      const expanded = data => {
        if (data && data.length > 0) {
          data.filter(d => d).forEach(e => {
            arr.push(e)
            expanded(e[childKey] || [])
          })
        }
      }
      expanded(treeData)
      return arr
    },
    // 子级携带父级id
    treeParent (treeData, childKey = 'children') {
      const expandParent = (data, parentId) => {
        if (data && data.length > 0) {
          data.filter(d => d).forEach(e => {
            if (parentId) {
              this.$set(e, 'parentId', parentId)
            }
            expandParent(e[childKey] || [], e.id || '')
          })
        }
      }
      expandParent(treeData)
      return treeData
    },
    listToTree (list) {
      const map = {};
      let node;
      let roots = [];
      for (let i = 0; i < list.length; i++) {
        map[list[i].id] = i;
        list[i].children = [];
      }
      for (let i = 0; i < list.length; i++) {
        node = list[i];
        if (node?.parentId) {
          list[map[node.parentId]].children.push(node);
        } else {
          roots.push(node);
        }
      }
      return roots;
    }
  }
}
</script>
<style>
.el-icon-arrow-right:before {
  content: none;
}
.el-table__expand-icon {
  width: 0px !important;
  margin-right: 0px !important;
}
.el-table__indent {
  /* padding-left: 0px !important; */
}
.el-table__placeholder {
  width: 0px !important;
}
.rowName {
  background: #d4d4d4 !important;
  font-size: 19px;
  font-weight: 650;
  color: #000;
}
.el-table__body tr.hover-row > td.el-table__cell {
  background: none;
}
/* .el-table__expand-icon {
  display: none !important;
} */
/* .el-table__expand-column {
  display: none;
}
.el-table__row--level-1 td:first-child {
  padding-left: 40px;
}
.el-table__row--level-2 td:first-child {
  padding-left: 80px;
} */
/* 根据层级嵌套,设置不同的padding-left值 */
</style>

请添加图片描述

<template>
  <div class="a_tree_box">
    <div>
      <el-table
        ref="cimsDictTable"
        default-expand-all
        :data="tableData"
        style="width: 100%"
        row-key="id"
        border
        stripe
        size="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 真正保存到数据库后会有真实id
          conditionName: '顶级条件',
          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是123
        this.getIdDate(123)
      }
    }

  },
  mounted () {
    if (!this.addOrEdit) {
      // 打开一个全新的列表
      this.getNewData()
    } else {
      // 根据id找到某个数据列表 回显 假设id是123
      this.getIdDate(123)
    }
  },
  beforeMount () {
  },
  methods: {
    getNewData () {
      this.$set(this.sourceData[0], 'childNode', [])
      this.initData()
    },
    // 获取页面数据回显
    getIdDate (id) {
      // 总数据回显 ---  假设给的数据  这条数据是默认数据的childNode
      let 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'] = levelNum

            setLevel(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'] = true
              noChildAndNoRate.push({ cantName: ruleName.trim() + '/' + element.conditionName.trim() })
            } else {
              element['isNeedLast'] = false
            }
          } else {
            element['isNeedLast'] = false
            checkIsNeedChild(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'] = true
              if ((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'] = true
              if ((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'] = delItemFlag

          if (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 = null
      if (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 = farOrSon
      let 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 = this
      function 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.formData
      function 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.conditionName
              element['strObj'] = val.strObj
              console.log(12121, element, val)
            }
          } else {
            if (element.id == Id) {
              element['conditionName'] = val.conditionName
              element['strObj'] = val.strObj
              console.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="scss" scoped>
// 树状表格样式
.a_tree_box {
  width: calc(100vw - 300px);
  height: 100%;
  margin-bottom: 20px;
  padding: 40px;
  .cd-tool {
    display: flex;
    flex-direction: row;
  }
  .data-table {
    .cell {
      display: flex;
      align-items: center;
    }

    // 固定表格高度
    td {
      height: 50px;
      padding: 0;
    }
    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;
  }

  .el-input__inner {
    margin-left: 3px !important;
    padding: 0 !important;
    width: 44px !important;
    height: 25px !important;
    text-align: center !important;
  }

  .dia_box {
    .el-input {
      text-align: left;
      .el-input__inner {
        width: 300px !important;
        height: 35px !important;
        text-align: left !important;
      }
    }
  }
}
</style>

实现把树里的某个url对象以list的形式输出出来

let arr = [{

      fileList:[],
      children: [
        {
          fileList:[{url: 'https://1.png&#39;},    {url: 'https://2.png&#39;}],   
          children: []
        },
        {
          fileList:[{url: 'https://3.png&#39;}],   
          children: []
        }
      ]
  },{
      fileList:[{url: 'https://4.png&#39;}],   
      children: [
        {
          fileList:[],
          children: []
        },
        {
          fileList:[{url: 'https://5.png&#39;}],   
          children: []
        }
      ]
  }]
  
 我想要这个  ['https://1.png&#39;,    'https://2.png&#39;,    'https://3.png&#39;,    'https://4.png&#39;,    'https://5.png&#39;]
 
 this.urlList = this.extractImageUrls(this.tableData)
 extractImageUrls (arr) {
  let urls = [];
  arr.forEach(item => {
    if (item.fileList && item.fileList.length > 0) {
      item.fileList.forEach(file => {
        urls.push(file.url);
      });
    }
    if (item.children && item.children.length > 0) {
      urls = urls.concat(this.extractImageUrls(item.children));
    }
  });
  return urls;
},
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值