封装图片选择器

109 阅读2分钟

最近有一个这样的需求:需要点击图片后实现单选的效果,再次点击该图片后取消选中

这里的实现方案大概有两种:
  1. 第一种就是利用 input元素和img元素,主要利用input元素的checked属性,具体的代码实现可参考我之前写的有关vue2实现:juejin.cn/post/728791…
  2. 第二种就是利用img元素以及数组的有关知识进行,这里着重介绍该种方法
实现效果如下:

gif-2024-04-26 at 08.46.13.gif

思路:
  • 为了能够实现这个类似于选中和取消选中的效果,这里需要对后台返回的数据加以处理,给每条数据增加一个isChecked: false,以此来初始化其选中与否的状态
<ImageCheckRadio :iconsList="iconsList" :itemsPerRow="8" @changeValueClick="changeValueClick"></ImageCheckRadio>

const iconsList = ref([]);
const changeValueClick = (val) => {
  if (Object.keys(val).length !== 0) {
    currentIconItem.value = val;
    let id = currentIconItem.value.jrjg_id[0].id;
    let jrjgname = currentIconItem.value.jrjgname;
    iconBankParams.value =
      '[{"id":"' + id + '","unitType":' + 1 + ',"name":"' + jrjgname + '"}]';
  } else {
    currentIconItem.value = [];
    iconBankParams.value = "";
  }
  queryParams.value.pageSize = 10;
  // 请求数据
  getInstitutionProductsListTwo();
};
// 请求数据
const getLoanInstitutionImg = () => {
    ...
    if (res.code == 200) {
        iconsList.value = res.data.sort(
          (a, b) => a.data.order_by - b.data.order_by
        );
        iconsList.value.forEach((v) => {
          v.bg_img = proxy.$imgUrl + v.data.img[0].refId;
          v.isCheck = false;
          v.checkOrder = 0;
        });
      }
}

子组件:ImageCheckRadio.vue

<template>
  <div class="image-checked-container">
    <div style="display: flex; align-items: center; flex-wrap: wrap">
      <div
        v-for="(item, index) in displayedIcons"
        :key="index"
        :class="{ checked: item.isCheck }"
        style="
          width: 122px;
          height: 39px;
          margin-right: 15px;
          margin-bottom: 10px;
          margin-top: 10px;
        "
      >
        <img
          :src="item.bg_img"
          class="img"
          alt="Radio Image"
          @click="currentBankClickHandle(item)"
        />
      </div>
    </div>
    <div class="tools">
      <p
        v-if="!showAll && iconsList.length > itemsPerRow"
        @click="showAll = true"
        style="
          cursor: pointer;
          padding-right: 20px;
          text-align: left;
          color: #578cf0;
          font-size: 15px;
        "
        class="flex-column-center"
      >
        <span style="padding-right: 5px; padding-left: 2px">...</span>
        <span>加载更多</span>
      </p>
      <p
        v-else-if="showAll && iconsList.length > itemsPerRow"
        @click="showAll = false"
        style="
          cursor: pointer;
          padding-right: 20px;
          text-align: left;
          color: #578cf0;
          font-size: 15px;
        "
        class="flex-column-center"
      >
        <el-icon><Top /></el-icon>
        收起
      </p>
    </div>
  </div>
</template>

<script setup>
import { ref, computed } from "vue";

const props = defineProps({
  iconsList: {
    type: Array,
    default: () => [],
  },
  itemsPerRow: {
    type: Number,
    default: 8,
  },
});

const emits = defineEmits(["changeValueClick"]);

const showAll = ref(false);

// 控制 加载更多/收起
const displayedIcons = computed(() => {
  if (showAll.value) {
    return props.iconsList;
  } else {
    // 只显示前itemsPerRow个项目
    return props.iconsList.slice(0, props.itemsPerRow);
  }
});

// 图片选中与取消选中
const chooseList = ref([]);
const currentBankClickHandle = (item) => {
  // 多选逻辑
  // // 选中
  // if (!item.isCheck) {
  //   chooseList.value.push(item);
  //   // 修改状态
  //   item.isCheck = true;
  //   return;
  // }
  // // 取消选中
  // // 找到在chooseList中的索引,
  // let i = chooseList.value.findIndex((v) => v.id == item.id);
  // if (i === -1) return;
  // // 删除
  // chooseList.value.splice(i, 1);
  // // 修改状态
  // item.isCheck = false;
  // console.log('多选', chooseList.value);

  // 单选逻辑
  // // 取消所有已选中的图片
  // chooseList.value.forEach((v) => {
  //   v.isCheck = false;
  // });
  // // 清空已选中的图片列表
  // chooseList.value = [];
  // // 选中当前点击的图片
  // item.isCheck = true;
  // chooseList.value.push(item);

  // 单选逻辑--当再次点击选中图片时会处于未选中状态
  // 如果当前图片已经被选中,则取消选中并清空chooseList数组
  if (item.isCheck) {
    item.isCheck = false;
    chooseList.value = [];
    emits("changeValueClick", {});
    // console.log('单选', chooseList.value);
    return;
  }
  // 取消所有已选中的图片
  chooseList.value.forEach((v) => {
    v.isCheck = false;
  });
  // 清空已选中的图片列表
  chooseList.value = [];
  // 选中当前点击的图片
  item.isCheck = true;
  chooseList.value.push(item);
  emits("changeValueClick", item.data);
  // console.log('单选', chooseList.value);
};
</script>

<style scoped lang="scss">
.image-checked-container {
  width: 1200px;
  height: 100%;
  margin: 0 auto;
  overflow: hidden;
  box-sizing: border-box;
  position: relative;

  .img {
    width: 120px;
    height: 37px;
    border: 1px solid #ccc;
    cursor: pointer;
  }

  .tools {
    position: absolute;
    right: 20px;
    top: 15px;
    font-size: 14px;
  }

  .checked {
    border: 1px solid red;
  }
}
</style>