vue3一个简易的轮播图

本文展示了如何使用Vue.js实现一个轮播图组件,包括基本的图片切换功能,并逐步增加了循环播放、鼠标悬停暂停、手动拖动和点击缩略图切换等功能。代码中详细注释了各个部分的作用,是Vue.js前端开发的一个实践案例。

一、前言

看别人做的效果不错,自己也搞一个试试

二、代码

<template>
  <div class="w-ful h-full flex justify-center items-center flex-col border border-red-300" ref="lunboref">
    <div class="flex-1 w-full overflow-hidden">
      <div class="h-full transition-all  duration-500" :style="[yidongjuli,allwidth]" >
        <div v-for="(item,index) in imagelist" :key="index+'a'" class="h-full float-left"
             :style="{width:`${kuandu}px`}">
          <img :src="item" alt="" class="h-full w-full object-contain">
        </div>
      </div>
    </div>
    <div class="h-10 w-full flex justify-center items-center  bg-gray-600">
      <div v-for="(item,index) in imagelist" :key="index"
           class=" py-1 flex h-full justify-center items-center flex-nowrap relative"
           :style="{width:`${1/imagelist.length*100}%`}">
        <img :src="item" alt="" class="w-full h-full object-contain">
        <div class="absolute inset-0 bg-gray-600  hover:bg-opacity-0 cursor-pointer"
             :class="[activeindex===index?'bg-opacity-0':'bg-opacity-50',]" @click="dianji(index)"></div>
      </div>
    </div>
  </div>
</template>

<script setup>
import img1 from "./tupian/01.jpg"
import img2 from "./tupian/02.jpg"
import img3 from "./tupian/03.jpg"
import img4 from "./tupian/04.jpg"
import {defineComponent, ref, onMounted, computed} from "vue";
import {useStore} from "vuex"
import {useRouter, useRoute} from "vue-router"

const store = useStore()
const router = useRouter()
const route = useRoute()
const lunboref = ref(null)
const activeindex = ref(0)
const yidongjuli = computed(()=>{
  return {transform:`translateX(-${activeindex.value * kuandu.value}px)`}
})
const allwidth = computed(()=>{
  return {width:`${imagelist.value.length * kuandu.value}px`}
})
const kuandu = ref(0)
const imagelist = ref([img1, img2, img3, img4])
const dianji = (index) => {
  activeindex.value = index
  console.log(activeindex.value)
}
onMounted(() => {
  // 获取元素宽度
  kuandu.value = lunboref.value.clientWidth
  console.log(kuandu.value, "宽度")
})
</script>

<style scoped>

</style>

没有自动播放功能,等有时间吧

三、功能完善版的来了
2021年9月17日 17:15:55

<template>
  <div class="w-full h-full border" ref="lunboref" @mouseover="zanting(false)" @mouseleave="zanting(true)">
    <div class="h-4/5 w-full overflow-hidden">
      <ul style="width:99999px;height: 100%;" :style="{transform:`translateX(-${yidongjuli}px)`}"
          class="transition-all duration-500">
        <li :style="{width:`${kuandu}px`}" class="h-full flex justify-center items-center float-left relative"
            v-for="(item,index) in imglist" :key="index+'a'">
          <img :src="item" alt="轮播图" class="w-full h-full object-contain">
          <div :style="{width:`${kuandu/10}px`}" @click="qiehuan(-1)" v-show="activeindex>0 || prop.xunhuan"
               class="group absolute top-0 bottom-0 left-0  flex justify-center items-center bg-opacity-0 hover:bg-opacity-40 bg-gray-400 cursor-pointer active:bg-gray-500 active:text-blue-300">
            <span class="text-white  text-opacity-0 group-hover:text-opacity-100 iconfont icon-zuojiantou2"></span>
          </div>
          <div :style="{width:`${kuandu/10}px`}" @click="qiehuan(1)"
               v-show="activeindex<imglist.length-1 || prop.xunhuan"
               class="group absolute top-0 bottom-0 right-0 w-6 flex justify-center items-center bg-opacity-0 hover:bg-opacity-40 bg-gray-400 cursor-pointer active:bg-gray-500 active:text-blue-300">
            <span class="text-white  text-opacity-0 group-hover:text-opacity-100 iconfont icon-youjiantou2"></span>
          </div>
        </li>
      </ul>
    </div>
    <div class="h-1/5 w-full overflow-hidden">
      <ul style="width:99999px;height: 100%;" :style="{transform:`translateX(${pianyix}px)`}" class="transition-all">
        <li class="flex justify-center items-center h-full float-left relative" :style="{width:`${kuandu/4}px`}"
            v-for="(item,index) in imglist" :key="index" @mousedown="mouseputdown2">
          <img :src="item" alt="缩略图" class="w-full h-full object-contain"
               :class="[activeindex===index?'border border-blue-400':'']">
          <div class="absolute inset-0 cursor-pointer bg-gray-500 hover:border hover:border-blue-400 select-none"
               :class="[activeindex===index?'bg-opacity-0':'bg-opacity-20']" @click="dianji(index)"></div>
        </li>
      </ul>
    </div>
  </div>
</template>

<script setup>
import img1 from "./tupian/01.jpg"
import img2 from "./tupian/02.jpg"
import img3 from "./tupian/03.jpg"
import img4 from "./tupian/04.jpg"
import {computed, onMounted, ref, watch, defineProps} from "vue";
import {useStore} from "vuex"
import {useRoute, useRouter} from "vue-router"

const store = useStore()
const router = useRouter()
const route = useRoute()
// 传递进来的数据
const prop = defineProps({
  // 播放的列表
  list1: {
    default(data) {
      return data || []
    }
  },
  // 是否开启循环
  xunhuan: {
    type: Boolean,
    default: false,
  },
  // 是否开启自动播放
  autoplay: {
    type: Boolean,
    default: false,
  },
  // 多久切换一次
  autotime: {
    type: Number,
    default: 3,
  }
})
// hover状态下不轮播
const lunbo = ref(true)
// 整个轮播组件
const lunboref = ref(null)
// 图片列表
// const imglist = ref([img1, img2,])
const imglist = ref([img1, img2, img3, img4, img1, img2, img3, img4, img1, img2, img3, img4, img1, img2, img3, img4])
// 当前激活的序号
const activeindex = ref(0)
// 每个图片的宽度
const kuandu = ref(0)
// 鼠标拖动的偏移量
const pianyix = ref(0)
const yidongjuli = computed(() => {
  return activeindex.value * kuandu.value
})
const dianji = (index) => {
  activeindex.value = index
}
onMounted(() => {
  kuandu.value = lunboref.value.offsetWidth
  // 判断是否开启自动播放
  if (prop.autoplay) {
    setTimeout(() => {
      playfunc(1)
    }, prop.autotime * 1000)
  }
})

// 边界计算
watch(pianyix, () => {
  if (imglist.value.length <= 4) {
    pianyix.value = 0
  } else if (pianyix.value > 0) {
    pianyix.value = 0
  } else if (pianyix.value < -(imglist.value.length - 4) * kuandu.value / 4) {
    pianyix.value = -(imglist.value.length - 4) * kuandu.value / 4
  }
})

const mouseputdown2 = (e) => {
  let startX = e.clientX;
  const zancun = pianyix.value
  document.onmousemove = (e) => {
    let endX = e.clientX;
    pianyix.value = endX - startX + zancun;
  }
  document.onmouseup = () => {
    document.onmousemove = null;
    document.onmouseup = null;

  }
}

// 点击前后箭头
const qiehuan = (index) => {
  activeindex.value = activeindex.value + index
  if (prop.xunhuan) {
    // 开启循环
    if (activeindex.value < 0) {
      activeindex.value = imglist.value.length
    } else if (activeindex.value > imglist.value.length - 1) {
      activeindex.value = 0
    }
  } else {
    // 没开循环
    if (activeindex.value < 0) {
      activeindex.value = 0
    } else if (activeindex.value > imglist.value.length - 1) {
      activeindex.value = imglist.value.length - 1
    }
  }
  const index2 = Math.floor(activeindex.value / 4)
  pianyix.value = -index2 * kuandu.value
}

// 自动播放
const playfunc = (canshu) => {
  let index = canshu
  if (!prop.xunhuan) {
    if (activeindex.value <= 0) {
      index = 1
    } else if (activeindex.value >= imglist.value.length - 1) {
      index = -1
    }
  }
  if(lunbo.value){
    qiehuan(index)
  }
  setTimeout(() => {
    playfunc(index)
  }, prop.autotime * 1000)
}

// 鼠标移入组件范围内时,轮播停止
const zanting=(status)=>{
  lunbo.value = status
}
</script>

<style scoped>

</style>

2021年9月17日 17:43:01

<template>
  <div class="w-full h-full border" ref="lunboref" @mouseover="zanting(false)" @mouseleave="zanting(true)">
    <div class="h-4/5 w-full overflow-hidden relative">
      <ul style="width:99999px;height: 100%;" :style="{transform:`translateX(-${yidongjuli}px)`}"
          class="transition-all duration-500">
        <li :style="{width:`${kuandu}px`}" class="h-full flex justify-center items-center float-left "
            v-for="(item,index) in prop.imglist" :key="index+'a'">
          <img :src="item" alt="轮播图" class="w-full h-full object-contain">
        </li>
      </ul>
      <div :style="{width:`${kuandu/10}px`}" @click="qiehuan(-1)" v-show="activeindex>0 || prop.xunhuan"
           class="group absolute top-0 bottom-0 left-0  flex justify-center items-center bg-opacity-0 hover:bg-opacity-40 bg-gray-400 cursor-pointer active:bg-gray-500 active:text-blue-300">
        <span class="text-white  text-opacity-0 group-hover:text-opacity-100 iconfont icon-zuojiantou2"></span>
      </div>
      <div :style="{width:`${kuandu/10}px`}" @click="qiehuan(1)"
           v-show="activeindex<prop.imglist.length-1 || prop.xunhuan"
           class="group absolute top-0 bottom-0 right-0 w-6 flex justify-center items-center bg-opacity-0 hover:bg-opacity-40 bg-gray-400 cursor-pointer active:bg-gray-500 active:text-blue-300">
        <span class="text-white  text-opacity-0 group-hover:text-opacity-100 iconfont icon-youjiantou2"></span>
      </div>
    </div>
    <div class="h-1/5 w-full overflow-hidden">
      <ul style="width:99999px;height: 100%;" :style="{transform:`translateX(${pianyix}px)`}" class="transition-all">
        <li class="flex justify-center items-center h-full float-left relative" :style="{width:`${kuandu/4}px`}"
            v-for="(item,index) in prop.imglist" :key="index" @mousedown="mouseputdown2">
          <img :src="item" alt="缩略图" class="w-full h-full object-contain"
               :class="[activeindex===index?'border border-blue-400':'']">
          <div class="absolute inset-0 cursor-pointer bg-gray-500 hover:border hover:border-blue-400 select-none"
               :class="[activeindex===index?'bg-opacity-0':'bg-opacity-20']" @click="dianji(index)"></div>
        </li>
      </ul>
    </div>
  </div>
</template>

<script setup>
import {computed, onMounted, ref, watch, defineProps} from "vue";
import {useStore} from "vuex"
import {useRoute, useRouter} from "vue-router"

const store = useStore()
const router = useRouter()
const route = useRoute()
// 传递进来的数据
const prop = defineProps({
  // 播放的列表
  imglist: {
    type:Array,
  },
  // 是否开启循环
  xunhuan: {
    type: Boolean,
    default: false,
  },
  // 是否开启自动播放
  autoplay: {
    type: Boolean,
    default: false,
  },
  // 多久切换一次
  autotime: {
    type: Number,
    default: 3,
  }
})
// hover状态下不轮播
const lunbo = ref(true)
// 整个轮播组件
const lunboref = ref(null)
// 图片列表
// const prop.imglist = ref([img1, img2,])
// const prop.imglist = ref([img1, img2, img3, img4, img1, img2, img3, img4, img1, img2, img3, img4, img1, img2, img3, img4])
// 当前激活的序号
const activeindex = ref(0)
// 每个图片的宽度
const kuandu = ref(0)
// 鼠标拖动的偏移量
const pianyix = ref(0)
const yidongjuli = computed(() => {
  return activeindex.value * kuandu.value
})
const dianji = (index) => {
  activeindex.value = index
}
onMounted(() => {
  kuandu.value = lunboref.value.offsetWidth
  // 判断是否开启自动播放
  if (prop.autoplay) {
    setTimeout(() => {
      playfunc(1)
    }, prop.autotime * 1000)
  }
})

// 边界计算
watch(pianyix, () => {
  if (prop.imglist.length <= 4) {
    pianyix.value = 0
  } else if (pianyix.value > 0) {
    pianyix.value = 0
  } else if (pianyix.value < -(prop.imglist.length - 4) * kuandu.value / 4) {
    pianyix.value = -(prop.imglist.length - 4) * kuandu.value / 4
  }
})

const mouseputdown2 = (e) => {
  let startX = e.clientX;
  const zancun = pianyix.value
  e.onmousemove = (e) => {
    let endX = e.clientX;
    pianyix.value = endX - startX + zancun;
  }
  e.onmouseup = () => {
    e.onmousemove = null;
    e.onmouseup = null;

  }
}

// 点击前后箭头
const qiehuan = (index) => {
  activeindex.value = activeindex.value + index
  if (prop.xunhuan) {
    // 开启循环
    if (activeindex.value < 0) {
      activeindex.value = prop.imglist.length
    } else if (activeindex.value > prop.imglist.length - 1) {
      activeindex.value = 0
    }
  } else {
    // 没开循环
    if (activeindex.value < 0) {
      activeindex.value = 0
    } else if (activeindex.value > prop.imglist.length - 1) {
      activeindex.value = prop.imglist.length - 1
    }
  }
  const index2 = Math.floor(activeindex.value / 4)
  pianyix.value = -index2 * kuandu.value
}

// 自动播放
const playfunc = (canshu) => {
  let index = canshu
  if (!prop.xunhuan) {
    if (activeindex.value <= 0) {
      index = 1
    } else if (activeindex.value >= prop.imglist.length - 1) {
      index = -1
    }
  }
  if(lunbo.value){
    qiehuan(index)
  }
  setTimeout(() => {
    playfunc(index)
  }, prop.autotime * 1000)
}

// 鼠标移入组件范围内时,轮播停止
const zanting=(status)=>{
  lunbo.value = status
}
</script>

<style scoped>

</style>
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值