1、先提前预祝大家国庆节玩的愉快,我国庆要见家长去了(忐忑)2、忍不住想要为小米正
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录制工具,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对脚本之家网站的支持! 如果你觉得本文对你有帮助,欢迎转载,烦请注明出处,谢谢!
vue轮播组件