vue实现卡片遮罩层交互式功能

news2024/11/29 0:36:49

前言

在前端开发中,卡片遮罩层是一种常见的交互设计元素,用于强调某个区域或内容,并提供用户操作的入口。本文将带大家在 vue 中结合实际案例实现此功能。


实现效果

在这里插入图片描述


完整代码

html

<template>
  <!-- 主容器 -->
  <div class="box">
    <div
      class="card"
      @click="cardDetails(index)"
      @mousedown.prevent="startLongPress($event, index)"
      @mouseup="stopLongPress"
      @mouseleave="stopLongPress"
      v-for="(item, index) in list"
      :key="index"
      ref="cardRef"
    >
      <!-- 卡片内容 -->
      <div class="content">
        <div class="cardImg">
          <img :src="item.imgUrl" alt="" />
        </div>
        <div class="introduce">{{ item.name }}</div>
      </div>
      <!-- 长按时显示的遮罩层 -->
      <div
        v-show="item.showOverlay"
        class="overlay"
        :class="{ 'expand-animation': item.showOverlay }"
        @click.stop
      >
        <div class="buttonCon">
          <div
            v-for="(shadeItem, shadeIndex) in shadeList"
            :key="shadeIndex"
            @click="onShade(shadeItem.title)"
          >
            {{ shadeItem.title }}
          </div>
        </div>
        <span class="close" @click="closeOverlay($event, index)">&times;</span>
      </div>
    </div>
  </div>
</template>

js

<script>
export default {
  data() {
    return {
      shadeList: [
        { title: "商品不感兴趣" },
        { title: "不想看到此类商品" },
        { title: "已经买了" },
        { title: "图片引起不适" },
        { title: "更多..." },
      ],
      longPressTimer: null, // 用于存储长按计时器
      list: [
        {
          imgUrl: "https://img01.yzcdn.cn/vant/cat.jpeg",
          name: "xxxxxxxxxxxxxxxxxxxxxxx",
          showOverlay: false,
        },
        {
          imgUrl: "https://img01.yzcdn.cn/vant/cat.jpeg",
          name: "xxxxxxxxxxxxxxxxxxxxxxx",
          showOverlay: false,
        },
        {
          imgUrl: "https://img01.yzcdn.cn/vant/cat.jpeg",
          name: "xxxxxxxxxxxxxxxxxxxxxxx",
          showOverlay: false,
        },
        {
          imgUrl: "https://img01.yzcdn.cn/vant/cat.jpeg",
          name: "xxxxxxxxxxxxxxxxxxxxxxx",
          showOverlay: false,
        },
        {
          imgUrl: "https://img01.yzcdn.cn/vant/cat.jpeg",
          name: "xxxxxxxxxxxxxxxxxxxxxxx",
          showOverlay: false,
        },
        {
          imgUrl: "https://img01.yzcdn.cn/vant/cat.jpeg",
          name: "xxxxxxxxxxxxxxxxxxxxxxx",
          showOverlay: false,
        },
        {
          imgUrl: "https://img01.yzcdn.cn/vant/cat.jpeg",
          name: "xxxxxxxxxxxxxxxxxxxxxxx",
          showOverlay: false,
        },
        {
          imgUrl: "https://img01.yzcdn.cn/vant/cat.jpeg",
          name: "xxxxxxxxxxxxxxxxxxxxxxx",
          showOverlay: false,
        },
      ],
    };
  },
  mounted() {
    // 监听窗口滚动
    window.addEventListener("scroll", this.closeAllOverlaysOnScroll);
  },
  // 实例销毁前移除监听窗口的滚动
  beforeDestroy() {
    window.removeEventListener("scroll", this.closeAllOverlaysOnScroll);
  },
  methods: {
    // 滚动时关闭遮罩层
    closeAllOverlaysOnScroll() {
      this.list.forEach((item) => {
        this.$set(item, "showOverlay", false);
      });
    },
    // 开始长按事件
    startLongPress(event, index) {
      event.preventDefault();
      event.stopPropagation();
      this.closeOtherOverlays(index);
      this.longPressTimer = setTimeout(() => {
        this.list[index].showOverlay = true;
        document.addEventListener("click", this.checkClickOutside);
      }, 100);
    },
    closeOtherOverlays(index) {
      this.list.forEach((item, i) => {
        if (i !== index) {
          item.showOverlay = false;
        }
      });
    },
    // 点击卡片详情
    cardDetails(index) {
      if (!this.list[index].showOverlay) {
        console.log("点击卡片");
      }
    },
    // 结束长按事件
    stopLongPress() {
      clearTimeout(this.longPressTimer);
      document.removeEventListener("click", this.checkClickOutside);
    },
    // 关闭遮罩层
    closeOverlay(event, index) {
      event.stopPropagation(); // 阻止事件冒泡
      this.$set(this.list[index], "showOverlay", false); // 关闭当前卡片的遮罩层
      document.removeEventListener("click", this.checkClickOutside);
    },
    // 检查点击区域是否在遮罩层外
    checkClickOutside(event) {
      // 遍历所有卡片,关闭非点击卡片的遮罩层
      this.list.forEach((item, index) => {
        if (!this.$refs.cardRef[index].contains(event.target)) {
          this.$set(item, "showOverlay", false);
        }
      });
      document.removeEventListener("click", this.checkClickOutside);
    },
    // 点击遮罩层内容
    onShade(name) {
      console.log(name);
    },
  },
};
</script>

css

<style scoped lang="less">
.box {
  font-size: 16px;
  min-height: 100vh;
  background: #f0f0f0;
  padding: 8px;
  .card {
    width: 49%;
    display: inline-block;
    background-color: white;
    position: relative;
    overflow-wrap: break-word;
    user-select: none;
    margin-bottom: 10px;
    border-radius: 8px;
    .introduce {
      text-align: justify;
      overflow: hidden;
      padding: 0px 6px 6px 6px;
      font-size: 14px;
      height: 50px;
      font-size: 14px;
    }
    .cardImg {
      img {
        border-top-left-radius: 8px;
        border-top-right-radius: 8px;
        width: 100%;
        height: 120px;
      }
    }
    .overlay {
      padding: 16px 10px;
      box-sizing: border-box;
      border-radius: 8px;
      position: absolute;
      top: 0;
      left: 0;
      width: 100%;
      height: 100%;
      background-color: rgba(35, 35, 35, 0.8);
      &.expand-animation {
        animation: expand 0.3s forwards;
      }
    }

    .buttonCon {
      font-size: 14px;
      width: 100%;
      color: rgb(213, 207, 207);
      div:not(:last-child) {
        border-bottom: 1px solid rgb(82, 82, 82);
        margin-bottom: 8px;
      }
      div {
        padding: 0px 2px 4px 2px;
      }
    }

    .close {
      position: absolute;
      top: 2px;
      right: 8px;
      font-size: 20px;
      cursor: pointer;
      color: white;
    }
  }
  .card:nth-child(even) {
    margin-left: 2%;
  }
}

@keyframes expand {
  0% {
    transform: scale(0);
    opacity: 0;
  }
  100% {
    transform: scale(1);
    opacity: 1;
  }
}
</style>

实现思路

这段代码实现了一个交互式的卡片列表功能,其中每个卡片包含一个图片和一些文字介绍。用户可以通过点击卡片来查看详情,同时也可以通过长按卡片来显示一个遮罩层,遮罩层上有一些操作按钮,如"商品不感兴趣"、"不想看到此类商品"等选项。此外,用户还可以点击遮罩层外的区域来关闭遮罩层。整体功能类似于一个商品展示页面,用户可以对商品进行不同的操作和反馈。

首先,实现卡片列表展示功能。通过循环遍历一个包含图片和文字介绍的数据数组,动态生成多个卡片组件。每个卡片组件包含一个图片元素和一个文字介绍元素,通过 vuev-for 指令实现数据绑定,将对应的图片和文字展示在每个卡片上。

其次,实现点击卡片查看详情的功能。为每个卡片组件添加点击事件监听器,当用户点击某个卡片时,触发相应的事件处理函数,展示该卡片的详细信息。这可以通过 vue@click 指令实现,为每个卡片元素添加点击事件处理逻辑。

接着,实现长按卡片显示遮罩层的功能。在代码中,为每个卡片组件添加长按事件监听器,当用户长按某个卡片时,显示遮罩层。通过 vue@touchstart 指令监听长按事件,并在事件触发时显示遮罩层。遮罩层可以是一个覆盖在卡片上方的半透明层,用来提供操作按钮和用户反馈选项。

在遮罩层上添加操作按钮,如"商品不感兴趣"、"不想看到此类商品"等选项。用户可以通过点击这些按钮来进行不同的操作和反馈。通过在遮罩层组件中添加按钮元素,并为每个按钮添加点击事件处理逻辑来实现。

最后,实现点击遮罩层外的区域关闭遮罩层的功能。为遮罩层外的区域添加点击事件监听器,当用户点击遮罩层外的区域时,关闭遮罩层。通过 vue@click 指令监听遮罩层外区域的点击事件,并在事件触发时关闭遮罩层。

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

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

相关文章

[C++] map、set 的 封装 (二):map、set和红黑树的双向奔赴

标题&#xff1a;[C] map、set 的 封装 &#xff08;二&#xff09; 水墨不写bug 前言 在正式深入进map、set封装之前&#xff0c;我有一些话想说&#xff0c;map和set的封装在初次理解时可能会比较困难&#xff0c;仅仅是模板&#xff0c;仿函数引起的回调就会把你拌入无底深…

【从Qwen2,Apple Intelligence Foundation,Gemma 2,Llama 3.1看大模型的性能提升之路】

从早期的 GPT 模型到如今复杂的开放式 LLM&#xff0c;大型语言模型 (LLM) 的发展已经取得了长足的进步。最初&#xff0c;LLM 训练过程仅侧重于预训练&#xff0c;但后来扩展到包括预训练和后训练。后训练通常包括监督指令微调和校准&#xff0c;这是由 ChatGPT 推广的。 自 …

redis AOF机制

在redis运行期间&#xff0c;不断将redis执行的写命令写到文件中&#xff0c;redis重启之后&#xff0c;只要将这些命令重复执行一遍就可以恢复数据。因为AOF只是将少量的写命令写入AOF文件中&#xff0c;因此其执行效率高于RDB&#xff0c;开启AOF即使Redis发生故障&#xff0…

Redis缓存场景

Redis缓存场景 文章目录 Redis缓存场景Redis做缓存旁路缓存缓存异常缓存穿透缓存击穿缓存雪崩 缓存一致性先写缓存再写数据库先写数据库再写缓存先删除缓存再写数据库先写数据库再删缓存缓存双删Binlog异步更新总结 Redis做缓存 部分图解来自于&#xff1a;https://www.miansh…

微课录制不再难:精选三款录屏软件助你一臂之力

在这个信息爆炸的时代&#xff0c;微课以其短小精悍、易于消化的特点&#xff0c;成为知识传播的新宠。无论是教师备课、企业培训&#xff0c;还是个人知识分享&#xff0c;微课都能以其独特的方式&#xff0c;让学习变得更加高效和便捷。在数字化教学的浪潮中&#xff0c;PPT课…

SAP SUBSCREEN使用

step1&#xff1a;在SELECTION-SCREEN中定义SUBSCREEN SELECTION-SCREEN BEGIN OF SCREEN 0101 AS SUBSCREEN. SELECT-OPTIONS S_XMGS FOR ZTPO0074-XMGS . SELECTION-SCREEN END OF SCREEN 0101.STEP2: 引用SUBSCREEN 关键字 CALL SUBSCREEN SUBSCR_0100 INCLUDING SY-RE…

Java基础核心知识学习笔记

方法重载 请记住下面重载的条件 方法名称必须相同。参数列表必须不同&#xff08;个数不同、或类型不同、参数类型排列顺序不同等&#xff09;。方法的返回类型可以相同也可以不相同。仅仅返回类型不同不足以成为方法的重载。重载是发生在编译时的&#xff0c;因为编译器可以根…

结合ChatGPT与Discord,提高团队合作效率

本文将教你如何集成Discord Bot&#xff0c;助力团队在工作中实现更高效的沟通与协作。通过充分发挥ChatGPT的潜力&#xff0c;进一步提升工作效率和团队协作能力。无需编写任何代码即可完成本文所述的操作&#xff0c;进行个性化定制只需对参数进行微调即可。 方案介绍 如果在…

联想闪电鲨移动硬盘文件没删除却消失了怎么办

在日常的数据存储与管理中&#xff0c;移动硬盘作为便携且容量可观的存储设备&#xff0c;深受用户青睐。然而&#xff0c;当您发现联想闪电鲨移动硬盘中的文件突然消失&#xff0c;而您确信并未进行删除操作时&#xff0c;这无疑会令人感到困惑与焦虑。本文旨在为您揭开这一谜…

MySQL各个版本root账号没有最高权限的解决方法

一、详细报错 ERROR 1045 (28000): Access denied for user ‘root’‘localhost’ (using password: YES) 报错原因&#xff08;分析过程&#xff09;&#xff1a; rootlocalhost用户密码修改导致 解决方法&#xff1a; 跳过权限验证启动数据库&#xff0c;并修改密码。如下…

[028-3].第05节:RabbitMQ中的交换机

1.什么是Exchanges(交换机&#xff09;: 1.RabbitMQ 消息传递模型的核心思想是: 生产者生产的消息从不会直接发送到队列。实际上&#xff0c;通常生产者甚至都不知道这些消息传递传递到了哪些队列中2.生产者只能将消息发送到交换机(exchange)&#xff0c;交换机工作的内容非常…

C++ TinyWebServer项目总结(7. Linux服务器程序规范)

进程 PID 进程的PID&#xff08;Process ID&#xff09;是操作系统中用于唯一标识一个进程的整数值。每个进程在创建时&#xff0c;操作系统都会分配一个唯一的PID&#xff0c;用来区分不同的进程。 PID的特点 唯一性&#xff1a; 在操作系统运行的某一时刻&#xff0c;每个…

江苏省第二中医院案例│“互联网+医疗”下的灾备建设

江苏省第二中医院&#xff0c;成立于1988年12月&#xff0c;是一所融医疗、教学、科研、预防保健为一体的公立省级综合性三级甲等中医院。目前&#xff0c;正对照“大学附属医院”“省级三甲医院”建设标准&#xff0c;全面推进医院建设高质量跨越式发展。 用户需求&#xff1a…

冒 泡 排 序

今天咱们单独拎出一小节来聊一聊冒泡排序昂 冒泡排序的核心思想就是&#xff1a;两两相邻的元素进行比较&#xff08;理解思路诸君可看下图&#xff09; 接下来我们上代码演示&#xff1a; 以上就是我们初步完成的冒泡排序&#xff0c;大家不难发现&#xff0c;不管数组中的元…

智能停车计费系统设计与实现_urqs9

TOC springboot552智能停车计费系统设计与实现_urqs9--论文 绪 论 1.1 研究背景 在新世纪的今天&#xff0c;计算机已经发展到一定的规模&#xff0c;带动了国内经济和科学技术的快速发展&#xff0c;科学技术的发展大大提高了生产效率&#xff0c;使人们的物质生活需求得到…

为啥每个语音的printf(“%d%d%d%d“,i,j,i++,j++)不一样

题目来源一位考研同学的题目。 第一眼&#xff1a;小子&#xff0c;这都不会&#x1f600; 第二眼&#xff1a;wok&#xff0c;咋没有选项&#x1f622; 作为一个大一学C语音&#xff0c;大二学Java的同学来说&#xff0c;我一看就觉得肯定是11 6 11 6 。 结果很遗憾&#xff0…

微服务开发相关问题

微服务开发相关问题 服务注册nacos 2.X注册问题[Nacos Config] config[dataIddatasource.yml, groupDEFAULT_GROUP] is empty 参考 持续更新… 服务注册 nacos 2.X注册问题 [Nacos Config] config[dataIddatasource.yml, groupDEFAULT_GROUP] is empty 因为&#xff1a;# 由于…

C++第十二弹 -- STL之list模拟实现

文章索引 前言模拟实现list1. ListNode节点类2. list的迭代器封装3. 反向迭代器4. list类的模拟实现测试代码 list的反向迭代器总结 前言 通过模拟实现可以让我们更加深刻的理解C底层STL的实现逻辑, 本篇就对list的底层进行模拟实现. 博客主页: 酷酷学!!! 点击关注 共同进步!…

影响五金精密零件加工价格的因素

在制造业中&#xff0c;五金精密零件的加工价格受到多种因素的影响。了解这些因素&#xff0c;对于企业合理控制成本、选择合适的加工供应商至关重要。 首先&#xff0c;零件的设计复杂度是一个重要因素。复杂的设计通常需要更先进的加工技术和更多的加工工序。例如&#xff0c…

intel ECI作为ACRN VM使用dpdk(vfio和iommu问题)以及img扩容

ACRN虚拟机内IOMMU 对非虚拟机而言&#xff0c;只要在BIOS里开启VT-d就可以用iommu去映射vfio使用DPDK&#xff0c;但是在虚拟机中即便BIOS开启了VT-d&#xff0c;它也传不到VM中。因此这个帖子解决一下这个问题。 在ACRN的launch脚本中需要passthru两个网卡&#xff0c;一个用…