1、介面設計
index.html:只提供了一個嚮導顯示位置的預留位置
複製代碼 代碼如下:<html>
<head>
<title>禮物推薦嚮導</title>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<link rel="stylesheet" type="text/css" href="style.css">
<script src="jquery.js" type="text/javascript"></script>
<script src="wizard.js" type="text/javascript"></script>
</head>
<body>
<div id="wizard"></div>
</body>
</html>
style.css:預設情況下嚮導裡有一個h2呈現的標題,一個ul呈現的主要內容,一個div呈現的按鈕條,我們簡單設計了一下他們的預設面板,實際應用中大家可以自由的美化它們。 複製代碼 代碼如下:body{
margin:0;
}
/*嚮導容器*/
#wizard{
height:400px;
width:600px;
background-color:#999;
}
/*嚮導的主體內容,用列表展示*/
#wizard ul{
margin:10px;
height:80%;
}
/*橫向顯示列表內容*/
#wizard li{
display:inline-block;
margin:10px;
cursor:pointer;
}
/*列表的標題*/
#wizard h2{
margin:10px;
}
/*列表的功能條,如返回按鈕*/
#wizard .bar{
margin:10px;
clear:both;
}
2、準備每一步驟
嚮導可以分為每一步驟,每個步驟需要呈現內容,捕捉使用者選擇,提供標題等功能,我們讓每一步都自己負責自己的事情,但要符合我們規定的一些契約。
每一個步驟用一個函數表示,第一個參數data_key是選擇本步驟資料的關鍵字,一般用於上一個步驟的結果決定下一個步驟顯示資料的情況,第二個參數result_callback是個回呼函數,就是在本步驟擷取結果時調用,它用於和嚮導類進行通訊,嚮導類在得到上一步的結果後儲存結果並跳向到下一步。
該函數返回一個二元組,第一個元素是本步驟的標題,第二個元素是本步驟主體部分的UI。
我們的樣本是一個禮物推薦系統,共分三步,第一步選擇送禮對象,第二步選擇關鍵字,其中第一步的選擇結果會影響到第二步顯示,第三步選擇價格區間,如下就是代碼的實現,其中繪製介面和事件捕捉用了jquery來簡化操作。 複製代碼 代碼如下:function step1(data_key, result_callback){
var targets = ['女朋友','男朋友','父親','媽媽','孩子'];
var warpper = $('<ul></ul>')
$.each(targets, function(k,v){
$('<li>'+v+'</li>').click(function(){result_callback(v)}).appendTo(warpper);
});
return ['第一步:請選擇送禮物的對象',warpper];
}
function step2(data_key, result_callback){
var tags = {
'女朋友':['創意','可愛','浪漫','激情','實用','數位',
'自製','毛絨玩具','衣服','包包'],
'男朋友':['男士用品','溫馨','實用','數位','創意','衣物'],
'父親' :['男士用品','健康','植物','衣物'],
'媽媽' :['溫馨','健康','創意','護膚品','實用'],
'孩子' :['玩具','學慣用品','實用','數位']
};
var warpper = $('<ul></ul>')
$.each(tags[data_key], function(k,v){
$('<li>'+v+'</li>').click(function(){result_callback(v)}).appendTo(warpper);
});
return ['第二步:請選擇關鍵詞',warpper];
}
function step3(data_key, result_callback){
var price_level = ['便宜','普通','稍貴','貴重'];
var warpper = $('<ul></ul>')
$.each(price_level, function(k,v){
$('<li>'+v+'</li>').click(function(){result_callback(v)}).appendTo(warpper);
});
return ['第三步:請選擇價格區間',warpper];
}
3、嚮導類的實現
嚮導類要設定嚮導所在的DOM元素,要執行的步驟列表,嚮導完成後執行的回調,嚮導還應該提供上一步和下一步的方法,所以我們用一個類來表示嚮導,在建構函式裡傳入DOM容器,步驟列表和回呼函數,用prototype給類增加三個方法。render用來呈現某一步驟的UI,並在本步驟收集結果的回調裡推向下一步,如果本步驟是最後一步,則調用嚮導執行完成的回呼函數。
另外兩個next和back函數分別是執行上一個步驟和下一個步驟,這兩個函數實用index的私人變數來維持整個嚮導的狀態 複製代碼 代碼如下:function Wizard(container, steps, callback){
this.container = container; //嚮導容器
this.steps = steps; //嚮導步驟
this.callback = callback; //嚮導執行完畢執行的回調
this.collect_data = []; //儲存嚮導每一步驟的結果
this.index = -1; //當前執行在那一步驟
}
//繪製某一步驟
Wizard.prototype.render = function(step, this_result){
var me = this;
//執行該步驟並得到該步驟的UI
var to_append = step(this_result,function(result){
me.collect_data.push(result); //收集本步驟結果
//嚮導執行完畢時調用回呼函數,否則執行下一步
if(me.collect_data.length == me.steps.length)
me.callback(me.collect_data);
else
me.next(result);
});
//繪製本步驟的UI
this.container.empty();
this.container.append("<h2>"+to_append[0]+"</h2>");
this.container.append(to_append[1]);
if(this.index > 0){
//後退按鈕
this.container.append($("<div class='bar'><a href='javascript:;'>後退</a></div>")
.click(function(){me.back()}
));
}
}
//執行下一步
Wizard.prototype.next = function(this_result){
if(this.index >= this.steps.length -1)
return;
var step = this.steps[++this.index];
this.render(step,this_result);
}
//後退到上一步
Wizard.prototype.back = function(){
if(this.index <= 0)
return;
var step = this.steps[--this.index];
//步驟回到上一步,但上一步的資料需要上上一步的結果來決定
this.collect_data = this.collect_data.slice(0, this.index);
this.render(step, this.collect_data[this.index - 1]);
}
4、小結
本嚮導結構簡單,可定製性強,結合了javascript的函數式編程特性和物件導向的特性,體現了javascript的強大和便利。
其中wizard類裡介面繪製的部分和步驟函數裡介面繪製的部分還是存在一些耦合,繼續重構的話,可以把所有繪製介面的部分再抽象到一起,使介面改動更方便。