vue2实现一个树型控件(支持展开树与checkbox勾选)

这篇具有很好参考价值的文章主要介绍了vue2实现一个树型控件(支持展开树与checkbox勾选)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

vue2实现一个树型控件(支持展开树与checkbox勾选)

TreeItem.vue

<template>
  <div class="tree-item">
    <span @click="toggleExpanded" class="icon" v-show="treeNode && treeNode.children && treeNode.children.length">
      <span
        class="triangle"
        :class="[ expanded ? 'triangle_down' : 'triangle_up']"
      ></span>
    </span>
    <span class="icon-font icon-kaiwenjianjia-shense icon-wenjianjia"></span>
    <span @click="toggleExpanded">{{ treeNode.deptName }}</span>
    <input class="check-item check-style" type="checkbox" v-model="treeNode.checked" @change="handleChange(treeNode)">
    <div class="children" v-show="expanded">
      <TreeItem v-for="childNode in treeNode.children" :key="childNode.id" :tree-node="childNode" @checkItem="handleChange"></TreeItem>
    </div>
  </div>
</template>

<script>
export default {
  name: 'TreeItem',
  props: {
    // 每一项的节点数据
    treeNode: {
      type: Object,
      required: true
    }
  },
  data() {
    return {
      // 是否展开
      expanded: false,
    };
  },
  methods: {
    toggleExpanded() {
      this.expanded = !this.expanded;
    },
    handleChange(item) {
      console.log('handleChange',item, "treeNode",this.treeNode);
      this.setChecked(item,item.checked);
      this.$emit('checkItem',item)
    },
    // 递归 当父集选中或者取消 联动子集
    setChecked(node, checked) {
      node.checked = checked;
      if (node.children && node.children.length > 0) {
        for (let child of node.children) {
          this.setChecked(child, checked);
        }
      }
    }
  }
};
</script>

<style lang="less" scoped>
.tree-item {
  position: relative;
  font-size: 14px;
  .check-item {
    position: absolute;
    top: 10px;
    right: 4px;
    z-index: 111;
    cursor: pointer;
  }
}
.icon {
  width: 16px;
  display: inline-block;
  margin-right: 4px;
  line-height: 20px;
  cursor: pointer;
}
.icon-wenjianjia {
  color: #ccc;
  margin-right: 6px;
}
.children {
  margin-left: 20px;
}
input[type="checkbox"] {
  /* 未选中时的样式 */
  appearance: none;
  border: 1px solid transparent;
  width: 14px;
  height: 14px;
  display: inline-block;
  position: relative;
  vertical-align: middle;
  cursor: pointer;
  background-color: #eee;
}
 /* 选中时的样式 */
input[type="checkbox"]:checked {
  background-color: #1bc5bd;
}
  /* ✔图标 */
input[type="checkbox"]:checked:after {
  content: "✔";
  position: absolute;
  left: 1px;
  top: -11px;
  font-size: 12px;
  color: #fff;
}
.triangle {
  position: relative;
  top: -4px;
  transition: 0.5s;
}
.triangle_up {
  display: inline-block;
  margin: 0px;
  width: 0px;
  height: 0px;
  border-left: 4px solid transparent;
  border-right: 4px solid transparent;
  border-bottom: 4px solid #ccc;
}
.triangle_down {
  display: inline-block;
  margin: 0px;
  width: 0px;
  height: 0px;
  border-left: 4px solid transparent;
  border-right: 4px solid transparent;
  border-top: 4px solid #ccc;
}
</style>

Tree.vue

<template>
  <div class="select-tree-com">
    <TreeItem
     class="tree-item" v-for="treeNode in treeData" :key="treeNode.id" :tree-node="treeNode"
    @checkItem="checkItem"
  ></TreeItem>
  </div>
</template>

<script>
import TreeItem from "./TreeItem"
export default {
  name:'SelectTreeCom',
  components:{
    TreeItem
  },
  props: {
    // 结构数据
    lists: {
      type: Array,
      default () {
        return []
      }
    },
    // 是否开启checkbox
    checkbox: {
      type: Boolean,
      default: false
    },
  },
  data() {
    return {
      treeData: [
        {
          id: 1,
          name: 'Node 1',
          deptCode:1,
          deptName:'Node-1',
          checked: false,
          children: [
            {
              id: 11,
              deptCode:11,
              deptName:'Node-11',
              parentId: 1,
              name: 'Node 11',
              checked: false,
              children: [
                {
                  id: 111,
                  deptName:'Node-111',
                  deptCode:111,
                  parentId: 11,
                  name: 'Node 111',
                  checked: false,
                  children: [
                    {
                      id: 1111,
                      deptName:'Node-1111',
                      deptCode:1111,
                      parentId: 111,
                      name: 'Node 1111',
                      checked: false,
                      children: []
                    },
                    {
                      id: 1112,
                      deptName:'Node-1112',
                      deptCode:1112,
                      parentId: 111,
                      name: 'Node 1112',
                      checked: false,
                      children: []
                    }
                  ]
                },
                {
                  id: 112,
                  deptName:'Node-112',
                  deptCode:112,
                  parentId: 11,
                  name: 'Node 112',
                  checked: false,
                  children: []
                }
              ]
            },
            {
              id: 12,
              deptName:'Node-12',
              deptCode:12,
              parentId: 1,
              name: 'Node 12',
              checked: false,
              children: []
            },
            {
              id: 13,
              deptName:'Node-13',
              deptCode:13,
              parentId: 1,
              name: 'Node 13',
              checked: false,
              children: [
                {
                  id: 131,
                  deptName:'Node-131',
                  deptCode:131,
                  parentId: 13,
                  name: 'Node 131',
                  checked: false,
                  children: [
                    {
                      id: 1311,
                      deptName:'Node-1311',
                      deptCode:1311,
                      parentId: 131,
                      name: 'Node 1311',
                      checked: false,
                      children: []
                    },
                    {
                      id: 1312,
                      deptName:'Node-1312',
                      deptCode:1312,
                      parentId: 131,
                      name: 'Node 1312',
                      checked: false,
                      children: []
                    }
                  ]
                },
                {
                  id: 132,
                  deptName:'Node-132',
                  deptCode:132,
                  parentId: 13,
                  name: 'Node 132',
                  checked: false,
                  children: []
                }
              ]
            },
          ]
        },
        {
          id:2,
          deptName:'Node-2',
          deptCode:2,
          name: 'Node 2',
          checked: false,
          children: []
        }
      ],
      // treeData: [],
      // 选中的所有项 check为true
      checkList:[],
    };
  },
  watch:{
    lists:{
      handler(newV){
        console.log('selectTreeeCom组件lists',newV);
        // this.treeData = [...newV]
      },
      // immediate: true
    }
  },
  created() {
  },
  methods: {
    // 拿到当前选中的所有item数据
    checkItem(item) {
      // console.log('selectcom-checkItem',item);
      let newArr = []
      newArr = this.flattenNodes(item)
      console.log('newArr',newArr);
      // 存储选中的!
      newArr && newArr.length && newArr.forEach(item => {
        if ( item.checked ) {
          this.checkList.push(item)
        }
      });
      console.log('存储选中的-this.checkList',this.checkList);
      // 处理再一次选中时 包含之前的选项,覆盖之前的选项 check
      this.checkList && this.checkList.length && this.checkList.forEach(itemB =>{
        newArr.some(itemA => {
          if ( itemA.id === itemB.id ) {
            itemB.checked = itemA.checked
          }
        })
      })
      console.log('处理this.checkList',this.checkList);
      // 过滤掉 check为false 得到实际选中的数据
      this.checkList = this.checkList.filter(item=>{
        if(item.checked) {
          return item;
        }
      })
      // console.log('res-this.checkList',this.checkList);
      // 去重
      let uniqueArr = []
      uniqueArr = Array.from(new Set(this.checkList.map(item => item.id))).map(id => this.checkList.find(item => item.id === id));
      console.log('uniqueArr',uniqueArr);
      this.$emit('getCheckList', uniqueArr)
    },
    // 把树对象 扁平化为父+子的数据
    flattenNodes(data) {
      let nodes = [];
      // 添加当前节点到结果数组中
      nodes.push({
        id: data.id,
        name: data.name,
        checked: data.checked,
        deptCode: data.deptCode,
        deptName: data.deptName
      });
      // 遍历子级节点并递归处理
      if (data.children && data.children.length > 0) {
        for (let child of data.children) {
          nodes = nodes.concat(this.flattenNodes(child));
        }
      }
      return nodes;
    },
    // 全选
    setCheckAll(params){
      // console.log('setCheckAll',params);
      const allTreeData = this.treeToOneArr(this.treeData)
      if ( params ) {
        this.checkList = [...allTreeData]
        return this.checkList
      } else {
        this.checkList = []
        return this.checkList
      }
    },
    // 取消全选
    cancelCheckAll(){
      this.checkList = []
    },
    // tree数据 扁平化
    treeToOneArr(arr) {
      const data = JSON.parse(JSON.stringify(arr))
      const newData = []
      const hasChildren = item => {
        (item.children || (item.children = [])).map(v => {
          hasChildren(v)
        })
        delete item.children
        newData.push(item)
      }
      data.map(v => hasChildren(v))
      return newData
    },
    oneArrToTree(data) {
    // 对源数据深度克隆
      const cloneData = JSON.parse(JSON.stringify(data))
      // filter嵌套filter相当于for循环嵌套for循环
      const result = cloneData.filter(parent => {
      // 返回每一项的子级数组
        const branchArr = cloneData.filter(child => parent.parentCode === child.parentCode)

        // 若子级存在,则给子级排序;且,赋值给父级
        if (branchArr.length > 0) {
          branchArr.sort(this.compare('order'))
          parent.children = branchArr
        }
        // 返回最高的父级,即,parent_id为0,
        return parent.parentCode === '00'
      })
      // 给最高级的父级排序
      result.sort(this.compare('order'))
      return result
    },
    // 对象数组排序
    compare(property) {
      return function(a, b) {
        const value1 = a[property]
        const value2 = b[property]
        return value1 - value2// 升序,降序为value2 - value1
      }
    },
  }

};
</script>

<style lang="less" scoped>
.select-tree-com {
  padding: 10px 0;
}
.tree-item {
    line-height: 34px;
  }
</style>

效果

vue2实现一个树型控件(支持展开树与checkbox勾选),vue组件,javascript,前端,html文章来源地址https://www.toymoban.com/news/detail-622243.html

到了这里,关于vue2实现一个树型控件(支持展开树与checkbox勾选)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Qt QWidget 抗锯齿圆角窗口的一个实现方案(支持子控件)

    由于 QWidget::setMask 接口设置圆角不支持抗锯齿,所以通常会使用透明窗口加圆角背景,但圆角背景不能满足对子控件的裁剪,子控件与圆角区域重叠的部分还是能显示出来。当然对于大多数窗口,留出足够的边距也是可以接受。 对一些特殊场景,比如QComboBox的列表框,UI设计

    2023年04月24日
    浏览(45)
  • vue2使用 element表格展开功能渲染子表格

     默认样式 修改后   样式2 模拟数据 修改默认样式 

    2024年01月17日
    浏览(37)
  • vue2 实现后台管理系统左侧菜单联动实现 tab根据路由切换联动内容,并支持移动端框架

    效果图: pc端  移动端    由于代码比较多,我这里就不一一介绍了,可以去我的git上把项目拉下来 git地址https://gitee.com/Flechazo7/htglck.git 后台我是用node写的有需要的可以评论联系

    2024年02月16日
    浏览(34)
  • vue2+element-ui,el-aside侧边栏容器收缩与展开

    一、概览 实现效果如下: 二、项目环境 1、nodejs版本 2、npm版本 3、vue脚手架版本 三、创建vue项目 1、创建名为vuetest的项目 选择Default([Vue2] babel,eslint)    2、切换到项目目录,启动项目   3、使用浏览器预览  http://localhost:8080/ 四、使用Visual Studio Code打开项目 1、查看源码

    2023年04月22日
    浏览(29)
  • 使用videjs+vue2+elementui自定义播放器控件

    videojs依赖: npm install --save-dev video.js elementui依赖(这个图方便就不按需引入了): npm i element-ui -S 增加以下几行: 在components文件夹下创建两个组件videoComponent和videoPlayer—— videoComponent挂载到App组件上 videoPlayer挂载到videoComponent上 先把两个组件最基本的结构搭好 videoComponen

    2023年04月08日
    浏览(37)
  • vue2 支持图片放大

    添加  :preview-src-list属性  

    2024年02月10日
    浏览(34)
  • Vue3 实现一个无缝滚动组件(支持鼠标手动滚动)

    前言 在日常开发中,经常遇到需要支持列表循环滚动展示,特别是在数据化大屏开发中,无缝滚动使用频率更为频繁,在jquery时代,我们常用的无缝滚动组件为liMarquee,在vue中已经有vue-seamless-scroll组件(通过Vue2实现,不支持鼠标手动滚动),但是在使用过程中,发现滚动后

    2024年02月08日
    浏览(33)
  • vue2+element-ui el-tree树形控件封装

    1.封装 根据官网配置项封装了下el-tree 方便维护和复用,有用的话点赞收藏叭~ 2.使用 如若要对不同的一级二级节点设置不同的样式可以参考这样:

    2024年02月12日
    浏览(40)
  • VUE2+Element-ui树形控件tree结构的值获取和传给后台

    最近做到了权限管理模块 其中的菜单权限需要用到tree结构进行多选功能的渲染操作 废话少说,直接上代码 将tree结构放在form中配合表单使用 并附带全选和全不选,展开和折叠功能 其中的show-checkbox作用是对tree数据的多选模式 要写在data中的数据 其中defaultProps一定不能忘记

    2024年02月05日
    浏览(43)
  • flask支持Vue2 mode history历史模式

    在Vue2 router里面增加 然后打包 @blue.route(\\\'/admin/\\\', defaults={\\\'path\\\': \\\'\\\'}) :这是 Flask 路由的第一个部分,匹配 /admin/ 路径。 defaults={\\\'path\\\': \\\'\\\'} 表示当没有提供额外路径时,默认将 path 参数设置为空字符串。 @blue.route(\\\'/admin/path:path\\\') :这是 Flask 路由的第二个部分,使用 path:path 模式匹

    2024年02月05日
    浏览(34)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包