上滑跑马灯
前言
產(chǎn)品說,我們做一個(gè)轉(zhuǎn)盤活動(dòng)吧,需要輪播中獎(jiǎng)信息。 當(dāng)然這需求完全沒有問題。
產(chǎn)品說,你聽我說完。
- 是從下往上輪播
- 如何數(shù)據(jù)沒有更新,就反復(fù)輪播。
- 如果數(shù)據(jù)有更新,要無縫更新。
- 進(jìn)入時(shí)間1s,暫停1S,出去時(shí)間1s.
沒問題吧。
額, 等等,沒多大問題。 那個(gè)誰,這個(gè)任務(wù)教你啦。
方案
然后,我的同事開始搜羅實(shí)現(xiàn)方案,很多都是勻速走的。
同事甚至和產(chǎn)品討論要不要換成跑馬燈,嘻嘻, 開玩笑。
說個(gè)笑話,csdn上有不少的這樣代碼,但是下載要積分,我可以說,日了*狗么!。
一個(gè)下午天氣晴,有涼風(fēng),心情還好。 于是花了一點(diǎn)時(shí)間思考了一種方案。
關(guān)于移動(dòng)端動(dòng)畫,無非是純js控制,js Animation API(兼容不理想), css動(dòng)畫,canvas, webgl以及雜交方案。 關(guān)于本需求,前兩種應(yīng)該比較適合,成本低,容易實(shí)現(xiàn)。
純js實(shí)現(xiàn)控制比較傳統(tǒng)的方案,要啟用定時(shí)器setTimeout/setInterval/requestAnimation等等,我很煩這。
采用css3 + js雜交方案,有戲靠譜。 既然有三個(gè)階段,那么我就把你拆成三段動(dòng)畫, 隨你去配置,隨你去high。 當(dāng)然你也可以用一段動(dòng)畫,通過設(shè)置來控制距離。
整體的思路
- 我把每個(gè)需要滾動(dòng)的每個(gè)元素獨(dú)立起來,每個(gè)元素有三段動(dòng)畫, in , pause , out. 怎么銜接, 通過animationend事件。
- 那么不同元素又怎么銜接,通過animationDelay來延時(shí)啟動(dòng)動(dòng)畫, 啟動(dòng)后依舊是走上面的三段動(dòng)畫。
- 怎么輪回播放,當(dāng)然你可以利用原來的節(jié)點(diǎn),重新修改屬性,設(shè)置延時(shí)啟動(dòng)。 我這里采用比較簡單的,直接刪除了原有,然后重新創(chuàng)建。 當(dāng)然重新創(chuàng)建是有講究的,你有很多選擇,只要控制好銜接的事件,我這里是在最后一個(gè)節(jié)點(diǎn)開始第一階段運(yùn)動(dòng)的時(shí)候,重新創(chuàng)建新節(jié)點(diǎn),最后節(jié)點(diǎn)第三階段運(yùn)動(dòng)結(jié)束,清除之前運(yùn)動(dòng)完畢的節(jié)點(diǎn)
- 關(guān)于無縫更新,當(dāng)然要讓最后一個(gè)運(yùn)動(dòng)的元素運(yùn)動(dòng)完, 所以我在第二個(gè)階段 pause階段執(zhí)行新的節(jié)點(diǎn)創(chuàng)建,并設(shè)置好相關(guān)的延時(shí)。
- 關(guān)于暫停能力, animationPlayState提供這個(gè)能力,paused和running。 暫停的手,animationDelay也會(huì)停止計(jì)時(shí),非常的棒。 因?yàn)閼?#xff0c;只實(shí)現(xiàn)了PC的暫停能力。移動(dòng)端嘛,添加touch,tap,pointer事件就好。 因?yàn)閼?#xff0c;所以。
改進(jìn)
- 每個(gè)元素三個(gè)動(dòng)畫,是有點(diǎn)消耗。可以用一個(gè)大的容器放好所有的元素,然后animationPlayState來控制,蠻不錯(cuò)的。 如何控制每個(gè)階段的計(jì)時(shí)呢,當(dāng)然可以用js,我有個(gè)想法,就是起一個(gè)三段動(dòng)畫,在這個(gè)事件里面去控制animationPlayState。
- 節(jié)點(diǎn)也沒回收利用,是有點(diǎn)浪費(fèi)。
- 移動(dòng)端的支持呢?
- 不太重要的其他......
效果呢?
怎么使用呢?
const contents = ["隊(duì)列1:春天 - first","隊(duì)列1:夏天","隊(duì)列1:秋天","隊(duì)列1:冬天","隊(duì)列1:夏夏湉","隊(duì)列1:求七天","隊(duì)列1:Who are You - last"];const contents2 = ["隊(duì)列2:這是怎么回事 - first","隊(duì)列2:誰是最可賴的人","隊(duì)列2:壯士一去不復(fù)返","隊(duì)列2:誰來拯救你","隊(duì)列2:家福樂團(tuán)購有沒有 - last"]const el = document.querySelector("#box");let upSlide = new UpSlide({el});upSlide.start(contents);document.getElementById('btnChange').addEventListener("click", () => {upSlide.start(contents);})document.getElementById('btnChange2').addEventListener("click", () => {upSlide.start(contents2);}) 源碼呢?
等等這個(gè)有點(diǎn)用, 源碼呢
上滑跑馬燈源碼
再貼出源碼,這樣文章長一點(diǎn)
const DEFAULT_OPTION = {inTime: 1000,pauseTime: 1500,outTime: 1000,className: "upslide-item",animationClass: "upslide-item-animation",animationInClass: "slideup-animation-in",animationPauseClass: "slideup-animation-pause",animationOutClass: "slideup-animation-out",pauseOnFocus: false
};const DELETING_CLASS_NAME = "__deleting__";function clearSiblings(el) {const parent = el.parentElement;// 移除前面節(jié)點(diǎn)while (el.previousElementSibling) {parent.removeChild(el.previousElementSibling);}// 移除后面的節(jié)點(diǎn)while (el.nextElementSibling) {parent.removeChild(el.nextElementSibling);}
}class UpSlide {constructor(options) {this.el = options.el;this.options = Object.assign({}, DEFAULT_OPTION, options);this.changeStatus = 0;this.currentContents = null;const { inTime, pauseTime, outTime } = this.options;this.totalTime = inTime + pauseTime + outTime;this.inPausePercent = (inTime + pauseTime) / this.totalTime;this.animationstartEvent = this.animationstartEvent.bind(this);this.animationendEvent = this.animationendEvent.bind(this);this.mouseenterEvent = this.mouseenterEvent.bind(this);this.mouseleaveEvent = this.mouseleaveEvent.bind(this);this.init();}createItems(datas, baseDelay = 0) {const { className, animationInClass, animationClass, inTime } = this.options;const { totalTime, inPausePercent } = this;const fragment = document.createDocumentFragment();datas.forEach((c, i) => {const newEl = document.createElement("div");newEl.dataset.isLast = i === datas.length - 1 ? 1 : 0;newEl.innerText = c;newEl.className = className + " " + animationClass;newEl.style.animationName = animationInClass;newEl.style.animationDelay = baseDelay + i * totalTime * inPausePercent + "ms";newEl.style.animationDuration = inTime + "ms";fragment.appendChild(newEl);});return fragment;}animationstartEvent(e) {const { totalTime, inPausePercent } = this;const { animationInClass } = this.options;// 開啟新的輪回if (e.animationName === animationInClass && e.target.dataset.isLast == 1) {this.innerStart(this.currentContents, totalTime * inPausePercent);}}animationendEvent(e) {const {animationInClass,animationPauseClass,animationOutClass,className,animationClass,pauseTime,outTime} = this.options;const { changeStatus } = this;const el = e.target;const parent = el.parentElement;const animationName = e.animationName;switch (animationName) {case animationInClass:el.style.animationName = animationPauseClass;el.style.animationDuration = pauseTime + "ms";el.style.animationDelay = "0ms";break;case animationPauseClass:el.style.animationName = animationOutClass;el.style.animationDuration = outTime + "ms";el.style.animationDelay = "0ms";// 切換if (changeStatus === 1) {clearSiblings(el);// 標(biāo)記el.classList.add(DELETING_CLASS_NAME);// 切換this.innerStart(this.currentContents, 0);this.changeStatus = 0;}break;case animationOutClass:e.target.classList.remove(animationClass);e.target.style.animationDelay = "";if (el.classList.contains(DELETING_CLASS_NAME)) {parent.removeChild(el);}// 輪回結(jié)束-清除節(jié)點(diǎn)if (e.target.dataset.isLast == 1) {const parent = e.target.parentElement;const delItems = parent.querySelectorAll(`.${className}:not(.${animationClass})`);if (delItems.length > 0) {for (let i = delItems.length - 1; i >= 0; i--) {parent.removeChild(delItems[i]);}}}break;default:break;}}mouseenterEvent() {const { className } = this.options;this.el.querySelectorAll("." + className).forEach(el => {el.style.animationPlayState = "paused";});}mouseleaveEvent() {const { className } = this.options;this.el.querySelectorAll("." + className).forEach(el => {el.style.animationPlayState = "running";});}init() {const { el } = this;el.addEventListener("animationstart", this.animationstartEvent);el.addEventListener("animationend", this.animationendEvent);const { pauseOnFocus } = this.options;if (pauseOnFocus === true) {el.addEventListener("mouseenter", this.mouseenterEvent);el.addEventListener("mouseleave", this.mouseleaveEvent);}}innerStart(content, delay = 0) {this.currentContents = content;const c = this.createItems(content, delay);this.el.appendChild(c);}start(content, delay = 0) {if (this.currentContents != null) {this.changeStatus = 1;this.currentContents = content;return;}this.innerStart(content, delay);}destroy() {this.el.removeEventListener("animationstart", this.animationstartEvent);this.el.removeEventListener("animationend", this.animationendEvent);const { pauseOnFocus } = this.options;if (pauseOnFocus === true) {el.removeEventListener("mouseenter", this.mouseoverEvent);el.removeEventListener("mouseleave", this.mouseleaveEvent);}this.el.innerHTML = null;this.el = null;this.options = null;}
}
轉(zhuǎn)載于:https://www.cnblogs.com/cloud-/p/11402598.html
總結(jié)
- 上一篇: redis连接
- 下一篇: 【USACO06JAN POJ3179