vue轮播组件实现,懂,但是写过才算,附带好用的gif录制工具

写这个组件起因

记得就这两天有掘友发一个沸点说找女票千万别找同行,好了,曾经我是erp软件实施,现在转前端。女票也是前端。然后她发我一个链接(打不开看gif图):http://ipark.jsboon.com/static/dashboard/yjw/yjw.html

这个链接的最右侧有一个轮播的效果。说起来这整个页面是不咋的,不过里面涉及的东西都比较复杂。附带gif录制工具:http://www.zdfans.com/html/1754.html

回到刚才说的,女票,对女票。不懂问我,就像之前评论的,干脆让我写得了。这下好了报应来了。(说起来真是无语,她比我早干一年,结果还不如我写了1年前端)

说起来我还没写过这种轮播组件,但是之前去看过源码,并且了解过。如果是写死的那种确实比较简单。但是我们今天用vue封装一个组件。

一、知识点涉及

1、vue组件化开发

2、vue组件嵌套组,就是两个组件相互耦合,然后必须配合使用的那种。参考elementUI里面的表单组件(分为from组件,item组件)或者轮播组件。

vue的$children和$parent

3、css动画和形变

二、开始写组件

1、先写你的框,主组件

这个是容器,负责组件定位和组件的整体运作的

html部分

<div
  @mouseenter.stop="handleMouseEnter"
  @mouseleave.stop="handleMouseLeave"
  class="dht-swiper-side"
  :style="{ zIndex: zIndex }"
>
  <slot></slot>
</div>

主要两个鼠标事件:mouseenter和mouseleave

第一个就是鼠标在元素上负责停止定时器,第二个就是鼠标离开重启定时器

对应的props和监听

 

props: {
  // 时间间隔
  interval: {
    type: Number,
    default: 8000
  },
  //是否自动播放
  autoplay: {
    type: Boolean,
    default: true
  },
  zIndex: {
    type: Number,
    default: 2000
  },
  // x轴变化
  axisx: {
    type: Number,
    default: 1000
  }
},
watch: {
  autoplay(val) {
    val ? this.startTimer() : this.stopTimer();
  }
},
data() {
  return {
    // 计时器
    timer: "",
    //子元素
    items: [],
    // 当前显示的元素
    active: 0
  };
},

看看就好,没啥多说的,我感觉挺清晰的

2、写你的子组件

这里必须跳跃一下,为什么呢?

因为:主组件主要负责动画运作和容器的作用。定义好你要的参数之后,其实主组件你直接看代码是不不符合编写逻辑的

有了主组件之后,我需要有子元素才能动起来,所以先把子元素加载进来

html部分

<div class="dht-swiper-side-item" :style="itemStyle">
  <slot></slot>
</div>

js核心部分

created() {
  //元素创建和需要更新父元素属性
  this.$parent && this.$parent.updateItems();
},
beforeMount() {},
mounted() {},
destroyed() {
  //元素销毁和需要更新父元素属性
  this.$parent && this.$parent.updateItems();
},

这里主要是创建元素的时候需要把元素加入主组件的items中,销毁的时候同样进行更新

主组件的更新代码

 

// 更新元素
updateItems() {
  this.items = this.$children.filter(
    // 更新元素需要确认为指定的子元素
    child => child.$options.name === "dhtSwiperSideItem"
  );
},

css核心部分

css部分主要是定义动画效果,和基础css,主要是看动画部分

 

.dht-swiper-side-item {
  position: absolute;
  transition: all 1s ease;
  transform: translateX(1000px);
  // 抖动动画
  @keyframes mymove {
    0% {
      left: 0;
    }
    50% {
      left: 15px;
    }
    100% {
      left: 0;
    }
  }
}

3、一般弹窗动画之类的编写原理讲解

1、不能用display:none,因为那样元素是直接显示出来的,动画是无法有的。

2、举例:下方弹窗划出

其实在写这些弹窗的时候元素已经在页面上面加载好了,只是被我们隐藏到显示器之外了。

所以我们要做的是在点击显示的时候把元素位移回来

3、所以其实页面上基本的动画都是先放在你看不到的地方,然后再通过transform

形变css给移动回来的。我这次的组件也是一样的。

4、主组件操作

1、回顾一下,刚才我们先写了主组件,主组件加载子组件,子组件会调用主组件函数,让主组件去更新自己的items,提前存好。方便使用

2、既然我们主组件拿到了子组件了,那么就可以直接操作子组件进行操作,其实核心原理在于主组件之间操作子组件。(我看了elementUI源码的走马灯部分,写的比我复杂。)

3、定时器部分

//开始计时器
startTimer() {
  //预先执行一次,保证不会出现第一次运行延迟双倍实际
  this.play();
  // 拦截处理
  if (this.interval <= 0 || !this.autoplay || this.timer) return;
  this.timer = setInterval(() => {
    this.play();
  }, this.interval);
},

这块其实没啥,除了预先的拦截剩下的就是启动定时器,然后运行动画播放函数

4、核心播放函数部分

//播放实际运行函数
play() {
  let len = this.items.length - 1;
  let now = this.active > len ? 0 : this.active;
  let old = this.active - 1 < 0 ? 0 : this.active - 1;
  //console.log("当前", now, "老的", old);
  //关闭老元素
  this.items[old].show = false;
  this.items[old].itemStyle = {
    transition: "all 1.5s ease",
    transform: `translateX(${this.axisx}px)`
  };
  //显示新元素
  this.items[now].show = true;
  this.items[now].itemStyle = {
    transition: "all 1.5s ease",
    transform: "translateX(0)",
    animation: "mymove 1.5s 2"
  };
  //记录数据
  this.active = now + 1;
}

这个其实很简单,每次运行的时候处理一下数据,拿到当前要运行的子元素id和老的元素,当前的展示,老的移动回去。最后记录一下新的id

这里有一个坑点:就是animation部分,记得运行2次,不然只是一次会导致下面的元素看不到抖动效果。原因是在移动的时候就抖动完毕了。

5、主组件css部分

.dht-swiper-side {
  position: absolute;
  z-index: 2000;
  right: 0;
  display: flex;
  flex-flow: row;
  width: 100%;
}

三、组件文档

dht-swiper-side侧边轮播组件intervalNumber5000时间间隔,默认5秒转换一次必须给该组件指定宽度,否则无法正常显示。内部子元素展示做最侧位置主要由该组件的宽度定义
autoplayBooleanTRUE是否自动播放,咱不支持false
zIndexNumber2000组件层级
axisxNumber1000隐藏的子元素位置,px单位,默认1000。当内部元素宽度过大时可以调节该参数
dht-swiper-side-itemdht-swiper-side     dht-swiper-side的子组件,用于存放内容
    
    
    

 

四、个人组件效果展示

<dht-swiper-side class="main">
  <dht-swiper-side-item>
    <div class="item">我是组件1</div>
  </dht-swiper-side-item>
  <dht-swiper-side-item>
    <div class="item">我是组件2</div>
  </dht-swiper-side-item>
  <dht-swiper-side-item>
    <div class="item">我是组件3</div>
  </dht-swiper-side-item>
  <dht-swiper-side-item>
    <div class="item">我是组件4</div>
  </dht-swiper-side-item>
</dht-swiper-side>
.main {
  width: 500px;
  .item {
    width: 100px;
    height: 100px;
    background: #009966;
    border: #409eff 1px solid;
    text-align: center;
    line-height: 100px;
  }
}

主组件全部代码

<template>
  <div
    @mouseenter.stop="handleMouseEnter"
    @mouseleave.stop="handleMouseLeave"
    class="dht-swiper-side"
    :style="{ zIndex: zIndex }"
  >
    <slot></slot>
  </div>
</template>

<script>
export default {
  name: "dhtSwiperSide",
  props: {
    // 时间间隔
    interval: {
      type: Number,
      default: 8000
    },
    //是否自动播放
    autoplay: {
      type: Boolean,
      default: true
    },
    zIndex: {
      type: Number,
      default: 2000
    },
    // x轴变化
    axisx: {
      type: Number,
      default: 1000
    }
  },
  watch: {
    autoplay(val) {
      val ? this.startTimer() : this.stopTimer();
    }
  },
  data() {
    return {
      // 计时器
      timer: "",
      //子元素
      items: [],
      // 当前显示的元素
      active: 0
    };
  },
  beforeCreate() {},
  created() {
    this.$nextTick(() => {
      this.updateItems();
      this.startTimer();
      this.$children[0].show = true;
    });
  },
  beforeMount() {},
  mounted() {},
  destroyed() {
    clearInterval(this.timer);
  },
  methods: {
    handleMouseEnter() {
      this.stopTimer();
    },

    handleMouseLeave() {
      this.startTimer();
    },
    //开始计时器
    startTimer() {
      //预先执行一次,保证不会出现第一次运行延迟双倍实际
      this.play();
      // 拦截处理
      if (this.interval <= 0 || !this.autoplay || this.timer) return;
      this.timer = setInterval(() => {
        this.play();
      }, this.interval);
    },
    // 停止计时器
    stopTimer() {
      clearInterval(this.timer);
    },
    // 更新元素
    updateItems() {
      this.items = this.$children.filter(
        // 更新元素需要确认为指定的子元素
        child => child.$options.name === "dhtSwiperSideItem"
      );
    },
    //播放实际运行函数
    play() {
      let len = this.items.length - 1;
      let now = this.active > len ? 0 : this.active;
      let old = this.active - 1 < 0 ? 0 : this.active - 1;
      //console.log("当前", now, "老的", old);
      //关闭老元素
      this.items[old].show = false;
      this.items[old].itemStyle = {
        transition: "all 1.5s ease",
        transform: `translateX(${this.axisx}px)`
      };
      //显示新元素
      this.items[now].show = true;
      this.items[now].itemStyle = {
        transition: "all 1.5s ease",
        transform: "translateX(0)",
        animation: "mymove 1.5s 2"
      };
      //记录数据
      this.active = now + 1;
    }
  }
};
</script>

<style lang="scss">
.dht-swiper-side {
  position: absolute;
  z-index: 2000;
  right: 0;
  display: flex;
  flex-flow: row;
  width: 100%;
}
</style>

子组件全部代码

<template>
  <div class="dht-swiper-side-item" :style="itemStyle">
    <slot></slot>
  </div>
</template>

<script>
export default {
  name: "dhtSwiperSideItem",
  data() {
    return {
      show: false,
      defaultStyle: {},
      itemStyle: {}
    };
  },
  watch: {},
  beforeCreate() {},
  created() {
    //元素创建和需要更新父元素属性
    this.$parent && this.$parent.updateItems();
  },
  beforeMount() {},
  mounted() {},
  destroyed() {
    //元素销毁和需要更新父元素属性
    this.$parent && this.$parent.updateItems();
  },
  methods: {}
};
</script>

<style lang="scss">
.dht-swiper-side-item {
  position: absolute;
  transition: all 1s ease;
  transform: translateX(1000px);
  // 抖动动画
  @keyframes mymove {
    0% {
      left: 0;
    }
    50% {
      left: 15px;
    }
    100% {
      left: 0;
    }
  }
}
</style>

致谢

感谢elementUI开源代码,本组件有部分是直接拷贝的elementUI的Carousel的代码。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值