• 技术文章 >web前端 >Vue.js

    聊聊Ant Design Vue中怎么实现省市穿梭框

    青灯夜游青灯夜游2021-12-23 19:15:58转载137
    本篇文章带大家了解一下利用Ant Design Vue实现省市穿梭框的方法,希望对大家有所帮助!

    树形穿梭框

    官方树穿梭框如下,左右是树结构,右边是列表。

    本质上是有两套数据源,tree 使用的是树状数据源,transfer 使用的是列表数据源,将多维的树状数据源转为一维的,就是列表数据了。

    具体使用可以查看官方文档之 带搜索框的穿梭框(https://antdv.com/components/transfer-cn/)

    1.png

    城市穿梭框

    改造穿梭框的原因:

    主要实现功能点:

    2.png

    改造的本质:基于transfer的二次改造,主要是对数据的处理,组件基本没啥改变

    组件参数和事件

    自定义参数:考虑对外暴露的参数,参数的作用,属性等 自定义事件:考虑暴露出去的回调事件

    // 自定义参数
    export default {
      props: {
        dataSource: {
          // 数据源
          type: Array,
          default: () => [],
        },
        targetKey: {
          // 右侧框数据的 key 集合
          type: Array,
          default: () => [],
        },
      },
    };
    
    // handleChange回调函数:treeData-左侧树结构数据,toArray-右侧树结构数据,targetKeys-选中城市key集合
    this.$emit("handleChange", this.treeData, toArray, this.targetKeys);

    穿梭框处理

    <template>
      <!-- 穿梭框组件,数据源为列表形式 -->
      <a-transfer
        class="mcd-transfer"
        ref="singleTreeTransfer"
        show-search
        :locale="localeConfig"
        :titles="['所有城市', '已选城市']"
        :data-source="transferDataSource"
        :target-keys="targetKeys"
        :render="(item) => item.label"
        :show-select-all="true"
        @change="handleTransferChange"
        @search="handleTransferSearch"
      >
        <template
          slot="children"
          slot-scope="{
            props: { direction, selectedKeys },
            on: { itemSelect, itemSelectAll },
          }"
        >
          <!-- 左边源数据框:树形控件 -->
          <a-tree
            v-if="direction === 'left'"
            class="mcd-tree"
            blockNode
            checkable
            :checked-keys="[...selectedKeys, ...targetKeys]"
            :expanded-keys="expandedKeys"
            :tree-data="treeData"
            @expand="handleTreeExpanded"
            @check="
              (_, props) => {
                handleTreeChecked(
                  _,
                  props,
                  [...selectedKeys, ...targetKeys],
                  itemSelect,
                  itemSelectAll
                );
              }
            "
            @select="
              (_, props) => {
                handleTreeChecked(
                  _,
                  props,
                  [...selectedKeys, ...targetKeys],
                  itemSelect,
                  itemSelectAll
                );
              }
            "
          />
        </template>
      </a-transfer>
    </template>

    数据源处理

    // 数据源示例
    const dataSource = [
      {
        pid: "0",
        key: "1000",
        label: "黑龙江省",
        title: "黑龙江省",
        children: [
          {
            pid: "1000",
            key: "1028",
            label: "大兴安岭地区",
            title: "大兴安岭地区",
          },
        ],
      },
    ];
    
    // ant-transfer穿梭框数据源
    transferDataSource() {
      // 穿梭框数据源
      let transferDataSource = [];
      // 穿梭框数据转换,多维转为一维
      function flatten(list = []) {
        list.forEach((item) => {
          transferDataSource.push(item);
          // 子数据处理
          if (item.children && item.children.length) {
            flatten(item.children);
          }
        });
      }
      if (this.dataSource && this.dataSource.length) {
        flatten(JSON.parse(JSON.stringify(this.dataSource)));
      }
      return transferDataSource;
    }
    
    // ant-tree树数据源
    treeData() {
      // 树形控件数据源
      const validate = (node, map) => {
        // 数据过滤处理 includes
        return node.title.includes(this.keyword);
      };
      const result = filterTree(
        this.dataSource,
        this.targetKeys,
        validate,
        this.keyword
      );
      return result;
    }
    
    // 树形结构数据过滤
    const filterTree = (tree = [], targetKeys = [], validate = () => {}) => {
      if (!tree.length) {
        return [];
      }
      const result = [];
      for (let item of tree) {
        if (item.children && item.children.length) {
          let node = {
            ...item,
            children: [],
            disabled: targetKeys.includes(item.key), // 禁用属性
          };
          // 子级处理
          for (let o of item.children) {
            if (!validate.apply(null, [o, targetKeys])) continue;
            node.children.push({ ...o, disabled: targetKeys.includes(o.key) });
          }
          if (node.children.length) {
            result.push(node);
          }
        }
      }
      return result;
    };

    穿梭框事件处理

    // 穿梭框:change事件
    handleTransferChange(targetKeys, direction, moveKeys) {
      // 过滤:避免头部操作栏“全选”将省级key选中至右边
      this.targetKeys = targetKeys.filter((o) => !this.pidKeys.includes(o));
      // 选中城市数据:带省级信息返回,满足接口要求
      const validate = (node, map) => {
        return map.includes(node.key) && node.title.includes(this.keyword);
      };
      let toArray = filterTree(this.dataSource, this.targetKeys, validate);
      // handleChange回调函数:treeData-左侧树结构数据,toArray-右侧树结构数据,targetKeys-选中城市key集合
      this.$emit("handleChange", this.treeData, toArray, this.targetKeys);
    },
    
    // 穿梭框:搜索事件
    handleTransferSearch(dir, value) {
      if (dir === "left") {
        this.keyword = value;
      }
    },

    树事件

    // 树形控件:change事件
    handleTreeChecked(keys, e, checkedKeys, itemSelect, itemSelectAll) {
      const {
        eventKey,
        checked,
        dataRef: { children },
      } = e.node;
      if (this.pidKeys && this.pidKeys.includes(eventKey)) {
        // 父节点选中:将所有子节点也选中
        let childKeys = children ? children.map((item) => item.key) : [];
        if (childKeys.length) itemSelectAll(childKeys, !checked);
      }
      itemSelect(eventKey, !isChecked(checkedKeys, eventKey)); // 子节点选中
    },
    // 树形控件:expand事件
    handleTreeExpanded(expandedKeys) {
      this.expandedKeys = expandedKeys;
    },

    清除事件

    重新打开时,需要还原组件状态,例如滚动条位置,搜索框关键字等

    handleReset() {
      this.keyword = "";
      this.$nextTick(() => {
        // 搜索框关键字清除
        const ele = this.$refs.singleTreeTransfer.$el.getElementsByClassName(
          "anticon-close-circle"
        );
        if (ele && ele.length) {
          ele[0] && ele[0].click();
          ele[1] && ele[1].click();
        }
        // 滚动条回到顶部
        if (this.$el.querySelector(".mcd-tree")) {
          this.$el.querySelector(".mcd-tree").scrollTop = 0;
        }
        // 展开数据还原
        this.expandedKeys = [];
      });
    }

    【相关推荐:《vue.js教程》】

    以上就是聊聊Ant Design Vue中怎么实现省市穿梭框的详细内容,更多请关注php中文网其它相关文章!

    声明:本文转载于:掘金社区,如有侵犯,请联系admin@php.cn删除
    上一篇:最系统的vue全套教程(详解及实例) 下一篇:vue和echarts的区别是什么

    相关文章推荐

    • React中Ant Design Mobile是什么• Ant Design作者公布版本更新背后的故事!• 如何安装Ant Design Pro?简单入门指南• Ant Design中如何定制动态主题?聊聊实现方法• Ant Design Vue中如何让Textarea组件有“字数统计”功能

    全部评论我要评论

  • 取消发布评论发送
  • 1/1

    PHP中文网