vue2 省市区联动组件封装

文章描述了如何在ElementUI中使用el-select组件实现省市区的联动选择,遇到三级数据需求时,作者选择自定义封装以适应动态展示。内容包括布局、数据绑定和监听逻辑的详细实现。
摘要由CSDN通过智能技术生成

在element ui中有级联选择器el-cascader,其实已经够用了,但是在实际需求中,发现el-cascader如果有三级,数据数组必须得三个才能完全展示,所以不符合实际需求,还是自定义封装吧

需求:省市区联动数组,有多少个显示多少个

这里使用element ui得el-select组件,思路是使用监听

布局

  <el-select
      ref="selectProvinces"
      v-model="provinces.value"
      placeholder="请选择省"
      :disabled="disableds.provinces"
    >
      <el-option
        v-for="province in provinces.children"
        :key="province.value"
        :label="province.label"
        :value="province.value"
      >
      </el-option>
    </el-select>
    <el-select
      ref="selectCitys"
      v-model="citys.value"
      placeholder="请选择市"
      :disabled="disableds.citys"
      :default-first-option="true"
      @change="changeCity"
    >
      <el-option
        v-for="city in citys.children"
        :key="city.value"
        :label="city.label"
        :value="city.value"
      >
      </el-option>
    </el-select>
    <el-select
      ref="selectAreas"
      v-model="areas.value"
      placeholder="请选择区"
      :disabled="disableds.areas"
    >
      <el-option
        v-for="area in areas.children"
        :key="area.value"
        :label="area.label"
        :value="area.value"
      >
      </el-option>
    </el-select>

传入省市区数组以及全部省市区json数据

也可不传

 props: {
    value: {
      type: Array,
      required: true
    },
    dataSource: Array,
  },

数据传入逻辑以及选择省市区联动逻辑

  data() {
    return {
      provinces: { label: "", value: "", children: [], index: "" },
      citys: { label: "", value: "", children: [], index: "" },
      areas: { label: "", value: "", children: [], index: "" },
      isForcibly: false,
    };
  },
  watch: {
    value: {
      handler: function() {
        //当传入的省市区数组为0时初始化 避免还存留上一个选择过的
        if (this.value.length == 0) {
          this.provinces = { label: "", value: "", children: [], index: "" };
          this.provinces.children = [...this.dataSource].map(item => {
            return { label: item.label, value: item.value };
          });
          this.citys = { label: "", value: "", children: [], index: "" };
          this.areas = { label: "", value: "", children: [], index: "" };
        }
        // 根据value渲染
        if (this.value && Array.isArray(this.value) && this.value.length > 0) {
          this.isForcibly = true;
          let keywords = ["provinces", "citys", "areas"];
          for (let index = 0; index < this.value.length; index++) {
            let keyword = keywords[index];
            this[keyword].value = this.value[index];
            if (index === 0) {
              this.provinces.index = this.dataSource.findIndex(
                item => item.value === this.value[index]
              );
              this.citys.children = this.dataSource[
                this.provinces.index
              ].children.map(item => {
                return { label: item.label, value: item.value };
              });
            }
            if (index === 1) {
              this.citys.index = this.dataSource[
                this.provinces.index
              ].children.findIndex(item => item.value === this.value[index]);
              if(this.citys.index !== -1) {
                this.areas.children = this.dataSource[
                  this.provinces.index
                ].children[this.citys.index].children.map(item => {
                  return { label: item.label, value: item.value };
                });
              } 
            }
          }

          this.$nextTick(() => (this.isForcibly = false));
        } else {
          this.provinces.value = "";
          this.citys.value = "";
          this.areas.value = "";
        }
      },
      immediate: true,
      deep: true
    },
    "provinces.value": {
      handler: function() {
        if (!this.provinces.value) return;
        this.provinces.index = this.dataSource.findIndex(
          item => item.value === this.provinces.value
        );
        if (this.isForcibly) return;
        this.citys = { label: "", value: "", children: [], index: "" };
        this.citys.children = this.dataSource[
          this.provinces.index
        ].children.map(item => {
          return { label: item.label, value: item.value };
        });
        this.areas = { label: "", value: "", children: [], index: "" };
        this.$emit("input", [this.provinces.value]);
      },
      deep: true
    },
    "citys.value": {
      handler: function() {
        if (!this.citys.value) return;
        this.citys.index = this.dataSource[
          this.provinces.index
        ].children.findIndex(item => item.value === this.citys.value);
        if (this.isForcibly) return;

        this.areas = { label: "", value: "", children: [], index: "" };
        this.areas.children = this.dataSource[this.provinces.index].children[
          this.citys.index
        ].children.map(item => {
          return { label: item.label, value: item.value };
        });
        this.$emit("input", [this.provinces.value, this.citys.value]);
      },
      deep: true
    },
    //监听区级选择 如果存在数据那么说明已经选择完毕
    "areas.value": {
      handler: function() {
        if (!this.areas.value || this.isForcibly) return;
        this.$emit("input", [
          this.provinces.value,
          this.citys.value,
          this.areas.value
        ]);
      },
      immediate: true,
      deep: true
    },
    },
  },
  created() {
    this.provinces.children = [...this.dataSource].map(item => {
      return { label: item.label, value: item.value };
    });
  },

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

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值