用ES6寫全屏滾動(dòng)插件的示例代碼
這篇文章將介紹如何使用原生 JS (主要使用 ES6 語(yǔ)法)實(shí)現(xiàn)全屏滾動(dòng)插件,兼容 IE 10+、手機(jī)觸屏,Mac 觸摸板優(yōu)化,支持自定義頁(yè)面動(dòng)畫,壓縮后 gzip 文件只有 2k。完整源碼在這 pure_full_page ,點(diǎn)這查看demo。
1)前面的話
現(xiàn)在已經(jīng)有很多全屏滾動(dòng)插件了,比如著名的 fullPage ,那為什么還要自己造輪子呢?
現(xiàn)有輪子有以下問(wèn)題:
- 首先,最大的問(wèn)題是最流行的幾個(gè)插件都依賴 jQuery,這意味著在使用 React 或者 Vue 的項(xiàng)目中使用他們是一件十分蛋疼的事:我只需要一個(gè)全屏滾動(dòng)功能,卻還需要把 jQuery 引入,有種殺雞使用宰牛刀的感覺(jué);
- 其次,現(xiàn)有的很多全屏滾動(dòng)插件功能往往都十分豐富,這在前幾年是優(yōu)勢(shì),但現(xiàn)在(2018-5)可以看作是劣勢(shì):前端開(kāi)發(fā)已經(jīng)發(fā)生了很大變化,其中很重要的一個(gè)變化是 ES6 原生支持模塊化開(kāi)發(fā),模塊化開(kāi)發(fā)最大的特點(diǎn)是一個(gè)模塊最好只專注做好一件事,然后再拼成一個(gè)完整的系統(tǒng),從這個(gè)角度看,大而全的插件有悖模塊化開(kāi)發(fā)的原則。
對(duì)比之下,通過(guò)原生語(yǔ)言造輪子有以下好處:
- 使用原生語(yǔ)言編寫的插件,自身不會(huì)受依賴的插件的使用場(chǎng)景而影響自身的使用(現(xiàn)在依賴 jQuery 的插件非常不適合開(kāi)發(fā)單頁(yè)面應(yīng)用),所以使用上更加靈活;
- 搭配模塊化開(kāi)發(fā),使用原生語(yǔ)言開(kāi)發(fā)的插件可以只專注一個(gè)功能,所以代碼量可以很少;
- 最后,隨著 JS/CSS/HTML 的發(fā)展以及瀏覽器不斷迭代更新,現(xiàn)在使用原生語(yǔ)言編寫插件的開(kāi)發(fā)成本越來(lái)越低,那為什么不呢?
2)實(shí)現(xiàn)原理及代碼架構(gòu)
2.1 實(shí)現(xiàn)原理
實(shí)現(xiàn)原理見(jiàn)下圖:容器及容器內(nèi)的頁(yè)面取當(dāng)前可視區(qū)高度,同時(shí)容器的父級(jí)元素 overflow 屬性值設(shè)為 hidden ,通過(guò)更改容器 top 值實(shí)現(xiàn)全屏滾動(dòng)效果。
2.2 代碼架構(gòu)
代碼編寫的思路是通過(guò) class 定義全屏滾動(dòng)類,使用時(shí)通過(guò) new PureFullPage().init()
使用。
/** * 全屏滾動(dòng)類 */ class PureFullPage { // 構(gòu)造函數(shù) constructor() {} // 原型方法 methods() {} // 初始化函數(shù) init() {} }
3)html 結(jié)構(gòu)
鑒于上述實(shí)現(xiàn)原理,對(duì)于 html 的結(jié)構(gòu)有特定要求,如下:頁(yè)面容器為 #pureFullPageContainer ,所有的頁(yè)面為其直接子元素,這里為了方便,直接取 body 為其直接父元素。
<body> <div id="pureFullPageContainer"> <div class="page"></div> <div class="page"></div> <div class="page"></div> </div> </body>
4)css 設(shè)置
首先,容器及容器內(nèi)的頁(yè)面取當(dāng)前可視區(qū)高度,為每次切換都顯示一個(gè)完整的頁(yè)面做準(zhǔn)備;
第二,容器的父級(jí)元素(此處是 body ) overflow 屬性值定為 hidden ,這樣可以保證每次只會(huì)顯示一個(gè)頁(yè)面,其他頁(yè)面被隱藏。
經(jīng)過(guò)上述設(shè)置,對(duì)容器 top 值,每次更改一個(gè)可視區(qū)高度的距離,便實(shí)現(xiàn)了頁(yè)面間的切換,部分代碼如下:
body { /* body 為容器直接的父元素 */ overflow: hidden; } #pureFullPage { /* 只有當(dāng) position 的值不是 static 時(shí),top 值才有效 */ position: relative; /* 設(shè)置初始值 */ top: 0; } .page { /* 此處不能為 100vh,后面詳述 */ /* 其父元素,也就是 #pureFullPage 的高度,通過(guò) js 動(dòng)態(tài)設(shè)置*/ height: 100%; }
Notice:
容器的 position 屬性值需要設(shè)置為 relative ,因?yàn)?top 只有在 position 屬性值不為 static 時(shí)才有效;
頁(yè)面高度需設(shè)置為當(dāng)前可視區(qū)高度,但不能直接設(shè)置為 100vh ,因?yàn)?safari 手機(jī)瀏覽器把地址欄算進(jìn)去計(jì)算 100vh ,但地址欄下面的不應(yīng)該算做“可視區(qū)”,畢竟實(shí)際上是“看不見(jiàn)”的區(qū)域。這會(huì)導(dǎo)致 100vh 對(duì)應(yīng)的像素值比 document.documentElement.clientHeight 獲取的像素值大。這樣在切換 top 值時(shí)就不是全屏切換了,實(shí)際上,這種情況下切換的高度小于頁(yè)面的高度。
解決 safari 手機(jī)瀏覽器可視區(qū)高度問(wèn)題:既然通過(guò) js 獲取的 document.documentElement.clientHeight 值是符合預(yù)期的可視區(qū)高度(不包括頂部地址欄和底部工具欄),那就 將該值通過(guò) js 設(shè)置為容器的高度,同時(shí),容器內(nèi)的頁(yè)面高度設(shè)置為 100% ,這樣就可以保證容器及頁(yè)面的高度和切換 top 值相同了,也就保證了全屏切換。
// 偽代碼 '#pureFullPage'.style.height = document.documentElement.clientHeight + 'px';
5)監(jiān)控滾動(dòng)/滑動(dòng)事件
這里的滾動(dòng)/滑動(dòng)事件包括鼠標(biāo)滾動(dòng)、觸摸板滑動(dòng)以及手機(jī)屏幕上下滑動(dòng)。
5.1 PC 端
PC 端主要解決的問(wèn)題是獲取鼠標(biāo)滾動(dòng)或觸摸板滑動(dòng)方向,觸摸板上下滑動(dòng)和鼠標(biāo)滾動(dòng)綁定的是同一個(gè)事件:
- firefox 是 DOMMouseScroll 事件,對(duì)應(yīng)的滾輪信息(向前滾還是向后滾)存儲(chǔ)在 detail 屬性中,向前滾,這個(gè)屬性值是 3 的倍數(shù),反之,是 -3 的倍數(shù);
- firefox 之外的其他瀏覽器是 mousewheel 事件,對(duì)應(yīng)的滾輪信息存儲(chǔ)在 wheelDelta 屬性中,向前滾,這個(gè)屬性值是 -120 的倍數(shù),反之, 120 的倍數(shù)。
macOS 如此,windows 相反?
所以,可以通過(guò) detail 或 wheelDelta 的值判斷鼠標(biāo)的滾動(dòng)方向,進(jìn)而控制頁(yè)面是向上還是向下滾動(dòng)。在這里我們只關(guān)心正負(fù),不關(guān)心具體值的大小,為了便于使用,下面基于這兩個(gè)事件封裝了一個(gè)函數(shù):如果鼠標(biāo)往前滾動(dòng),返回負(fù)數(shù),反之,返回正數(shù),代碼如下:
// 鼠標(biāo)滾輪事件 getWheelDelta(event) { if (event.wheelDelta) { return event.wheelDelta; } else { // 兼容火狐 return -event.detail; } },
有了滾動(dòng)事件,就可以據(jù)此編寫頁(yè)面向上或者向下滾動(dòng)的回調(diào)函數(shù)了,如下:
// 鼠標(biāo)滾動(dòng)邏輯(全屏滾動(dòng)關(guān)鍵邏輯) scrollMouse(event) { let delta = utils.getWheelDelta(event); // delta < 0,鼠標(biāo)往前滾動(dòng),頁(yè)面向下滾動(dòng) if (delta < 0) { this.goDown(); } else { this.goUp(); } }
goDown 、 goUp 是頁(yè)面滾動(dòng)的邏輯代碼,需要特別說(shuō)明的是必須 判斷滾動(dòng)邊界,保證容器中顯示的始終是頁(yè)面內(nèi)容 :
- 上邊界容易確定,為 1 個(gè)頁(yè)面(也即可視區(qū))的高度,即如果容器當(dāng)前的上外邊框距離整個(gè)頁(yè)面頂部的距離(這里此值正是容器的 offsetTop 值的絕對(duì)值,因?yàn)樗冈氐?offsetTop 值都是 0 )大于等于當(dāng)前可視區(qū)高度時(shí),才允許向上滾動(dòng),不然,就證明上面已經(jīng)沒(méi)有頁(yè)面了,不允許繼續(xù)向上滾動(dòng);
- 下邊界為 n - 2 (n 表示全屏滾動(dòng)的頁(yè)面數(shù)) 個(gè)可視區(qū)的高度,當(dāng)容器的 offsetTop 值的絕對(duì)值小于等于 n - 2 個(gè)可視區(qū)的高度時(shí),表示還可以向下滾動(dòng)一個(gè)頁(yè)面。
具體代碼如下:
goUp() { // 只有頁(yè)面頂部還有頁(yè)面時(shí)頁(yè)面向上滾動(dòng) if (-this.container.offsetTop >= this.viewHeight) { // 重新指定當(dāng)前頁(yè)面距視圖頂部的距離 currentPosition,實(shí)現(xiàn)全屏滾動(dòng), // currentPosition 為負(fù)值,越大表示超出頂部部分越少 this.currentPosition = this.currentPosition + this.viewHeight; this.turnPage(this.currentPosition); } } goDown() { // 只有頁(yè)面底部還有頁(yè)面時(shí)頁(yè)面向下滾動(dòng) if (-this.container.offsetTop <= this.viewHeight * (this.pagesNum - 2)) { // 重新指定當(dāng)前頁(yè)面距視圖頂部的距離 currentPosition,實(shí)現(xiàn)全屏滾動(dòng), // currentPosition 為負(fù)值,越小表示超出頂部部分越多 this.currentPosition = this.currentPosition - this.viewHeight; this.turnPage(this.currentPosition); } }
最后添加滾動(dòng)事件:
// 鼠標(biāo)滾輪監(jiān)聽(tīng),火狐鼠標(biāo)滾動(dòng)事件不同其他 if (navigator.userAgent.toLowerCase().indexOf('firefox') === -1) { document.addEventListener('mousewheel', scrollMouse); } else { document.addEventListener('DOMMouseScroll', scrollMouse); }
5.2 移動(dòng)端
移動(dòng)端需要判斷是向上還是向下滑動(dòng),可以結(jié)合 touchstart (手指開(kāi)始接觸屏幕時(shí)觸發(fā)) 和 touchend (手指離開(kāi)屏幕時(shí)觸發(fā)) 兩個(gè)事件實(shí)現(xiàn)判斷:分別獲取兩個(gè)事件開(kāi)始觸發(fā)時(shí)的 pageY 值,如果觸摸結(jié)束時(shí)的 pageY 大于觸摸開(kāi)始時(shí)的 pageY ,表示手指向下滑動(dòng),對(duì)應(yīng)頁(yè)面向上滾動(dòng),反之亦然。
此處我們需要觸摸事件跟蹤觸摸的屬性:
- touches :當(dāng)前跟蹤的觸摸操作的 Touch 對(duì)象的數(shù)組,用于獲取觸摸開(kāi)始時(shí)的 pageY 值;
- changeTouches :自上次觸摸以來(lái)發(fā)生了改變的 Touch 對(duì)象的數(shù)組,用于獲取觸摸觸摸結(jié)束時(shí)的 pageY 值。
相關(guān)代碼如下:
// 手指接觸屏幕 document.addEventListener('touchstart', event => { this.startY = event.touches[0].pageY; }); //手指離開(kāi)屏幕 document.addEventListener('touchend', event => { let endY = event.changedTouches[0].pageY; if (endY - this.startY < 0) { // 手指向上滑動(dòng),對(duì)應(yīng)頁(yè)面向下滾動(dòng) this.goDown(); } else { // 手指向下滑動(dòng),對(duì)應(yīng)頁(yè)面向上滾動(dòng) this.goUp(); } });
為了避免下拉刷新,可以阻止 touchmove 事件的默認(rèn)行為:
// 阻止 touchmove 下拉刷新 document.addEventListener('touchmove', event => { event.preventDefault(); });
6)PC 端滾動(dòng)事件性能優(yōu)化
6.1 防抖函數(shù)和截流函數(shù)介紹
優(yōu)化主要從兩方便入手:
- 更改頁(yè)面大小時(shí),通過(guò)防抖動(dòng)(debounce)函數(shù)限制 resize 事件觸發(fā)頻率;
- 滾動(dòng)/滑動(dòng)事件觸發(fā)時(shí),通過(guò)截流(throttle)函數(shù)限制滾動(dòng)/滑動(dòng)事件觸發(fā)頻率。
既然都是限制觸發(fā)頻率(都通過(guò)定時(shí)器實(shí)現(xiàn)),那這兩者有什么區(qū)別?
首先,防抖動(dòng)函數(shù)工作時(shí),如果在指定的延遲時(shí)間內(nèi),某個(gè)事件連續(xù)觸發(fā),那么綁定在這個(gè)事件上的回調(diào)函數(shù)永遠(yuǎn)不會(huì)觸發(fā),只有在延遲時(shí)間內(nèi),這個(gè)事件沒(méi)再觸發(fā),對(duì)應(yīng)的回調(diào)函數(shù)才會(huì)執(zhí)行。防抖動(dòng)函數(shù)非常適合改變窗口大小這一事件,這也符合 拖動(dòng)到位以后再觸發(fā)事件,如果一直拖個(gè)不停,始終不觸發(fā)事件 這一直覺(jué)。
而截流函數(shù)是在延遲時(shí)間內(nèi),綁定到事件上的回調(diào)函數(shù)能且只能觸發(fā)一次,這和截流函數(shù)不同,即便是在延遲時(shí)間內(nèi)連續(xù)觸發(fā)事件,也不會(huì)阻止在延遲時(shí)間內(nèi)有一個(gè)回調(diào)函數(shù)執(zhí)行。并且截流函數(shù)允許我們指定回調(diào)函數(shù)是在延遲時(shí)間開(kāi)始時(shí)還是結(jié)束時(shí)執(zhí)行。
鑒于截流函數(shù)的上述兩個(gè)特性,尤其適合優(yōu)化滾動(dòng)/滑動(dòng)事件:
- 可以限制頻率;
- 不會(huì)因?yàn)闈L動(dòng)/滑動(dòng)事件太靈敏(在延遲時(shí)間內(nèi)不斷觸發(fā))導(dǎo)致注冊(cè)在事件上的回調(diào)函數(shù)無(wú)法執(zhí)行;
- 可以設(shè)置在延遲時(shí)間開(kāi)始時(shí)觸發(fā)回調(diào)函數(shù),從而避免用戶感到操作之后的短暫延時(shí)。
這里不介紹防抖動(dòng)函數(shù)和截流函數(shù)的實(shí)現(xiàn)原理,感興趣的可以看 Throttling and Debouncing in JavaScript ,下面是實(shí)現(xiàn)的代碼:
// 防抖動(dòng)函數(shù),method 回調(diào)函數(shù),context 上下文,event 傳入的時(shí)間,delay 延遲函數(shù) debounce(method, context, event, delay) { clearTimeout(method.tId); method.tId = setTimeout(() => { method.call(context, event); }, delay); }, // 截流函數(shù),method 回調(diào)函數(shù),context 上下文,delay 延遲函數(shù), // immediate 傳入 true 表示在 delay 開(kāi)始時(shí)執(zhí)行回調(diào)函數(shù) throttle(method, context, delay, immediate) { return function() { const args = arguments; const later = () => { method.tID = null; if (!immediate) { method.apply(context, args); } }; const callNow = immediate && !method.tID; clearTimeout(method.tID); method.tID = setTimeout(later, delay); if (callNow) { method.apply(context, args); } }; },
《JavaScript 高級(jí)程序設(shè)計(jì) - 第三版》 22.33.3 節(jié)中介紹的 throttle 函數(shù)和此處定義的不同,高程中定義的 throttle 函數(shù)對(duì)應(yīng)此處的 debounce 函數(shù),但網(wǎng)上大多數(shù)文章都和高程中的不同,比如 lodash 中定義的 debounce 。
6.2 改造 PC 端滾動(dòng)事件
通過(guò)上述說(shuō)明,我們已經(jīng)知道截流函數(shù)可以通過(guò)限定滾動(dòng)事件觸發(fā)頻率提升性能,同時(shí),設(shè)置在 延遲時(shí)間開(kāi)始階段立即調(diào)用滾動(dòng)事件的回調(diào)函數(shù) 并不會(huì)犧牲用戶體驗(yàn)。
截流函數(shù)上文已經(jīng)定義好,使用起來(lái)就很簡(jiǎn)單了:
// 設(shè)置截流函數(shù) let handleMouseWheel = utils.throttle(this.scrollMouse, this, this.DELAY, true); // 鼠標(biāo)滾輪監(jiān)聽(tīng),火狐鼠標(biāo)滾動(dòng)事件不同其他 if (navigator.userAgent.toLowerCase().indexOf('firefox') === -1) { document.addEventListener('mousewheel', handleMouseWheel); } else { document.addEventListener('DOMMouseScroll', handleMouseWheel); }
上面這部分代碼是寫在 class 的 init 方法中,所以截流函數(shù)的上下文(context)傳入的是 this ,表示當(dāng)前 class 實(shí)例。
7)其他
7.1 導(dǎo)航按鈕
為了簡(jiǎn)化 html 結(jié)構(gòu),導(dǎo)航按鈕通過(guò) js 創(chuàng)建。這里的難點(diǎn)在于 如何實(shí)現(xiàn)點(diǎn)擊不同按鈕實(shí)現(xiàn)對(duì)應(yīng)頁(yè)面的跳轉(zhuǎn)并更新對(duì)應(yīng)按鈕的樣式 。
解決的思路是:
- 頁(yè)面跳轉(zhuǎn):頁(yè)面?zhèn)€數(shù)和導(dǎo)航按鈕的個(gè)數(shù)一致,所以點(diǎn)擊第 i 個(gè)按鈕也就是跳轉(zhuǎn)到第 i 個(gè)頁(yè)面,而第 i 個(gè)頁(yè)面對(duì)應(yīng)的容器 top 值恰好是 -(i * this.viewHeight)
- 更改樣式:更改樣式即先刪除所有按鈕的選中樣式,然后給當(dāng)前點(diǎn)擊的按鈕添加選中樣式。
// 創(chuàng)建右側(cè)點(diǎn)式導(dǎo)航 createNav() { const nav = document.createElement('div'); nav.className = 'nav'; this.container.appendChild(nav); // 有幾頁(yè),顯示幾個(gè)點(diǎn) for (let i = 0; i < this.pagesNum; i++) { nav.innerHTML += '<p class="nav-dot"><span></span></p>'; } const navDots = document.querySelectorAll('.nav-dot'); this.navDots = Array.prototype.slice.call(navDots); // 添加初始樣式 this.navDots[0].classList.add('active'); // 添加點(diǎn)式導(dǎo)航點(diǎn)擊事件 this.navDots.forEach((el, i) => { el.addEventListener('click', event => { // 頁(yè)面跳轉(zhuǎn) this.currentPosition = -(i * this.viewHeight); this.turnPage(this.currentPosition); // 更改樣式 this.navDots.forEach(el => { utils.deleteClassName(el, 'active'); }); event.target.classList.add('active'); }); }); }
7.2 自定義參數(shù)
得當(dāng)?shù)淖远x參數(shù)可以增加插件的靈活性。
參數(shù)通過(guò)構(gòu)造函數(shù)傳入,并通過(guò) Object.assign() 進(jìn)行參數(shù)合并:
constructor(options) { // 默認(rèn)配置 const defaultOptions = { isShowNav: true, delay: 150, definePages: () => {}, }; // 合并自定義配置 this.options = Object.assign(defaultOptions, options); }
7.3 窗口尺寸改變時(shí)更新數(shù)據(jù)
瀏覽器窗口尺寸改變的時(shí)候,需要重新獲取可視區(qū)、頁(yè)面元素高度,并重新確定容器當(dāng)前的 top 值。
同時(shí),為了避免不必要的性能開(kāi)支,這里使用了防抖動(dòng)函數(shù)。
// window resize 時(shí)重新獲取位置 getNewPosition() { this.viewHeight = document.documentElement.clientHeight; this.container.style.height = this.viewHeight + 'px'; let activeNavIndex; this.navDots.forEach((e, i) => { if (e.classList.contains('active')) { activeNavIndex = i; } }); this.currentPosition = -(activeNavIndex * this.viewHeight); this.turnPage(this.currentPosition); } handleWindowResize(event) { // 設(shè)置防抖動(dòng)函數(shù) utils.debounce(this.getNewPosition, this, event, this.DELAY); } // 窗口尺寸變化時(shí)重置位置 window.addEventListener('resize', this.handleWindowResize.bind(this));
7.4 兼容性
這里的兼容性主要指兩個(gè)方面:一是不同瀏覽器對(duì)同一行為定義了不同 API,比如上文提到的獲取鼠標(biāo)滾動(dòng)信息的 API Firefox 和其他瀏覽器不一樣;第二點(diǎn)就是 ES6 新語(yǔ)法、新 API 的兼容處理。
對(duì)于 class、箭頭函數(shù)這類新語(yǔ)法的轉(zhuǎn)換,通過(guò) babel 就可完成,鑒于本插件代碼量很小,都處于可控的狀態(tài),并沒(méi)有引入 babel 提供的 polyfill 方案,因?yàn)樾?API 只有 Object.assign() 需要做兼容處理,單獨(dú)寫個(gè) polyfill 就好,如下:
// polyfill Object.assign polyfill() { if (typeof Object.assign != 'function') { Object.defineProperty(Object, 'assign', { value: function assign(target, varArgs) { if (target == null) { throw new TypeError('Cannot convert undefined or null to object'); } let to = Object(target); for (let index = 1; index < arguments.length; index++) { let nextSource = arguments[index]; if (nextSource != null) { for (let nextKey in nextSource) { if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) { to[nextKey] = nextSource[nextKey]; } } } } return to; }, writable: true, configurable: true, }); } },
引用自: MDN-Object.assign()
因?yàn)楸静寮患嫒莸?IE10,所以不打算對(duì)事件做兼容處理,畢竟IE9 都支持 addEventListener 了。
7.5 通過(guò)惰性載入進(jìn)一步優(yōu)化性能
在 5.1 中寫的 getWheelDelta 函數(shù)每次執(zhí)行都需要檢測(cè)是否支持 event.wheelDelta ,實(shí)際上,瀏覽器只需在第一次加載時(shí)檢測(cè),如果支持,接下來(lái)都會(huì)支持,再做檢測(cè)是沒(méi)必要的。
并且這個(gè)檢測(cè)在頁(yè)面的生命周期中會(huì)執(zhí)行很多次,這種情況下可以通過(guò) 惰性載入 技巧進(jìn)行優(yōu)化,如下:
getWheelDelta(event) { if (event.wheelDelta) { // 第一次調(diào)用之后惰性載入,無(wú)需再做檢測(cè) this.getWheelDelta = event => event.wheelDelta; // 第一次調(diào)用使用 return event.wheelDelta; } else { // 兼容火狐 this.getWheelDelta = event => -event.detail; return -event.detail; } },
參考資料
Throttling and Debouncing in JavaScript
Debouncing and Throttling Explained Through Examples
Viewport height is taller than the visible part of the document in some mobile browsers
Babel 編譯出來(lái)還是 ES 6?難道只能上 polyfill?- Henry 的回答
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
JS獲取本周周一,周末及獲取任意時(shí)間的周一周末功能示例
這篇文章主要介紹了JS獲取本周周一,周末及獲取任意時(shí)間的周一周末功能,結(jié)合實(shí)例形式分析了js通過(guò)擴(kuò)展實(shí)現(xiàn)針對(duì)日期的運(yùn)算相關(guān)技巧,需要的朋友可以參考下2017-02-02JavaScript實(shí)現(xiàn)封閉區(qū)域布爾運(yùn)算的示例代碼
這篇文章主要介紹了JavaScript實(shí)現(xiàn)封閉區(qū)域布爾運(yùn)算的示例代碼,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-06-06BootStrap Select清除選中的狀態(tài)恢復(fù)默認(rèn)狀態(tài)
PC端項(xiàng)目中經(jīng)常會(huì)出現(xiàn)大量的數(shù)據(jù)列表頁(yè)面,涉及到下拉框選擇篩選條件;當(dāng)時(shí)用到bootstrap-select下拉框時(shí)該如何點(diǎn)擊重置按鈕就清除下拉框的選中狀態(tài)呢?下面通過(guò)本文給大家介紹下,需要的的朋友參考下吧2017-06-06js switch case default 的用法示例介紹
switch case default的用法應(yīng)該存在一部分人不會(huì)使用吧,其實(shí)很簡(jiǎn)單就是每個(gè)case后,一定要加:break;default,就相當(dāng)于else,不會(huì)的朋友可以了解下2013-10-10JavaScript 格式化數(shù)字、金額、千分位、保留幾位小數(shù)、舍入舍去
這篇文章主要介紹了JavaScript 格式化數(shù)字、金額、千分位、保留幾位小數(shù)、舍入舍去,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-07-07Bootstrap框架結(jié)合jQuery仿百度換膚功能實(shí)例解析
這篇文章主要為大家詳細(xì)介紹了Bootstrap框架結(jié)合jQuery仿百度換膚功能實(shí)現(xiàn)代碼解析,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-09-09(推薦一個(gè)超好的JS函數(shù)庫(kù))S.Sams Lifexperience ScriptClassLib
(推薦一個(gè)超好的JS函數(shù)庫(kù))S.Sams Lifexperience ScriptClassLib...2007-04-04微信小程序?qū)崿F(xiàn)canvas分享朋友圈海報(bào)
這篇文章主要為大家詳細(xì)介紹了微信小程序?qū)崿F(xiàn)canvas分享朋友圈海報(bào),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-06-06基于cssSlidy.js插件實(shí)現(xiàn)響應(yīng)式手機(jī)圖片輪播效果
cssSlidy是一款支持手機(jī)移動(dòng)端的焦點(diǎn)圖輪播插件,支持標(biāo)題設(shè)置,滑動(dòng)動(dòng)畫,間隔時(shí)間等。這篇文章主要基于cssSlidy.js插件實(shí)現(xiàn)響應(yīng)式手機(jī)圖片輪播效果,2016-08-08