可能題目的表述不是特別清晰,具體有一下截圖看這會比較明顯
頁面上的功能描述
1. 當頁面加載完成后,需要根據不同規格的商品刷新出對應規格商品的價格,
2.重置默認數量,這個功能在input標簽中設置默認的value值即可,或者添加一個js函數,重置對應class集合中的值,這個不多說,比較簡單,
3.點擊添加購物車,需要把例如上圖中的不同規格中的商品能全部添加到購物車
解題思路,
要求1,這個任務比較簡單,由於這種方式,后台里的商品規格選項必須用單選按鈕來做,否則頁面效果不容易實現
具體要實現什么樣式自己來定義,我的代碼如下
1 <style> 2 .text-align{ text-align: center;} 3 #table_title li div{border: 1px solid red; font-size: 18px; font-weight: bold;} 4 </style> 5 <!--備注,由於需求限制這里只對單選的單選按鈕做出控制--> 6 <!--更改的購買流程開始--> 7 <div> 8 <!-- {* 開始循環所有可選屬性 *} --> 9 <!-- {foreach from=$specification item=spec key=spec_key} --> 10 11 <!--不用了屏蔽掉--> 12 <div class="te" style="disply:none;">{$spec.name}</div> 13 <!--不用了屏蔽掉--> 14 15 <ul id="table_title" style="width:100%;"> 16 <li> 17 <div class="f_l text-align" style="width: 50%;">Description</div> 18 <div class="f_l text-align" style="width: 12%;">TF Model</div> 19 <div class="f_l text-align" style="width: 12%;">Availability</div> 20 <div class="f_l text-align" style="width: 12%;">Price</div> 21 <div class="f_l text-align" style="width: 12%;">Quantity</div> 22 <div class="clear"></div> 23 </li> 24 </ul> 25 26 <!-- {* 判斷屬性是復選還是單選 *} --> 27 <!-- {if $spec.attr_type eq 1} --> <!--$spec.attr_type eq 1 是單選--> 28 <!-- {if $cfg.goodsattr_style eq 1} --> <!--單選按鈕--> 29 30 <ul style="width:100%;"> 31 <!--{foreach from=$spec.values item=value key=key} --> 32 <li class="noprivate" style="border:0px;"> 33 <div class="f_l" style="width: 50%;"> 34 {$value.label} 35 <input style="display:none" class="spec_value" id="spec_value_{$value.id}" type="radio" name="spec_{$spec_key}" value="{$value.id}" {if $key eq 0}checked{/if} /> 36 </div> 37 <div class="f_l text-align" style="width: 12%;">1212</div> 38 <div class="f_l text-align" style="width: 12%;">Availability</div> 39 <div class="f_l text-align" style="width: 12%;"> 40 <font id="price_{$value.id}">{$goods.shop_price_formated}</font> 41 </div> 42 <div class="f_l text-align" style="width: 12%;"> 43 <font id="plus"> 44 <var onclick="goods_cut(this);" class="imgl"><img src="images/classjj.gif"></var> 45 <input name="number" type="text" id="number" class="inum" value="1" size="4" onblur="changePrice();get_shipping_list(forms['ECS_FORMBUY'],{$goods.goods_id});"/> 46 <var onclick="goods_add(this);" class="imgr"><img src="images/classj.gif"></var> 47 </font> 48 </div> 49 <div class="clear"></div> 50 <input type="hidden" class="hidNum" name="hidNum" value="1"> 51 </li> 52 <!-- {/foreach} --> 53 </ul> 54 <input type="hidden" name="spec_list" value="{$key}" /> 55 <!-- {else} --><!--下拉菜單--> 56 <select name="spec_{$spec_key}" onchange="changePrice()"> 57 <!-- {foreach from=$spec.values item=value key=key} --> 58 <option label="{$value.label}" value="{$value.id}">{$value.label} {if $value.price gt 0}{$lang.plus}{elseif $value.price lt 0}{$lang.minus}{/if}{if $value.price neq 0}{$value.format_price}{/if}</option> 59 <!-- {/foreach} --> 60 </select> 61 <input type="hidden" name="spec_list" value="{$key}" /> 62 <!-- {/if} --> 63 <!-- {else} --> <!--多選--> 64 <!-- {foreach from=$spec.values item=value key=key} --> 65 <label for="spec_value_{$value.id}"> 66 <input type="checkbox" name="spec_{$spec_key}" value="{$value.id}" id="spec_value_{$value.id}" onclick="changePrice()" /> 67 {$value.label} [{if $value.price gt 0}{$lang.plus}{elseif $value.price lt 0}{$lang.minus}{/if} {$value.format_price|abs}] </label><br /> 68 <!-- {/foreach} --> 69 <input type="hidden" name="spec_list" value="{$key}" /> 70 <!-- {/if} --> 71 <!-- {/foreach} --> 72 <!-- {* 結束循環可選屬性 *} --> 73 </div> 74 75 <!--更改的購買流程結束--> 76 <div class="blank"></div>
由於空間編輯器可能識別代碼不是很好,建議復制出去看
這樣上面的樣式就出來了
這里去觀察原版的ecshop中,對於價格的刷新是利用了一個changePrice2函數來做ajax,所以這里我們根據已有的結構
<!--{foreach from=$spec.values item=value key=key} --> <li class="noprivate" style="border:0px;"> <div class="f_l" style="width: 50%;"> {$value.label}<input style="display:none" class="spec_value" id="spec_value_{$value.id}" type="radio" name="spec_{$spec_key}" value="{$value.id}" {if $key eq 0}checked{/if} /> </div> <div class="f_l text-align" style="width: 12%;">1212</div> <div class="f_l text-align" style="width: 12%;">Availability</div> <div class="f_l text-align" style="width: 12%;"> <font id="price_{$value.id}">{$goods.shop_price_formated}</font> </div> <div class="f_l text-align" style="width: 12%;"> <font id="plus"> <var onclick="goods_cut(this);" class="imgl"><img src="images/classjj.gif"></var> <input name="number" type="text" id="number" class="inum" value="1" size="4" onblur="changePrice();get_shipping_list(forms['ECS_FORMBUY'],{$goods.goods_id});"/> <var onclick="goods_add(this);" class="imgr"><img src="images/classj.gif"></var> </font> </div> <div class="clear"></div> <input type="hidden" class="hidNum" name="hidNum" value="1"> </li> <!-- {/foreach} --> <!--{foreach from=$spec.values item=value key=key} --> <li class="noprivate" style="border:0px;"> <div class="f_l" style="width: 50%;"> {$value.label}<input style="display:none" class="spec_value" id="spec_value_{$value.id}" type="radio" name="spec_{$spec_key}" value="{$value.id}" {if $key eq 0}checked{/if} /> </div> <div class="f_l text-align" style="width: 12%;">1212</div> <div class="f_l text-align" style="width: 12%;">Availability</div> <div class="f_l text-align" style="width: 12%;"> <font id="price_{$value.id}">{$goods.shop_price_formated}</font> </div> <div class="f_l text-align" style="width: 12%;"> <font id="plus"> <var onclick="goods_cut(this);" class="imgl"><img src="images/classjj.gif"></var> <input name="number" type="text" id="number" class="inum" value="1" size="4" onblur="changePrice();get_shipping_list(forms['ECS_FORMBUY'],{$goods.goods_id});"/> <var onclick="goods_add(this);" class="imgr"><img src="images/classj.gif"></var> </font> </div> <div class="clear"></div> <input type="hidden" class="hidNum" name="hidNum" value="1"> </li> <!-- {/foreach} -->
這里循環的是li
添加幾個函數
function noprivate(good_id){ var noprivate = document.getElementsByClassName("noprivate"); //alert(noprivate.length); for(i = 0; i < noprivate.length; i++){ changePrice2(noprivate[i]); } } /* * 專門用於處理頁面初始化完成后,對於屬性列表中的價格處理 * 仿照上面的changePrice函數來寫 */ function changePrice2(divElement){ var attr_arr = divElement.getElementsByClassName('spec_value'); var inum_arr = divElement.getElementsByClassName('hidNum'); var attr = attr_arr[0].value; var inum = inum_arr[0].value; Ajax.call('goods.php', 'act=price&id=' + {$goods_id} + '&attr=' + attr + '&number=' + inum, changePriceResponse2, 'GET', 'JSON'); } function changePriceResponse2(res){ if (res.err_msg.length > 0) { alert(res.err_msg); } else { // document.forms['ECS_FORMBUY'].elements['number'].value = res.qty; // // if (document.getElementById('ECS_GOODS_AMOUNT')) // document.getElementById('ECS_GOODS_AMOUNT').innerHTML = res.result; document.getElementById('price_' + res.attr).innerHTML = res.result; } }
但是這里的 具體這里為什么要這樣寫,需要研究一下那些input標簽里的屬性,觀察一下會有發現
attr的值在原函數中是沒有被返回的,這里在goods.php文件的if (!empty($_REQUEST['act']) && $_REQUEST['act'] == 'price')這里加入一行
$res['attr'] = $attr_id;這樣
res.attr就有值了
noprivate 的參數根據頁面變量來var goods_id = {$goods_id};也就是商品的id
這樣做ajax循環,就可以刷新出每種規格的商品的價格了
還有一個就是加減商品數量,這里比較簡單,稍微改造一下原函數就可以了
function goods_cut(obj){ var inum_arr = obj.parentNode.getElementsByClassName('inum'); var inum = inum_arr[0]; var new_num=inum.value; if(isNaN(new_num)){alert('請輸入數字');return false} var Num = parseInt(new_num); if(Num>0)Num=Num-1; inum.value=Num; } function goods_add(obj){ var inum_arr = obj.parentNode.getElementsByClassName('inum'); var inum = inum_arr[0]; var new_num=inum.value; var new_num=inum.value; if(isNaN(new_num)){alert('請輸入數字');return false} var Num = parseInt(new_num); Num=Num+1; inum.value=Num; }
下一步就是要根據不同規格商品的不同購買數量來提交到購物車,查看原函數可知,原本提交到購物撤是要在頁面中查找商品的屬性,然后來提交,這里只做了一個屬性,所以會比較簡單,如果是多個屬性,看看原函數怎么弄的就行
當要提交的時候,根據用戶需求,可能不是所有規格都會有一個數量》0 所以這里只要提交商品數量大於0的那些行即可
所以把提交到購物車按鈕點擊事件的函數換一下
對應的函數如下
function check_car(good_id){ //獲得被循環的li元素的集合 var noprivate = document.getElementsByClassName("noprivate"); var z = 0; var rei = new Array(); //循環這個集合 for(i = 0; i < noprivate.length; i++){ var inum_arr = noprivate[i].getElementsByClassName('inum'); //得到某一行的選定的數量 var inum = inum_arr[0].value; //如果數量大於零,那么就將這個行的行號存入數組中,用z變量來記錄總共需要提交的行數 if(inum > 0){ rei[z] = i; z++; } } //alert(rei); //這里來提交到購物車用上面的z來控制循環次數 for(y = 0; y < z; y++){ //rei[y] 里面存的是一個行號,這一行一定是購物數量大於0的, //noprivate[x]變量就是集合中的具體某一個,不多廢話了 var x = rei[y]; //如果條件成立,說明這是最后一次提交到購物車的操作,就傳遞給addToCart2一個(1) if((y+1) == z){ addToCart2(1, noprivate[x], good_id); } else{ addToCart2(0, noprivate[x], good_id); } } }
再來看addToCart2這個函數,也是要稍微改造一下的
/* * * 使用與本站的添加商品到購物車 */ function addToCart2(check_good, divElement, goodsId, parentId) { var attr_arr = divElement.getElementsByClassName('spec_value'); var inum_arr = divElement.getElementsByClassName('inum'); var attr = attr_arr[0].value; var inum = inum_arr[0].value; var goods = new Object(); var spec_arr = new Array(); //var fittings_arr = new Array();//這個變量好像原版里也沒有用到。 var number = 0; //var formBuy = document.forms['ECS_FORMBUY']; var quick = 0; //這里的處理邏輯需要改變,如果某一個屬性的購買數量大於0,那么就做ajax提交,否則就不提交到購物車,所以goods.quick 可以直接設置為1, if(parseInt(inum) > 0){ number = parseInt(inum); spec_arr = attr; quick = 1; goods.quick = quick; goods.spec = spec_arr; goods.goods_id = goodsId; goods.number = number; goods.parent = (typeof(parentId) == "undefined") ? 0 : parseInt(parentId); if(check_good == 1){ Ajax.call('flow.php?step=add_to_cart', 'goods=' + goods.toJSONString(), addToCartResponse, 'POST', 'JSON'); } else if(check_good == 0){ Ajax.call('flow.php?step=add_to_cart', 'goods=' + goods.toJSONString(), function(res){return 2;}, 'POST', 'JSON'); } } }
把這個函數對比一下原函數找一下區別把,就是查找屬性的時候不太一樣,再有就是最后的ajax提交,的返回不同,如果是最后一次才用addToCartResponse作為回調函數,其他情況用一個匿名函數function(res){return 2;},這里我返回2,其實無所謂,就是不寫都沒事,主要是讓客戶端程序不要有操作就可以了,
再來看看回調函數
/* * * 處理添加商品到購物車的反饋信息 */ function addToCartResponse(result) { if (result.error > 0) { // 如果需要缺貨登記,跳轉 if (result.error == 2) { if (confirm(result.message)) { location.href = 'user.php?act=add_booking&id=' + result.goods_id + '&spec=' + result.product_spec; } } // 沒選規格,彈出屬性選擇框 else if (result.error == 6) { openSpeDiv(result.message, result.goods_id, result.parent); } else { alert(result.message); } } else { //這里會更新屏幕上面的購物車數據 var cartInfo = document.getElementById('ECS_CARTINFO'); var cart_url = 'flow.php?step=cart'; //這里我屏蔽了,再下面會用到,其中result.content; 中的content元素在php文件中 //是這么定義的$result['content'] = insert_cart_info();至於insert_cart_info函數的作用自己看咯 // if (cartInfo) // { // cartInfo.innerHTML = result.content; // } if (result.one_step_buy == '1') { location.href = cart_url; } else { switch(result.confirm_type) { case '1' : //如果成功了就會進入到這里原函數中只是調用了opencartDiv(,,,,....)這個函數, //為什么用下面的ajax下面會解釋 Ajax.call( 'flow.php?step=re_select_cart', 'goods_id=' + result.goods_id, function(result){ if (cartInfo) { cartInfo.innerHTML = result.content; } opencartDiv(result.shop_price,result.goods_name,result.goods_thumb,result.goods_brief,result.goods_id,result.goods_price,result.goods_number); }, 'POST', 'JSON'); //opencartDiv(result.shop_price,result.goods_name,result.goods_thumb,result.goods_brief,result.goods_id,result.goods_price,result.goods_number); break; case '2' : if (!confirm(result.message)) location.href = cart_url; break; case '3' : location.href = cart_url; break; default : break; } } } }
if(check_good == 1){ Ajax.call('flow.php?step=add_to_cart', 'goods=' + goods.toJSONString(), addToCartResponse, 'POST', 'JSON'); } else if(check_good == 0){ Ajax.call('flow.php?step=add_to_cart', 'goods=' + goods.toJSONString(), function(res){return 2;}, 'POST', 'JSON'); }
這里按照道理來說是最后一個屬性提交后才會調用ajax,但是在實際中可能存在一個線程問題,就是前面的ajax還沒有執行完成,后面的ajax請求已經來了,所以前面的可能被服務器掛起,這樣當最后調用回調函數的時候,調用的數據就不是應該有的最后一次的執行結果,
又由於js本身沒有一個合適的休眠函數,好像就算是休眠也不見得很好用,所以這里在回調函數中,判斷執行成功后重新發起一次ajax請求,重新獲得頁面上想要的數據所以
case '1' :
Ajax.call(
'flow.php?step=re_select_cart',
'goods_id=' + result.goods_id, //要記得傳遞商品的id,這個id是從當前的回調數據中取得
function(result){
if (cartInfo)
{
cartInfo.innerHTML = result.content;
}
opencartDiv(result.shop_price,result.goods_name,result.goods_thumb,result.goods_brief,result.goods_id,result.goods_price,result.goods_number);
},
'POST',
'JSON');
//opencartDiv(result.shop_price,result.goods_name,result.goods_thumb,result.goods_brief,result.goods_id,result.goods_price,result.goods_number);
break;
case ‘1’ 內部的這個ajax請求就誕生了
對應的php代碼 flow.php文件中找到$_REQUEST['step'] == 'add_to_cart'
在這個代碼段的下面添加一段查詢代碼
elseif($_REQUEST['step'] == 're_select_cart')
{
//加載json類,ecshop里面都沒有用php自帶的json函數,可能是由於歷史原因
include_once('includes/cls_json.php');
$goods_id = $_REQUEST['goods_id'];//接收參數
$json = new JSON;//實例化json類
$rows = $GLOBALS['db']->getRow("select goods_brief,shop_price,goods_name,goods_thumb,promote_price from ".$GLOBALS['ecs']->table('goods')." where goods_id=".$goods_id);
$result['shop_price'] = price_format($rows['shop_price']);
$result['goods_name'] = $rows['goods_name'];
$result['goods_thumb'] = $rows['goods_thumb'];
$result['goods_brief'] = $rows['goods_brief'];
if ($rows['promote_price'] > 0)
{
$result['shop_price'] = price_format($rows['promote_price']);
}
else
{
$result['shop_price'] = price_format($rows['shop_price']);
}
$result['goods_id'] = $goods_id;
$sql = 'SELECT SUM(goods_number) AS number, SUM(goods_price * goods_number) AS amount' .
' FROM ' . $GLOBALS['ecs']->table('cart') .
" WHERE session_id = '" . SESS_ID . "' AND rec_type = '" . CART_GENERAL_GOODS . "'";
$rowss = $GLOBALS['db']->GetRow($sql);
$result['goods_price'] = price_format($rowss['amount']);
$result['goods_number'] = $rowss['number'];
$result['confirm_type'] = !empty($_CFG['cart_confirm']) ? $_CFG['cart_confirm'] : 2;
//這里要重新執行一邊$result['content'] = insert_cart_info(); //這個數據是提供給給頁面頭部里的購物車數據
$result['content'] = insert_cart_info();
die($json->encode($result));
}
到這這個功能算是完成,后面的就是一些頁面上的美化工作,這個功能做了一天半才完全搞定,有點慢了