使用elementUI的tree实现省市区街小区的选择

本文介绍了如何利用ElementUI的Tree组件实现省市区街小区的层级选择,包括懒加载、全选/半选状态记忆、搜索功能。通过设置变量保存真实选中状态,实现树和列表的同步更新。在懒加载中,展开节点时加载下一层数据,滚动加载列表。关键在于处理树节点的半选中状态,通过接口判断并更新节点状态。组件已封装为PlotMultiSelectDialog.vue,可在项目中直接使用。
摘要由CSDN通过智能技术生成

具体需求:

  • 支持按层级选择一个/多个小区
  • 层级懒加载
  • 选中非小区节点时默认选中该节点范围下的所有小区
  • 支持按列表选择一个/多个小区
  • 列表懒加载
  • “全部小区”选项和树/列表中的选项互斥
  • 按树结构和按列表结构选中的小区是同步更新的
  • 记忆节点选中状态
  • 支持搜索,可以在搜索出来的列表中进行选中/取消选中操作

效果如图:
在这里插入图片描述
在这里插入图片描述

设计思路:

  • 用一个变量a来存放真实选中的小区信息,树/列表只做展示用
  • 树的懒加载:展开节点时再加载下一层信息
  • 列表的懒加载:先加载50个小区,滚动到底部时再加载下一批小区,虚拟分页
  • 树的节点选中:如果选中非小区节点,则向接口请求该节点下的所有小区放到变量a中;如果选中小区节点,则直接将小区信息放到变量a中
  • 列表的节点选中:直接将选中信息同步到变量a中
  • 选择“全部小区”后,清空所有树/列表节点的选中状态,并且清空变量a;选择树/列表节点时,取消“全部小区”的选中状态,并且更新变量a
  • 切换tab时,同步更新树/列表的节点选中状态
  • 树节点选中状态的设置(重点):由于需要记忆节点选中状态,这就意味着树结构需要记忆全选/半选状态。如果树是全量加载的,那么不需要我们自己来判断,只需要告诉树选中的小区即可,但麻烦的是,现在树节点是懒加载的,在未打开某个节点的情况下,无法根据当前选中的小区来判断某个省市区街是全选还是半选,这个时间就需要依赖接口的判断,也就是说,需要在请求某一层的树节点信息时,把当前选中的小区传回去,由接口来告诉你某个节点需要全选还是半选
  • 列表选中状态的设置:直接更新就可以了

重点代码:
1.开发时遇到的比较麻烦的一个事情就是设置树的半选中状态,官方并没有提供半选的api,找了好久最后发现可以使用以下方法来直接修改节点状态:

let node = this.$refs.asyncTree.getNode(id);
node.indeterminate = true // 半选
node.checked = true // 全选
node.expand() // 展开
nodedata.loadData() // 加载数据

没错,就是这么简单粗暴,直接拿到节点,然后更改节点的属性或者调用节点的方法就好,需要哪个做哪个

2.想重新渲染树的话直接给树设置一个key,想渲染的时候更新下key就好了,简单方便

封装好的组件以及组件的使用:

PlotMultiSelectDialog.vue

<!-- 顶栏的选择小区的组件 -->
<!-- 只可用于全局,作为全局小区范围的控制 -->
<template>
  <div>
    <el-dialog
      :visible="visible"
      :append-to-body="true"
      :show-close="true"
      :close-on-click-modal="false"
      :close-on-press-escape="false"
      @close="clickCancle"
      @open="open"
      width="660px"
      v-dialogDrag
    >
      <div slot="title">
        <span class="dialog-title">更换小区</span>
      </div>
      <div class="plotSelectRoot">
        <el-input
          clearable
          placeholder="请输入小区名称"
          prefix-icon="el-icon-search"
          v-model="searchText"
        >
          <i slot="suffix" class="el-icon-loading" v-if="searchLoading"></i>
        </el-input>

        <div
          class="checkRect"
          v-show="searchText !== ''"
          style="margin-top: 20px"
        >
          <div style="height: 440px; overflow-y: auto">
            <div
              v-for="(item, index) in searchList"
              :key="index"
              class="plotItem"
            >
              <el-checkbox
                v-model="item.checked"
                @change="(val) => searchChange(item, val)"
                >{
   {
    item.plotName }}
              </el-checkbox>
            </div>
          </div>
        </div>

        <el-tabs
          v-show="searchText === ''"
          v-model="activeTabName"
          @tab-click="handleTablick"
        >
          <el-tab-pane label="按地区选" name="byRegion">
            <div class="selectAllBox">
              <el-checkbox
                v-model="allChecked"
                @change="allCheckedChange"
                style="margin-left: 23px"
                >全部小区</el-checkbox
              >
              <div class="selectAllButton" @click="clickSelectNone">清空</div>
              <div class="selectCount">(已选择: {
   {
    flatNum }}个小区)</div>
            </div>
            <div class="checkRect" :key="treeKey">
              <div style="height: 440px; overflow-y: auto" class="innerbox">
                <el-tree
                  :props="props"
                  :load="loadTreeNode"
                  node-key="id"
                  lazy
                  show-checkbox
                  ref="plotTree"
                  :expand-on-click-node="false"
                  :default-expanded-keys="defaultExpandedKeys"
                  @check="checkedTreeNodeChange"
                >
                </el-tree>
              </div>
            </div>
          </el-tab-pane>
          <el-tab-pane label="按小区选" name="byCommunity">
            <div class="selectAllBox">
              <el-checkbox
                v-model="allChecked"
                @change="allCheckedChange"
                style="margin-left: 23px"
                >全部小区</el-checkbox
              >
              <div class="selectAllButton" @click="clickSelectNone">清空</div>
              <div class="selectCount">(已选择: {
   {
    flatNum }}个小区)</div>
            </div>

            <div class="checkRect">
              <div
                style="height: 440px; overflow-y: auto"
                class="innerbox"
                @scroll="scrollEvent"
              >
                <el-checkbox-group id="checkboxGroup" v-model="checkedPlotList">
                  <el-checkbox
                    v-for="plot in flatPlotList"
                    :key="plot.id"
                    :label="plot.id"
                    @change="checkedListNodeChange"
                    >{
   {
    plot.plotName }}</el-checkbox
                  >
                </el-checkbox-group>
              </div>
            </div>
          </el-tab-pane>
        </el-tabs>
      </div>
      <span slot="footer">
        <div>
          <el-button @click="clickCancle">取消</el-button>
          <el-button type="primary" @click="clickConfirm">确定</el-button>
        </div>
      </span>
    </el-dialog>
  </div>
</template>
<script  lang="ts">
import {
    Component, Vue, Watch, Pr
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值