看了好多網上的文字元件,發現好多都有這樣那樣的問題;特別是滾動的時候失真的感覺,今天整合了文字滾動的方式用CSS的
animation寫出一套元件;VUE專案直接用。感覺有用的朋友關注下
效果圖,gif製作有卡頓,實際效果我是沒發現卡頓
使用方法
<template> <div id="app"> <h5>橫向文字滾動</h5> <div class="inner2"> <horizontal-text-scroll> <ul class="scroll"> <li v-for="item in arr2" :key="item"> {{item}} </li> </ul> </horizontal-text-scroll> </div> <div class="inner2"> <horizontal-text-scroll> <ul class="scroll"> <li v-for="item in arr" :key="item"> {{item}} </li> </ul> </horizontal-text-scroll> </div> <h5>多行間歇滾動</h5> <div class="inner"> <interval-text-scroll :scrollArr="arr"></interval-text-scroll> </div> <h5>單行間歇滾動</h5> <div class="inner2"> <interval-text-scroll :scrollArr="arr2"></interval-text-scroll> </div> <h5>無縫滾動</h5> <div class="inner"> <seamless-text-scroll :scrollArr="arr"></seamless-text-scroll> </div> <h5>無縫滾動內容不足停止滾動</h5> <div class="inner3"> <seamless-text-scroll :scrollArr="arr2"></seamless-text-scroll> </div> </div> </template> <script> import IntervalTextScroll from './components/IntervalTextScroll' import SeamlessTextScroll from './components/SeamlessTextScroll' import HorizontalTextScroll from './components/HorizontalTextScroll' export default { data () { return { arr: [ '最美的相遇,不言過往;最好的離別,不問歸期。', '一個人,一座城,一生心疼', '靜水流深,滄笙踏歌;三生陰晴圓缺,一朝悲歡離合。', '原來地久天長,只是誤會一場。', '生能盡歡,死亦無憾。', '大概是一起吹過晚風的人會比較難忘。' ], arr2: ['許我浮生一世安,還你笑顏承你歡。'] } }, components: { IntervalTextScroll, SeamlessTextScroll, HorizontalTextScroll } } </script> <style lang="less" scoped> .inner { height: 90px; overflow: hidden; margin: 10px; border: 1px solid red; padding: 0 20px; margin-bottom: 20px; } .inner2 { height: 30px; overflow: hidden; margin: 10px; border: 1px solid red; padding: 0 20px; margin-bottom: 20px; } .inner3 { height: 150px; overflow: hidden; margin: 10px; border: 1px solid red; padding: 0 20px; margin-bottom: 20px; } </style>
1. 橫向文字滾動
/* 橫向文字滾動 */ <template> <div class="scroll-inner" ref="scrollInner"> <div class="scroll-wrap" ref="scrollWrap" :style="wrapStyle"> <slot></slot> </div> <div class="scroll-wrap"> <slot></slot> </div> <!-- <ul class="scroll-wrap"> <li v-for="item in runArr" :key="item"> {{item}} </li> </ul> --> </div> </template> <script> /** * speed 1 速度 * * 格式要求類名scroll、ul、li格式勿變,li內排版可自定義 * <horizontal-text-scroll> <ul class="scroll"> <li v-for="item in arr2" :key="item"> {{item}} </li> </ul> </horizontal-text-scroll> */ export default { data () { return { runArr: [], wrapWidth: 0, innerWidth: 0, retry: 0, tim: Math.floor(Math.random() * (99999 - 10000) + 10000) } }, props: { // 滾動速度 speed: { type: Number, default: 1 } }, computed: { wrapStyle () { const s = this.wrapWidth / (30 + this.speed * 5) return { animationDuration: `${s}s`, animationIterationCount: 'infinite', animationName: `move${this.tim}`, animationTimingFunction: 'linear' } } }, mounted () { this.getWrapWidth() }, methods: { getWrapWidth () { this.$nextTick(() => { this.wrapWidth = this.$refs.scrollWrap.clientWidth this.innerWidth = this.$refs.scrollInner.clientWidth console.log(this.wrapWidth) console.log(this.innerWidth) if (!this.wrapWidth && this.retry < 3) { this.getWrapWidth() this.retry++ return } else if (!this.wrapWidth && this.retry === 3){ console.error('獲取元素高度失敗或高度為0') return } this.createStyle() }) }, createStyle () { const style = ` @keyframes move${this.tim} { from {margin-left: 0;} to {margin-left: -${this.wrapWidth}px;} } ` let el = document.createElement('style') el.innerHTML = style document.head.appendChild(el) } } } </script> <style scoped> *{ padding: 0; margin: 0; } .scroll-inner { width: 100%; white-space: nowrap; overflow: hidden; height: 100%; } .scroll-wrap { box-sizing: border-box; min-width: 100%; height: 100%; font-size: 0; white-space: nowrap; display: inline-block; } .scroll-wrap li { height: 30px; line-height: 30px; list-style: none; display: inline-block; font-size: 16px; margin-right: 20px; } .scroll { display: inline-block; } </style>
2. 斷點滾動
/* 間歇滾動 */ <template> <div class="scroll-inner"> <ul class="scroll-wrap" :style="scrollWrapClass" v-bind="$attrs"> <li v-for="(item, index) in runArr" :key="index"> {{item}} </li> </ul> </div> </template> <script> /** * 根據inner標籤的高度可控制單行多行 * * scrollArr 滾動陣列 * time 2000 滾動間隔 * animationTime 500 滾動動畫時間 * distance 30 滾動距離 * */ export default { data () { return { isRun: false, runArr: [] } }, computed: { scrollWrapClass () { let c if (this.isRun) { c = { transition: `margin ${this.animationTime / 1000}s`, marginTop: `-${this.distance}` } } else { c = { transition: '', marginTop: '' } } return c } }, props: { // 滾動陣列 scrollArr: { required: true }, // 滾動間隔 time: { type: Number, default: 2000 }, // 滾動動畫時間 animationTime: { type: Number, default: 500 }, // 滾動距離 distance: { type: String, default: '30px' } }, mounted() { this.runArr = JSON.parse(JSON.stringify(this.scrollArr )) document.addEventListener('visibilitychange', this.handleVisiable) this.startScroll() }, methods: { startScroll () { this.interval = setInterval (() => { this.isRun = true this.runArr.push(this.runArr[0]) this.timeOut = setTimeout (() => { this.runArr.shift() this.isRun = false }, this.animationTime) }, this.time) }, handleVisiable (e) { if (e.target.visibilityState === 'visible') { // 要執行的方法 this.startScroll() } else { this.interval && clearInterval(this.interval) } } }, destroyed () { this.interval && clearInterval(this.interval) this.timeOut && clearTimeout(this.timeOut) } } </script> <style scoped> *{ padding: 0; margin: 0; } .scroll-wrap { box-sizing: border-box; } .scroll-wrap li { height: 30px; line-height: 30px; list-style: none; } .scroll-inner { overflow: hidden; } .scroll-wrap.active { transition: margin 0.5s; margin-top: -30px; } </style>
3. 無縫滾動
/* 無縫滾動 */ <template> <div class="scroll-inner" ref="scrollInner"> <ul class="scroll-wrap" v-bind="$attrs" :class="{canPause: canPause}" :style="wrapStyle" ref="scrollWrap"> <li v-for="item in runArr" :key="item"> {{item}} </li> </ul> <ul class="scroll-wrap" v-if="canRun"> <li v-for="item in runArr" :key="item"> {{item}} </li> </ul> </div> </template> <script> /** * scrollArr 滾動陣列 * speed 1 滾動速度 * canPause false 滑鼠劃過停止 */ export default { data () { return { runArr: [], wrapHeight: 0, innerHeight: 0, retry: 0, canRun: true, tim: Math.floor(Math.random() * (99999 - 10000) + 10000) } }, props: { // 滾動陣列 scrollArr: { required: true }, // 滾動速度 speed: { type: Number, default: 1 }, // 滑鼠劃過停止 canPause: { type: Boolean, default: false } }, computed: { wrapStyle () { const s = this.wrapHeight / (20 + this.speed * 5) return { animationDuration: `${s}s`, animationIterationCount: 'infinite', animationName: `move${this.tim}`, animationTimingFunction: 'linear' } } }, mounted () { this.runArr = JSON.parse(JSON.stringify(this.scrollArr)) this.getWrapHeight() }, methods: { getWrapHeight () { this.$nextTick(() => { this.wrapHeight = this.$refs.scrollWrap.clientHeight this.innerHeight = this.$refs.scrollInner.clientHeight if (!this.wrapHeight && this.retry < 3) { this.getWrapHeight() this.retry++ return } else if (!this.wrapHeight && this.retry === 3){ console.error('獲取元素高度失敗或高度為0') return } if (this.innerHeight >= this.wrapHeight) { this.canRun = false return } this.createStyle() }) }, createStyle () { const style = ` @keyframes move${this.tim} { from {margin-top: 0;} to {margin-top: -${this.wrapHeight}px;} } ` let el = document.createElement('style') el.innerHTML = style document.head.appendChild(el) } } } </script> <style lang="less" scoped> *{ padding: 0; margin: 0; } .scroll-wrap { box-sizing: border-box; } .canPause { &:hover{ animation-play-state: paused; } } .scroll-wrap li { height: 30px; line-height: 30px; list-style: none; } .scroll-inner { overflow: hidden; position: relative; height: 100%; } </style>