商品列表頁一次添加多個規格


可能題目的表述不是特別清晰,具體有一下截圖看這會比較明顯

頁面上的功能描述
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    

<li class="noprivate" style="border:0px;">

添加幾個函數

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;
    }
}
在返回的處理函數中需要 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的那些行即可
所以把提交到購物車按鈕點擊事件的函數換一下

<href="javascript:;" onclick="check_car({$goods.goods_id})"><img src="images/bnt_cat.gif" /></a>

對應的函數如下

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));
}

到這這個功能算是完成,后面的就是一些頁面上的美化工作,這個功能做了一天半才完全搞定,有點慢了

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM