vue 树形结构应用

树形结构 说实话 el-tree 已经封装的挺好的  但是样式确实不敢恭维  所以就模仿了一个ztree结构形成

先看效果图吧

 

一说到树形结构   肯定涉及递归了  这是毋庸置疑的   看着图片 效果确实就是爽  

想当年刚开始写的时候真是要命呢   还是来一段代码吧

 

<style lang="scss">
div.ztree_content_wrap {
  height: 100%;
  overflow: hidden;
}
div.ztree_content_wrap div.left {
}
div.zTreeDemoBackground {
  width: 100%;
  text-align: left;
}

.expendIcon {
  background-position: -74px -36px;
  line-height: 0;
  margin: 0;
  width: 16px;
  height: 16px;
  display: inline-block;
  vertical-align: middle;
  border: 0 none;
  cursor: pointer;
  outline: none;
  position: absolute;
  top: 4px;
  background-color: transparent;
  background-repeat: no-repeat;
  background-attachment: scroll;
  background-image: url("../../../../static/img/zTreeStandard.png");
}
.el-container.left .el-main {
  border: 1px solid #ddd;
  margin-right: 5px;
}
ul.ztree {
  /* border: 1px solid #ddd; */
  background: #ffffff;
  width: 168px;
  overflow: hidden;
}

.ztree * {
  padding: 0;
  margin: 0;
  font-size: 12px;
  color: #74797b;
  /* font-family: Verdana, Arial, Helvetica, AppleGothic, sans-serif; */
  font-family: Microsoft YaHei, \\5fae\8f6f\96c5\9ed1, Helvetica Neue, Helvetica,
    PingFang SC, Hiragino Sans GB, Arial, sans-serif;
}
.ztree {
  margin: 0;
  padding: 5px;
  color: #333;
}
.ztree li {
  position: relative;
  padding: 0;
  margin: 0;
  list-style: none;
  line-height: 22px;
  text-align: left;
  white-space: nowrap;
  outline: 0;
}
.ztree li ul {
  margin: 0;
  padding: 0 0 0 18px;
}
.ztree li ul.line {
  background: url("../../../../static/img/zTreeStyle-line.png") 4px 0 repeat-y;
}

.ztree li a {
  padding: 1px 3px 0 1px;
  margin: 0;
  cursor: pointer;
  height: 17px;
  color: #333;
  background-color: transparent;
  text-decoration: none;
  vertical-align: top;
  display: inline-block;
}
.ztree li a:hover {
  text-decoration: underline;
  color: blue;
}
.ztree li a.curSelectedNode {
  padding-top: 0px;
  background-color: #191d22;
  color: #fff;
  height: 22px;
  border: 1px #191d22 solid;
  opacity: 0.8;
}
.ztree li a.curSelectedNode_Edit {
  padding-top: 0px;
  background-color: #ffe6b0;
  color: black;
  height: 16px;
  border: 1px #ffb951 solid;
  opacity: 0.8;
}
.ztree li a.tmpTargetNode_inner {
  padding-top: 0px;
  background-color: #316ac5;
  color: white;
  height: 16px;
  border: 1px #316ac5 solid;
  opacity: 0.8;
  filter: alpha(opacity=80);
}
.ztree li a.tmpTargetNode_prev {
}
.ztree li a.tmpTargetNode_next {
}
.ztree li a input.rename {
  height: 14px;
  width: 80px;
  padding: 0;
  margin: 0;
  font-size: 12px;
  border: 1px #7ec4cc solid;
  *border: 0px;
}
.ztree li span {
  line-height: 16px;
  margin-right: 2px;
  top: 3px;
  display: inline-block;
}
.ztree li span.button {
  line-height: 0;
  margin: 0;
  width: 16px;
  height: 16px;
  display: inline-block;
  vertical-align: middle;
  border: 0 none;
  cursor: pointer;
  outline: none;
  background-color: transparent;
  background-repeat: no-repeat;
  background-attachment: scroll;
  background-image: url("../../../../static/img/zTreeStandard.png");
  *background-image: url("../../../../static/img/zTreeStandard.gif");
}

.ztree li span.button.chk {
  width: 13px;
  height: 13px;
  margin: 0 3px 0 0;
  cursor: auto;
}
.ztree li span.button.chk.checkbox_false_full {
  background-position: 0 0;
}
.ztree li span.button.chk.checkbox_false_full_focus {
  background-position: 0 -14px;
}
.ztree li span.button.chk.checkbox_false_part {
  background-position: 0 -28px;
}
.ztree li span.button.chk.checkbox_false_part_focus {
  background-position: 0 -42px;
}
.ztree li span.button.chk.checkbox_false_disable {
  background-position: 0 -56px;
}
.ztree li span.button.chk.checkbox_true_full {
  background-position: -14px 0;
}
.ztree li span.button.chk.checkbox_true_full_focus {
  background-position: -14px -14px;
}
.ztree li span.button.chk.checkbox_true_part {
  background-position: -14px -28px;
}
.ztree li span.button.chk.checkbox_true_part_focus {
  background-position: -14px -42px;
}
.ztree li span.button.chk.checkbox_true_disable {
  background-position: -14px -56px;
}
.ztree li span.button.chk.radio_false_full {
  background-position: -28px 0;
}
.ztree li span.button.chk.radio_false_full_focus {
  background-position: -28px -14px;
}
.ztree li span.button.chk.radio_false_part {
  background-position: -28px -28px;
}
.ztree li span.button.chk.radio_false_part_focus {
  background-position: -28px -42px;
}
.ztree li span.button.chk.radio_false_disable {
  background-position: -28px -56px;
}
.ztree li span.button.chk.radio_true_full {
  background-position: -42px 0;
}
.ztree li span.button.chk.radio_true_full_focus {
  background-position: -42px -14px;
}
.ztree li span.button.chk.radio_true_part {
  background-position: -42px -28px;
}
.ztree li span.button.chk.radio_true_part_focus {
  background-position: -42px -42px;
}
.ztree li span.button.chk.radio_true_disable {
  background-position: -42px -56px;
}

.ztree li span.button.switch {
  width: 18px;
  height: 22px;
}
.ztree li span.button.root_open {
  background-position: -92px -53px;
}
.ztree li span.button.root_close {
  background-position: -74px -53px;
}
.ztree li span.button.roots_open {
  background-position: -92px 0;
}
.ztree li span.button.roots_close {
  background-position: -74px 0;
}
.ztree li span.button.center_open {
  background-position: -92px -17px;
}
.ztree li span.button.center_close {
  background-position: -74px -17px;
}
.ztree li span.button.bottom_open {
  background-position: -92px -36px;
}
.ztree li span.button.bottom_close {
  background-position: -74px -36px;
}
.ztree li span.button.noline_open {
  background-position: -92px -72px;
}
.ztree li span.button.noline_close {
  background-position: -74px -72px;
}
.ztree li span.button.root_docu {
  background: none;
}
.ztree li span.button.roots_docu {
  background-position: -56px 0;
}
.ztree li span.button.center_docu {
  background-position: -56px -16px;
}
.ztree li span.button.bottom_docu {
  background-position: -56px -36px;
}
.ztree li span.button.noline_docu {
  background: none;
}

.ztree li span.button.ico_open {
  margin-right: 2px;
  background-position: -110px -16px;
  vertical-align: top;
  *vertical-align: middle;
}
.ztree li span.button.ico_close {
  margin-right: 2px;
  background-position: -110px 0;
  vertical-align: top;
  *vertical-align: middle;
}
.ztree li span.button.ico_docu {
  margin-right: 2px;
  background-position: -110px -32px;
  vertical-align: top;
  *vertical-align: middle;
}
.ztree li span.button.edit {
  margin-right: 2px;
  background-position: -110px -48px;
  vertical-align: top;
  *vertical-align: middle;
}
.ztree li span.button.remove {
  margin-right: 2px;
  background-position: -110px -64px;
  vertical-align: top;
  *vertical-align: middle;
}

/*.ztree li span.button.ico_loading{margin-right:2px; background:url('../../static/images/loading.gif') no-repeat scroll 0 0 transparent; 
	            vertical-align:top; *vertical-align:middle}*/

ul.tmpTargetzTree {
  background-color: #ffe6b0;
  opacity: 0.8;
  filter: alpha(opacity=80);
}

span.tmpzTreeMove_arrow {
  width: 16px;
  height: 16px;
  display: inline-block;
  padding: 0;
  margin: 2px 0 0 1px;
  border: 0 none;
  position: absolute;
  background-color: white;
  background-repeat: no-repeat;
  background-attachment: scroll;
  background-position: -110px -80px;
  background-image: url("../../../../static/img/zTreeStandard.png");
  *background-image: url("../../../../static/img/zTreeStandard.gif");
}

ul.ztree.zTreeDragUL {
  margin: 0;
  padding: 0;
  position: absolute;
  width: auto;
  height: auto;
  overflow: hidden;
  background-color: #cfcfcf;
  border: 1px #00b83f dotted;
  opacity: 0.8;
  filter: alpha(opacity=80);
}

.zTreeMask {
  z-index: 10000;
  background-color: #cfcfcf;
  opacity: 0;
  filter: alpha(opacity=0);
  position: absolute;
}

.loadSyncNode {
  width: 16px;
  height: 16px;
  position: relative;
  display: inline-block;
  background-image: url("data:image/gif;base64,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");
}
ul.ztree span.file {
  width: 20px;
  height: 20px;
  display: inline-block;
  background-image: url("../../../../static/img/file_icon.png");
  background-repeat: no-repeat;
  float: left;
  margin: 1px 4px 0 0;
  background-position: 0 -280px;
}
</style>

<template>
	<!--(ztree-?)-->
	<div class="ztree_content_wrap" v-if='treeDataSource.length>0'>
		<div class="zTreeDemoBackground left">
			<ul class="ztree">
				<ztree-item v-for='(m,i) in treeDataSource' :key='i' :model.sync="m" :num.sync='i' root='0' :nodes.sync='treeDataSource.length' :callback='func' :expandfunc='expand' :cxtmenufunc='contextmenu' :trees.sync='treeDataSource'></ztree-item>
			</ul>
		</div>
	</div>
</template>

<script>
import Vue from "vue";
export default {
  data() {
    return {
      treeDataSource: []
    };
  },
  props: {
    // 树数据
    list: {
      type: Array,
      twoWay: true
    },
    // 点击节点回调
    func: {
      type: Function,
      default: null
    },
    // 点击展开回调
    expand: {
      type: Function,
      default: null
    },
    // 右击事件
    contextmenu: {
      type: Function,
      default: function() {
        //console.log("defalt click contextmenu");
      }
    },
    // 是否展开
    isOpen: {
      type: Boolean,
      twoWay: true,
      default: false
    }
  },
  watch: {
    list: {
      handler: function() {
        // //console.log("value改版", this.list);
        this.initTreeData();
      },
      deep: true
    }
  },
  methods: {
    initTreeData() {
      var tempList = JSON.parse(JSON.stringify(this.list)),
        that = this;
      // //console.log("接收对象渲染")
      // 递归操作,增加删除一些属性。比如: 展开/收起
      var recurrenceFunc = data => {
        data.forEach(m => {
          if (!m.hasOwnProperty("clickNode")) {
            m.clickNode = m.hasOwnProperty("clickNode") ? m.clickNode : false;
          }

          m.children = m.children || [];
          if (!m.hasOwnProperty("isFolder")) {
            m.isFolder = m.hasOwnProperty("open") ? m.open : this.isOpen;
          }

          if (!m.hasOwnProperty("isExpand")) {
            m.isExpand = m.hasOwnProperty("open") ? m.open : this.isOpen;
          }
          m.loadNode = 0;
          // recurrenceFunc(m.children);
        });
      };
      recurrenceFunc(this.list);
      this.treeDataSource = tempList;
    }
  },
  components: {
    // 组件
    ztreeItem: {
      name: "ztreeItem",
      props: {
        model: {
          type: Object,
          twoWay: true
        },
        num: {
          type: Number,
          twoWay: true
        },
        nodes: {
          type: Number,
          twoWay: true,
          default: 0
        },
        trees: {
          type: Array,
          twoWay: true,
          default: []
        },
        root: {
          type: String,
          twoWay: true
        },
        callback: {
          type: Function
        },
        expandfunc: {
          type: Function
        },
        cxtmenufunc: {
          type: Function
        }
      },
      methods: {
        Func(m) {
          // 查找点击的子节点
          var recurFunc = (data, list) => {
            data.forEach(i => {
              // 组织Id  类型Id  实例Id
              if (i.orgId == m.orgId) {
                i.clickNode = true;

                if (typeof this.callback == "function") {
                  this.callback.call(null, m, list, this.trees);
                }
              } else {
                i.clickNode = false;
              }

              if (i.children) {
                recurFunc(i.children, i);
              }
            });
          };

          recurFunc(this.trees, this.trees);
        },
        open(m) {
          //
          m.isExpand = !m.isExpand;

          if (typeof this.expandfunc == "function" && m.isExpand) {
            if (m.loadNode != 2) {
              //
              this.expandfunc.call(null, m);
            } else {
              m.isFolder = !m.isFolder;
            }
          } else {
            m.isFolder = !m.isFolder;
          }
        }
      },
      computed: {
        // 给(根 和 子树)赋值不同的样式
        rootClass() {
          var strRootClass = "";

          // 根判断
          if (this.root == "0") {
            strRootClass =
              this.num == 0 && this.model.children.length == 0
                ? "roots_docu"
                : this.nodes == 1 ||
                  (this.num == 0 && this.nodes != this.num + 1)
                  ? "root_"
                  : this.nodes == this.num + 1 ? "bottom_" : "center_";

            // 子树判断
          } else if (this.root == "1") {
            // //console.log("model:",this.model,"children:",this.model.children)
            strRootClass =
              this.nodes > 1 &&
              this.model.children.length > 0 &&
              this.nodes != this.num + 1
                ? "center_"
                : (this.num == 0 && this.nodes > 1) ||
                  this.nodes != this.num + 1
                  ? "center_docu"
                  : (this.nodes == 1 && this.num != 0) ||
                    (this.nodes == this.num + 1 &&
                      this.model.children.length > 0)
                    ? "bottom_"
                    : "bottom_docu";
          }

          return strRootClass;
        },
        // 是否有儿子节点
        isChildren() {
          return this.num + 1 != this.nodes;
        },
        // 展开/收起
        prefixClass() {
          var returnChar = "";
          if (this.rootClass.indexOf("docu") == -1) {
            if (this.model.isFolder) {
              returnChar = "open";
            } else {
              returnChar = "close";
            }
          }

          if (
            this.model.children.length == 0 &&
            this.rootClass.indexOf("docu") == -1
          ) {
            returnChar = "docu";
          }

          return returnChar;
        },
        liClassVal() {
          return "level" + this.num;
        },
        spanClassVal() {
          return (
            "button level" +
            this.num +
            " switch " +
            this.rootClass +
            this.prefixClass
          );
        },
        aClassVal() {
          return this.model.clickNode
            ? "level" + this.num + " curSelectedNode"
            : "level" + this.num;
        },
        ulClassVal() {
          return this.isChildren && this.model.children.length > 0
            ? "level" + this.num + " line"
            : "level" + this.num;
        }
      },
      template: `<li :class="liClassVal">
				<span :class="spanClassVal" @click='open(model)'></span>
				<a :class="aClassVal" @click='Func(model)' @contextmenu.prevent='cxtmenufunc(model)'>
				    <span :class="{loadSyncNode:model.loadNode==1}" v-if='model.loadNode==1'></span>
				    <span :class='model.iconClass' v-show='model.iconClass' v-else></span>
            <el-tooltip popper-class="treetip" effect="dark" :content="model.orgName" placement="top" :open-delay="1000">
              <span class="node_name">{{model.orgName}}</span>
            </el-tooltip>
				</a>
				<ul :class="ulClassVal" v-show='model.isFolder'>
					<ztree-item v-for="(item,i) in model.children" :key='i' :callback='callback' :expandfunc='expandfunc' :cxtmenufunc='cxtmenufunc' :model.sync="item" :num.sync='i' root='1' :nodes.sync='model.children.length' :trees.sync='trees'></ztree-item>
				</ul>
      </li>`
      
      
    }
  },
  update() {
    this.initTreeData();
  },
  mounted() {
    Vue.nextTick(() => {
      this.initTreeData();
    });
   
  }
};
</script>

结构简单  但不好写说实话   样式也免费赠送  就是设置一些背景图片啥的 就没了   这个当然有两种方式了 懒加载 和  俗称的PID渲染  先说这么多吧

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值