Vue 实现全选、多选、单选效果

需求

假如这里有多个卡片,点击相应卡片之后需要提交卡片内信息,我们需要把点击的卡片筛选出来,在不使用组件库的前提下实现全选,多选,单选操作(其中全选和多选为一个需求,单选为一个需求)

全选+多选

思路

首先我们需要给全选设置一个状态(showAllSelected),用此状态来控制全显是否点击。那怎么控制每个卡片的状态呢?由于数据是后端请求得到,我们需要对请求的数据进行改造,添加checked属性来控制是否点击每个卡片。

代码实现

HTML

xml 复制代码
    <!-- 多选 -->
    <template>
      <div style="display: flex">
        <span>全选</span>
        <span
          :style="{
            backgroundColor: showAllSelected ? '#009aff' : '#fff',
            borderColor: showAllSelected ? 'transparent' : 'black',
          }"
          class="circle"
          @click="handleselectedAll"
          >{{ showAllSelected ? '√' : '' }}</span
        >
      </div>

      <div class="item-detail" v-for="(tmp, index) in itemData" :key="index">
        <div class="module-item">
          <span>序号:{{ tmp.flowOrder }}</span>
          <span
            :style="{
              backgroundColor: tmp.checked ? '#009aff' : '#fff',
              borderColor: tmp.checked ? 'transparent' : 'black',
            }"
            class="circle"
            @click="handleMultiple(index)"
            >{{ tmp.checked ? '√' : '' }}</span
          >
        </div>
      </div>
    </template>

首先对后端请求数据进行改造,为每个item添加checked属性

ini 复制代码
    handleData() {
      let returnData = [
        {
          flowOrder: 1,
        },
        {
          flowOrder: 2,
        },
        {
          flowOrder: 3,
        },
      ]
      returnData.forEach((item) => {
        item.checked = false
      })
      this.itemData = returnData
    },

全选

showAllSelected: false, 用来控制全选。

当点击全选时,首先对全选状态取反,当我们第一次点击全选,下面的子项要全部选中,再次点击全选,子项也要改变,所以子项的状态和全选状态完全一致,直接对每个子项赋值为全选的状态即可。

javascript 复制代码
    // 全选
    handleselectedAll() {
      // 每次点击将选择框状态改变为全选状态即可
      this.showAllSelected = !this.showAllSelected
      this.itemData.forEach((item) => {
        item.checked = this.showAllSelected
      })
    },

点击全选之后的效果

再次点击效果

可以看到全选多次点击效果已经实现了~

多选

多选就是去点击每个子项,子项之间互相不干扰。注意当子项全部被选中时,全选也要被选中, 子项没有被全部选中时,全选状态为false。

当选中当前子项,对当前子项的状态进行取反。

每次点击都要判断是否所有的子项被选中,对每次判断状态赋值给全选的状态即可,every函数功能为只有当所有条件成立才会返回true,有一项不成立就返回false,符合我们的需求。

javascript 复制代码
    // 多选
    handleMultiple(index) {
      // 点击将相应状态改变
      this.itemData[index].checked = !this.itemData[index].checked
      // 每次点击判断是否全部选中,将状态赋值给
      let isSelectedAll = this.itemData.every((item) => item.checked)
      this.showAllSelected = isSelectedAll
    },

没有全部选中

全部选中

我们看到多选状态也实现了。同时全选状态也会跟着变化呢~

提交

点击提交之后拿到相应数据,只需要把 checked 为true的筛选出来即可。

javascript 复制代码
    // 提交
    submit() {
      let data = this.itemData.filter((item) => item.checked)
      console.log('data: ', data)
    },

单选

思路

单选和多选不一致,每次只能点击一个,再次点击当前的,需要状态取反。

因为第二次不一定点击当前这个还是其他的,所有需要设置一个currentIndex来标识是不是当前index,如果是就进行取反,如果不是就让先让所有的状态取消,设置当前状态为true即可。

代码实现

HTML

xml 复制代码
    <!-- 单选 -->
    <template>
      <div class="item-detail" v-for="(tmp, index) in itemData" :key="index">
        <div class="module-item">
          <span>序号:{{ tmp.flowOrder }}</span>
          <span
            :style="{
              backgroundColor: tmp.checked ? '#009aff' : '#fff',
              borderColor: tmp.checked ? 'transparent' : 'black',
            }"
            class="circle"
            @click="handleSingle(index)"
            >{{ tmp.checked ? '√' : '' }}</span
          >
        </div>
      </div></template
    >

currentIndex 标识当前 index

kotlin 复制代码
    handleSingle(index) {
      // 如果是当前项取反
      if (this.currentIndex === index) {
        this.itemData[index].checked = !this.itemData[index].checked
      } else {
        // 不是先取消所有状态
        this.itemData.forEach((item) => {
          item.checked = false
        })
        // 当前项设置为true
        this.itemData[index].checked = true
      }
      //记录当前index
      this.currentIndex = index
    },

效果

提交

点击提交之后拿到相应数据,只需要把checked为true的筛选出来即可。

javascript 复制代码
    // 提交
    submit() {
      let data = this.itemData.filter((item) => item.checked)
      console.log('data: ', data)
    },

我们看到单选效果也实现了~

所有源码

这里附上全部代码,感兴趣的小伙伴可以自己试试,如果感觉对你有帮助,可以给作者点下赞呢~

xml 复制代码
<template>
  <div>
    <!-- 多选 -->
    <template v-if="false">
      <div style="display: flex">
        <span>全选</span>
        <span
          :style="{
            backgroundColor: showAllSelected ? '#009aff' : '#fff',
            borderColor: showAllSelected ? 'transparent' : 'black',
          }"
          class="circle"
          @click="handleselectedAll"
          >{{ showAllSelected ? '√' : '' }}</span
        >
      </div>
      <div class="item-detail" v-for="(tmp, index) in itemData" :key="index">
        <div class="module-item">
          <span>序号:{{ tmp.flowOrder }}</span>
          <span
            :style="{
              backgroundColor: tmp.checked ? '#009aff' : '#fff',
              borderColor: tmp.checked ? 'transparent' : 'black',
            }"
            class="circle"
            @click="handleMultiple(index)"
            >{{ tmp.checked ? '√' : '' }}</span
          >
        </div>
      </div>
    </template>
    <!-- 单选 -->
    <template>
      <div class="item-detail" v-for="(tmp, index) in itemData" :key="index">
        <div class="module-item">
          <span>序号:{{ tmp.flowOrder }}</span>
          <span
            :style="{
              backgroundColor: tmp.checked ? '#009aff' : '#fff',
              borderColor: tmp.checked ? 'transparent' : 'black',
            }"
            class="circle"
            @click="handleSingle(index)"
            >{{ tmp.checked ? '√' : '' }}</span
          >
        </div>
      </div></template
    >
  </div>
</template>
<script>
export default {
  name: 'DataTest',
  data() {
    return {
      itemData: [],
      showAllSelected: false,
      currentIndex: -1,
    }
  },
  created() {
    this.handleData()
  },
  methods: {
    // 多选
    handleMultiple(index) {
      // 点击将相应状态改变
      this.itemData[index].checked = !this.itemData[index].checked
      // 每次点击判断是否全部选中,将状态赋值给
      let isSelectedAll = this.itemData.every((item) => item.checked)
      this.showAllSelected = isSelectedAll
    },
    // 全选
    handleselectedAll() {
      // 每次点击将选择框状态改变为全选状态即可
      this.showAllSelected = !this.showAllSelected
      this.itemData.forEach((item) => {
        item.checked = this.showAllSelected
      })
    },
    // 单选
    handleSingle(index) {
      // 如果是当前项取反
      if (this.currentIndex === index) {
        this.itemData[index].checked = !this.itemData[index].checked
      } else {
        // 不是先取消所有状态
        this.itemData.forEach((item) => {
          item.checked = false
        })
        // 当前项设置为true
        this.itemData[index].checked = true
      }
      //记录当前index
      this.currentIndex = index
    },
    // 初始化数据
    handleData() {
      let returnData = [
        {
          flowOrder: 1,
        },
        {
          flowOrder: 2,
        },
        {
          flowOrder: 3,
        },
      ]
      returnData.forEach((item) => {
        item.checked = false
      })
      this.itemData = returnData
    },
  },
}
</script>
<style scoped>
.module-item {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 10px;
  margin: 10px;
  border: 1px solid #409eff;
  border-radius: 8px;
}
.circle {
  display: flex;
  justify-content: center;
  align-items: center;
  border-width: 1px;
  border-style: solid;
  border-radius: 50%;
  color: #fff;
  width: 20px;
  height: 20px;
  margin-left: 10px;
  line-height: 35px;
  text-align: center;
}
</style>

相关推荐
摸鱼的春哥13 分钟前
春哥的Agent通关秘籍07:5分钟实现文件归类助手【实战】
前端·javascript·后端
念念不忘 必有回响16 分钟前
viepress:vue组件展示和源码功能
前端·javascript·vue.js
C澒21 分钟前
多场景多角色前端架构方案:基于页面协议化与模块标准化的通用能力沉淀
前端·架构·系统架构·前端框架
崔庆才丨静觅23 分钟前
稳定好用的 ADSL 拨号代理,就这家了!
前端
江湖有缘24 分钟前
Docker部署music-tag-web音乐标签编辑器
前端·docker·编辑器
恋猫de小郭2 小时前
Flutter Zero 是什么?它的出现有什么意义?为什么你需要了解下?
android·前端·flutter
崔庆才丨静觅8 小时前
hCaptcha 验证码图像识别 API 对接教程
前端
passerby60619 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了9 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅9 小时前
实用免费的 Short URL 短链接 API 对接说明
前端