vue手写列表多级联动

一、项目需求

用户登录后展示条件筛选页面,多层条件筛选,存在单选和多选情况,以及视图样式根据选中情况有相应的变,点击清空按钮后恢复初始状态。效果图如下:
20191215_163317.gif

二、数据分析

列表渲染的数据部分前端写死,部分是从后端接口调取:

// 获取接口数据
mounted () {
    let param = {
      enableFlag: 'Y',
    }
    let promise0 = fetchCarBrand(param)
    let promise1 = fetchSelectTList('APP.CAR.ENERGY_TYPE')
    let promise2 = fetchSelectTList('APP.CAR.DISPLACEMENT')
    let promise3 = fetchSelectTList('APP.CAR.CLOUR')
    let promise4 = fetchSelectTList('APP.CAR.PASSENGERS')
    Promise.all([promise0, promise1, promise2, promise3, promise4]).then(
      res => {
        console.log(res)
        this.carBrandData = res[0].rows
        this.newCarBrandData = this.carBrandData.map(item => {
          return Object.assign(item, { isPiont: false })
        })
        this.energyType = res[1].rows
        this.displacement = res[2].rows
        this.carColor = res[3].rows
        this.persons = res[4].rows
      }
    )
}

(1)三级联动---以车辆品牌为例:
image.png
  • dom结构:
<!-- 一层列表 -->
<li
    :class="{ switch: activeIndex === 1 }"
    class="car-model"
    @click="handleSwitchLiTwo"
  >
    <div
      :class="{
        bluecolor: selectParam.brandList || selectParam.modelList
      }"
    >
      <i
        :class="{
          bluepoint: selectParam.brandList || selectParam.modelList
        }"
      />车辆品牌
    </div>
    <!-- 二层列表 -->
    <ul v-if="isModelShow">
      <li
        v-for="(item, index) in newCarBrandData"
        :key="index"
        @click="selectCarModel(item)"
      >
        <div
          :class="{
            bluecolor:
              selectParam.brandList &&
              selectParam.brandList.find(e => e === item.brandId)
          }"
        >
          <i
            :class="{
              bluepoint: modelMap[item.brandId] && modelMap[item.brandId].length
            }"
          />
          {{ item.brandName }}
        </div>
      </li>
    </ul>
   <!-- 三层列表 -->
    <ul v-if="isModel" class="car-model-child">
      <li
        v-for="(v, i) in newModelData"
        :key="i"
        :class="{
          bluecolor:
            modelMap[v.brandId] && modelMap[v.brandId].includes(v.modelId)
        }"
        @click.stop="handleSelectModel(v)"
      >
        {{ v.modelName }}
      </li>
    </ul>
  </li>

此处将二层列表和三层列表写成并列结构,原本写的是嵌套结构,但由于后来属性控制出现问题,改成了并列结构。
同时针对动态类名的控制这里使用的是我点击选中后生成的条件列表数组去控制,如果用boolean值就会有一堆的变量需要在不同阶段去改变,很繁琐。
首先一层列表的切换通过判断当前点击下标是否等于该元素在列表中的下标相等,来控制状态。关于tab切换操作方法可参考vue写tab切换

  • 接下来的事件处理才是实现这个功能的重点:
  • 第二级列表的点击事件
// 品牌选择
    selectCarModel (item) {
      this.isModel = true
      // 判断筛选参数里是否存在该列表属性,若没有给一个初始空数组
      if (!this.selectParam.brandList) this.selectParam.brandList = []
     // 若存在则先判断是首次点击选中还是要再次点击取消
      if (this.selectParam.brandList.indexOf(item.brandId) > -1) {
        // 再次点击取消操作
        this.newModelData = []  // 清空第三层列表
        // 过滤掉对应品牌列表里的当前点击项
        this.selectParam.brandList = this.selectParam.brandList.filter(
          i => i !== item.brandId
        )
      } else {
        // 点击选中操作 
       // 设置第三层列表项的数据
        this.newModelData = item.modelList
       // 向对应品牌列表里添加当前点击的品牌id
        this.selectParam.brandList.push(item.brandId)
      }
      // 如果品牌列表为空
      if (this.selectParam.brandList.length === 0) {
        delete this.selectParam.brandList  // 删除筛选参数中的品牌列表属性
        this.isModel = false  // 隐藏第三层列表
      }
      this.$forceUpdate()  // 强制页面更新(重点)
    },
  • 第三级列表的点击事件
    其实实现该模块最难得点就在于这第三层列表要与第二层以及第一层列表的关联,此处我采用的做法是创建一个类似Map结构的对象属性来存选中的数据,利用第三层列表与第二层列表之间的共同的属性brandId作为属性,将选中的modelId存到对应的brandId中,每次点击就判断该map对象下是否存在该modelId,存在则过滤掉不存在则添加。当某个brandId为空是则要删除该属性,最终还要将改对象解构成数组拼接到筛选接口的参数里。
 const mapList = {
     brandId1:[modelId1,model2,...],
     brandId2:[modelId1,model2,...],
     ...
}

上代码:

// 车型选择
    handleSelectModel (item) {
      if (!this.selectParam.modelList) this.selectParam.modelList = []
      if (!this.modelMap[item.brandId]) this.modelMap[item.brandId] = []
      if (this.modelMap[item.brandId].indexOf(item.modelId) > -1) {
        this.modelMap[item.brandId] = this.modelMap[item.brandId].filter(
          i => i !== item.modelId
        )
        if (this.modelMap[item.brandId].length === 0) {
          delete this.modelMap[item.brandId]
        }
      } else {
        this.modelMap[item.brandId].push(item.modelId)
      }
      let modelList = Object.values(this.modelMap)
      if (modelList.length === 0) {
        delete this.selectParam.modelList
      } else {
        this.selectParam.modelList = [].concat(...modelList)
      }
      this.$forceUpdate()
    },

总结

当拿到一个复杂的页面时首先要分析业务需求理清业务逻辑,然后根据接口数据格式去构思页面结构,这样子写起来相对轻松一点。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

  • 专业考题类型管理运行工作负责人一般作业考题内容选项A选项B选项C选项D选项E选项F正确答案 变电单选GYSZ本规程...
    小白兔去钓鱼阅读 13,315评论 0 13
  • 元符三年,宋徽宗即位。改国号为建中靖国。任用蔡京为相,穷奢极侈,民不聊生。宣和元年,宋江率众起于水泊梁山。 白云悠...
    你的荣光阅读 9,959评论 4 13
  • 日更第45天 昨天晚饭两个小时后,正趴在家里的吧台上做功课,突然没有精神,就像皮球泄了气,很快就感觉到胃里翻搅、恶...
    花枝笑阅读 2,256评论 0 3
  • 阳光明媚,万里无云…… 期待康巴什第一幼儿园苗苗二班的小朋友vs大朋友参观和效鄂电,感受和效文化,一切准备就绪……...
    天使精灵的生活阅读 3,544评论 0 3

友情链接更多精彩内容