本文由雲+社區發表javascript
做者:陳紀庚html
最近看了一些文章,知道了實現引導動畫的基本原理,因此決定來本身親手作一個通用的引導動畫類。java
咱們先來看一下具體的效果:點這裏git
${rect.width}px
; newEle.style.height = ${rect.height}px
; newEle.style.left = ${rect.left}px
; newEle.style.top = ${rect.top}px
; this.modal.appendChild(newEle);原理聽起來是否是很簡單?可是其實真正實現起來,仍是有坑的。好比說,當須要展現的元素不在頁面的可視範圍內如何處理。github
當要展現的元素不在頁面可視範圍內,主要分爲三種狀況:canvas
因爲我是經過getBoundingClientRect這個api來獲取元素的位置、大小信息的。這個api獲取的位置信息是相對於視口左上角位置的(以下圖)。api
對於第一種狀況,這個api獲取的top值爲負值,這個就比較好處理,直接調用window.scrollBy(0, rect.top)來將頁面滾動到展現元素的頂部便可。app
而對於第2、三種狀況,咱們能夠看下圖ide
從圖片咱們能夠看出來,當rect.top+rect.height < window.innerHeight的時候,說明展現的元素不在視野範圍內,或者展現不全。對於這種狀況,咱們也能夠經過調用window.scrollBy(0, rect.top)的方式來讓展現元素儘量在頂部。函數
對上述狀況的調節代碼以下:
// 若引導的元素不在頁面範圍內,則滾動頁面到引導元素的視野範圍內 adapteView(ele) { const rect = ele.getBoundingClientRect(); const height = window.innerHeight; if (rect.top < 0 || rect.top + rect.height > height) { window.scrollBy(0, rect.top); } }
接下來,咱們就來一塊兒實現下這個引導動畫類。
咱們先無論具體的展現邏輯實現,咱們先實現一個簡單的Modal功能。
class Guidences { constructor() { this.modal = null; this.eleList = []; } // 入口函數 showGuidences(eleList = []) { // 容許傳入單個元素 this.eleList = eleList instanceof Array ? eleList : [eleList]; // 若以前已經建立一個Modal實例,則不重複建立 this.modal || this.createModel(); } // 建立一個Modal實例 createModel() { const modalContainer = document.createElement('div'); const modalMask = document.createElement('div'); this.setMaskStyle(modalMask); modalContainer.style.display = 'none'; modalContainer.appendChild(modalMask); document.body.appendChild(modalContainer); this.modal = modalContainer; } setMaskStyle(ele) { ele.style.zIndex = '1000'; ele.style.background = 'rgba(0, 0, 0, 0.8)'; ele.style.position = 'fixed'; ele.style.top = 0; ele.style.right = 0; ele.style.bottom = 0; ele.style.left = 0; } hideModal() { this.modal.style.display = 'none'; this.modal.removeChild(this.modalBody); this.modalBody = null; } showModal() { this.modal.style.display = 'block'; } }
複製一個要展現元素的副本,根據要展現元素的位置信息來放置該副本,而且將副本當成Modal的主體內容展現。
class Guidences { constructor() { this.modal = null; this.eleList = []; } // 容許傳入單個元素 showGuidences(eleList = []) { this.eleList = eleList instanceof Array ? eleList : [eleList]; this.modal || this.createModel(); this.showGuidence(); } // 展現引導頁面 showGuidence() { if (!this.eleList.length) { return this.hideModal(); } // 移除上一次的展現元素 this.modalBody && this.modal.removeChild(this.modalBody); const ele = this.eleList.shift(); // 當前要展現的元素 const newEle = ele.cloneNode(true); // 複製副本 this.modalBody = newEle; this.initModalBody(ele); this.showModal(); } createModel() { // ... } setMaskStyle(ele) { // ... } initModalBody(target) { this.adapteView(target); const rect = target.getBoundingClientRect(); this.modalBody.style.zIndex = '1001'; this.modalBody.style.position = 'fixed'; this.modalBody.style.width = `${rect.width}px`; this.modalBody.style.height = `${rect.height}px`; this.modalBody.style.left = `${rect.left}px`; this.modalBody.style.top = `${rect.top}px`; this.modal.appendChild(this.modalBody); // 當用戶點擊引導元素,則展現下一個要引導的元素 this.modalBody.addEventListener('click', () => { this.showGuidence(this.eleList); }); } // 若引導的元素不在頁面範圍內,則滾動頁面到引導元素的視野範圍內 adapteView(ele) { const rect = ele.getBoundingClientRect(); const height = window.innerHeight; if (rect.top < 0 || rect.top + rect.height > height) { window.scrollBy(0, rect.top); } } hideModal() { // ... } showModal() { // ... } }
完整的代碼能夠在點擊這裏
const guidences = new Guidences(); function showGuidences() { const eles = Array.from(document.querySelectorAll('.demo')); guidences.showGuidences(eles); } showGuidences();
除了使用cloneNode的形式來實現引導動畫外,還能夠使用box-shadow、canvas等方式來作。
此文已由騰訊雲+社區在各渠道發佈
獲取更多新鮮技術乾貨,能夠關注咱們騰訊雲技術社區-雲加社區官方號及知乎機構號