javaScript PC端网页特效
PC端網頁特效
- 1. 元素偏移量 offset 系列
- 1.1 offset 概述
- 1.2 offset 與 style 區別
- 2. 元素可視區 client 系列
- 2.1 立即執行函數
- 2.2 load 事件的觸發
- 3. 元素滾動 scroll 系列
- 3.1 元素 scroll 系列屬性
- 3.2 頁面被卷去的頭部
- 3.3 頁面被卷去的頭部兼容性解決方案
- 三大系列總結
- mouseenter 和mouseover的區別
- 4. 動畫函數封裝
- 4.1 動畫實現原理
- 4.2 動畫函數的簡單封裝
- 4.3 動畫函數給不同元素記錄不同定時器
- 4.4 緩動效果原理
- 4.5 動畫函數多個目標值之間移動
- 4.6 動畫函數添加回調函數
- 4.7 動畫函數封裝到單獨的JS文件
- 5. 常見網頁特效案例
- 5.1 案例:網頁輪播圖(JavaScript原生寫法)
- 5.2 節流閥
1. 元素偏移量 offset 系列
1.1 offset 概述
offset — 偏移量, 使用 offset 系列相關屬性可動態的得到該元素的位置(偏移)、大小等。
- 獲得元素距離帶有定位父元素的位置;
- 獲得元素自身的大小(寬度高度)。
- 注: 返回的數值都不帶單位
offset 系列常用屬性:
| element.offsetParent | 返回作為該元素帶有定位的父級元素,如果父級元素沒有定位,則返回body |
| element.offsetTop | 返回元素相對帶有定位父元素上方的偏移 |
| element.offsetLeft | 返回元素相對帶有定位父元素左邊框的偏移 |
| element.offsetWidth | 返回自身包括padding、邊框、內容區的寬度、返回數值不帶單位。 |
| element.offsetHeight | 返回自身包括padding、邊框、內容區的高度、返回數值不帶單位。 |
1.2 offset 與 style 區別
| offset 可以得到任意樣式表中的樣式值 | style 只能得到行內樣式表中的樣式值 |
| offset 系列獲得的數值沒有單位 | style.width 獲得的是帶有單位的字符串 |
| offsetWidth 包含padding+border+width | style.width 獲得不包含padding和border 的值 |
| offsetWidth 是只讀屬性,只能獲取不能賦值 | style.width 是可讀寫屬性,可獲取也可以賦值 |
因此,
想要獲取元素大小位置,用offset更合適;
想要給元素更改值,則需要用style改變。
- 獲得元素距離帶有定位父元素的位置;
- 獲得元素自身的大小(寬度高度)。
案例:獲取鼠標在盒子內的坐標
-
實現思路
① 得到鼠標在頁面中的坐標(e.pageX, e.pageY)
② 得到盒子在頁面中的距離 ( box.offsetLeft, box.offsetTop)
③ 鼠標在頁面中的坐標減去盒子在頁面中的距離,得到鼠標在盒子內的坐標
④ 移動鼠標,獲取最新的坐標,使用鼠標移動事件 mousemove。 -
實現代碼
2. 元素可視區 client 系列
client (客戶端),利用 client 系列的相關屬性來獲取元素可視區的相關信息。通過 client 系列的相關屬性可以動態的得到該元素的邊框大小、元素大小等。
| element.clientTop | 返回元素上邊框的大小 |
| element.clientLeft | 返回元素左邊框的大小 |
| element.clientWidth | 返回自身,包換padding/內容區的寬度,不含邊框,返回數據不帶單位 |
| element.clientHeight | 返回自身,包換padding/內容區的高度,不含邊框,返回數據不帶單位 |
2.1 立即執行函數
- 立即執行函數不需要調用,立馬能夠自己執行;
- 主要作用:創建一個獨立的作用域,里面所有的變量都是局部變量,避免了命名沖突問題
- 立即執行函數的用法:
下面是 淘寶 flexible.js 源碼分析
(function flexible (window, document) {// 獲取html的根元素var docEl = document.documentElement// dpr 是物理像素比var dpr = window.devicePixelRatio || 1// adjust body font size 設置body的字體大小function setBodyFontSize () {// 如果頁面中有body這個元素,就設置body的字體大小if (document.body) {document.body.style.fontSize = (12 * dpr) + 'px'}else {// 如果頁面中沒有body這個元素,則等著頁面的主要DOM元素加載完畢再去設置body的字體大小document.addEventListener('DOMContentLoaded', setBodyFontSize)}}setBodyFontSize();// set 1rem = viewWidth / 10 設置html元素的文字大小function setRemUnit () {var rem = docEl.clientWidth / 10docEl.style.fontSize = rem + 'px'}setRemUnit()// reset rem unit on page resize 當頁面尺寸大小發生變化的時候,要重新設置下rem的大小window.addEventListener('resize', setRemUnit)// pageshow 是重新加載頁面觸發的事件window.addEventListener('pageshow', function (e) {// e.persisted 返回的是true,就是說如果這個頁面是從緩存取過來的頁面,也需要重新計算一下rem的大小if (e.persisted) {setRemUnit()}})// detect 0.5px supports 有些移動端的瀏覽器不支持0.5像素的寫法if (dpr >= 2) {var fakeBody = document.createElement('body')var testElement = document.createElement('div')testElement.style.border = '.5px solid transparent'fakeBody.appendChild(testElement)docEl.appendChild(fakeBody)if (testElement.offsetHeight === 1) {docEl.classList.add('hairlines')}docEl.removeChild(fakeBody)} }(window, document))2.2 load 事件的觸發
下面三種情況都會刷新頁面都會觸發 load 事件
a標簽的超鏈接
F5或者刷新按鈕(強制刷新)
前進后退按鈕
但是,火狐中有個特點——“往返緩存”,這個緩存中不僅保存著頁面數據,還保存了DOM和JavaScript的狀態;實際上是將整個頁面都保存在了內存里。所以此時后退按鈕不能刷新頁面。
—— 但可以使用 pageshow事件來觸發。該事件在頁面顯示時觸發,無論頁面是否來自緩存。在重新加載頁面中,pageshow會在load事件觸發后觸發;根據事件對象中的persisted來判斷是否是緩存中的頁面觸發的pageshow事件,注意這個事件給window添加。
3. 元素滾動 scroll 系列
3.1 元素 scroll 系列屬性
scroll 意為滾動,使用 scroll 系列的相關屬性可動態獲得該元素的大小、滾動距離等。
| element.scrollTop | 返回被卷去的上側距離,返回值不帶單位 |
| element.scrollLeft | 返回被卷去的左側距離,返回值不帶單位 |
| element.scrollWidth | 返回自身實際的寬度,不含邊框,返回數值不帶單位 |
| element.scrollHeight | 返回自身實際的高度,不含邊框,返回數值不帶單位 |
3.2 頁面被卷去的頭部
如果瀏覽器的高度或寬度不足以顯示整個頁面時,會自動出現滾動條。當滾動條向下滾動時,頁面上面被隱藏掉的高度,我們就稱為頁面被卷去的頭部。滾動條在滾動時會觸發 onscroll 事件。
案例:淘寶固定右側側邊欄
- 原先側邊欄是絕對定位
- 當頁面滾動到一定位置,側邊欄改為固定定位;
- 頁面繼續滾動,會讓 返回頂部顯示出來。
實現思路
① 頁面滾動事件 scroll,事件源:document;
② 滾動到某個位置,獲取頁面被卷去的上部值;
③ 頁面被卷去的頭部:通過window.pageYOffset獲得。(如果是被卷去的左側,則通過window.pageXOffset獲得);
④ 注:元素被卷去的頭部是 element.scrollTop ;如果是頁面被卷去的頭部則是 window.pageYOffset;
這個值,也可以通過盒子的 offsetTop得到,如果≥這個值,就讓盒子變成固定定位.。
3.3 頁面被卷去的頭部兼容性解決方案
需要注意的是,頁面被卷去的頭部,有兼容性問題,因此被卷去的頭部通常有如下幾種寫法:
兼容性函數封裝
function getScroll() {return {left: window.pageXOffset || document.documentElement.scrollLeft ||document.body.scrollLeft||0,top: window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop || 0}; }兼容性函數調用
getScroll().left三大系列總結
| element.offsetWidth | 返回自身,包括padding、邊框、內容區的寬度,返回值不帶單位 |
| element.clientWidth | 返回自身,包括padding、內容區的寬度,不含邊框。返回值不帶單位 |
| element.scrollWidth | 返回自身實際的寬度,不含邊框。返回值不帶單位 |
主要用途/用法:
| offset系列 | 經常用于獲得元素位置 offsetLeft、offsetTop |
| client系列 | 經常用于獲取元素大小 clientWidth、 clientHeight |
| scroll系列 | 經常用于獲取滾動距離 scrollTop 、scrollLeft |
注:頁面滾動距離通過 window.pageXOffset 獲得
mouseenter 和mouseover的區別
- mouseenter 鼠標事件
| 當鼠標移動到元素上時就會觸發 | |
| 只會經過自身盒子觸發(mouseenter不會冒泡) | 鼠標經過自身盒子會觸發,經過子盒子還會觸發。 |
| 跟它搭配,mouseleave(鼠標離開) 同樣不會冒泡 |
4. 動畫函數封裝
4.1 動畫實現原理
核心原理:通過定時器 setInterval() 不斷移動盒子位置。
實現步驟:
注:此元素需要添加定位,才能使用element.style.left
4.2 動畫函數的簡單封裝
函數需要傳遞2個參數,動畫對象和移動到的距離。
<div></div> <span>文化長廊</span> <script>// obj:目標對象 target:目標位置function animate(obj, target) {var timer = setInterval(function() {if (obj.offsetLeft >= target) {// 停止動畫 其實質是停止定時器。clearInterval(timer);}obj.style.left = obj.offsetLeft + 1 + 'px';}, 30);}var div = document.querySelector('div');var span = document.querySelector('span');// 調用函數animate(div, 250);animate(span, 420); </script>4.3 動畫函數給不同元素記錄不同定時器
如果多個元素都使用同一動畫函數,則無需每次都去聲明定時器。可給不同的元素使用不同的定時器
核心原理:由于JavaScript是一門動態語言,所以可以很方便的給當前對象添加屬性。
實例代碼如下:
<button>點我</button><div></div><span>文化長廊</span><script>// var obj = {};// obj.name = 'Rose';// obj:目標對象;target:目標位置// 給不同的元素指定不同的定時器function animate(obj, target) {// 當連續點擊按鈕,元素的速度會逐漸加快,原因是開啟了多個定時器;// 解決方案:確保只有一個定時器執行;// 清除先前的定時器,只保留執行當前一個定時器,clearInterval(obj.timer);obj.timer = setInterval(function() {if (obj.offsetLeft >= target) {// 停止動畫 其實質是停止定時器clearInterval(obj.timer);}obj.style.left = obj.offsetLeft + 1 + 'px';}, 30);}var div = document.querySelector('div');var span = document.querySelector('span');var btn = document.querySelector('button');// 調用函數animate(div, 450);btn.addEventListener('click', function() {animate(span, 250);})</script>4.4 緩動效果原理
緩動動畫:就是讓元素運動速度有所變化,最常見的是讓速度慢慢停下來
實現思路:
注:步長值需要取整。
實例代碼(緩動動畫函數封裝):
// 緩動動畫函數封裝 <button>點我</button> <span>文化長廊</span><script>// obj:目標對象;target:目標位置// 1. 讓盒子每次移動的距離逐漸變小。// 2. 每次移動的距離(步長):(目標值 - 現在的位置) / 10 // 3. 停止條件: 當前盒子位置 = 目標位置時function animate(obj, target) {// 清除先前的定時器,只保留執行當前一個定時器clearInterval(obj.timer);obj.timer = setInterval(function() {// 步長值寫到定時器的里面var step = (target - obj.offsetLeft) / 10;if (obj.offsetLeft == target) {// 停止動畫 其實質是停止定時器clearInterval(obj.timer);}// 將每次加1這個步長值改為一個慢慢變小的值 步長公式:(目標值 - 當前位置) / 10obj.style.left = obj.offsetLeft + step + 'px';}, 15);}var span = document.querySelector('span');var btn = document.querySelector('button');btn.addEventListener('click', function() {// 調用函數animate(span, 500);})// 勻速動畫 就是 盒子是當前的位置 + 固定的值 10 // 緩動動畫就是 盒子當前的位置 + 變化的值(目標值 - 現在的位置) / 10)</script>4.5 動畫函數多個目標值之間移動
可以讓動畫函數從 800 移動到 500。
當點擊按鈕時,判斷步長是正值還是負值
實例代碼:
// 緩動動畫函數封裝 <button class="btn500">按鈕1</button><button class="btn800">按鈕2</button><span>文化長廊</span><script>// obj:目標對象;target:目標位置// 1. 讓盒子每次移動的距離逐漸變小。// 2. 每次移動的距離(步長):(目標值 - 現在的位置) / 10 // 3. 停止條件: 當前盒子位置 = 目標位置時function animate(obj, target) {// 清除先前的定時器,只保留執行當前一個定時器clearInterval(obj.timer);obj.timer = setInterval(function() {// 步長值寫到定時器的里面// 把步長值改為整數 避免出現小數// var step = Math.ceil((target - obj.offsetLeft) / 10);var step = (target - obj.offsetLeft) / 10;step = step > 0 ? Math.ceil(step) : Math.floor(step);if (obj.offsetLeft == target) {// 停止動畫 其實質是停止定時器clearInterval(obj.timer);}// 將每次加1這個步長值改為一個慢慢變小的值 步長公式:(目標值 - 當前位置) / 10obj.style.left = obj.offsetLeft + step + 'px';}, 15);}var span = document.querySelector('span');var btn500 = document.querySelector('.btn500');var btn800 = document.querySelector('.btn800');btn500.addEventListener('click', function() {// 調用函數animate(span, 500);})btn800.addEventListener('click', function() {// 調用函數animate(span, 800);})// 勻速動畫 就是 盒子是當前的位置 + 固定的值 10 // 緩動動畫就是 盒子當前的位置 + 變化的值(目標值 - 現在的位置) / 10)</script>4.6 動畫函數添加回調函數
回調函數原理:
函數可以作為一個參數。將這個函數作為參數傳到另一個函數里面,當那個函數執行完之后,再執行傳進去的這個函數,這個過程就叫做回調。
寫回調函數的位置:定時器結束的位置。
4.7 動畫函數封裝到單獨的JS文件
經常使用的動畫函數,可單獨封裝到一個JS文件里,使用的時候引用此JS文件即可。
5. 常見網頁特效案例
5.1 案例:網頁輪播圖(JavaScript原生寫法)
5.1.1 功能需求:
1.鼠標經過輪播圖模塊,左右按鈕顯示,離開隱藏左右按鈕。
2.點擊右側按鈕一次,圖片往左播放一張,以此類推, 左側按鈕同理。
3.圖片播放的同時,下面小圓圈模塊跟隨一起變化。
4.點擊小圓圈,可以播放相應圖片。
5.鼠標不經過輪播圖, 輪播圖也會自動播放圖片。
6.鼠標經過,輪播圖模塊, 自動播放停止。
5.1.2 思路
① 單獨新建js文件夾和js文件,并引入HTML頁面中;
② 添加 load 事件;
③ 鼠標經過輪播圖模塊,左右按鈕顯示,離開隱藏左右按鈕;
④ 顯示隱藏 display 按鈕。
5.1.3 動態生成小圓圈
核心思路:
① 小圓圈的個數要跟圖片張數一致;
② 首先得到ul里面圖片的張數(圖片放入li里面,所以就是li的個數);
③ 利用循環動態生成小圓圈(這個小圓圈要放入ol里面);
④ 創建節點 var li = createElement('li');
⑤ 插入節點 ol. appendChild(li);
⑥ 第一個小圓圈需要添加 current 類。
5.1.4 設定當前小圓圈(排他思想)
① 點擊當前小圓圈,就添加current類
② 其余的小圓圈就移除current類
注: 在生成小圓圈的同時,就可直接綁定點擊事件。
5.1.5 點擊小圓圈滾動圖片
① 需要用到animate動畫函數,將js文件引入(注,因為index.js 依賴 animate.js 所以animate.js 要寫到 index.js 上面);
② 使用動畫函數的前提:該元素必須有定位;
③ 注意是ul 移動 而不是小li;
④ 滾動圖片的核心算法: 點擊某個小圓圈 ,圖片滾動。 ul移動距離=小圓圈的索引號×圖片的寬;
⑤ 需要獲取小圓圈的索引號,在生成小圓圈時,給它設置一個自定義屬性,點擊時獲取此自定義屬性即可。
5.1.6 點擊右側按鈕,圖片滾動。
① 聲明變量num, 每點擊1次,num自增1, ul 滾動距離 = 變量 × 圖片寬度。
圖片無縫滾動原理:
把ul 第一個li 復制一份,放到ul 的最后面;
當圖片滾動到克隆的最后一張圖片時, 讓ul 快速的、不做動畫的跳到最左側: left 為0,同時num 賦值為0,從重新開始滾動圖片
② 克隆第一張圖片;克隆ul 第一個li, cloneNode()
復制里面的子節點。cloneNode()括號內加true 是深克隆, false 淺克隆。
③ 添加到 ul 最后面 appendChild。
5.1.7 點擊右側按鈕, 小圓圈跟隨變化
① 再聲明一個變量circle,每次點擊自增1,因左右側按鈕都需要此變量,因此聲明為全局變量。
② 但是圖片張數比小圓圈多一個(首尾圖片相同),需增加一個判斷條件
③如有5張圖片,則小圓點只能有4個,即判斷寫為 if(circle == 4) 就 從新復原為 0。
5.1.8 自動播放功能
① 添加定時器;
自動播放輪播圖,實際就類似于點擊了右側按鈕
② 此時可接手動調用右側按鈕點擊事件(如 right_btn.click())
③ 鼠標經過輪播圖focus 時,就停止定時器;
④ 鼠標離開focus則開啟定時器。
5.2 節流閥
防止輪播圖按鈕連續點擊造成播放過快。
節流閥目的:當上一個函數動畫內容執行完畢,再執行下一個函數動畫時,讓事件無法連續觸發。
實現思路:利用回調函數,添加一個變量來控制,鎖住函數和解鎖函數。
開始設置一個變量 var flag = true;
利用回調函數 動畫執行完畢, flag = true 打開水龍頭。
5.2.1 案例:返回頂部
滾動窗口至文檔中的特定位置。
注意,里面的x和y 不跟單位,直接寫數字。
帶有動畫的返回頂部
① 此時可繼續使用之前封裝的動畫函數;
② 只需把所有的left相關的值改為跟頁面垂直滾動距離相關即可;
③ 頁面滾動了多少,可通過 window.pageYOffset 獲得;
④ 最后是頁面滾動,使用 window.scroll(x,y)。
總結
以上是生活随笔為你收集整理的javaScript PC端网页特效的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 快速部署web项目上线云服务器
- 下一篇: iscroll的使用