前端新手引導功能

背景

筆者最近做一個新手引導功能,這個引導獨立於實際產品,但是卻包含部分產品的功能,是一個單獨的模塊。

在實現上,一開始想的儘量把引導功能和產品功能分開。做的時候也儘量這樣做了。

最外層是引導功能的組件,實現引導相關的邏輯,這個組件包含了產品功能組件,產品功能組件不用不關心引導組件的存在。功能組件只需要實現功能並且提供相應的事件函數就行。

最後爲了能在功能組件裏高亮顯示引導區,直接在引導組件裏通過選擇器把功能組件裏的元素層級改爲比較高。這樣當引導組件遮擋這個屏幕時,功能區元素是高亮顯示且可以點擊的。邊實際操作產品功能邊完成整個引導邏輯。

當筆者做完以後,發現如果要在引導中間加入一個流程,不能通過修改一個配置就完成。需要修改一些代碼,相當於需要熟悉整個引導流程當代碼才能進行修改和添加。這缺乏一定當擴展性,而且維護成本會比較高。於是筆者在網上尋找其他人是如何做新手引導的。

 

經過

在網上找了一圈,有對引導功能進行總結的:

  • 引導功能代碼,不能混入正常遊戲邏輯代碼中,後患無窮,應儘量分離;(難以忍受優雅的代碼被無情的打亂,更難忍受糟糕的代碼被弄的支離破碎)
  • 界面只發生簡單的UI位移、Size大小、節點層次的調整,不需要修改具引導代碼;
  • 定位UI指引矩形區域應儘可能簡單,能自適應不同的屏幕尺寸;

顯然,我目前的代碼是不能滿足這個總結的。

如果只是讓用戶看引導,並且點擊引導層,然後一步一步說明。這樣做還比較簡單,網上的實現方案找着找着就找到張哥那裏區了。張哥用border做遮罩,元素本身沒背景,所以高亮了引導區。然後可以通過配置定製引導,基本滿足了上面的總結。具體代碼如下:

CSS代碼:
.cover {
    display: none;
    position: absolute;
    width: 0; height: 0;
    left: 0; top: 0; right: 0; bottom: 0;
    border: 0 solid #000;
    opacity: .75;
    filter: alpha(opacity=75);
    z-index: 9;
    /* 過渡效果 */
    transition: all .25s;
    /* 邊緣閃動問題fix */
    box-shadow: 0 0 0 100px #000;
    overflow: hidden;
}
.cover::before {
    content: '';
    width: 100%; height:100%;
    border-radius: 50%;
    border: 400px solid #000;
    position: absolute;
    left: -400px; top: -400px;
    box-shadow: inset 0 0 5px 2px rgba(0,0,0,.75);
}
/* IE7, IE8 img */
.cover > img {
    width: 100%; height: 100%;    
}
HTML代碼:
<div id="cover" class="cover"></div>
JS代碼:
var coverGuide = function(cover, target) {
    var body = document.body, doc = document.documentElement;
    if (cover && target) {
        // target size(width/height)
        var targetWidth = target.clientWidth,
            targetHeight = target.clientHeight;

        // page size
        var pageHeight = doc.scrollHeight,
            pageWidth = doc.scrollWidth;
        
        // offset of target    
        var offsetTop = target.getBoundingClientRect().top + (body.scrollTop || doc.scrollTop),
            offsetLeft = target.getBoundingClientRect().left + (body.scrollLeft || doc.scrollLeft);
        
        // set size and border-width
        cover.style.width = targetWidth + 'px';
        cover.style.height = targetHeight + 'px';    
        cover.style.borderWidth = 
            offsetTop + 'px ' + 
            (pageWidth - targetWidth - offsetLeft) + 'px ' +
            (pageHeight - targetHeight - offsetTop) + 'px ' + 
            offsetLeft + 'px';
        
        cover.style.display = 'block';
            
        // resize
        if (!cover.isResizeBind) {
            if (window.addEventListener) {
                window.addEventListener('resize', function() {
                    coverGuide(cover, target);
                });    
                cover.isResizeBind = true;
            } else if (window.attachEvent) {
                window.attachEvent('onresize', function() {
                    coverGuide(cover, target);
                });
                cover.isResizeBind = true;
                
                // IE7, IE8 box-shadow hack
                cover.innerHTML = '<img src="guide-shadow.png">';
            }
        }
    }
};

var elCover = document.getElementById('cover');
var arrElTarget = [
    document.getElementsByTagName('a')[0], 
    document.getElementById('backTo'), 
    document.getElementById('image')
], index = 0;

coverGuide(elCover, arrElTarget[index]);

elCover.onclick = function() {
    index++;
    if (!arrElTarget[index]) {
        index = 0;    
    }
    coverGuide(elCover, arrElTarget[index]);
};

代碼還兼容了IE7和IE8,真的很厲害耶。但是這個模式並不適合在引導過程中,是真的在操作功能。但是稍微改一改能不能滿足呢?

 

思考

功能組件如果提供自身被用戶操作的各種事件,然後引導功能可以訂閱各種事件,且引導的高亮層是可以被點穿的(但是按照上面的模式,高亮層和遮罩是同一個元素,如果高亮層被點穿,遮罩層可能也被點穿)。

還思考了一種方法,就是假設所有的組件都繼承引導功能。可以通過外部配置激活這些組件的引導功能。從而使得可以配置引導,而且引導是組件的一部分,繼而能獲得組件所有的狀態和操作組件。這個方法前期組件如果做好了,感覺會很好用。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章