vue el-cascader 省市区封装及使用

使用了 Element UI 中的 el-cascader 组件,并对其进行了进一步封装和定制

创建组件index.vue (src/components/addressCascader/index.vue)
vue 复制代码
<template>
  <div>
    <el-cascader
        v-if="showca"
        size="large"
        :props="props"
        :options="cascaderOption"
        :placeholder="placeholder || '选择省/市/区'"
        v-model="selectedOptions"
        @change="addressChange"
        ref="place"
        :disabled="disabled"
        :clearable="clearable"
        :popper-class=" 'cascader-default'
      "
    >
    </el-cascader>
  </div>
</template>

<script>
  import { getDistrictAllSelect, getDistrictFilterSelect } from '@/api/district'
  export default {
    props: {
      selectedVal: {
        type: [Number, String],
        default: ''
      },
      disabled: {
        type: Boolean,
        default: false
      },
      checkStrictly: {
        type: Boolean,
        default: false
      },
      isNeedFilter: {
        type: Boolean,
        default: true
      },
      clearable: {
        type: Boolean,
        default: false
      },
      placeholder: String
    },
    data () {
      return {
        props: {
          value: 'id',
          label: 'name',
          checkStrictly: this.checkStrictly,
          expandTrigger: 'hover'
        },
        newDistictId: '',
        selectedOptions: [],
        showca: true,
        timeout: null,
        isChoose: false,
        chooseLevel: 0,
        cascaderOption: [],
        originData: [],
        cascaderList: []
      }
    },
    watch: {
      selectedVal: {
        handler (val) {
          if (val) {
            if(this.originData.length>0) {
              this.cascaderList = []
              this.findParent(Number(this.selectedVal))
              this.cascaderList.push(Number(this.selectedVal))
              this.selectedOptions = this.cascaderList
              this.$nextTick(() => {
                let label = this.$refs.place.getCheckedNodes()
                    ? this.$refs.place.getCheckedNodes()[0].pathLabels
                        ? this.$refs.place.getCheckedNodes()[0].pathLabels.join('')
                        : ''
                    : ''
                let level = this.$refs.place.getCheckedNodes()
                    ? this.$refs.place.getCheckedNodes()[0].level
                    : ''

                this.$emit(
                    'getVal',
                    this.selectedOptions[this.selectedOptions.length - 1],
                    label,
                    level
                )
              })
            }
          } else {
            this.clearVal()
          }
        },
        immediate: true
      }
    },
    mounted () {
      this.getDistrictAllSelect()
    },
    beforeDestroy () {},
    methods: {
      findParent (idx) {
        this.originData.forEach(item => {
          if (idx.toString() === item.id.toString()) {
            let pid = item['parentId']

            if (pid !== 0) {
              this.cascaderList.unshift(pid)
              this.findParent(pid)
            }
          }
        })
      },

      addressChange (arr) {
        if (arr.length > 1) {
          this.isChoose = true
        }
        if (arr.length == 1) {
          this.chooseLevel = 0
        } else if (arr.length == 2) {
          this.chooseLevel = 1
        } else if (arr.length == 3) {
          this.chooseLevel = 3
        }
        if (arr.length == 0) {
          this.$emit('getVal', '')
          return
        }
        console.log(
            this.$refs.place.getCheckedNodes()[0],
            'this.$refs.place.getCheckedNodes()[0]'
        )
        let label = this.$refs.place.getCheckedNodes()[0].pathLabels
            ? this.$refs.place.getCheckedNodes()[0].pathLabels.join('')
            : ''
        let level = this.$refs.place.getCheckedNodes()[0].level

        this.$emit('getVal', arr[arr.length - 1], label, level)
        if (arr.length > 2) {
          this.$refs.place.dropDownVisible = false
        }
      },
      clearVal () {
        if (this.$refs.place) {
          this.selectedOptions = []
          this.$refs.place.$refs.panel.checkedValue = []
          this.$refs.place.$refs.panel.activePath = []
          this.$refs.place.$refs.panel.syncActivePath()
        }
      },
      async getDistrictAllSelect () {

        let data
        if (this.checkStrictly && this.isNeedFilter) {
          data = await getDistrictFilterSelect()
          this.originData = data || []
          this.cascaderOption = this.transTree(data)
        } else {
          if (sessionStorage.pvRegionData&&sessionStorage.pvRegionOriginData!='undefined') {
            this.originData = JSON.parse(sessionStorage.pvRegionOriginData)
            this.cascaderOption = JSON.parse(sessionStorage.pvRegionData)
          } else {
            data = await getDistrictAllSelect()
            this.originData = data || []
            sessionStorage.setItem('pvRegionOriginData', JSON.stringify(data))
            this.cascaderOption = this.transTree(data)
            sessionStorage.setItem(
                'pvRegionData',
                JSON.stringify(this.cascaderOption)
            )
          }
        }
        if (this.selectedVal) {
          this.cascaderList = []
          this.findParent(Number(this.selectedVal))
          this.cascaderList.push(Number(this.selectedVal))
          this.selectedOptions = this.cascaderList
          this.$nextTick(() => {
            let label = this.$refs.place.getCheckedNodes()
                ? this.$refs.place.getCheckedNodes()[0].pathLabels
                    ? this.$refs.place.getCheckedNodes()[0].pathLabels.join('')
                    : ''
                : ''
            let level = this.$refs.place.getCheckedNodes()
                ? this.$refs.place.getCheckedNodes()[0].level
                : ''

            this.$emit(
                'getVal',
                this.selectedOptions[this.selectedOptions.length - 1],
                label,
                level
            )
          })
        }
      },
      transTree (data) {
        let result = []
        let map = {}
        if (!Array.isArray(data)) {
          //验证data是不是数组类型
          return []
        }
        data.forEach(item => {
          //建立每个数组元素id和该对象的关系
          map[item.id] = item //这里可以理解为浅拷贝,共享引用
        })
        data.forEach(item => {
          let parent = map[item.parentId] //找到data中每一项item的爸爸
          if (parent) {
            //说明元素有爸爸,把元素放在爸爸的children下面
            ;(parent.children || (parent.children = [])).push(item)
          } else {
            //说明元素没有爸爸,是根节点,把节点push到最终结果中
            result.push(item) //item是对象的引用
          }
        })
        return result //数组里的对象和data是共享的
      }
    }
  }
</script>

<style scoped lang="scss"></style>
页面引入
  • 在需要使用addressCascader组件的地方,通过import语句引入组件注册并使用
vue 复制代码
<template>
  <div>
    <address-cascader
        :selectedVal="selectedValue"
        @getVal="
              (districtVal, districtLabel, districtLevel) =>
                setDistrictId(districtVal, districtLabel, info, districtLevel)
            "
        :isNeedFilter="info.isNeedFilter"
        :checkStrictly="info.checkStrictly"
        ref="addressCascader"
        :disabled="info.disabled"
    ></address-cascader>
  </div>
</template>
<script>
  import addressCascader from "@/components/addressCascader/index";

  export default {
    components: {
      addressCascader
    },
    data() {
      return {
        info:{
          clearable: true,
          isNeedFilter:false,
          valueFormat:'yyyy-MM-dd',
          checkStrictly: false,
          pickerOptions:{}
        },
        dataSource: [],
        selectedValue: ''
      }
    },
    methods: {
      setDistrictId(val, label, info, districtLevel) {
        console.log("选中的值,文字,信息,级别", val, label, info, districtLevel);
      }
    }
    // ...
  }
</script>

确保你已经安装了Vue.js和Element UI,并在项目中引入它们。

相关推荐
zl0_00_0几秒前
isctf2025 部分wp
linux·前端·javascript
m0_6161884914 分钟前
循环多个表单进行表单校验
前端·vue.js·elementui
不一样的少年_37 分钟前
WebTab等插件出事后:不到100行代码,带你做一个干净透明的新标签页
前端·javascript·浏览器
幸运小圣37 分钟前
关于Vue 3 <script setup> defineXXX API 总结
前端·javascript·vue.js
AAA阿giao1 小时前
从零开始:用 Vue 3 + Vite 打造一个支持流式输出的 AI 聊天界面
前端·javascript·vue.js
玉宇夕落1 小时前
Vue 3 实现 LLM 流式输出:从零搭建一个简易 Chat 应用
前端·vue.js
悦来客栈的老板1 小时前
AST反混淆实战|reese84_jsvmp反编译前的优化处理
java·前端·javascript·数据库·算法
爱看书的小沐1 小时前
【小沐学WebGIS】基于Cesium.JS绘制雷达波束/几何体/传感器Sensor(Cesium / vue / react )
javascript·vue.js·react.js·雷达·cesium·传感器·波束
zlpzlpzyd1 小时前
vue.js是干什么的?各个版本有什么区别?
前端·javascript·vue.js
被考核重击1 小时前
【无标题】
前端·javascript·vue.js