springboot+vue省市县街道地区四级联动

springboot+vue省市县街道地区四级联动

1. 级联选择器实现省市县街道四级联动

2. 下拉框实现省市县街道四级联动

1. 级联选择器实现省市县街道四级联动

​ 首先我们可以看到[Element ui](组件 | Element) 官网里的级联选择器的数据其实是树形的,所以我们可以在后端就把数据构造成树形结构的。有需要的小伙伴可以看我的另一篇博客:java–list转树形结构,这里就不再多讲。
在这里插入图片描述

1. 如果后台传过来的数据是树形结构的,那么我们直接绑定数据就可以了:

后台传过来的数据:
在这里插入图片描述

<template>
  <div>
    <el-row>
      <el-cascader
        v-model="value"
        :props="props"
        :options="result"
        style="width: 50%"
      ></el-cascader>
    </el-row>
  </div>
</template>
<script>
import { getAddress } from "@/utils/api";
export default {
  name: "Home",
  data() {
    return {
      //这里需要改成和后端传过来的属性名一致,不然渲染不上,因为默认的是label,value,当然也可以把后端传过来的属性名改变为label和value
      props: {
        label: "name",  
        value: "name",
        children: "children",
      },
      value: "",
      result: [],
    };
  },
  created() {
    this.getAllAddress();
  },
  methods: {
    getAllAddress() {
      getAddress().then((res) => {
        this.result = res.data.data;
      });
    },
  },
};
</script>

效果:

在这里插入图片描述

2.如果后台传过来的不是树形结构,那我们就要在前端把它构造成树形结构。

后台传过来的数据:
在这里插入图片描述

前端代码(主要代码是使用递归将扁平数据构造为树形数据):

<template>
  <div>
    <el-row>
      <el-cascader
        v-model="value"
        :props="props"
        :options="result"
        style="width: 50%"
      ></el-cascader>
    </el-row>
  </div>
</template>
<script>
import { getAddress } from "@/utils/api";
export default {
  name: "Home",
  data() {
    return {
      props: {
        label: "name",
        value: "name",
        children: "children",
      },
      value: "",
      result: [],
    };
  },
  created() {
    this.getAllAddress();
  },
  methods: {
    getAllAddress() {
      getAddress().then((res) => {
        var list = [];
        let addressData = res.data.data;
        // 调用递归方法 传入的值(源数据,根节点的pid,一个空数组)
        this.result = this.getTree(addressData, "0", list);
      });
    },
    getTree(rootList, id, list) {
      // 遍历源数组
      for (var i = 0; i < rootList.length; i++) {
        // 如果数组里每一个对象的pid==0
        if (rootList[i].pid == id) {
          // 就把当前对象push到list中,list中装的数据就是pid==0的对象,也就是根节点
          list.push(rootList[i]);
        }
      }
      // 遍历根节点list
      for (var j = 0; j < list.length; j++) {
        // 给list设置一个children属性
        list[j].children = [];
        // 再次调用递归  传入的值(源数据,根节点的id,一个空数组(也就是根节点的children))
        // 这样就会无线循环完所有的数据
        this.getTree(rootList, list[j].id, list[j].children);
        // 这里需要判断根节点的children是否有值
        if (list[j].children.length == 0) {
          // 如果没有把它删除
          delete list[j].children;
        }
      }
      return list;
    },
  },
};
</script>

效果:
在这里插入图片描述
至于为什么要判断根节点的children是否有值。如果不判断,就会出现children是一个空数组,对比下面两张图就知道了。

判断后:
在这里插入图片描述
没有判断:
在这里插入图片描述

2. 下拉框实现省市县街道四级联动

​ 如果后端返回的数据也是扁平数据,那么我们可以先筛选出省份数据(pid==0),在改变省份数据的时候,又筛选出市级数据,也就是市级的pid等于省级的id,以此内推即可;代码如下:

<template>
  <div>
    <el-row>
      <el-select v-model="privince" @change="changeProvince">
        <el-option
          v-for="item in privinceData"
          :key="item.id"
          :value="`${item.id}|${item.name}`"
          :label="item.name"
        >
        </el-option>
      </el-select>
      <el-select v-model="city" @change="changeCity">
        <el-option
          v-for="item in cityData"
          :key="item.id"
          :value="`${item.id}|${item.name}`"
          :label="item.name"
        >
        </el-option>
      </el-select>
      <el-select v-model="area" @change="changeArea">
        <el-option
          v-for="item in areaData"
          :key="item.id"
          :value="`${item.id}|${item.name}`"
          :label="item.name"
        >
        </el-option>
      </el-select>
      <el-select v-model="stree">
        <el-option
          v-for="item in streeData"
          :key="item.id"
          :value="item.name"
          :label="item.name"
        >
        </el-option>
      </el-select>
      <el-button @click="save" type="primary">提交</el-button>
    </el-row>
  </div>
</template>
<script>
import { getAddress } from "@/utils/api";
export default {
  name: "Home",
  data() {
    return {
      privince: "",
      city: "",
      area: "",
      stree: "",
      privinceData: [],
      cityData: [],
      areaData: [],
      streeData: [],
      address: [],
    };
  },
  created() {
    this.getProvince();
  },
  methods: {
    getProvince() {
      // 获取数据
      getAddress().then((res) => {
        this.address = res.data.data;
        // 筛选出身份数据
        this.privinceData = this.address.filter((itme) => itme.pid == "0");
      });
    },
    changeProvince(value) {
    // 当省份数据改变时,根据id查找出当前省份下的城市
    // 为什么会用`${item.id}|${item.name}`,因为我们只能根据省份的id找到它下面的城市,但是我们存入数据库的又是它的名字(例如江苏省),所以我用了`${}`来拼接变量
      
       var id = value.split("|")[0];
      // 上面代码的意思(举例):
      // 此时的 value = 0|江苏省,根据 | 分割为一个数组,数组里第一个元素为0,第二个元素为江苏省,再取第一个元素
     // 此时的id==0
      this.cityData = this.address.filter((item) => item.pid == id);
      this.city = "";
      this.area = "";
      this.stree = "";
    },
    changeCity(value) {
      var id = value.split("|")[0];
      this.areaData = this.address.filter((item) => item.pid == id);
      this.area = "";
      this.stree = "";
    },
    changeArea(value) {
      var id = value.split("|")[0];
      this.streeData = this.address.filter((item) => item.pid == id);
      this.stree = "";
    },
  },
};
</script>

效果:
在这里插入图片描述
解释得可能不是那么清楚,大家多多包涵!

  • 2
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值