zoukankan      html  css  js  c++  java
  • vue手动制作地址选择器

    方法一:4级地址选择器(基于elementui   Cascader 级联选择器) 推荐

    效果图:

     组件源码:

    <template>
      <div class="select-city" ref="selectCity">
        <el-cascader
          :options="options2"
          @change="change"
          v-model="selCity"
          :props="props"
        ></el-cascader>
      </div>
    
    </template>
    
    <style>
      .select-city .el-input{
         350px;
      }
    </style>
    
    <script>
      import addressData from 'common/json/class4new.json'
      export default {
        props: {
          value: {
            required: true
          },
          getCityName: {
    
          }
        },
        data() {
          return {
            options2: addressData,
            props: {
              label: 'name',
              value: 'id',
              children: 'children'
            },
            selCity: []
          }
        },
        watch: {
          value (val) {
            this.init()
          }
        },
        created() {
          // 组件刚载入并不会触发watch value
        },
        methods: {
          init() {
            let el = this.$refs.selectCity
            if (!this.value) {
              if (this.selCity.length) {
                this.selCity = []
                el.getElementsByClassName('el-cascader__label')[0].innerHTML = ''
                el.getElementsByClassName('el-input__inner')[0].setAttribute('placeholder', '请选择')
              }
            } else {
              if (this.selCity.length===0 || this.selCity[3] !== this.value) {
                this.selCity[0] = this.value.substr(0, 2) + '0000'
                this.selCity[1] = this.value.substr(0, 4) + '00000000'
                this.selCity[2] = this.value.substr(0, 6) + '000000'
                this.selCity[3] = this.value
                let name = this.getNode().join('<span>/</span>')
                el.getElementsByClassName('el-cascader__label')[0].innerHTML = name
                el.getElementsByClassName('el-input__inner')[0].setAttribute('placeholder', '')
              }
            }
          },
          change(val) {
            // 只有选完了,才会将数据返回给父组件
            this.$emit('input', val[3])
            this.returnCityName()
          },
          returnCityName() {
            if (typeof this.getCityName === 'function') {
              this.getCityName(this.getNode().join(''))
            }
          },
          getNode() {
            let name = []
            this.options2.filter(v => {
              if (name[0]) return
              if (v.id===this.selCity[0]) {
                name.push(v.name)
                v.children.filter(v => {
                  if (name[1]>0) return
                  if (v.id===this.selCity[1]) {
                    name.push(v.name)
                    v.children.filter(v => {
                      if (name[2]>0) return
                      if (v.id===this.selCity[2]) {
                        name.push(v.name)
                        v.children.filter(v => {
                          if (name[3]>0) return
                          if (v.id===this.selCity[3]) {
                            name.push(v.name)
                            return false
                          }
                        })
                      }
                    })
                  }
                })
              }
            })
            return name
          }
        }
      }
    </script>

    方法二:4级地址选择器(基于elementui  select选择器 )

    适用环境: PC

    开发过程中遇到的问题:

    1. 自定义组件如何做到双向数据绑定

    2. 自定义组件在刚加载完毕,会执行一次created和mounted,当组件上绑定的v-model变化时候,也就是做编辑的时候,触发的watch监听的value方法

    3.这个程序刚好是一个自循环,一旦更新了地址组件绑定的值立刻就触发this.$emit,把执行结果返回至父组件。这边需要visible-change(下拉框出现/隐藏时触发, 出现则为 true,隐藏则为 false),来组件地址组件数据的初始化,导致向父组件传递错误数据

    小小的程序,把我折腾了好几天,仔细想想,两个2原因:1.缺少自己写组件的经历导致对vue的很多api不熟悉  2.缺乏独自面对困难的恒心

    效果图:

    地址组件代码:

    <style>
      .block .el-select{display: block;}
      .block .el-select{margin-bottom: 20px}
    </style>
    
    <template>
      <div>
        <div :class="{block: block}">
          <el-select v-model="proviceCode" popper-class="tab-select" placeholder="请选择省" @change="proviceChange" @visible-change="vChange($event, 'provice')">
            <el-option
              v-for="(item, index) in provice"
              :key="item.id"
              :label="item.name"
              :value="item.id">
            </el-option>
          </el-select>
          <el-select v-model="cityCode" popper-class="tab-select" placeholder="请选择市" @change="cityChange" @visible-change="vChange($event, 'city')">
            <el-option
              v-for="(item, index) in city"
              :key="item.id"
              :label="item.name"
              :value="item.id">
            </el-option>
          </el-select>
          <el-select v-model="areaCode" popper-class="tab-select" placeholder="请选择区或县" @change="areaChange" @visible-change="vChange($event, 'area')">
            <el-option
              v-for="(item, index) in area"
              :key="item.id"
              :label="item.name"
              :value="item.id">
            </el-option>
          </el-select>
          <el-select v-model="villageCode"  popper-class="tab-select" placeholder="请选择乡" @change="villageChange"  @visible-change="vChange($event, 'village')">
            <el-option
              v-for="(item, index) in village"
              :key="item.id"
              :label="item.name"
              :value="item.id">
            </el-option>
          </el-select>
          <input type="hidden" :value="value">
        </div>
      </div>
    </template>
    
    <script>
      import address from 'common/json/class4new.json'
      export default {
        props: {
          block: {
            type: Boolean,
            default: false
          },
          value: {
            required: false
          }
        },
        data() {
          return {
            provice: address,
            city: [],
            area: [],
            village: [],
            proviceCode: '',
            cityCode: '',
            areaCode: '',
            villageCode: '',
            isOpen: {
              provice: false,
              city: false,
              area: false,
              village: false
            }
          }
        },
        watch: {
          value (val) {
            if (val.code !== this.villageCode) {
              this.init()
            }
          }
        },
        created() {
          this.villageCode = this.value.code
          this.init()
        },
        mounted () {
          this.$root.eventHub.$on("reset-addressSelect", () => {
            this.city = []
            this.area = []
            this.village = []
            this.proviceCode = ''
            this.cityCode = ''
            this.areaCode = ''
            this.villageCode = ''
          })
        },
        methods: {
          vChange(val, type) {
            this.isOpen[type] = val
          },
          init() {
            let code = this.value.code;
            if (code) {
              let v = code.toString()
              this.proviceCode = v.substr(0,2) + '0000'
              this.cityCode = v.substr(0,4)+'00000000'
              this.areaCode = v.substr(0,6)+'000000'
              this.villageCode = v
              this.proviceChange(this.proviceCode).then(_ => {
                this.cityChange(this.cityCode).then(_ => {
                  this.areaChange(this.areaCode)
                })
              })
            } else {
              this.city = []
              this.area = []
              this.village = []
              this.proviceCode = ''
              this.cityCode = ''
              this.areaCode = ''
              this.villageCode = ''
            }
          },
          proviceChange(id) {
            return new Promise((resolve, reject) => {
              if (this.isOpen.provice) {
                this.city = []
                this.area = []
                this.village = []
                this.cityCode = ''
                this.areaCode = ''
                this.villageCode = ''
              }
              this.provice.filter(v => {
                if (v.id === id) {
                  this.city = v.children
                  resolve()
                  return false
                }
              })
            })
          },
          cityChange(id) {
            return new Promise((resolve, reject) => {
              if (this.isOpen.city) {
                this.area = []
                this.village = []
                this.areaCode = ''
                this.villageCode = ''
              }
              this.city.filter(v => {
                if (v.id === id) {
                  this.area = v.children
                  resolve()
                  return false
                }
              })
            })
          },
          areaChange(id) {
            return new Promise((resolve, reject) => {
              if (this.isOpen.area) {
                this.village = []
                this.villageCode = ''
              }
              this.area.filter(v => {
                if (v.id === id) {
                  this.village = v.children
                  resolve()
                  return false
                }
              })
            })
          },
          villageChange(id) {
            var text = []
            this.provice.filter(v => {
              if (v.id === this.proviceCode) {
                text.push(v.name)
                return false
              }
            })
            this.city.filter(v => {
              if (v.id === this.cityCode) {
                text.push(v.name)
                return false
              }
            })
            this.area.filter(v => {
              if (v.id === this.areaCode) {
                text.push(v.name)
                return false
              }
            })
            this.village.filter(v => {
              if (v.id === id) {
                text.push(v.name)
                return false
              }
            })
            this.$emit('input', {
              text: text.join(''),
              code: id
            })
          }
        }
      }
    </script>
  • 相关阅读:
    指出在 spring aop 中 concern 和 cross-cutting concern 的不同之处?
    什么是 spring bean?
    Java 中,Serializable 与 Externalizable 的区别?
    spring DAO 有什么用?
    spring 支持集中 bean scope?
    Spring 应用程序有哪些不同组件?
    什么是切点JoinPoint?
    @Required 注解有什么用?
    用什么命令对一个文件的内容进行统计?(行号、单词数、 字节数) ?
    区分构造函数注入和 setter 注入?
  • 原文地址:https://www.cnblogs.com/zph666/p/7661524.html
Copyright © 2011-2022 走看看