树形结构实现

318 阅读3分钟

最近在写树形结构,发现可以直接拿来用又很舒服的很难找,就自己写了两种~

以下是效果~


前者是自己完全用jquery写的,后者借助element-UI写的,下边是代码。本人Node后端,大佬轻喷~

<template>  <div class="md-layout user-relation">    <!-- 分割线 -->    <div class="md-layout-item md-size-100 line1">      <v-divider />    </div>    <!-- 1.搜索(Safumax LIVE)待审核入金记录 -->    <!-- <md-button class="md-primary md-sm padding" @click="$router.push({name:'agentForm'})">创建代理</md-button> -->    <span class="buttonspace"></span>    <!-- 2.代理管理表 -->    <div class="md-layout-item md-size-100">      <md-card>        <!-- 标题 -->        <md-card-header class="md-card-header-icon md-card-header-green">          <div class="card-icon">            <md-icon>repeat</md-icon>          </div>          <h4 class="title">客户层级关系</h4>        </md-card-header>        <md-card-header>          <div class="md-layout">            <!-- 1.昵称 -->            <div class="input md-layout-item md-size-30 md-xsmall-size-100">              <el-select                clearable                filterable                v-model="filter.id"                remote                placeholder="请输入中文名或MT账号"                :remote-method="remoteMethod"                @change="getData"                :loading="loading"              >                <el-option                  v-for="item in users"                  :key="item.id"                  :label="`${item.chineseName}--${item.phone}--${item.email}`"                  :value="item.id"                ></el-option>              </el-select>            </div>            <!-- 7.表单提交按钮 -->            <div class="md-layout-item md-size-70">              <el-button                type="success" size=""                style="float:left;margin-top:0px"                @click="getData()"              >查询</el-button>            </div>          </div>        </md-card-header>        <!-- 内容 -->        <md-card-content>          <div v-show="powershow && item" :class="isbeyong? 'powerleft':'powertop'" id="powerdiv">            <div class="item_div">              <md-icon>face</md-icon>              {{item.chineseName}}            </div>            <div class="item_div">              <span class="item_span">账户ID: {{item.id}}</span>              <span class="item_span">注册时间: {{$method.timeformatYMD(item.create_time)}}</span>              <span class="item_span">手机号码: {{item.phone}}</span>            </div>            <!-- <div class="item_div">            </div> -->            <div class="item_div">              <span class="item_span">电子邮箱: {{item.email}}</span>            </div>            <div class="item_div">              <span class="item_span mtid">MT账号: {{(item.mtids && item.mtids.length>5)? item.mtids.slice(0,5).join()+'......' : item.mtids && item.mtids.join()}}</span>            </div>            <div class="item_div">              <md-icon>hdr_weak</md-icon>            </div>          </div>          <div class="all">            <div class="first-main">              <div class="item firstItem" v-for="item in data" :key="item.id" :id="item.id" @click="loadAndCreate(item)">                {{item.chineseName}}                <span :id="`${item.id}content`" style="display:none">{{JSON.stringify(item)}}</span>                <i v-show="item.agentCount>0" class="icon el-icon-arrow-right"></i>              </div>            </div>          </div>        </md-card-content>      </md-card>    </div>  </div></template><script>import $ from "jquery";import { setTimeout, setInterval } from 'timers';export default {  data() {    return {      loading: false,      data: [],      getRelation: false,      users: [],      powershow:false,      isbeyong: false,      createtime:0,      destroytime:0,      item:{},      filter: {        id: ""      }    };  },  async mounted() {    await this.loadAndCreate();    this.bindEvent()  },  methods: {    async getData() {      this.data = await this.list();      $('.main').remove()    },    // 查找    async list(id) {      if (this.getRelation) return;      this.getRelation = true;      const data = { ...this.filter };      if (id) data.id = id;      const res = await this.$axios.get("userRelation", { params: data });      this.getRelation = false;      this.addchildren(res.data.result.user.children);      return [...[res.data.result.user]];    },    // 处理children    addchildren(list) {      for (let item of list) {        if (item.agentCount > 0) {          item.children = [{}];        }      }    },    // 远程搜索    async remoteMethod(query) {      this.loading = true;      this.loading = false;      const res = await this.$axios.get("getUsersByName", {        params: { content: query }      });      this.users = res.data.result.users;    },    // html拼接    async loadAndCreate(data){      const _this = this;      const id = (data && data.id) || (data && data.currentTarget && data.currentTarget.id) || '';      let result = await this.list(id);      if(!result) return;      if(!id) this.data = result      let html = '<div class="main">'      const user = result[0];      $(`#${user.id}`).siblings().css({'background-color': '','color': ''})      $(`#${user.id}`).css({'background-color': '#f2f7fa','color': '#5992c8'})      if( user.children.length < 1) return      user.children.forEach(item=>{        html += `                <div class="item" id="${item.id}">                  ${item.chineseName}                  <span id="${item.id}content" style="display:none">${JSON.stringify(item)}</span>                  ${item.children? `<i class="icon el-icon-arrow-right"></i>`:``}                </div>`      })      html += '</div>'      $(`#${user.id}`).parent().nextAll().remove()      $(`#${user.id}`).parent().parent().append(html)      this.bindEvent()    },    // 给需要的元素动态绑定事件    bindEvent(){      const _this = this;      $('.item').click(this.loadAndCreate)      $('.item').mouseover(function(){        // 时间判断        const now = new Date().getTime();        // if(now-_this.destroytime<1000) return;        _this.powershow = true        _this.createtime = new Date().getTime();        // 获取页面宽度        const isBeyong = $(this).position().left > document.body.clientWidth/2        let thistop,thisleft;        // 判断是不是当前列的第一个元素        if(isBeyong){          _this.isbeyong = true          thistop = $(this).position().top          thisleft = $(this).position().left - parseInt($('#powerdiv').css('width')) - 10;        }else{          _this.isbeyong = false          thistop = $(this).position().top - parseInt($('#powerdiv').css('height')) - 10;          thisleft = $(this).position().left        }        // 判断不是第一个元素则往下移动10        if($('.firstItem').position().top !== $(this).position().top){          thistop = thistop + 10        }        $('#powerdiv').css({'top': thistop, 'left': thisleft});        _this.item = JSON.parse($(`#${$(this).attr('id')}content`).text());      }).mouseout(function(event){        // 消失的时候延时消失        _this.destroytime = new Date().getTime();        setTimeout(()=>{          const now =  new Date().getTime();           if(now - _this.createtime > 1000){            _this.powershow = false          }        },1000)      })      $('#powerdiv').hover(function(){        _this.powershow = true        _this.createtime = new Date().getTime();      },function(event){        // 消失的时候延时消失        setTimeout(()=>{          const now = new Date().getTime();          if(now - _this.createtime > 1000){            _this.powershow = false          }        },1000)      })    }  }};</script><style lang="scss">.user-relation {  .powerleft,.powertop{    border: 1px solid #F5F4F4;    border-radius: 3px;    position: relative;    width: 400px;    font-size: 12px;    line-height: 1.5;    position: absolute;    background: #fff;    box-sizing: border-box;    box-shadow: 2px 2px 2px 1px rgba(0, 0, 0, 0.08);  }  .powertop:after{    content: "";    display: block;    width: 10px;    height: 10px;    background: #F5F4F4;    border-left: 1px solid rgba(226, 222, 222, 0.849);    border-bottom: 1px solid rgba(226, 222, 222, 0.849);    position: absolute;    /* 加上border的高度 */    top: 98%;     left: 10%;    transform: rotate(-45deg);  }  .powerleft:after{    content: "";    display: block;    width: 10px;    height: 10px;    background: #F5F4F4;    border-left: 1px solid rgba(226, 222, 222, 0.849);    border-bottom: 1px solid rgba(226, 222, 222, 0.849);    position: absolute;    /* 加上border的高度 */    top: 10%;     left: 99%;    transform: rotate(225deg);  }  .item_div{    font-size:12px;    border-bottom: 1px solid #F5F4F4;    height: 40px;    line-height: 40px;    padding:0px 10px;  }  .item_div:first-child {    background-color: #F5F4F4;  }  .item_div:last-child {    float: right;    border: none;    height: 100%;    width:100%;    background-color: #F5F4F4;    .md-icon{      margin-left:90%;      line-height: 40px;    }  }  .item_div:nth-child(4) > .item_span {    width: 100%;  }  .item_span{    display: inline-block;    padding: 10px;    // width:50%;  }    .all{    border: 1px solid rgba(226, 222, 222, 0.849);    padding: 20px;    width: 100%;    overflow: auto;    display: flex;  }  .first-main{    min-height: 500px;    width: 160px;    border: 1px solid rgba(226, 222, 222, 0.849);    float: left;  }  .main {    min-height: 500px;    width: 160px;    margin-left: -1px;    border: 1px solid rgba(226, 222, 222, 0.849);    float: left;  }  .item {    margin-top:-1px;    width: 160px;    line-height: 42px;    text-align: left;    height: 40px;    font-size: 12px;    display: inline-block;    padding-left: 5px;  }  .icon {    margin-right:8px;    float: right;    line-height: 42px;  }}</style>

<--------------------------------------第二种实现方式-------------------------------------->
<template>  <div class="md-layout">    <!-- 分割线 -->    <div class="md-layout-item md-size-100 line1">      <v-divider />    </div>    <!-- 1.搜索(Safumax LIVE)待审核入金记录 -->    <!-- <md-button class="md-primary md-sm padding" @click="$router.push({name:'agentForm'})">创建代理</md-button> -->    <span class="buttonspace"></span>    <!-- 2.代理管理表 -->    <div class="md-layout-item md-size-100">      <md-card>        <!-- 标题 -->        <md-card-header class="md-card-header-icon md-card-header-green">          <div class="card-icon">            <md-icon>repeat</md-icon>          </div>          <h4 class="title">客户层级关系</h4>        </md-card-header>        <md-card-header>          <div class="md-layout">            <!-- 1.昵称 -->            <div class="input md-layout-item md-size-30 md-xsmall-size-100">              <el-select                clearable                filterable                v-model="filter.id"                remote                placeholder="请输入中文名或MT账号"                :remote-method="remoteMethod"                :loading="loading"              >                <el-option                  v-for="item in users"                  :key="item.id"                  :label="`${item.chineseName}--${item.phone}--${item.email}`"                  :value="item.id"                ></el-option>              </el-select>            </div>            <!-- 7.表单提交按钮 -->            <div class="md-layout-item md-size-70">              <el-button                type="success" size=""                style="float:left;margin-top:0px"                @click="getData()"              >查询</el-button>            </div>          </div>        </md-card-header>        <!-- 内容 -->        <md-card-content>            <el-tree              highlight-current              ref="tree"              :data="data"                            :render-after-expand="false"              node-key="id"              check-strictly              @node-expand="nodeClick"              :expand-on-click-node="true"            >              <span slot-scope="{ data }">                <div>                  <md-icon                    style="color:#f173ac;margin-top:-5px"                    type="md-warning"                    v-if="data.agentCount<1"                  >person</md-icon>                  <md-icon style="color:#FFC125;margin-top:-5px" type="md-warning" v-else>group</md-icon>                  <el-popover                    placement="top-start"                    title="MT账号详情"                    width="200"                    trigger="hover"                    :content="data.mtids.join(',')">                    <span class="tree-span" slot="reference">{{ formatData(data) }}</span>                  </el-popover>                </div>              </span>            </el-tree>          <!-- </el-popover> -->        </md-card-content>      </md-card>    </div>  </div></template><script>import { isArray } from 'util';export default {  data() {    return {      loading: false,      data: [],      getRelation: false,      users: [],      filter: {        id: ""      }    };  },  async mounted() {    this.data = await this.list();    console.log("data", this.data);  },  methods: {    async getData() {      this.data = await this.list();    },    // 查找    async list(id) {      if (this.getRelation) {        return;      }      this.getRelation = true;      const data = { ...this.filter };      if (id) data.id = id;      const res = await this.$axios.get("userRelation", { params: data });      this.getRelation = false;      this.addchildren(res.data.result.user.children);      return [...[res.data.result.user]];    },    // node树拼接    async nodeClick(data, node) {      // console.log(1,data);      if (data.children) {        data.children = [];        let result = await this.list(data.id);        // console.log(2,result)        if (result && result.length > 0) {          this.$nextTick(() => {            // console.log(3,data.id, result[0].children)            this.$refs["tree"].updateKeyChildren(data.id, result[0].children);          });        }      }    },    // 数据处理    formatData(data) {      let str = `${data.chineseName} [直属客户数: ${data.agentCount};`;      if (isArray(data.mtids) && data.mtids.length === 1) str += `MT账号: ${data.mtids[0]}`;      if (isArray(data.mtids) && data.mtids.length > 1) str += `MT账号: ${data.mtids[0]}...`;      return str += ` ]`;    },    // 处理children    addchildren(list) {      for (let item of list) {        if (item.agentCount > 0) {          item.children = [{}];        }      }    },    // 远程搜索    remoteMethod(query) {      const res = await this.$axios.get("getUsersByName", {        params: { content: query }      });      // console.log(res.data.result.users)      this.users = res.data.result.users;    }  }};</script><style>.md-menu-content.md-select-menu {  z-index: 9999 !important;  width: 100% !important;}.el-tree {  color: rgb(1, 26, 3);  text-align: center;  font-size: 15px;  margin: 0px !important;  font-weight: 500;}.el-tree-node__content {  height: 45px !important;}.el-tree-node__children {  border-style: none none none none;  border-width: 0.05em;  border-color: #aaa;}.tree-span {  margin-top: 0px;  margin-left: 5px;  display: inline-block;}.md-rose md-simple table-button tree-icon {  margin-left: -30px;}</style>