基于Vue的下拉select选择区间组件

业务场景 选择职级范围,ant-design-vue的适用的组件是两个select并用,前值后值充当区间范围,这样会比较麻烦,对用户不友好,与是开发一个 模拟下拉select,但是可选择区间,回显样式类似于 A -B

注意组件文档注释采用js-doc规范,生成说明文档,js-doc使用详见我之前的文章

https://blog.csdn.net/weixin_38500689/article/details/111921114?spm=1001.2014.3001.5502
看图:
vueselect下拉区间选择组件
这样一个select就可以完成区间选择了。

调用:

可直接传 codeId 调通过用接口(这个接口就自行定义参数吧,这里只是我的实现)获取码表数据源
也可以通过 selectList 外部传入数据源。
valueName和codeName 数据源的关键字以及回显字段名 默认 code和name

<eg-select-range
      v-model="selectRange"
      codeId="GW_JOBLEVEL"
      :valueName="'code'"
      :codeName="'name'"
    ></eg-select-range>

下面看代码:

首先基于antdv的基础组件 dropdown、input、icon、menu

template部分:这个ant基础组件的使用就不在这里解释了

<template>
  <a-dropdown
    class="eg-select-range"
    :getPopupContainer="getContainer"
    :trigger="triggerArr"
    :placement="placement"
    :overlayClassName="'dropconditonSelectWidth'"
    v-model="dropVisible"
  >
    <a-input class="selectrangeinput" :disabled="disabled" v-model="selectRangeLabels">
      <a-icon @click.stop="deleteRnage" class="selectrangeclose" slot="suffix" type="close-circle" />
    </a-input>
    <a-menu slot="overlay" @click="handleMenuClick" :key="count">
      <template v-for="(item, index) in sourceList">
        <a-menu-item
          :key="index"
          :disabled="item.disabled"
          :class="{
            egselectrangeselectRow: isSelect(index),
            egselectrangerangeRow: isRange(index),
            egselectrangeenterrow: isenter(index)
          }"
          ><p @mouseenter="menuEnter(index)" @mouseleave="menuLeave" class="menu-select-range">
            {{ item.name }}
          </p></a-menu-item
        >
      </template>
    </a-menu>
  </a-dropdown>
</template>

重点讲解script部分

data部分:

selectRangeLabels:回显字段
selectKeyRange:选中项对应的关键字(码值或者id,是要传回给后端的)
sourceList: 下拉数据源
enterIndex: 鼠标hover下拉项的索引

prop部分:

/**

  • Props 接受父组件的传值 重要参数
  • @prop {String} valueName 数据源的关键字字段名 默认 code
  • @prop {String} labelName 数据源的显示字段名 默认 name
  • @prop {String} placement 下拉框显示位置 可选 bottomLeft bottomCenter bottomRight topLeft topCenter topRight 默认 bottomCenter
  • @prop {String} codeId 此处为通用接口的码表名称,通过codeId获取数据源
  • @prop {Array} triggerArr dropDown的触发方式,默认 click
  • @prop {String} formItemKey 此处为在form中使用时的表单项key(单独使用selectRange不需要)
  • @prop {String} triggerNode 定义dropDown的pop的挂载节点 属性getPopupContainer
  • @prop {String} value v-model的值
  • @prop {Array} selectList 数据源,父组件传入
    */
methods 部分

getselectLabels方法:
/**
* @function getselectLabels
* @param {Array} val - 当前选中值
* @description 解析选中项,得到页面显示内容 (根据val 获取对应的name,设置回显)
*/

    getselectLabels(val) {
      if (val) {
        let label = [];
        this.sourceList.forEach(item => {
          if (val.indexOf(item[this.valueName]) > -1) {
            label.push(item.name);
          }
        });
        if (val.split(",")[0] == val.split(",")[1]) {
          this.selectRangeLabels = label[0] ? label[0] : "";
        } else {
          let str1 = label[0] ? label[0] : "";
          let str2 = label[1] ? label[1] : "";

          this.selectRangeLabels = str2 + "-" + str1;
        }
      }
    },

方法上边都有注释,也就不一一拿出来解释一遍了。

代码双手奉上,如果觉得有帮助请点赞关注评论,谢谢

<template>
  <a-dropdown
    class="eg-select-range"
    :getPopupContainer="getContainer"
    :trigger="triggerArr"
    :placement="placement"
    :overlayClassName="'dropconditonSelectWidth'"
    v-model="dropVisible"
  >
    <a-input class="selectrangeinput" :disabled="disabled" v-model="selectRangeLabels">
      <a-icon @click.stop="deleteRnage" class="selectrangeclose" slot="suffix" type="close-circle" />
    </a-input>
    <a-menu slot="overlay" @click="handleMenuClick" :key="count">
      <template v-for="(item, index) in sourceList">
        <a-menu-item
          :key="index"
          :disabled="item.disabled"
          :class="{
            egselectrangeselectRow: isSelect(index),
            egselectrangerangeRow: isRange(index),
            egselectrangeenterrow: isenter(index)
          }"
          ><p @mouseenter="menuEnter(index)" @mouseleave="menuLeave" class="menu-select-range">
            {{ item.name }}
          </p></a-menu-item
        >
      </template>
    </a-menu>
  </a-dropdown>
</template>

<script>
import Vue from "vue";
import { Dropdown, Menu } from "ant-design-vue";
Vue.use(Dropdown);
Vue.use(Menu);
import "ant-design-vue/lib/menu/style/css";
import "ant-design-vue/lib/dropdown/style/css";
/**
 * 自定义下拉选择区间组件
 * @module EgSelectRange
 * @author 何志强
 * @description 自定义下拉选择区间组件,可以传selectList数据源, 也可以传codeId 组件自行请求数据源,对外暴露 onChange 事件
 */
export default {
  name: "EgSelectRange",
  data() {
    return {
      dropVisible: false,
      selectRangeLabels: "",
      selectKeyRange: [],
      count: 0,
      enterIndex: "",
      sourceList: []
    };
  },
  /**
   * Props 接受父组件的传值 重要参数
   * @prop {String} valueName 数据源的关键字字段名 默认 code
   * @prop {String} labelName 数据源的显示字段名 默认 name
   * @prop {String} placement 下拉框显示位置 可选 bottomLeft bottomCenter bottomRight topLeft topCenter topRight 默认 bottomCenter
   * @prop {String} codeId 此处为通用接口的码表名称,通过codeId获取数据源
   * @prop {Array} triggerArr dropDown的触发方式,默认 click
   * @prop {String} formItemKey 此处为在form中使用时的表单项key(单独使用selectRange不需要)
   * @prop {String} triggerNode 定义dropDown的pop的挂载节点 属性getPopupContainer
   * @prop {String} value v-model的值
   * @prop {Array} selectList 数据源,父组件传入
   */
  props: {
    disabled: {
      default: false
    },
    valueName: {
      default: "code"
    },
    labelName: {
      default: "name"
    },
    codeId: {
      type: String
    },
    triggerArr: {
      type: Array,
      default: function() {
        return ["click"];
      }
    },
    formItemKey: {
      type: String
    },
    placement: {
      type: String,
      default: "bottomCenter"
    },
    triggerNode: {
      default: "parent"
    },
    value: { type: String },
    selectList: {
      type: Array,
      default: function() {
        return [
          // {
          //   id: "01",
          //   name: "程咬金",
          //   disabled: false
          // },
          // {
          //   id: "02",
          //   name: "亚瑟",
          //   disabled: false
          // },
          // {
          //   id: "03",
          //   name: "牛魔",
          //   disabled: false
          // },
          // {
          //   id: "04",
          //   name: "李元芳",
          //   disabled: false
          // },
          // {
          //   id: "05",
          //   name: "后裔",
          //   disabled: false
          // },
          // {
          //   id: "06",
          //   name: "狄仁杰",
          //   disabled: false
          // }
        ];
      }
    }
  },
  watch: {
    selectList: {
      deep: true,
      immediate: true,
      handler: function(list) {
        if (list && list.length > 0) {
          this.sourceList = list;
          this.getselectLabels(this.value);
        }
      }
    }
  },
  mounted() {
    if (this.codeId) {
      this.loadData();
    }
  },
  methods: {
    deleteRnage() {
      this.selectKeyRange = [];
      this.selectRangeLabels = "";
      this.$emit("input", "");
      this.count++;
    },
    loadData() {
      let par = {
        serviceName: "newPlugin",
        servicePath: "code",
        code: this.codeId, // 类型:String  必有字段  备注:代码表表名
        sync: "1", // 类型:String  可有字段  备注:是否一次性返回代码全部数据,默认为"1"
        filter: this.filter ? this.filter : "", // 类型:String  可有字段  备注:过滤条件,根据加载的代码表自行拼写SQL条件
        parentCode: "mock" // 类型:String  可有字段  备注:父代码,分级加载时使用
      };
      this.$request(par).then(res => {
        if (res.status === "1") {
          this.sourceList = res.msgDetail;
          this.getselectLabels(this.value);
        }
      });
    },
    /**
     * @function getselectLabels
     * @param {Array} val - 当前选中值
     * @description 解析选中项,得到页面显示内容 (根据val 获取对应的name,设置回显)
     */

    getselectLabels(val) {
      if (val) {
        let label = [];
        this.sourceList.forEach(item => {
          if (val.indexOf(item[this.valueName]) > -1) {
            label.push(item.name);
          }
        });
        if (val.split(",")[0] == val.split(",")[1]) {
          this.selectRangeLabels = label[0] ? label[0] : "";
        } else {
          let str1 = label[0] ? label[0] : "";
          let str2 = label[1] ? label[1] : "";

          this.selectRangeLabels = str2 + "-" + str1;
        }
      }
    },
    getContainer(Node) {
      if (!this.triggerNode) return Node.parentNode;
      if (this.triggerNode == "parent") {
        return Node.parentNode;
      } else if (this.triggerNode == "body") {
        return document.body;
      } else {
        let x = Node;
        while (x.tagName != this.triggerNode) {
          x = x.parentNode;
        }
        return x;
      }
    },
    /**
     * @function menuEnter
     * @param {Number} index - 鼠标移入项的索引
     * @description  鼠标移入触发 记录鼠标所在位置
     */
    menuEnter(index) {
      this.enterIndex = index;
      // this.count++;
    },
    menuLeave() {
      // this.enterIndex = "";
      // this.count++;
    },
    /**
     * @function isenter
     * @param {Number} index - 遍历时 下拉选项的索引
     * @description 判断当前索引值是否等于鼠标移入项
     */
    isenter(index) {
      if (this.enterIndex !== "" && this.selectKeyRange.length == 1) {
        let first = this.selectKeyRange[0];
        if (this.enterIndex < first) {
          if (index > this.enterIndex && index < first) {
            return true;
          } else {
            return false;
          }
        } else if (this.enterIndex > first) {
          if (index > first && index < this.enterIndex) {
            return true;
          } else {
            return false;
          }
        }
        return false;
      } else return false;
    },
    /**
     * @function isSelect
     * @param {Number} index - 遍历时 下拉选项的索引
     * @description 判断当前索引值是否等于已选中节点的索引值
     */
    isSelect(index) {
      if (this.selectKeyRange.indexOf(index) > -1) {
        return true;
      } else {
        return false;
      }
    },
    /**
     * @function isRange
     * @param {Number} index - 遍历时 下拉选项的索引
     * @description 判断当前下拉项是否在已选中节点的区间内
     */
    isRange(index) {
      let first = this.selectKeyRange[0];
      let second = this.selectKeyRange[1];
      if (index > first && index < second) {
        return true;
      } else return false;
    },
    handleMenuClick(s) {
      let index = s.key;
      if (this.selectKeyRange.length == 1) {
        let first = this.selectKeyRange[0];
        if (index > first) {
          this.selectKeyRange[1] = index;
        } else {
          this.selectKeyRange = [index, first];
        }
        // 选择结束
        let ids = [
          this.sourceList[this.selectKeyRange[0]][this.valueName],
          this.sourceList[this.selectKeyRange[1]][this.valueName]
        ].join(",");
        this.$emit("input", ids);
        this.getselectLabels(ids);
        this.$emit("onChange", { type: "change", key: this.formItemKey, labels: this.selectRangeLabels });
        this.dropVisible = false;
      } else if (this.selectKeyRange.length == 2) {
        this.selectKeyRange = [index];
      } else {
        this.selectKeyRange.push(index);
      }
      this.count++;
    }
  }
};
</script>

<style lang="scss">
.selectrangeinput {
  .dropconditonSelectWidth {
    overflow: auto;
    max-height: 400px;
  }
  .selectrangeclose {
    font-size: 12px;
    display: none !important;
    color: rgba(0, 0, 0, 0.25);
    cursor: pointer;
    &:hover {
      color: rgba(0, 0, 0, 0.45);
    }
  }
  &:hover {
    .selectrangeclose {
      display: block !important;
    }
  }
}

.egselectrangeselectRow {
  background-color: #3f8fff;
  color: #ffffff !important;
  &:hover {
    background-color: #3f8fff !important;
  }
}
.egselectrangerangeRow {
  background-color: #e6f7ff;
}
.egselectrangeenterrow {
  background-color: #e6f7ff;
}
.menu-select-range {
  margin: 0;
}
</style>

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值