vue轮播组件实现$children和$parent 附带好用的gif录制工具


Posted in Javascript onSeptember 26, 2019

1、先提前预祝大家国庆节玩的愉快,我国庆要见家长去了(忐忑)

2、忍不住想要为小米正名,虽然我是米粉但是我是理智粉。

24号不是mix alpha发布会啊,看了真滴是惊艳(现场直接有人喊“ 牛逼 ”,看过好多发布会,就没有看到这样直接喊出来“牛逼”的)。不知道大家还记不记得13年那会吹苹果的时候的一块ppt手机(其实是媒体做的图),但是现在小米做出来了,甚至更好。但是我最近在uc上面那真是到处黑。以前我不相信水军说法,现在信了。如果关注小米mix alpha新闻的在uc下面经常能看到一个叫“决胜千里”的人,每次都是千篇一律的复制黏贴黑。

我想说,没买过没资格。就像写代码,没写过别说懂。写了你才知道这里面有哪些细节和关键因素。

写这个组件起因

记得就这两天有掘友发一个沸点说找女票千万别找同行,好了,曾经我是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 侧边轮播组件 interval Number 5000 时间间隔,默认5秒转换一次 必须给该组件指定宽度,否则无法正常显示。 内部子元素展示做最侧位置主要由该组件的宽度定义
autoplay Boolean TRUE 是否自动播放,咱不支持false
zIndex Number 2000 组件层级
axisx Number 1000 隐藏的子元素位置,px单位,默认1000。当内部元素宽度过大时可以调节该参数
dht-swiper-side-item dht-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的代码。

总结

以上所述是小编给大家介绍的vue轮播组件实现$children和$parent 附带好用的gif录制工具,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对三水点靠木网站的支持!
如果你觉得本文对你有帮助,欢迎转载,烦请注明出处,谢谢!

Javascript 相关文章推荐
ExtJS 2.0实用简明教程 之获得ExtJS
Apr 29 Javascript
浅析onsubmit校验表单时利用ajax的return false无效问题
Jul 10 Javascript
完美解决IE低版本不支持call与apply的问题
Dec 05 Javascript
单击和双击事件的冲突处理示例代码
Apr 03 Javascript
JavaScript indexOf方法入门实例(计算指定字符在字符串中首次出现的位置)
Oct 17 Javascript
jQuery解决IE6、7、8不能使用 JSON.stringify 函数的问题
May 31 Javascript
js与jquery正则验证电子邮箱、手机号、邮政编码的方法
Jul 04 Javascript
浅析JS抽象工厂模式
Dec 14 Javascript
详解基于Vue2.0实现的移动端弹窗(Alert, Confirm, Toast)组件
Aug 02 Javascript
vue初始化动画加载的实例
Sep 01 Javascript
vue-cli项目代理proxyTable配置exclude的方法
Sep 20 Javascript
vue图片上传组件使用详解
Dec 23 Javascript
小程序调用微信支付的方法
Sep 26 #Javascript
细说webpack6 Babel的使用详解
Sep 26 #Javascript
微信小程序实现拖拽功能
Sep 26 #Javascript
vue用BMap百度地图实现即时搜索功能
Sep 26 #Javascript
layui.tree组件的使用以及搜索节点功能的实现
Sep 26 #Javascript
微信小程序点击列表跳转到对应详情页过程解析
Sep 26 #Javascript
vue+element tabs选项卡分页效果
Jun 29 #Javascript
You might like
php中将数组存到文件里的实现代码
2012/01/19 PHP
php 对输入信息的进行安全过滤的函数代码
2012/06/29 PHP
php正则匹配文章中的远程图片地址并下载图片至本地
2015/09/29 PHP
jQuery滚动加载图片效果的实现
2013/03/06 Javascript
JavaScript中数组对象的那些自带方法介绍
2013/03/12 Javascript
AngularJS入门教程之Hello World!
2014/12/06 Javascript
JavaScript插件化开发教程 (一)
2015/01/27 Javascript
jQuery插件jRumble实现网页元素抖动
2015/06/05 Javascript
Javascript中判断对象是否为空
2015/06/10 Javascript
jQuery实现输入框下拉列表树插件特效代码分享
2015/08/27 Javascript
如何用jQuery实现ASP.NET GridView折叠伸展效果
2015/09/26 Javascript
js省市县三级联动效果实例
2020/04/15 Javascript
深入分析node.js的异步API和其局限性
2016/09/05 Javascript
angularjs定时任务的设置与清除示例
2017/06/02 Javascript
如何编写一个完整的Angular4 FormText 组件
2017/11/18 Javascript
详解React之父子组件传递和其它一些要点
2018/06/25 Javascript
微信小程序使用map组件实现获取定位城市天气或者指定城市天气数据功能
2019/01/22 Javascript
使用ESLint禁止项目导入特定模块的方法步骤
2019/03/04 Javascript
Nodejs实现用户注册功能
2019/04/14 NodeJs
移动端手指操控左右滑动的菜单
2019/09/08 Javascript
vue Tab切换以及缓存页面处理的几种方式
2019/11/05 Javascript
vue中使用v-for时为什么不能用index作为key
2020/04/04 Javascript
[10:24]郎朗助力完美“圣”典,天籁交织奏响序曲
2016/12/18 DOTA
[56:48]FNATIC vs EG 2019国际邀请赛小组赛 BO2 第二场 8.15
2019/08/16 DOTA
python实现给数组按片赋值的方法
2015/07/28 Python
如何在Python函数执行前后增加额外的行为
2016/10/20 Python
pytorch对可变长度序列的处理方法详解
2018/12/08 Python
Python脚本如何在bilibili中查找弹幕发送者
2020/06/04 Python
美国网上购买眼镜:Eyeconic
2017/07/29 全球购物
编辑硕士自荐信范文
2013/11/27 职场文书
公司年会搞笑主持词
2014/03/24 职场文书
工作鉴定评语
2014/05/04 职场文书
个人工作总结范文2014
2014/11/07 职场文书
毕业实习指导教师评语
2014/12/31 职场文书
建筑工程催款函
2015/06/24 职场文书
MySQL 8.0 之不可见列的基本操作
2021/05/20 MySQL