当前位置: 代码迷 >> 综合 >> Vue2.0 进阶组件篇 5 解析 vux(无逢 marquee 组件)
  详细解决方案

Vue2.0 进阶组件篇 5 解析 vux(无逢 marquee 组件)

热度:120   发布时间:2023-10-22 08:43:23.0

https://juejin.im/post/58f3a372a22b9d006cfba9ab

给vux打打广告吧,我感觉功能最强大的还是vux ui库,我带大家看看这玩意如何实现的,你别看学别人写组件,还能学到一些你平常用不到的弱知识点,双击,666666,没毛病。

在这里打个广告,如果有谁私底下有兴趣的,想和我一起打造一套基础vue的ui组件库的话,请联系我!!!!!!

接下来还是按着我们约定的来

2.代码运行vue-cli 2.1版本

3.组件代码都在components文件夹里

4.主代码逻辑都在 App.vue文件夹里

我什么都不要我只要

在vux中marquee里分成了两组件,分别进行slot

1.第一个组件中slot是用来放入每个marquee节点
2.第二个组件中solt是在每个节点放入文案

这有什么好处呢?

1.第一可以让代码更清楚,在第一个组进行逻辑层编写和初始化配置
2.第二个组件进行逻辑启动

这里的无逢滚动又是如何做到的呢?

1.这里进行了上滚动和下滚动,分别进行了不同的初始化配置
2.通过cloneChild(true)进行深复制分别辨别direction的位置进行配置

在compoents>marquee>marquee.vue

我们先看看template部分

<template><div class="vux-marquee" :style="{height: height + 'px'}"><ul class="vux-marquee-box" ref="box" :style="{transform: `translate3d(0,${currenTranslateY}px,0)`, transition: `transform ${noAnimate ? 0 : duration}ms`}"><slot></slot></ul></div>
</template>

解析:
1.首先在class=’vux-marquee’dom节点中, 对height进行了样式配置,这里的hight起什么作用,之所以要配置,肯定是要有作用才配置,就是对第一条marquee公告的高度进行复制放入,来进行每条的显示
2.{transform:translate3d(0,${currenTranslateY}px,0)对每条显示的位置进行改动 3.transform ${noAnimate ? 0 : duration}ms}对初化第一条和无逢滚动接入的一个时间点我们对动画时间进行0s设置

再看看script中prop部分

props: {interval: {type: Number,default: 2000},duration: {type: Number,default: 300},direction: {type: String,default: 'up'}},

对外暴露的三个属性
1.interval:每个marquee条目间格多少换一次
2.duration:对动画时长多少设置
3.direction:对上或下marquee的配置

再看看script中data数据的

data () {return {currenTranslateY: 0,height: '',length: 0,currentIndex: 0,noAnimate: false}},

1.currenTranslateY :改变的y轴解度存放
2.height:高度存放的值存放
3.length:marquee条目的总长度存放
4.当前每个条目的index下标值存放
5.是否是进行动化的配置值存放

再看看script中methods中三大方法

init () {this.destroy()if (this.cloneNode) {this.$refs.box.removeChild(this.cloneNode)}this.cloneNode = nulllet firstItem = this.$refs.box.firstElementChild //获取box节点下的第一个元素if (!firstItem) {return false }    //如果没有li元素则退出this.length = this.$refs.box.children.length //获得ul下li节点的长度this.height = firstItem.offsetHeightif (this.direction === 'up') {this.cloneNode = firstItem.cloneNode(true)this.$refs.box.appendChild(this.cloneNode)} else {this.cloneNode = this.$refs.box.lastElementChild.cloneNode(true)this.$refs.box.insertBefore(this.cloneNode, firstItem)}},

这里是初始化配置方法,我们就挑重要的说
1.this.cloneNode=null进行存放,以但于从新渲染时可以删除标记
2.firstItem这个变量是拿全marquee盒子中第一个条目dom节点
3.this.length是所有条目的总数
4.this.height是第一个条目的高度,然后滚动视图就基于第一个条目的高度进行配置
5.在最后的一个this.direction === 'up'这个判断语句中,可以看出对属性dircetion来进行初始化配置,这里同时也是对无逢滚动的操作进行配置,如果是向上滚动,就深度复制第一条目进行最后节点插入,如果是down,就对最后一个条目深度复制插入到第一个条目前

go (toFirst) {this.noAnimate = trueif (toFirst) {this.currentIndex = 0this.currenTranslateY = 0} else {this.currentIndex = this.length - 1  //当我们向下marquee的时候,此时最后一个下标为总长度-1this.currenTranslateY = -(this.currentIndex + 1) * this.height//因为如果向下的话,我们在li的最项部插入了最后一dom此时我们要+1}}

这个Go方法就是中间转换层
1.在无逢滚动时候对动画时间设为false则为0,
2.如果tofirst参数为ture时则是向上滚动配置
3.如果tofirst参数为false时则是下面滚洞配置

再看看start方法

start () {if (this.direction === 'down') this.go(false) //对初始样式方向this.timer = setInterval(() => {if (this.direction === 'up') {this.currentIndex += 1this.currenTranslateY = -this.currentIndex * this.height} else {this.currentIndex -= 1this.currenTranslateY = -(this.currentIndex + 1) * this.height}if (this.currentIndex === this.length) {setTimeout(() => {this.go(true)}, this.duration)} else if (this.currentIndex === -1) {setTimeout(() => {this.go(false)}, this.duration)} else {this.noAnimate = false}}, this.interval + this.duration)},

start方法则是启动方法
if (this.direction === 'down') this.go(false) //对初始样式方向的第一个条目进行配置,如果是down,则是从最后一条开始,如果是up则是从第一条开始
2.开始定时器开始进行条止滚动如果没有滚动到深度复制的dom的时候则一直开始动画时长,如果下标配置到深度复制的dom条目时则传入false进行go方法过度加入无逢滚动协条!改变translate3d的y方法

marquee.vue完整代码

<template><div class="vux-marquee" :style="{height: height + 'px'}"><ul class="vux-marquee-box" ref="box" :style="{transform: `translate3d(0,${currenTranslateY}px,0)`, transition: `transform ${noAnimate ? 0 : duration}ms`}"><slot></slot></ul></div>
</template><script>
export default {props: {interval: {type: Number,default: 2000},duration: {type: Number,default: 300},direction: {type: String,default: 'up'}},beforeDestroy () {this.destroy()},data () {return {currenTranslateY: 0,height: '',length: 0,currentIndex: 0,noAnimate: false}},methods: {destroy () {this.timer && clearInterval(this.timer)},init () {this.destroy()if (this.cloneNode) {this.$refs.box.removeChild(this.cloneNode)}this.cloneNode = nulllet firstItem = this.$refs.box.firstElementChild //获取box节点下的第一个元素if (!firstItem) {return false}    //如果没有li元素则退出this.length = this.$refs.box.children.length //获得ul下li节点的长度this.height = firstItem.offsetHeightif (this.direction === 'up') {this.cloneNode = firstItem.cloneNode(true)this.$refs.box.appendChild(this.cloneNode)} else {this.cloneNode = this.$refs.box.lastElementChild.cloneNode(true)this.$refs.box.insertBefore(this.cloneNode, firstItem)}},start () {if (this.direction === 'down') this.go(false) //对初始样式方向this.timer = setInterval(() => {if (this.direction === 'up') {this.currentIndex += 1this.currenTranslateY = -this.currentIndex * this.height} else {this.currentIndex -= 1this.currenTranslateY = -(this.currentIndex + 1) * this.height}if (this.currentIndex === this.length) {setTimeout(() => {this.go(true)}, this.duration)} else if (this.currentIndex === -1) {setTimeout(() => {this.go(false)}, this.duration)} else {this.noAnimate = false}}, this.interval + this.duration)},go (toFirst) {this.noAnimate = trueif (toFirst) {this.currentIndex = 0this.currenTranslateY = 0} else {this.currentIndex = this.length - 1  //当我们向下marquee的时候,此时最后一个下标为总长度-1this.currenTranslateY = -(this.currentIndex + 1) * this.height//因为如果向下的话,我们在li的最项部插入了最后一dom此时我们要+1}}}
}
</script>
<style lang="less">
.vux-marquee {width: 100%;overflow:hidden;
}
.vux-marquee-box {padding: 0;margin: 0;width: 100%;height: auto;li {margin: 0;width: 100%;padding:10px 0;box-sizing:border-box;}
}
</style>

marquee-item配置

在components>marquee>marquee-item.vue

<template><li><slot></slot></li>
</template><script>
export default {mounted () {this.$nextTick(() => {this.$parent.destroy()this.$parent.init()this.$parent.start()})}
}
</script>

当每个条目加載dom完毕则开始调用,如果是从新渲染,或者切换出去缓存的组件则进行时间关毕,再进行Init()初始化,再start()开始滚动

App.vue

<template>
<div><marquee direction='down'><marquee-item class='bb' v-for="i in number" :key = "i">混无霹雳手-ziksang{
    {i}}</marquee-item></marquee>
</div>
</template><script>
import Marquee from './components/marquee/marquee.vue'
import MarqueeItem from './components/marquee/marquee-item.vue'
export default {components: {Marquee,MarqueeItem},data () {return {number : 10}}
}
</script>
<style>
.bb{font-size:20px;
}
</style>

然后你就可以启动了,看看效果如何