Vue 实现商品详情多播图(点击图片列表轮播图)NEW

Vue 实现商品详情多播图(点击轮播图)

公司有这种需求,搜了很多没找到,找到下面这个,但是这个链接不是很符合公司需求
部分内容也存在点问题,所以补充一下

经过不断对标各大厂商写出第二套方案

原文基础链接:https://blog.csdn.net/LONGYog/article/details/124341749

实现效果old:

点击左右按钮图片左右移动
点击小图片图片展示到大图
图片从第一张切换到最后一张、最后一张切换到第一张

实现效果new一:

点击左右按钮图片左右移动
点击小图片图片展示到大图
图片从第一张切换到最后一张、最后一张切换到第一张
修改计算方式

这个方案改造后存在一个问题,
当我切换之后点击之前的一张,之后再点击向右切换会继续移动,
这个目前还没去找解决办法,暂且搁置,
如果有好的想法,欢迎T我哈

屏幕录制 2024-09-05 093446

HTML代码:

<template>
    <div class="head_flex">
      <div class="head_flex_img">
        <img :src="mainImgUrl" class="head_flex_img_top" />
        <div class="head_flex_img_bottom">
          <img src="@/assets/imgs/icon_left.png" alt="" class="arrow" @click="imgLeft()" />
          <div class="goods_items">
            <img
              v-for="(item, index) in images"
              :key="index"
              :src="item"
              class="goods_items_img"
              :style="imgStyle"
              @click="changeImg(item, index)"
              :class="index == imgActiveIndex ? 'img_activeBorder' : ''"
            />
          </div>
          <img src="@/assets/imgs/icon_right.png" alt="" class="arrow" @click="imgRight()" />
        </div>
      </div>
    </div>
</template>

JavaScript:

<script lang="ts" setup>
//记得替换下面图片的路径
import image from '@/assets/imgs/avatar.jpg'
import icon_success from '@/assets/imgs/icon_success.png'
import icon_error from '@/assets/imgs/icon_error.png'
import { ref, computed } from 'vue'

const images = ref([
  image,
  icon_success,
  image,
  icon_error,
  image,
  icon_success,
  image,
  icon_success,
  image,
  icon_error,
  image,
  icon_success,
  image
])

const imgDistance = ref(0) // 当前移动图片的索引值
const imgActiveIndex = ref(0) // 移动的距离
const mainImgUrl = ref(images.value[imgDistance.value])

const imgStyle = computed(() => {
  return {
    transform: `translate3d(${imgDistance.value}px, 0, 0)` // 计算移动的距离(x,y,z)
  }
})

const changeImg = (item, index) => {
  mainImgUrl.value = item
  imgActiveIndex.value = index
}

/*
  先判断是否从第一张切换到最后一张 || 从最后一张切换到第一张

    images.value.length - 4 这里减4是因为宽度限制一次只展示4张所以为4

    newIndex < 42  这里42 是一张图片的占位数值

*/

const imgLeft = () => {
  if (imgActiveIndex.value == 0) {
    imgActiveIndex.value = images.value.length - 1
    moveIndex('left', images.value.length - 4)
  } else if (imgActiveIndex.value > 0) {
    imgActiveIndex.value-- // 索引值-1
    images.value.forEach((item, index) => {
      if (imgActiveIndex.value === index) {
        mainImgUrl.value = item
      }
    })
    if (imgActiveIndex.value <= 9 && imgActiveIndex.value != 0) {
      moveIndex('left')
    }
  }
}
const imgRight = () => {
  if (imgActiveIndex.value < images.value.length - 1) {
    imgActiveIndex.value++
    images.value.forEach((item, index) => {
      if (imgActiveIndex.value == index) {
        mainImgUrl.value = item
      }
    })
    if (imgActiveIndex.value >= 4) {
      moveIndex('right')
    }
  } else if (imgActiveIndex.value == images.value.length - 1) {
    imgActiveIndex.value = 0
    mainImgUrl.value = images.value[0]
    moveIndex('right', images.value.length - 4)
  }
}

const moveIndex = (direction, val) => {
  let newIndex = 0
  const temp = window.setInterval(() => {
    if (direction == 'right') {
      if (val) {
        if (newIndex < 42 * val) {
          // 取绝对值再除
          imgDistance.value += 1
          newIndex++
          return
        } else {
          window.clearInterval(temp)
        }
      } else {
        if (newIndex < 42) {
          // 取绝对值再除
          imgDistance.value -= 1
          newIndex++
          return
        } else {
          window.clearInterval(temp)
        }
      }
    } else {
      if (val) {
        if (newIndex < 42 * val) {
          // 取绝对值再除
          imgDistance.value -= 1
          newIndex++
          return
        } else {
          window.clearInterval(temp)
        }
      } else {
        if (newIndex < 42) {
          // 取绝对值再除
          imgDistance.value += 1
          newIndex++
          return
        } else {
          window.clearInterval(temp)
        }
      }
    }
  }, 1)
}
</script>

css:

<style lang="less" scoped>
.head_flex {
  display: flex;
  justify-content: space-between;
  margin-bottom: 50px;

  &_img {
    width: 198px;
    height: 198px;
    border-radius: 4px;

    &_top {
      width: 100%;
      height: 100%;
      background-color: #f00;
    }
  }
}

.head_flex_img_bottom {
  width: 198px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-top: 12px;
}

.arrow {
  width: 14px;
  height: 14px;
}

.goods_items {
  width: 300px;
  height: 36px;
  display: flex;
  align-items: center;
  overflow: hidden;

  .goods_items_img {
    width: 36px;
    height: 36px;
    margin-right: 6px;
    border-radius: 4px;
    padding: 2px;
    box-sizing: border-box;
  }
}

.img_activeBorder {
  border: 1px solid #1762ff;
}
</style>

实现效果new二:

点击左右选中不切换,改为鼠标移入切换选中状态
点击左右,右侧隐藏图片展示

HTML代码:

<template>
       <div class="head_flex">
      <div class="head_flex_img">
        <img :src="mainImgUrl" class="head_flex_img_top" />

        <div class="head_flex_img_bottom">
          <img src="@/assets/imgs/icon_left.png" alt="" class="arrow" @click="imgLeft()" />
          <div class="goods_items">
            <div class="goods_item_slick_width" :style="imgStyle">
              <div
                v-for="(item, index) in data.goods_photo"
                :key="index"
                :ariaHidden="index > 3 ? false : true"
                class="goods_item_slick"
                :class="{
                  'slick-current': noneActionIndex === index
                }"
              >
                <img
                  :src="item"
                  @mouseover="handleMouseOver(item, index)"
                  class="goods_items_img"
                  :class="imgActiveIndex == index ? 'img_activeBorder' : ''"
                  :style="{}"
                />
              </div>
            </div>
          </div>
          <img src="@/assets/imgs/icon_right.png" alt="" class="arrow" @click="imgRight()" />
        </div>
      </div>
    </div>
</template>

JavaScript:

<script lang="ts" setup>
import { ref, computed } from 'vue'
const imgDistance = ref(0) // 移动的距离


const imgStyle = computed(() => {
  return {
    opacity: 1,
    transform: `translate3d(${imgDistance.value}px, 0, 0)`,
    transition: ' -webkit-transform 200ms' // 计算移动的距离(x,y,z)
  }
})

const handleMouseOver = (item, index) => {
  mainImgUrl.value = item
  imgActiveIndex.value = index
}
//先计算出向右点击能移动几次  -4 是一页设计只能展示4个
const onRightClickNum = computed(() => data.value.goods_photo.length - 4) //点击次数原始数值

const newonRightClickNum = ref(data.value.goods_photo.length - 4) //计算点击次数数值

const imgLeft = () => {
  // 计算出可以点击的差额,再减去剩余次数,自增恢复到原始差额
  //当前点击的次数   小于   点击总次数时 让其自增
  if (newonRightClickNum.value < onRightClickNum.value) {
    newonRightClickNum.value++
  }

  if (noneActionIndex.value === 0) return

  noneActionIndex.value--

  if (noneActionIndex.value <= onRightClickNum.value - 1 && noneActionIndex.value >= 0) {
    imgDistance.value += 46
  }
}

const imgRight = () => {
  const lastIndex = data.value.goods_photo.length - 1

  // 判断是否在最后一个隐藏节点
  if (noneActionIndex.value === lastIndex) return

  // 增加隐藏节点索引
  if (noneActionIndex.value < lastIndex) {
    noneActionIndex.value++
  }

  // 如果当前点击次数不为0且非最后一个节点,隐藏选中状态继续自增
  if (newonRightClickNum.value !== 0 && noneActionIndex.value < lastIndex) {
    newonRightClickNum.value--
    imgDistance.value -= 46
  }
}
</script>

css:

<style lang="less" scoped>
.head_flex {
  display: flex;
  justify-content: space-between;
  margin-bottom: 50px;

  &_img {
    width: 198px;
    height: 198px;

    &_top {
      width: 100%;
      height: 100%;
      border-radius: 4px;
    }
  }
}

.head_flex_img_bottom {
  width: 198px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-top: 12px;
}

.arrow {
  width: 14px;
  height: 14px;
}

.goods_items {
  width: 168px;
  height: 36px;
  white-space: nowrap;
  overflow: hidden;
  position: relative;
  .goods_item_slick_width {
    width: 900px;
  }

  .goods_item_slick {
    display: inline-block;
    width: 36px;
    height: 36px;
    margin-right: 8px;
  }

  .goods_items_img {
    width: 36px !important;
    height: 36px !important;
    border-radius: 4px;
    padding: 2px;
    box-sizing: border-box;
  }
}

.img_activeBorder {
  border: 1px solid #1762ff;
}

.head_flex_content {
  flex: 1;
  padding-left: 20px;
  box-sizing: border-box;

  .flex_content_top_title {
    font-weight: bold;
    font-size: 18px;
    color: #333333;
  }

  .flex_content_top_other {
    display: flex;
    align-items: center;
    margin-top: 16px;
    color: #333;
    font-size: 16px;
  }

  .other_label {
    color: #a4a4a4;
  }
}

.flex_content_data {
  display: flex;
  align-items: center;
  margin-top: 26px;

  .flex_content_data_item {
    margin-right: 48px;

    .data_item_top {
      font-size: 16px;
      color: #a4a4a4;
    }

    .data_item_num {
      display: flex;
      align-items: center;
      height: 22px;
      line-height: 22px;
      font-size: 21px;
      color: #333333;
      font-weight: bold;
      margin-top: 16px;
    }
  }
}

.data_sku {
  display: inline-block;
  width: 44px;
  background: #fff2dd;
  border-radius: 4px;
  text-align: center;
  font-size: 12px;
  color: #ffb842;
  margin-left: 10px;
}
</style>

写的不好请见谅,讲解的比较粗糙,如果有不懂的欢迎随时私信

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值