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

作者 : 混元霹雳手-ziksang

我这里就不帖图了,marquee就是轮播广告或公告。。。。。

给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 = null
      let firstItem = this.$refs.box.firstElementChild //获取box节点下的第一个元素
      if (!firstItem) {
        return false 
      }    //如果没有li元素则退出
      this.length = this.$refs.box.children.length //获得ul下li节点的长度
      this.height = firstItem.offsetHeight
      if (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 = true
      if (toFirst) {
        this.currentIndex = 0
        this.currenTranslateY = 0
      } else {
        this.currentIndex = this.length - 1  //当我们向下marquee的时候,此时最后一个下标为总长度-1
        this.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 += 1
          this.currenTranslateY = -this.currentIndex * this.height
        } else {
          this.currentIndex -= 1
          this.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 = null
      let firstItem = this.$refs.box.firstElementChild //获取box节点下的第一个元素
      if (!firstItem) {
        return false
      }    //如果没有li元素则退出
      this.length = this.$refs.box.children.length //获得ul下li节点的长度
      this.height = firstItem.offsetHeight
      if (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 += 1
          this.currenTranslateY = -this.currentIndex * this.height
        } else {
          this.currentIndex -= 1
          this.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 = true
      if (toFirst) {
        this.currentIndex = 0
        this.currenTranslateY = 0
      } else {
        this.currentIndex = this.length - 1  //当我们向下marquee的时候,此时最后一个下标为总长度-1
        this.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>复制代码

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

渣渣前端开发工程师,喜欢钻研,热爱分享和讲解教学, 微信 zzx1994428 QQ494755899

支持我继续创作和感到有收获的话,请向我打赏点吧

如果转载请标注出自@混元霹雳手ziksang

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值