【VUE】用vue写一个轮播图组件(二)

接上篇

  • 先总结下上篇技巧:
  • 提供一个v-model进行父子组件间数据交换。
  • 使用vue内置动画实现移动的动画效果。
  • 另外用watch监控value的变动来显示子组件变化。
  • 这次要实现的功能:
  • 完成可以正序播放和逆序播放功能。
  • 完成鼠标移入停止,移出继续轮播功能。
  • 加入轮播图小点功能,点击小点可以切换轮播页面。
  • 建立index.html支持手机端大小。
  • 加入轮播图左右按钮,可左右切换轮播。

代码

App.vue

<template>
  <swiper v-model="selected" autoplay>
    <swiperItem name="box1">
      <div class="content" style="background:red">页面1div>
    swiperItem>
    <swiperItem name="box2">
      <div class="content" style="background:green">页面2div>
    swiperItem>
    <swiperItem name="box3">
      <div class="content" style="background:yellow">页面3div>
    swiperItem>
  swiper>
template>
<script>
import swiperItem from "./components/SwiperItem";
import swiper from "./components/Swiper";
export default {
  data: () => {
    return { selected: "box3" };
  },
  components: {
    swiper,
    swiperItem
  }
};
script>
<style lang="stylus">
.content {
  width: 100%;
  height: 300px;
  text-align: center;
  margin: auto;
}
style>

Swiper.vue

<template>
  
<div class="viewport"> <slot>slot> <div class="dot"> <span v-for="(item,index) in len " :key="index" :class="{active:active===index}" @click="select(index)" >{{item}}span> div> <div class="sidebutton"> <div @click="leftclick">div> <div @click="rightclick">div> div> div> div> template> <script> export default { props: { value: { type: String, default: "" }, autoplay: { type: Boolean, default: true } }, methods: { touchmove(e){ console.log('移动'); console.log(e); }, touchstart(e){ this.startx = e.touches[0].clientX clearInterval(this.timer) }, touchend(e){ let endx = e.changedTouches[0].clientX let distance = endx-this.startx let trifNum = 20 if(distance>trifNum){ this.select(this.active-1) }else if(distance < -trifNum){ this.select(this.active+1) } this.autoShow() }, leftclick() { let newIndex = this.active - 1; this.select(newIndex); }, rightclick() { let newIndex = this.active + 1; this.select(newIndex); }, select(newIndex) { this.prev = this.active; if (newIndex === this.names.length) newIndex = 0; if (newIndex === -1) newIndex = this.names.length - 1; this.$emit("input", this.names[newIndex]); }, showChild() { this.currentName = this.value || this.$children[0].name; this.$children.forEach(vm => { this.$nextTick(() => { vm.selected = this.currentName; }); let updateIndex = this.active; let reverse = updateIndex > this.prev ? false : true; if (this.prev === 0 && updateIndex === this.len - 1) reverse = true; if (this.prev === this.len - 1 && updateIndex === 0) reverse = false; vm.reverse = reverse; }); }, autoShow() { if (this.autoplay) { this.timer = setInterval(() => { let index = this.active; let newIndex; let isreverse = false; if (isreverse) { newIndex = index - 1; } else { newIndex = index + 1; } this.select(newIndex); }, 2000); } }, mouseEnter() { clearInterval(this.timer); this.timer = null; }, mouseLeave() { if (!this.timer) { this.autoShow(); } } }, computed: { active() { return this.names.indexOf(this.currentName); } }, watch: { value() { this.showChild(); } }, beforeDestroy() { clearInterval(this.timer); }, data() { return { currentName: "", len: 0 }; }, mounted() { this.names = this.$children.map(vm => vm.name); this.len = this.names.length; this.showChild(); this.autoShow(); this.prev = this.active; } }; script> <style lang="stylus"> .swiper { border: 5px solid black; height: 300px; margin: auto; text-align: center; } .viewport { position: relative; overflow: hidden; width: 100%; height: 100%; } .dot { display: flex; justify-content: center; position: absolute; left: 0; right: 0; bottom: 0; span { height: 30px; width: 30px; border-radius: 100%; background-color: white; text-align: center; line-height: 30px; border: 1px solid black; margin: 0 10px 0; cursor: pointer; &.active { background-color: red; } } } .sidebutton { display: flex; justify-content: space-between; position: absolute; width: 100%; height: w = 30px; top: 50%; transform: translateY(-50%); text-align: center; line-height: w; font-size: 15px; div { background-color: purple; padding: 1px; &:nth-child(1) { border-top-left-radius: 80%; border-bottom-left-radius: 80%; } &:nth-child(2) { border-top-right-radius: 80%; border-bottom-right-radius: 80%; } } } style>

SwiperItem.vue

<template>
  <transition>
    <div class="swiper-item" v-if="isShow" :class="{reverse}">
      <slot>slot>
    div>
  transition>
template>

<script>
export default {
  props: {
    name: {
      type: String,
      required: true
    }
  },
  data() {
    return { selected: "", reverse: "" };
  },
  mounted() {},
  computed: {
    isShow() {
      return this.name === this.selected;
    }
  }
};
script>
<style lang="stylus">
.v-enter-active, .v-leave-active {
  transition: all 0.5s linear;
}

.v-leave-to {
  transform: translate(-100%);
}

.v-enter {
  transform: translate(100%);
}

.v-leave-to.reverse {
  transform: translate(100%);
}

.v-enter.reverse {
  transform: translate(-100%);
}

.v-leave-active {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
}
style>
  • html就是直接感叹号出来的就不发了。使用vue serve 默认挂到id为app的节点。
  • 总的来说还有不少缺点,样式不够美观,功能没完全放给用户,再学习一段时间后准备重弄个更好的试试。

你可能感兴趣的:(VUE)