新手引導動畫的4種實現方式
前一陣子忙著找工作,面試過程中,碰到一個感覺比較有意思的問題,儘量多的列舉出新手引導動畫的實現方式 , 昨天稍微總結了一下, 實現了4種.原始碼在最後,如果想直接看結果的,可以拉到最後去看.
這裡假設所有的彈出層都是基於頁面上原有的元素
實現一 複製目標內容
具體步驟:
getBoundingClientRect
核心程式碼:
let target = document.querySelector('.mid-center') let pos = target.getBoundingClientRect() let clone = target.cloneNode(true) clone.style.position = 'fixed' clone.style.left = pos.left clone.style.top = pos.top clone.style.width = pos.width clone.style.height = pos.height clone.style.zIndex = 100 document.body.appendChild(clone) 複製程式碼
優缺點比較平凡的實現方式,普普通通的,沒啥特色.
實現二 利用box-shadow
具體步驟:
- 設定目標物件的 box-shadow 為一個比較大的,半透明的值
- 設定目標物件的 position 為 relative
核心程式碼:
let target = document.querySelector('.mid-center') target.style.boxShadow = '0 0 0 4000px rgba(0, 0, 0, 0.85)' target.style.position = 'relative' 複製程式碼
這裡設定 position:relative 是為了讓 box-shadow 陰影不被父容器所擋住. 如果沒有設定, box-shadow 會顯示不全
優缺點
優點: 實現方式簡單易懂
缺點: box-shadow 是個比較耗效能的屬性, 而且依靠 position:relative 不知道會不會出現無法覆蓋的問題
實現三 利用 html2canvas 將目標內容繪製的一個底色半透明的 canvas 裡面
具體步驟:
getBoundingClientRect html2canvas
核心程式碼:
let target = document.querySelector('.mid-center') let pos = target.getBoundingClientRect() let w = ~~pos.width let h = ~~pos.height let canvas = document.querySelector('#canvas') canvas.width = document.documentElement.clientWidth canvas.height = document.documentElement.clientHeight let ctx = canvas.getContext("2d"); canvas.style.display = 'block' html2canvas(target, { width: w, height: h, }).then( (cvs) => { ctx.drawImage(cvs, pos.left, pos.top) }) 複製程式碼
需要注意的是 這裡 canvas.width 和 canvas.height 要手動設定,否則預設是 300 * 150,這樣如果在樣式裡設定寬高的話,會導致畫布被拉伸.
優缺點
優點: 效能應該相對會比較好一點(如果html2canvas效能內有太差的話), 用 canvas 實現, 也比較不容易碰到各種層級遮擋或顯示不全的問題.
缺點: 實現方式相對繁瑣一點,而且需要藉助外部工具
實現四 把其他元素都設成半透明的.然後給 body 加一個黑色的底色
具體步驟:
- 給整個文件最外層的元素,設定一個黑色的底色
- 遍歷整個文件,把非目標內容,和非目標內容的父容器,都設成半透明的
核心程式碼:
function showGuidance() { let main = document.querySelector('.main') main.className += ' darkBackGround' setOpticity(main) } function setOpticity (element) { let doms = Array.from(element.children) || [] let hasMatched = false for (let el of doms) { if (!el.className.match(/mid-center/i) && el.children.length) { hasMatched = setOpticity(el) if (!hasMatched) el.className += ' halfTransparent' } else if(el.className.match(/mid-center/i)) { hasMatched = true } else { el.className += ' halfTransparent' } } return hasMatched } 複製程式碼
如果不小心把目標元素的父元素也設定成半透明的,那麼就算目標元素沒有設定半透明,也會變透明,因為父元素裡面的所有內容,都會透明
優缺點
優點: 感覺沒有優點哈
缺點: 批量操作 dom, dom 元素多的情況下,效能極差
最後
以上所有實現方式,均按最簡單的實現方式來,未考慮一些特殊情況(如:resize, 有動畫等) 附上ofollow,noindex">原始碼