利用 ant-design-vue 实现一个支持多选的级联选择器

2018-11-18 admin

Preface

I need to make a cascader which can support multiple choices. However, I didn’t find any ui which supports that until 2018.11.18. That was a little pity.

Main

I check the element-ui and find multiple cascader was in toDoList while ant-design refuse to support that directly. Maybe because they have already implemented TreeSelect. Here is what TreeSelect looks like:

Almost the result I want except the ui. It doesn’t look like a cascader but a tree.

Anyway, I built a multiple cascader component based on select and cascader in ant-design-vue. Here is the result:

The principle is easy. I use the input in select and hide the popup. And then I hide the input in cascader and show the popup. So, MultipleCascader is equal to input in select plus popup in cascader and use transform to let them stay together.

Talking about the event, you have to listen and change the data to show correctly. That is a little troublesome.

Anyway, here is the demo in codesandbox. I am not sure if the demo would be always able to visit. So, here is the main code:

App.vue

<template>
  <div id="app" class="app"><MultipleCascader /></div>
</template>

<script>
import MultipleCascader from './components/MultipleCascader'
export default {
  name: 'app',
  components: {
    MultipleCascader
  }
}
</script>

<style scoped></style>

MultipleCascader.vue

<template>
  <div class="multi_cascader">
    <a-cascader
      size="large"
      class="multi_cascader__cascader"
      :popupVisible="cascaderPopupVisible"
      :popupClassName="'multi_cascader__cascader_popup' + timestamp"
      changeOnSelect
      expandTrigger="hover"
      :options="cascaderOptions"
      :fieldNames="{ label: 'label', value: 'id', children: 'children' }"
      v-model="cascaderValues"
      ref="cascader"
      :showSearch="{ cascaderFilter }"
      @change="cascaderChange"
    ></a-cascader>
    <a-select
      size="large"
      class="multi_cascader__select"
      dropdownClassName="hide"
      mode="multiple"
      :value="selectValues"
      allowClear
      placeholder="Please select"
      :options="selectOptions"
      @focus="cascaderPopupVisible = true"
      @deselect="deleteOption"
      @change="selectChange"
      @search="selectSearch"
    ></a-select>
  </div>
</template>

<script>
export default {
  name: 'MultipleCascader',
  data: function() {
    return {
      timestamp: Date.now(),
      selectOptions: [],
      selectValues: [],
      cascaderPopupVisible: false,
      cascaderValues: [],
      cascaderOptions: [
        {
          id: 1,
          value: '1',
          label: '1',
          children: [
            { id: 1.1, value: 1.1, label: '1-1' },
            {
              id: 1.2,
              value: 1.2,
              label: '1-2',
              children: [
                { id: 1.21, value: 1.21, label: '1-2-1' },
                { id: 1.22, value: 1.22, label: '1-2-2' }
              ]
            }
          ]
        },
        { id: 2, value: 2, label: '2' }
      ]
    }
  },
  mounted() {
    document.addEventListener('click', this.hideCascaderPopup)
  },
  destroyed() {
    document.removeEventListener('click', this.hideCascaderPopup)
  },
  methods: {
    cascaderChange(values, options) {
      // you may have different logic with the selected option, here I just want the last one.
      let targetValue = values.slice(-1).pop()
      let targetOption = options.slice(-1).pop()
      let selectedValIndex = this.selectValues.indexOf(targetValue)
      if (selectedValIndex >= 0) {
        this.selectValues.splice(selectedValIndex, 1)
        this.selectOptions.splice(selectedValIndex, 1)
      } else {
        this.selectValues.push(targetValue)
        this.selectOptions.push(targetOption)
      }
    },
    deleteOption(value) {
      let selectedValIndex = this.selectValues.indexOf(value)
      this.cascaderChange([value], [this.selectOptions[selectedValIndex]])
    },
    selectChange(values, vNodes) {
      if (values.length === 0) {
        this.selectValues = []
        this.selectOptions = []
      }
    },
    selectSearch(keyword) {
      let searchInput = this.$refs.cascader.$el.querySelector('input')
      if (searchInput) {
        searchInput.value = keyword
        searchInput.dispatchEvent(new Event('input'))
      }
    },
    cascaderFilter(inputValue, path) {
      return path.some(
        option =>
          option.label.toLowerCase().indexOf(inputValue.toLowerCase()) > -1
      )
    },
    hideCascaderPopup(event) {
      let cascaderPopup = document.querySelector(
        '.multi_cascader__cascader_popup' + this.timestamp
      )
      let isClickCascaderPopup =
        cascaderPopup && cascaderPopup.contains(event.target)
      if (isClickCascaderPopup) {
        return
      }
      this.cascaderPopupVisible = false
    }
  }
}
</script>

<style scoped>
.multi_cascader {
  height: 100vh;
  display: flex;
  flex-flow: column;
  justify-content: center;
  align-items: center;
}
.multi_cascader__select {
  width: 50%;
  margin-top: 0;
  margin-bottom: auto;
  transform: translate(0, -100%);
}
.multi_cascader__cascader {
  width: 50%;
  margin-top: auto;
  margin-bottom: 0;
  opacity: 0;
}
</style>

<style>
/* global style*/
.hide {
  display: none;
}
</style>

原文链接:https://segmentfault.com/a/1190000017054484

本站文章除注明转载外,均为本站原创或编译。欢迎任何形式的转载,但请务必注明出处。

转载请注明:文章转载自 JavaScript中文网 [https://www.javascriptcn.com]

本文地址:https://www.javascriptcn.com/read-45813.html

文章标题:利用 ant-design-vue 实现一个支持多选的级联选择器

相关文章
10个强大的纯CSS3动画案例分享
我们的网页外观主要由CSS控制,编写CSS代码可以任意改变我们的网页布局以及网页内容的样式。CSS3的出现,更是可以让网页增添了不少动画元素,让我们的网页变得更加生动有趣,并且更易于交互。本文分享了10个非常炫酷的CSS3动画案例,希望大家...
2015-11-16
css布局的各种FC简单介绍:BFC,IFC,GFC,FFC
什么是FC? Formatting Context,格式化上下文,指页面中一个渲染区域,拥有一套渲染规则,它决定了其子元素如何定位,以及与其他元素的相互关系和作用。 BFC 什么是BFC Block Formatting Context,块...
2018-05-17
Android中Okhttp3实现上传多张图片同时传递参数
之前上传图片都是直接将图片转化为io流传给服务器,没有用框架传图片。 最近做项目,打算换个方法上传图片。 Android发展到现在,Okhttp显得越来越重要,所以,这次我选择用Okhttp上传图片。 Okhttp目前已经更新到Okhttp...
2017-03-17
JavaScript实现PC手机端和嵌入式滑动拼图验证码三种效果
PC和手机端网站滑动拼图验证码效果源码,同时包涵了弹出式Demo,使用ajax形式提交二次验证码所需的验证结果值,嵌入式Demo,使用表单形式提交二次验证所需的验证结果值,移动端手动实现弹出式Demo三种效果 首先要确认前端使用页面,比如...
2017-03-17
Vue获取DOM元素样式和样式更改示例
在 vue 中用 document 获取 dom 节点进行节点样式更改的时候有可能会出现 ‘style’ is not definde的错误,这时候可以在 mounted 里用 $refs 来获取样式,并进行更改: &lt;template...
2017-03-13
Vue.js组件tab实现选项卡切换
本文实例为大家分享了vue插件tab选项卡的具体代码,供大家参考,具体内容如下 效果图: 代码如下: &lt;!DOCTYPE html&gt; &lt;html lang=&quot;en&quot;&gt; &lt;head&gt; ...
2017-03-13
从2014年的发展来展望JS的未来将会如何
&lt;font face=&quot;寰�杞�闆呴粦, Arial, sans-serif &quot;&gt;2014骞达紝杞�浠惰�屼笟鍙戝睍杩呴€燂紝鍚勭�嶈��瑷€灞傚嚭涓嶇┓锛屼互婊¤冻鐢ㄦ埛涓嶆柇鍙樺寲鐨勯渶姹傘€傝繖浜涜��...
2015-11-12
12个你未必知道的CSS小知识
虽然CSS并不是一种很复杂的技术,但就算你是一个使用CSS多年的高手,仍然会有很多CSS用法/属性/属性值你从来没使用过,甚至从来没听说过。 1.CSS的color属性并非只能用于文本显示 对于CSS的color属性,相信所有Web开发人员...
2015-11-12
ajax为什么令人惊异?ajax的优缺点
使用Ajax的最大优点,就是能在不更新整个页面的前提下维护数据。这使得Web应用程序更为迅捷地回应用户动作,并避免了在网络上发送那些没有改变的信息。 Ajax不需要任何浏览器插件,但需要用户允许JavaScript在浏览器上执行。就像DHT...
2015-11-12
HTML5的5个不错的开发工具推荐
HTML5规范终于在今年正式定稿,对于从事多年HTML5开发的人员来说绝对是一个重大新闻。数字天堂董事长,DCloud CEO王安也发表了文章,从开发者和用户两个角度分析了HTML对两个人群的优势。其实,关于HTML5的开发工具,我们以往的...
2015-11-12
回到顶部