vue 多级联动选择器

JavaScript08

vue 多级联动选择器,第1张

对于我们的最终效果来说,是不是很简单呢?

当然,如果我这里写三个h-wrapper的话,我们自然而然就变成了三级联

最外层的slector组件用来暴露在外部显示的文字,以及控制级联选择器的显示隐藏,在每一次开始一个新的功能的时候,我们应该先完成重点的功能,重点功能完成之后,再去修改一些样式包括交互效果

对于这个模板来说,需要解释的地方很少,我都写在注释里边

首先需要重点提一下的是在mounted方法中,我们使用了this.$on方法,订阅了一个在当前组件内并没有发布的事件,这个事件,我定义在了h-wrapper这个组件中,稍后可以看到

其余的地方没有太复杂的功能和逻辑,就不一一解释

在模板中,需要重点关注的其实就是两个style,以及四个事件,当然了,还有插槽的位置,我这里使用了一个小技巧,在原始位置直接写好了四个option,并且其中一个还显示请选择,用来保证可选项的位置永远都可以处在最中间的位置

在逻辑中,我通过操作activeIndex这个索引值来动态的修改数据中ul的位移,使得当前永远显示的是对应索引与option高度计算出的位置

通过touchstart、touchmove、touchend三个事件来操作元素的位置与滑动

通过watch侦听对应属性,并实时触发事件,使得级联选择器发生改变,达到内外同步

通过mounted与updated钩子函数来保证当前的级联选择器属性会随着刷新而刷新

通过slot插槽来显示外部传入的option选项

对于option组件来说,并没有多少内容,它只需要负责显示数据,以及让级联选择器可以正确的获取到值即可

首先当前这个级联选择器的样式,我没有做太多的处理,但是已经很好看了有没有!

最终,我们就已经成功的打造了一款移动端的级联选择器,可以实现一级二级三级联动,当然了,多级也没有任何问题,但是在移动端,我建议最多到三级联动,否则的话影响用户体验感

对于我们的最终效果来说,是不是很简单呢?

当然,如果我这里写三个h-wrapper的话,我们自然而然就变成了三级联动

最外层的slector组件用来暴露在外部显示的文字,以及控制级联选择器的显示隐藏,在每一次开始一个新的功能的时候,我们应该先完成重点的功能,重点功能完成之后,再去修改一些样式包括交互效果

对于这个模板来说,需要解释的地方很少,我都写在注释里边

首先需要重点提一下的是在mounted方法中,我们使用了this.$on方法,订阅了一个在当前组件内并没有发布的事件,这个事件,我定义在了h-wrapper这个组件中,稍后可以看到

其余的地方没有太复杂的功能和逻辑,就不一一解释

在模板中,需要重点关注的其实就是两个style,以及四个事件,当然了,还有插槽的位置,我这里使用了一个小技巧,在原始位置直接写好了四个option,并且其中一个还显示请选择,用来保证可选项的位置永远都可以处在最中间的位置

在逻辑中,我通过操作activeIndex这个索引值来动态的修改数据中ul的位移,使得当前永远显示的是对应索引与option高度计算出的位置

通过touchstart、touchmove、touchend三个事件来操作元素的位置与滑动

通过watch侦听对应属性,并实时触发事件,使得级联选择器发生改变,达到内外同步

通过mounted与updated钩子函数来保证当前的级联选择器属性会随着刷新而刷新

通过slot插槽来显示外部传入的option选项

对于option组件来说,并没有多少内容,它只需要负责显示数据,以及让级联选择器可以正确的获取到值即可

首先当前这个级联选择器的样式,我没有做太多的处理,但是已经很好看了有没有!

最终,我们就已经成功的打造了一款移动端的级联选择器,可以实现一级二级三级联动,当然了,多级也没有任何问题,但是在移动端,我建议最多到三级联动,否则的话影响用户体验感

最近做项目经常会用到一些UI库,比如 element 、 iview 等,这些能够快速构建应用的库真的十分方便。比如 iview 的级联菜单很是好用,但是在使用的同时不免起了一些疑惑,它是怎么做到多级联动,依我所知,如果一个数据是多层的,我们就要多次使用 v-for ,并且需要知道要循环几次,但是这个组件貌似不需要多次复用。好啦,下面进入正题!

首先我们手里是一份这样的 JSON 数据:

这是最重要的环节,组件的递归实现了级联菜单的多级联动,这个过程就如同实现对象的深复制一样。那么接下来我们按照这份数据写一个递归组件:

这里要强调以下,组件的 name 属性必须要有,否则无法实现递归,当然递归也需要有终止的条件,上边的 isFloder 便是了。

这里也有需要注意的, v-for 循环需要绑定 key ,否则会报警告。

最后来看下这个简单级联菜单的效果:

 <Col span="24">

            <FormItem label="所属区域" prop="areaValue"> 

              <Cascader :data="areatree" v-model="formData.areaValue" @on-change="getAreaData"  placeholder="请选择所属区域" change-on-select></Cascader>

            </FormItem>

        </Col>

<script>

import { interFaceImpl } from "@/api/index" // 封装的方法,用于调用指定接口

import { api } from '@/views/sluiceConfig/lockRoomInfo/index' //请求接口

export default {

  data() {

    return {

      defaultTree: [], //默认区域数据

      areatree: [],//所属区域树形列表

      formData: { // 表单字段对象

        areaCode: "", // 所属闸室

        areaValue: [],

      },

  watch: {

    // 监听详细信息赋值

    detailData(newVal) {

      if (JSON.stringify(newVal) !== "{}") {

        this.formData = newVal

        this.formData.areaValue = []

        if (this.formData.areaCode) {

          this.getAreaValue(this.formData.areaCode)

        }

      } else {

        this.formData = {

          areaCode: "", // areaCode

        }

        this.formData.areaValue = []

        this.$refs["formDataValidate"].resetFields()

      }

    }

  },

  created() {

        this.getAreaTreeData()

  },

  methods: {

   getAreaTreeData() { // 获取区域树信息

      var that = this

      return new Promise((resolve,reject) => {

        this.$interFaceImpl(api['area_findTree']).then(res => {

          // debugger

          if (res && res.data) {

            res.data.data.forEach(ele => {

              if (ele.areaCode != '-1') {

                that.defaultTree.push({

                  value: ele.areaCode,

                  label: ele.areaName,

                  parentValue: ele.parAreaCode

                })

              }

            })

            that.areatree = transform(that.defaultTree, 'value', 'parentValue', 'children')

          }

          resolve()

        }).catch(err => {

          reject(err)

        })

      })

    },

    //级联选择赋值

    getAreaData: function(val){

      val.forEach(ele => {

        this.formData.areaValue.unshift(ele)

      })

      this.formData.areaCode = val[val.length-1]

    },

 //初始化默认值

    getAreaValue: function(id){

      var that = this

      that.defaultTree.forEach(ele => {

        if(ele.value == id){

          that.formData.areaValue.unshift(ele.value)

          that.formData.areaCode = that.formData.areaValue[that.formData.areaValue.length-1]

          that.getAreaValue(ele.parentValue)

        }

      })

    },

  }

}

</script>