大家好!先上图看看本次案例的整体效果。

浪奔,浪流,万里涛涛江水永不休。如果在jq时代来实这个功能简直有些噩梦了,但是自从前端思想发展到现在的以MVVM为主流的大背景下,来实现一个这样繁杂的功能简直不能容易太多。下面就手把手带您一步步拨开这个案例的层层迷雾。

实现步骤如下:

1. api构建部门和员工信息接口,vuex全局存放部门list和员工list数据信息。
api:

export default {  getEmployeeList () {    return {      returncode: 0,      message: '',      result: [        {          id: 1,          employeeName: '吴亦凡',          departmentId: 44        },        {          id: 2,          employeeName: '鹿晗',          departmentId: 45        },        {          id: 3,          employeeName: '孙红雷',          departmentId: 44        },        {          id: 4,          employeeName: '周杰伦',          departmentId: 45        },        {          id: 5,          employeeName: '张国荣',          departmentId: 45        },        {          id: 6,          employeeName: '陈百强',          departmentId: 45        },        {          id: 7,          employeeName: '谭咏麟',          departmentId: 41        },        {          id: 8,          employeeName: '谷村新司',          departmentId: 45        },        {          id: 9,          employeeName: '中岛美雪',          departmentId: 46        },        {          id: 10,          employeeName: '周润发',          departmentId: 47        },        {          id: 14,          employeeName: '周慧敏',          departmentId: 58        },        {          id: 13,          employeeName: '张学友',          departmentId: 58        }      ]    }  },  getDepartmentList () {    return {      returncode: 0,      message: '',      result: [        {          id: 40,          name: '研发一部',          parentId: 37,          sequence: 2        },        {          id: 41,          name: '研发二部',          parentId: 37,          sequence: 4        },        {          id: 43,          name: '市场',          parentId: 0,          sequence: 6        },        {          id: 44,          name: '销售',          parentId: 0,          sequence: 4        },        {          id: 45,          name: '财务',          parentId: 0,          sequence: 5        },        {          id: 46,          name: '研发三部',          parentId: 37,          sequence: 1        },        {          id: 47,          name: '研发四部',          parentId: 37,          sequence: 3        },        {          id: 37,          name: '研发',          parentId: 0,          sequence: 5        },        {          id: 58,          name: '研发一部',          parentId: 57,          sequence: 1        },        {          id: 59,          name: '测试',          parentId: 0,          sequence: 5        },        {          id: 60,          name: '测试一部',          parentId: 59,          sequence: 1        },        {          id: 61,          name: '测试二部',          parentId: 59,          sequence: 2        },        {          id: 62,          name: '研发二部',          parentId: 57,          sequence: 2        }      ]    }  }}

store:

import dataApi from '@/api/data.api.js'const state = {  employeeList: [],  departmentList: []}const getters = {  employeeList: state => state.employeeList,  departmentList: state => state.departmentList}const mutations = {  SetEmployeeList (state, { employeeList }) {    state.employeeList = employeeList  },  SetDepartmentList (state, { departmentList }) {    state.departmentList = departmentList  }}const actions = {  getEmployeeList ({ commit }) {    let employeeResult = dataApi.getEmployeeList()    if (employeeResult.returncode === 0) {      commit('SetEmployeeList', { employeeList: employeeResult.result })    }  },  getDepartmentList ({ commit }) {    let departmentResult = dataApi.getDepartmentList()    if (departmentResult.returncode === 0) {      commit('SetDepartmentList', { departmentList: departmentResult.result })    }  }}export default {  state,  getters,  mutations,  actions,  namespaced: true}

2. vue.$set为员工对象增加响应式属性checked控制是否选中,methods中创建选中方法如下:

selectEmployee () {      var self = this      if (self.employee.checked === undefined) {        this.$set(self.employee, 'checked', true)      } else {        self.employee.checked = !self.employee.checked      }    }

3. computed计算属性监控文本框输入字段searchKey的变化实现左侧员工列表实时检索功能。

searchEmployeeList () {      var self = this      if (self.searchKey.trim() === '') {        console.log(self.employeeList)        return self.employeeList.filter(item => item.checked === undefined || !item.checked)      } else {        return self.employeeList.filter(item => (item.employeeName.indexOf(self.searchKey.trim()) !== -1) && (item.checked === undefined || !item.checked))      }    }

4. 构建组织结构树的部门组件,部门下可能存在子部门和员工,所以组件内部再调用部门组件和员工组件,以达到循环递归的效果。

<template>  <li @click.stop="expandTree()">    <a :class="lvl|level">      <span class="expand-tree-icon">        <i class="fa fa-caret-right" :class="{'active':department.expand}"></i>      </span>      <span>        <i class="lcfont lc-department-o"></i>      </span>      <span class="title">        <span>{{department.name}}</span>        <span class="title-desc">({{allChildEmployeeList.length}}人 )</span>        <i class="lcfont lc-add" @click.stop="selectDepartmentEmployees()" title="添加整个部门成员"></i>      </span>    </a>    <ul v-show="department.expand">      <child-employee        v-for="(employee,index) in childEmployeeList"        :employee="employee"        :lvl="lvl+1"        :key="index"      ></child-employee>      <child-department        v-for="(department,index) in childDepartmentList"        :department="department"        :employeeList="employeeList"        :departmentList="departmentList"        :lvl="lvl+1"        :key="index"      ></child-department>    </ul>  </li></template>

5. 结构树之员工组件

<template>  <li v-on:click.stop="selectEmployee()">    <a class="member-item" v-bind:class="lvl|level" href="javascript:;">      <div class="lc-avatar flex-se1" name="true" size="30">        <div class="lc-avatar-30" :title="employee.employeeName">          <span class="lc-avatar-def" style="background-color: rgb(112, 118, 142);">            <div>{{employee.employeeName}}</div>          </span>          <div class="lc-avatar-name">{{employee.employeeName}}</div>        </div>      </div>      <i class="lcfont" v-bind:class="{'lc-check':employee.checked}"></i>    </a>  </li></template>

6. 和上面员工的选中原理类似,控制部门节点的展开和合并也通过$set方法扩展一个响应式的expand属性。

expandTree () {      var self = this      if (self.department.expand === undefined) {        self.$set(self.department, 'expand', true)      } else {        self.department.expand = !self.department.expand      }    }

以上就是核心步骤的整体思路,欢迎讨论。