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,并在项目中引入它们。

相关推荐
Martin -Tang2 小时前
Vue 3 中,ref 和 reactive的区别
前端·javascript·vue.js
FakeOccupational3 小时前
nodejs 020: React语法规则 props和state
前端·javascript·react.js
放逐者-保持本心,方可放逐3 小时前
react 组件应用
开发语言·前端·javascript·react.js·前端框架
曹天骄4 小时前
next中服务端组件共享接口数据
前端·javascript·react.js
郝晨妤6 小时前
鸿蒙ArkTS和TS有什么区别?
前端·javascript·typescript·鸿蒙
AvatarGiser6 小时前
《ElementPlus 与 ElementUI 差异集合》Icon 图标 More 差异说明
前端·vue.js·elementui
喝旺仔la6 小时前
vue的样式知识点
前端·javascript·vue.js
别忘了微笑_cuicui6 小时前
elementUI中2个日期组件实现开始时间、结束时间(禁用日期面板、控制开始时间不能超过结束时间的时分秒)实现方案
前端·javascript·elementui
尝尝你的优乐美6 小时前
vue3.0中h函数的简单使用
前端·javascript·vue.js
windy1a7 小时前
【C语言】js写一个冒泡顺序
javascript