vue3+js 实现轮播滚动

效果:(可控制鼠标hover时停止滚动)
在这里插入图片描述
实现:
1.新建vue文件封装组件

<template>
  <!-- 滚动容器,用于包裹整个滚动内容,设置了固定高度并隐藏溢出部分 -->
  <div class="seamless-scroll" ref="scrollContainer">
    <!-- 滚动内容区域,根据滚动方向添加不同的类名以应用相应的动画 -->
    <div class="scroll-content" :class="{
        'scroll-up': direction === 'up',
        'scroll-down': direction === 'down',
      }">
      <!-- 第一组内容,展示原始的滚动项 -->
      <div class="scroll-item">
        <!-- 使用 v-for 指令遍历数据源数组 items,为每个项目渲染一个滚动项 -->
        <div v-for="(item, index) in items" :key="item.key || index" class="scroll-item-content">
          <!-- 使用插槽插入每个滚动项的具体内容 -->
          <slot :item="item" :index="index"></slot>
        </div>
      </div>
      <!-- 第二组内容,与第一组内容相同,用于实现无缝衔接滚动效果 -->
      <!-- <div class="scroll-item">
        <div v-for="(item, index) in items" :key="item.key || index" class="scroll-item-content">
          <slot :item="item" :index="index"></slot>
        </div>
      </div> -->
    </div>
  </div>
</template>
 
<script setup>
import { ref, onMounted, onBeforeUnmount } from "vue";

// 组件属性定义
const props = defineProps({
  // 滚动速度(秒),值越小滚动越快
  speed: {
    type: Number,
    default: 30,
  },
  // 滚动方向:up-向上,down-向下,left-向左,right-向右
  direction: {
    type: String,
    default: "up",
    // 验证传入的方向值是否合法
    validator: (value) => ["up", "down", "left", "right"].includes(value),
  },
  // 是否启用鼠标悬停暂停
  hover: {
    type: Boolean,
    default: false,
  },
  // 数据源数组,用于渲染滚动项
  items: {
    type: Array,
    default: () => [],
  },
  // 每个项目的高度(像素),目前未在代码中使用,可用于后续计算滚动距离等
  itemHeight: {
    type: Number,
    default: 40,
  },
});

// 组件状态和引用
// 引用滚动容器元素,用于添加和移除鼠标事件监听器
const scrollContainer = ref(null);
// 记录鼠标是否悬停在滚动容器上的状态
const isHovered = ref(false);

// 处理鼠标进入事件
const handleMouseEnter = () => {
  // 如果启用了鼠标悬停暂停功能
  if (props.hover) {
    // 将鼠标悬停状态设置为 true
    isHovered.value = true;
  }
};

// 处理鼠标离开事件
const handleMouseLeave = () => {
  // 如果启用了鼠标悬停暂停功能
  if (props.hover) {
    // 将鼠标悬停状态设置为 false
    isHovered.value = false;
  }
};

// 生命周期钩子:在组件挂载后执行
onMounted(() => {
  // 如果启用了鼠标悬停暂停功能
  if (props.hover) {
    // 为滚动容器添加鼠标进入事件监听器,触发 handleMouseEnter 方法
    scrollContainer.value?.addEventListener("mouseenter", handleMouseEnter);
    // 为滚动容器添加鼠标离开事件监听器,触发 handleMouseLeave 方法
    scrollContainer.value?.addEventListener("mouseleave", handleMouseLeave);
  }
});

// 生命周期钩子:在组件卸载前执行
onBeforeUnmount(() => {
  // 如果启用了鼠标悬停暂停功能
  if (props.hover) {
    // 移除滚动容器的鼠标进入事件监听器
    scrollContainer.value?.removeEventListener("mouseenter", handleMouseEnter);
    // 移除滚动容器的鼠标离开事件监听器
    scrollContainer.value?.removeEventListener("mouseleave", handleMouseLeave);
  }
});

// 监听窗口大小变化
window.addEventListener("resize", () => {
  // 这里需要重新计算滚动样式,因为窗口大小变化可能会影响滚动距离
  // 但是这里没有提供重新计算滚动样式的方法,所以暂时保留原来的样式
  // 后续可添加根据窗口大小重新计算滚动距离和动画的逻辑
});
</script>
 
<style lang="scss" scoped>
/* 滚动容器样式 */
.seamless-scroll {
  width: 100%;
  height: 200px;
  overflow: hidden;
  position: relative;

  /* 滚动内容区域样式 */
  .scroll-content {
    position: absolute;
    width: 100%;
    /* 性能优化相关属性 */
    will-change: transform;
    backface-visibility: hidden;
    transform-style: preserve-3d;
    perspective: 1000px;

    /* 向上滚动动画 */
    &.scroll-up {
      // 使用 Vue 的 v-bind 指令动态绑定动画的持续时间,根据传入的 speed 属性设置
      animation: scrollUp 20s linear infinite;
      // animation: scrollUp v-bind('speed + "s"') linear infinite;
      // 当鼠标悬停在滚动内容上时,暂停动画
      &:hover {
        animation-play-state: paused;
      }
    }

    /* 向下滚动动画 */
    &.scroll-down {
      // 动态绑定动画的持续时间
      // animation: scrollDown v-bind('speed + "s"') linear infinite;
      animation: scrollDown 20s linear infinite;
      // 鼠标悬停时暂停动画
      &:hover {
        animation-play-state: paused;
      }
    }

    /* 滚动项样式 */
    .scroll-item {
      width: 100%;
    }
  }
}

/* 向上滚动动画关键帧 */
@keyframes scrollUp {
  0% {
    transform: translateY(0);
  }
  100% {
    transform: translateY(-50%);
  }
}

/* 向下滚动动画关键帧 */
@keyframes scrollDown {
  0% {
    transform: translateY(-50%);
  }
  100% {
    transform: translateY(0);
  }
}

/* 水平滚动时的布局方式 */
.scroll-content[style*="translateX"] {
  display: flex;
  align-items: center;

  .scroll-item {
    display: flex;
    flex-shrink: 0;
  }
}
</style>

  1. 引入使用
import Scroll from "./ScrollVue.vue"
<Scroll :speed="5" direction="up" :hover="true" :items="orderList" :itemHeight="40">
     <!-- 自定义滚动项内容- -->
     <template #default="{ item }">
           <div class="scroll-item-content">
               <img src="@/assets/pageImg/start.png" class="start_icon" />
               {{item}}
            </div>
       </template>
</Scroll>
<think>根据用户需求,需要在Vue2中使用JavaScript和CSS实现轮播图功能。我们将采用Vue2的过渡组件(transition-group)结合CSS过渡效果来实现轮播图的基本功能,包括图片切换和指示器(bullet)效果。 ### 实现思路 1. 使用Vue2的`<transition-group>`组件实现图片的切换动画。 2. 使用CSS定义进入和离开的过渡效果(例如:水平滑动)。 3. 通过定时器自动轮播,并可以通过指示器或左右箭头手动切换。 4. 使用`computed`属性计算当前显示的图片索引,并更新指示器状态。 ### 代码实现 #### HTML结构(Vue模板) ```html <template> <div class="carousel"> <transition-group name="image" tag="ul" class="slide"> <li v-for="(img, index) in images" :key="index" v-show="index === currentIndex"> <img :src="img" alt="轮播图"> </li> </transition-group> <!-- 指示器 --> <div class="bullet"> <span v-for="(item, index) in images" :key="index" :class="{active: index === currentIndex}" @click="bulletClick(index)"> </span> </div> <!-- 左右箭头 --> <button class="btn left" @click="prev">❮</button> <button class="btn right" @click="next">❯</button> </div> </template> ``` #### JavaScript部分 ```javascript <script> export default { data() { return { currentIndex: 0, // 当前显示图片的索引 images: [ "https://example.com/image1.jpg", // 替换为实际图片URL "https://example.com/image2.jpg", "https://example.com/image3.jpg" ], timer: null // 定时器 }; }, mounted() { this.startAutoPlay(); }, beforeDestroy() { if (this.timer) { clearInterval(this.timer); } }, methods: { // 上一张 prev() { this.currentIndex = (this.currentIndex - 1 + this.images.length) % this.images.length; }, // 下一张 next() { this.currentIndex = (this.currentIndex + 1) % this.images.length; }, // 指示器点击 bulletClick(index) { this.currentIndex = index; }, // 开始自动播放 startAutoPlay() { this.timer = setInterval(() => { this.next(); }, 3000); // 3秒切换一次 }, // 停止自动播放(可选,例如鼠标悬停时停止) stopAutoPlay() { if (this.timer) { clearInterval(this.timer); this.timer = null; } } } }; </script> ``` #### CSS样式 ```css <style scoped> .carousel { width: 500px; height: 300px; margin: 0 auto; overflow: hidden; position: relative; } .slide { width: 500px; height: 300px; } li { position: absolute; top: 0; left: 0; } img { width: 500px; height: 300px; } .bullet { width: 100%; position: absolute; bottom: 10px; margin: 0 auto; text-align: center; z-index: 10; } span { width: 20px; height: 5px; border: 1px solid; background: white; display: inline-block; margin-right: 10px; cursor: pointer; } .active { background: red; } /* 过渡效果 */ .image-enter-active, .image-leave-active { transition: all 1s ease; } .image-enter { transform: translateX(100%); } .image-leave-to { transform: translateX(-100%); } .image-enter-to, .image-leave { transform: translateX(0); } /* 左右箭头 */ .btn { position: absolute; top: 50%; transform: translateY(-50%); background: rgba(0,0,0,0.5); color: white; border: none; padding: 10px; cursor: pointer; } .left { left: 10px; } .right { right: 10px; } </style> ``` ### 功能说明 1. **自动轮播**:通过`setInterval`每3秒切换到下一张图片。 2. **手动切换**:可以通过左右箭头按钮切换图片。 3. **指示器**:底部的小圆点指示当前图片位置,点击可切换到对应图片。 4. **过渡效果**:使用Vue的过渡组件实现图片水平滑动的切换效果。 ### 注意事项 1. 图片路径需要替换为实际可用的URL。 2. 如果需要鼠标悬停停止自动轮播,可以在轮播图容器上添加`@mouseenter="stopAutoPlay"`和`@mouseleave="startAutoPlay"`。 3.实现使用了绝对定位,所有图片重叠在一起,通过改变`currentIndex`控制显示哪一张。 ### 相关问题 1. 如何实现垂直滚动轮播图效果? 2. 如何添加淡入淡出效果代替滑动效果? 3. Vue2中如何实现无限循环的轮播图(即第一张向前切换是最后一张)? 4. 如何优化轮播图的性能,避免不必要的渲染? 希望以上实现能够满足您的需求。 参考文献: [^1]: Vuejs实现轮播图。 [^2]: vue2项目中使用轮播图。</think>### Vue2 轮播图实现方案 下面是一个完整的 Vue2 轮播图实现方案,使用 JavaScript 控制逻辑和 CSS 实现动画效果: ```html <template> <div class="carousel-container"> <!-- 轮播图主体 --> <div class="carousel" @mouseenter="stopAutoPlay" @mouseleave="startAutoPlay"> <transition-group name="slide" tag="div" class="slides-container"> <div v-for="(slide, index) in slides" :key="index" class="slide" v-show="currentIndex === index" > <img :src="slide.image" :alt="&#39;Slide &#39; + (index + 1)"> </div> </transition-group> <!-- 左右导航按钮 --> <button class="nav-btn prev" @click="prevSlide">❮</button> <button class="nav-btn next" @click="nextSlide">❯</button> <!-- 指示器 --> <div class="indicators"> <span v-for="(slide, index) in slides" :key="index" :class="{ active: currentIndex === index }" @click="goToSlide(index)" ></span> </div> </div> </div> </template> <script> export default { data() { return { currentIndex: 0, slides: [ { image: "https://example.com/image1.jpg" }, { image: "https://example.com/image2.jpg" }, { image: "https://example.com/image3.jpg" } ], autoPlayInterval: null }; }, mounted() { this.startAutoPlay(); }, beforeDestroy() { this.stopAutoPlay(); }, methods: { startAutoPlay() { this.autoPlayInterval = setInterval(() => { this.nextSlide(); }, 3000); // 每3秒切换一次 }, stopAutoPlay() { if (this.autoPlayInterval) { clearInterval(this.autoPlayInterval); this.autoPlayInterval = null; } }, nextSlide() { this.currentIndex = (this.currentIndex + 1) % this.slides.length; }, prevSlide() { this.currentIndex = (this.currentIndex - 1 + this.slides.length) % this.slides.length; }, goToSlide(index) { this.currentIndex = index; } } }; </script> <style scoped> /* 轮播图容器 */ .carousel-container { display: flex; justify-content: center; margin: 20px 0; } .carousel { position: relative; width: 600px; height: 400px; overflow: hidden; border-radius: 8px; box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15); } /* 幻灯片容器 */ .slides-container { position: relative; width: 100%; height: 100%; } /* 单个幻灯片 */ .slide { position: absolute; top: 0; left: 0; width: 100%; height: 100%; transition: opacity 0.5s ease; } .slide img { width: 100%; height: 100%; object-fit: cover; } /* 导航按钮 */ .nav-btn { position: absolute; top: 50%; transform: translateY(-50%); background: rgba(0, 0, 0, 0.5); color: white; border: none; width: 40px; height: 40px; border-radius: 50%; font-size: 18px; cursor: pointer; transition: background 0.3s ease; z-index: 10; } .nav-btn:hover { background: rgba(0, 0, 0, 0.8); } .prev { left: 15px; } .next { right: 15px; } /* 指示器 */ .indicators { position: absolute; bottom: 15px; left: 0; right: 0; display: flex; justify-content: center; gap: 8px; z-index: 10; } .indicators span { display: inline-block; width: 12px; height: 12px; border-radius: 50%; background: rgba(255, 255, 255, 0.5); cursor: pointer; transition: background 0.3s ease; } .indicators span.active { background: #fff; transform: scale(1.2); } .indicators span:hover { background: rgba(255, 255, 255, 0.8); } /* 过渡动画 */ .slide-enter-active, .slide-leave-active { transition: transform 0.5s ease, opacity 0.5s ease; } .slide-enter { transform: translateX(100%); opacity: 0; } .slide-leave-to { transform: translateX(-100%); opacity: 0; } </style> ``` ### 功能说明 1. **自动轮播**: - 默认每3秒自动切换图片 - 鼠标悬停时暂停轮播 - 鼠标离开时恢复轮播 2. **手动控制**: - 左右箭头按钮可手动切换 - 底部指示器可直接跳转到指定图片 3. **平滑过渡效果**: - 使用Vue的`<transition-group>`实现滑动动画 - CSS过渡效果确保切换流畅 4. **响应式设计**: - 容器尺寸可调整 - 图片自适应容器大小 ### 自定义选项 1. **修改轮播间隔**: 在`startAutoPlay()`方法中修改`setInterval`的时间参数(单位毫秒) 2. **添加更多幻灯片**: 在`data`的`slides`数组中添加新的图片对象 3. **调整尺寸**: 修改`.carousel`的宽度和高度值 4. **更改动画效果**: 在CSS的`.slide-enter-active`和`.slide-leave-active`中修改过渡属性 ### 相关问题 1. 如何实现轮播图的无限循环效果? 2. 如何在Vue2轮播图中添加淡入淡出动画? 3. 如何让轮播图自适应不同屏幕尺寸? 4. 轮播图性能优化的常见方法有哪些?[^1][^2] 参考文献: [^1]: Vuejs实现轮播图 [^2]: vue2项目中使用轮播图
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值