Element的Select分组全选模式

news2024/12/25 22:45:04

Select 选择器选择器的分组,如上图所示,我们希望做到的效果是,点击“热门城市”或“城市名”的时候全选分组的options。

思路

思路一:目前的Select 选择器分组OptionGroup的Title只是一个文本DOM,没用其他东西,我们需要给这个文本DOM添加一个点击事件,实现全选的功能。

<template>
  <ul class="el-select-group__wrap" v-show="visible">
   // option-group中只显示文本
    <li class="el-select-group__title">{{ label }}</li>
    <li>
      <ul class="el-select-group">
        <slot></slot>
      </ul>
    </li>
  </ul>
</template>

思路二:直接在<el-option-group>中添加一个<el-checkbox>然后隐藏分组的标题,用多选框中的标题替换分组标题,如下图所示

思路一实现

 搭建基本结构

直接到官网粘贴复制:Element - The world's most popular Vue UI framework

这里的<option-group>,就是重写的组件

<template>
  <div>
    <el-select v-model="value" placeholder="请选择" multiple style="width: 400px;" clearable @change="changeSelect">
      <option-group
        v-for="group in options"
        :key="group.label"
        :label="group.label"
        @click="handleClick"
      >
        <el-option
          v-for="item in group.options"
          :key="item.value"
          :label="item.label"
          :value="item.value">
        </el-option>
      </option-group>
    </el-select>
  </div>

</template>

<script>
import optionGroup from '../components/selectGroup'
export default {
  name: 'ruleInput',
  components: { optionGroup },
  data () {
    return {
      options: [
        {
          label: '热门城市',
          options: [
            {
              value: 'Shanghai',
              label: '上海'
            },
            {
              value: 'Beijing',
              label: '北京'
            }
          ]
        },
        {
          label: '城市名',
          options: [
            {
              value: 'Chengdu',
              label: '成都'
            },
            {
              value: 'Shenzhen',
              label: '深圳'
            },
            {
              value: 'Guangzhou',
              label: '广州'
            },
            {
              value: 'Dalian',
              label: '大连'
            }]
        }],
      value: []
    }
  },
  methods: {
   // 点击事件,实现全选
    handleClick (e) {
      const options = this.options.filter(item => e === item.label)[0].options
      const newMap = options.filter(item => {
        return !this.value.includes(item.value)
      })
      const result = newMap.length === 0 ? options : newMap
      result.forEach(item => {
        const index = this.value.indexOf(item.value)
        if (index > -1) {
          this.value.splice(index, 1)
        } else {
          this.value.push(item.value)
        }
      })
    },
    changeSelect () {
      // console.log(this.value)
    }
  }
}
</script>

实现OptionGroup

通过vue的extends(继承),Element的OptionGroup,在monuted生命周期方法中,绑定一个点击事件。

新建一个selectGroup.vue文件,去掉<template>,只留下<script>和<style>的部分。


<script>
import { OptionGroup } from 'element-ui'

export default {
  extends: OptionGroup,
  name: 'SelectGroup',
  mounted () {
    const select = this.$el
    const _this = this
    // 绑定一个点击事件
    select.addEventListener('click', function (e) {
      if (e.target.matches('li.el-select-group__title')) {
       // 获取当前点击的DOM文本
        _this.$emit('click', e.target.textContent)
      }
    })
  }
}
</script>

<style scoped lang="scss">
.el-select-group__title{
  cursor: pointer;
}
</style>

思路二实现

实现OptionGroup

新建一个自己的option-group.vue,

<script>
import { OptionGroup } from 'element-ui'

export default {
  extends: OptionGroup,
  name: 'SelectGroup',
  props: {
    // showTitle为true显示标题
    showTitle: {
      type: Boolean,
      default: false
    }
  },
  mounted () {
    const select = this.$el
    const _this = this
    // 这里兼容一下思路一的思想
    if (this.showTitle) {
      const group = select.querySelector('.el-select-group')
      group.style.marginLeft = '10px'
      select.addEventListener('click', function (e) {
        if (e.target.matches('li.el-select-group__title')) {
          _this.$emit('click', e.target.textContent)
        }
      })
      return
    }
   // 思路二的实现,隐藏文本
    const titleDom = select.querySelector('.el-select-group__title')
    titleDom.style.display = 'none'
  }
}
</script>

<style scoped lang="scss">
.el-select-group__title{
  cursor: pointer;
  font-size: 15px;
  color: #606266;
  font-weight: bold;
  &:hover{
    color: #409eff;
  }
}
</style>

主逻辑 

在新建一个select.vue,编写主要逻辑

<template>
  <el-select v-model="model.value" placeholder="请选择" multiple style="width: 700px;" clearable @change="changeSelect">
    <option-group
      :show-title="showTitle"
      v-for="group in model.options"
      :key="group.id"
      :label="group.label"
      @click="handleClick"
    >
      <i>{{title}}</i>
      <el-checkbox
        v-if="!showTitle"
        v-model="group.checked"
        class="group-check"
        :indeterminate="isIndeterminate || groupsJudge(group.options,model.value)"
        @change='selectAll($event,group.id)'>
        {{group.label}}
      </el-checkbox>
      <el-option
        v-for="item in group.options"
        :key="item.value"
        :label="item.label"
        :value="item.value">
      </el-option>
    </option-group>
  </el-select>
</template>

<script>
import optionGroup from './option-group'
export default {
  components: { optionGroup },
  name: 'index',
  props: {
    value: {
      type: Object,
      default: () => {}
    },
    // showTitle为true显示标题
    showTitle: {
      type: Boolean,
      default: false
    },
    title: {
      type: String,
      default: ''
    }
  },
  computed: {
    // 利用Proxy,监听整个对象变化,优化父子组件传值
    model: {
      get () {
        const that = this
        return new Proxy(this.value, {
          set (obj, name, val) {
            that.$emit('update:value', {
              ...obj,
              [name]: val
            })
            return true
          }
        })
      },
      set (val) {
        this.$emit('update:value', val)
      }
    }
  },
  data () {
    return {
      isIndeterminate: false
    }
  },
  methods: {
    // 点击全选框时
    selectAll (val, id) {
      const arr = this.model.options.find(f => f.id === id).options.map(m => m.value)
      if (val) {
        arr.forEach(item => {
          if (!this.model.value.includes(item)) {
            this.model.value.push(item)
          }
        })
      } else {
        this.model.value.forEach((item, index) => {
          if (arr.includes(item)) {
            this.model.value.splice(index, 1, '')
          }
        })
      }
      this.model.value = this.model.value.filter(f => f !== '')
      this.isIndeterminate = false
    },
    // 选项发生变化时
    changeSelect (val) {
      this.model.options.forEach(item => {
        const arr = item.options.map(m => m.value)
        item.checked = arr.every((v) => {
          return val.some(s => s === v)
        })
      })
    },
    // 多选框indeterminate的状态判定
    groupsJudge (options, item) {
      const groups = options.map(v => v.value)
      if (groups.length === 0 || groups.every(e => item.includes(e))) {
        return false
      }
      return groups.some(e => item.includes(e))
    },
    // 【思路一的实现】点击事件,实现全选
    handleClick (e) {
      const options = this.model.options.filter(item => e === item.label)[0].options
      const newMap = options.filter(item => {
        return !this.model.value.includes(item.value)
      })
      const result = newMap.length === 0 ? options : newMap
      result.forEach(item => {
        const index = this.model.value.indexOf(item.value)
        if (index > -1) {
          this.model.value.splice(index, 1)
        } else {
          this.model.value.push(item.value)
        }
      })
    }
  }
}
</script>

<style scoped lang="scss">
.group-check{
  font-size: 15px;
  font-weight: bold;
  margin-left: 20px;
}
</style>

使用组件

<template>
   <selectGroup :value.sync="optionsData" style="margin: 40px"></selectGroup>
</template>

<script>
import selectGroup from '../components/selectGroup/index'
export default {
  name: 'ruleInput',
  components: { selectGroup },
  data () {
    return {
      optionsData: {
        options: [
          // id和check必须要有
          {
            label: '热门城市',
            id: 1, // 必须存在
            check: false, // 必须存在
            options: [
              {
                value: 'Shanghai',
                label: '上海'
              },
              {
                value: 'Beijing',
                label: '北京'
              }
            ]
          },
          {
            label: '城市名',
            id: 2,
            check: false,
            options: [
              {
                value: 'Chengdu',
                label: '成都'
              },
              {
                value: 'Shenzhen',
                label: '深圳'
              },
              {
                value: 'Guangzhou',
                label: '广州'
              },
              {
                value: 'Dalian',
                label: '大连'
              }]
          }],
        value: []
      }
    }
  }
}
</script>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/628222.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

详解基于罗德里格斯(Rodrigues)公式由旋转向量到旋转矩阵的 Python 实现

文章目录 旋转向量 rotation vector旋转矩阵 rotation matrix罗德里格斯公式 Rodrigues formula基于 Python 和 NumPy 实现 Rodrigues 公式 旋转向量 rotation vector 任何一个旋转都可以通过一个 旋转轴 加一个 旋转角 进行描述, 即围绕 旋转轴 旋转一个 旋转角. 此时可以通过…

javascript 中的 URL 解码

文章目录 需要URL编解码JavaScript 中的 URL 解码使用 unescaped() 方法解码编码的 URL使用 decodeURI() 方法解码编码的 URL使用 decodeURIComponent() 方法解码编码的 URL 总结 本文着眼于 URL 解码以及如何使用 JavaScript 对编码的 URL 进行解码。 需要URL编解码 URL 应具…

政企HTTPS加密国产化替代的四要素

信创产业是数字经济、信息安全发展的基础&#xff0c;也是“新基建”的重要内容&#xff0c;将成为拉动中国经济增长的重要抓手之一。随着国资委79号文的发布&#xff0c;国央企落实信息化系统的信创国产化改造的步伐加快&#xff0c;贯彻“28N”战略&#xff0c;从党政机关扩展…

Doris学习笔记

1.数据模型 数据模型 - Apache Doris 1.1 Aggregate 模型(聚合&#xff09; 可以发现&#xff0c;user_id、date、age ...等没有设置 AggregationType, 那么这几个字段就成了一个key了。设置了 AggregationType 字段&#xff0c;说明该列的属性已经成value了。 我们导入一张…

Linux·Binder机制原理

目录 前言 目录 1. Binder到底是什么&#xff1f; 2. 知识储备 2.1 进程空间划分 2.2 进程隔离 & 跨进程通信&#xff08; IPC &#xff09; 2.5 内存映射 3. Binder 跨进程通信机制 模型 3.1 模型原理图 3.3 模型原理步骤说明 3.4 额外说明 4. Binder机制 在An…

自学黑客(网络安全),一般人我劝你还是算了

写在开篇 笔者本人 17 年就读于一所普通的本科学校&#xff0c;20 年 6 月在三年经验的时候顺利通过校招实习面试进入大厂&#xff0c;现就职于某大厂安全联合实验室。 我为啥说自学黑客&#xff0c;一般人我还是劝你算了吧&#xff01;因为我就是那个不一般的人。 ​ 首先我…

elementui tree 支持虚拟滚动和treeLine (下)

​ 由于我之前没有发布过npm 包&#xff0c;这里还得现学一下。 参考资料&#xff1a; 链接: 如何写一个vue组件发布到npm&#xff0c;包教包会&#xff0c;保姆级教学链接: vue组件发布npm最佳实践 按照上面的步骤&#xff0c;我通过 vue-sfc-rollup 生成了项目&#xff0c;…

六级备考8天|CET-6|阅读强化|16:00~17:20

调整做题顺序&#xff1a;仔细阅读——>长篇阅读(信息匹配)——>翻译——>选词填空 顺关系 or 反关系 正态度 or 负态度 阅读要有针对性 理解要有空白性 2&#xff09;高大上的思维来自于中文的语言特点 练习 第一段&#xff1a;例子&#xff0c;无观点&am…

微伴助手如何增加客户积分?如何自动给客户添加企业标签?

微伴助手是一款企业微信第三方应用&#xff0c;已经为电商、教育、金融、保险、医疗等机构提供技术支持&#xff0c;适用于引流获客、客户意向跟进、销售转化、社群运营等全方位营销场景&#xff0c;旨在帮助企业构建高转化率的私域流量池。 微伴助手基于企业微信开放的接口&a…

adb shell 调试 Android 串口 百度AI也很

在 Android 平台上进行串口调试需要使用 Android Debug Bridge (ADB) 工具。ADB 是一个命令行工具&#xff0c;可以通过 USB 连接 Android 设备&#xff0c;并执行各种命令来调试应用程序。 以下是使用 ADB shell 进行 Android 串口调试的步骤&#xff1a; 连接 Android 设备…

【2023最全教程】什么是自动化测试框架?熬夜7天整理出这一份3000字超全学习指南

所有软件在提供给用户之前都必须经过测试。软件测试是开发生命周期中必不可少的一步因为它确保用户必须收到符合其开发目的的高质量产品。每个企业都优先考虑测试;因此&#xff0c;大多数人更愿意从手动测试转向自动化。因此&#xff0c;自动化测试框架是任何软件测试过程的基础…

安全测试网站-DWVA下载安装启动

参考&#xff1a;DVWA下载、安装、使用&#xff08;漏洞测试环境搭建&#xff09;教程 - 付杰博客 (fujieace.com) DVWA全称为Damn Vulnerable Web Application&#xff0c;意为存在糟糕漏洞的web应用。它是一个基于PHP/MySQL开发的存在糟糕漏洞的web应用&#xff0c;旨在为专…

华为OD机试真题B卷 Java 实现【自守数】,附详细解题思路

一、题目描述 自守数是指一个数的平方的尾数等于该数自身的自然数。例如&#xff1a;25^2 625&#xff0c;76^2 5776&#xff0c;9376^2 87909376。请求出n(包括n)以内的自守数的个数。 数据范围&#xff1a; 1≤n≤10000 二、输入描述 int型整数。 三、输出描述 n以内…

看板可视化工作流的7个步骤

工作流是任务或产品从工作开始到完成所经历的一系列特征步骤。 人脑处理视觉图像的能力比文本快 60,000 倍&#xff0c;这意味着我们消费图像等视觉内容的速度比文本快得多。在看板中&#xff0c;工作流的可视化意味着将独特的工作步骤映射到看板的列中&#xff0c;并在工作项…

【数据结构与算法】02 栈 (栈的多重含义,静态、动态数组栈(顺序栈),链式栈,双端栈,括号匹配)

一、栈的多重含义1.1 硬件栈1.2 运行时栈1.3 软件栈1.4 技术栈1.5 TCP/IP协议栈 二、数据结构中的栈2.1 概念2.2 栈的操作2.3 数组栈&#xff08;顺序栈&#xff09;2.31 数组栈特性2.32 C语言实现▶ 静态数组栈▶ 动态数组栈 2.4链式栈2.41 链式栈特性2.42 C语言实现 三、进阶…

【2023最新教程】一文3000字从0到1教你做app自动化测试(保姆级教程)

一、什么是App自动化&#xff1f;为什么要做App自动化&#xff1f; App自动化是指给 Android或iOS上的软件应用程序做的自动化测试。手工测试和自动化测试的对比如下&#xff1a; 手工测试优势&#xff1a;不可替代、发现更多bug、包含了人的想象力与理解力。 注意&#xff0c…

嵌入式 - UART介绍

概述 嵌入式系统经常需要集成电路之间的通信。举个例子&#xff0c;一个数字温度传感器向主控芯片报告房间的环境温度。通常情况&#xff0c;这种数据会通过一个串行接口来传输。 那么&#xff0c;什么是串行接口&#xff1f; 在最基本的角度来说&#xff0c;串行接口是一个移…

微信原生小程序自定义顶部导航

都2023了&#xff0c;自定义顶部导航应该不是什么新鲜事了&#xff0c;这里只是简单记录下 微信自己也提供了自定义顶部导航navigation-bar&#xff0c;大概看了下&#xff0c;可配置的也不少&#xff0c;所以看需求了&#xff0c;如果简单可以采用微信提供的&#xff0c;老规矩…

【Mysql】安装和基础环境配置

本文首发于 慕雪的寒舍 在本地安装mysql&#xff0c;以mariadb为例。 所有命令都需要在root下面执行or使用sudo 系统 CentOS 8 1.安装mariadb开发包 yum install -y mariadb yum install -y mariadb-server yum install -y mariadb-devel2.修改配置文件中的编码 为了保证对…

亚马逊美国站 儿童陀螺玩具CPC认证 陀螺的详细介绍 CPC认证方案的流程

什么是陀螺陀螺指的是绕一个支点高速转动的刚体。陀螺是中国民间最早的娱乐工具之一.形状上半部分为圆形&#xff0c;下方尖锐。从前多用木头制成&#xff0c;现代多为塑料或铁制。玩时可用绳子缠绕&#xff0c;用力抽绳&#xff0c;使直立旋转。或利用发条的弹力旋转。传统古陀…