功能點
節前碰到一個需求:「新人引導效果」針對第一次使用平臺的使用者進行主要功能引導。
具體引導路徑為:點選“新增按鈕”,對彈出的內容進行解釋,並引導使用者填充表單,最後提交表單。
下面為效果截圖(感興趣的兄弟們可以自己實現一下,我用的 vue
+ ElementUI
):
我們打工人要的就是效率,我們不生產輪子,我們都是輪子的搬運工。
是否有現成的輪子?
通過搜尋引擎來查詢解決辦法。
常見外掛
- vue-introjs
- driver.js
- http://bootstraptour.com/api/
- https://github.com/pulsardev/...
- https://github.com/shipshapec...
- https://github.com/zurb/joyride
實現
我試用了一下 introjs 和 driver.js,最後使用了 introjs 來實現,但是兩個庫都有不如意的點。
introjs
- http://jsrun.net/ERQKp/edit 新增按鈕是好使的,但是彈窗中的 input 無法單擊。(也有可能是 elementUI 有毒)
我最後使用pointer-events: none;user-select: none;
+ 引導中狀態來自行實現的功能。 - 不支援 next 回撥,不支援 delay 控制。
我最後把引導分為了兩步來實現,手動實現 delay 邏輯
- http://jsrun.net/ERQKp/edit 新增按鈕是好使的,但是彈窗中的 input 無法單擊。(也有可能是 elementUI 有毒)
driver.js
- http://jsrun.net/PmQKp/edit 看上去彈窗的時候,層級關係就不對了。我直接就麻了。
當然了,即使這麼難,但還是有辦法的。introjs 實現案例:http://jsrun.net/KAQKp/edit,雖然相容性有可能堪憂。
拆解功能點
雖然有外掛,但是我們也可以瞭解一下如何實現。我們來拆解一下
高亮功能&遮罩功能
fixed
+z-index
層級box-shadow
border
+ 位移
- 獲取元素位置方便定位
- 上一步、下一步等回撥方便處理邏輯。
高亮功能&遮罩功能
https://jsrun.net/cRQKp/edit
可以看到基本能滿足,但是底部還是可單擊的。而且並沒有分層。
通過增加遮罩層來實現分層功能,這樣就可以阻止事件了。https://jsrun.net/duQKp/edit
但是這裡還是有一個問題的。z-index
不能超過父級。所以我們需要增加多個層,來規避這個問題。
獲取元素位置 popper 定位
popper 的功能我們可以使用一些三方庫來實現
- popper.js
https://jsrun.net/duQKp/edit 很快我們就實現了想要的功能。 自己通過 offsetParent 和 遞迴 parentNode 來實現。
absolute + event (pageY)
tooltip.style.position = 'absolute'; tooltip.style.top = `${e.pageY}px`; tooltip.style.left = `${e.pageX}px`;
fixed + event (clientY)
tooltip.style.position = 'fixed'; tooltip.style.top = `${e.clientY}px`; tooltip.style.left = `${e.clientX}px`;
absolute + 遞迴 offset
const getOffestValue = function getOffestValue(el, offsetLeft="offsetLeft"){ if(!el) return 0; return el[offsetLeft] + (getOffestValue(el.offsetParent, offsetLeft) || 0) } tooltip.style.position = 'absolute'; tooltip.style.top = `${getOffestValue(el, 'offsetTop') - 30}px`; tooltip.style.left = `${getOffestValue(el) - 20}px`;
- fixed + getBoundingClientRect
const {x,y} = el.getBoundingClientRect() tooltip.style.position = 'fixed'; tooltip.style.top = `${y - 30}px`; tooltip.style.left = `${x - 30}px`;
回撥邏輯
可以通過 bus 或者 $emit 丟擲。