上一篇文章學(xué)習(xí)如何簡(jiǎn)單開始一個(gè)Angular程序,跟著網(wǎng)上的教程我也來(lái)實(shí)現(xiàn)一個(gè)購(gòu)物車功能戈盈,為了減少頁(yè)面樣式設(shè)計(jì)我使用了bootstrap來(lái)偷懶奠衔,下面先來(lái)看看我做的demo谆刨,效果圖如下:
一、代碼
如果看了這個(gè)效果還有興趣想知道怎么做出來(lái)的話归斤,那就繼續(xù)往下看吧痊夭。,廢話補(bǔ)多少脏里,直接上代碼她我。
代碼地址: https://github.com/wangqingqiang/Angularjs
html代碼:
<pre>
<!DOCTYPE html>
<html lang="en" ng-app="cart">
<head>
<meta charset="UTF-8">
<title>購(gòu)物車</title>
<link rel="stylesheet" href="../scripts/angular-1.4.0-rc.2/docs/components/bootstrap-3.1.1/css/bootstrap.min.css">
<link rel="stylesheet" href="main.css">
</head>
<body ng-controller="cartCtr">
<table class="table table-hover" ng-show="items.length">
<caption>AngularJS實(shí)現(xiàn)購(gòu)物車</caption>
<tr>
<th>序號(hào)</th>
<th>商品信息</th>
<th>單價(jià)(元)</th>
<th>數(shù)量</th>
<th>金額(元)</th>
<th>操作</th>
</tr>
<tr ng-repeat=" item in items">
<td>{{$index + 1}}</td>
<td><a href="{{item.linkUrl}}" target="_blank" title="此鏈接將跳轉(zhuǎn)到淘寶相關(guān)頁(yè)面...">{{item.title}}</a></td>
<td class="bold">{{item.price|number:2}}</td>
<td>
<button type="button" class="btn btn-default btn-xs" ng-click="reduce(item.id)" ng-disabled="item.quantity<=1">-</button>
<input type="text" size="5" ng-model="item.quantity" ng-keydown="quantityKeydown()" ng-keyup="quantityKeyup()">
<button type="button" class="btn btn-default btn-xs" ng-click="add(item.id)">+</button>
</td>
<td class="bold mark">{{item.price*item.quantity|number:2}}</td>
<td>
<button type="button" class="btn btn-default btn-xs" ng-click="delete(item.id)">刪除</button>
</td>
</tr>
</table>
<div class="empty" ng-show="!items.length">購(gòu)物車空空屠凶,快去尋找寶貝</div>
<div class="total">
已選商品:<span>{{getQuantites()}} </span>
合計(jì):
<span class=" mark" ng-show="getTotalAmount()<15000">{{getTotalAmount()|number:2}}</span>
<span class=" mark" ng-show="getTotalAmount()>=15000">
{{getTotalAmount()*discount|number:2}}<span class="btn btn-xs">(9折)</span>
<span class="discount">({{getTotalAmount()|number:2}})</span>
</span>
<button type="button" class="btn btn-primary btn-sm" ng-click="alertSubmit()">結(jié) 算</button>
</div>
<script src="../scripts/angular-1.4.0-rc.2/angular.js"></script><script src="app.js"></script>
</body>
</html>
</pre>
js代碼:
<pre>
/* Created by wqq on 2016/5/25. */
var cartModule = angular.module('cart', []);
cartModule.controller('cartCtr', ['$scope', function ($scope) {
$scope.discount = 0.9;
$scope.items = [{id: 10001,title: "Web全棧工程師的自我修養(yǎng) 余果", price: 40.80,quantity: 2,linkUrl: "https://detail.tmall.com/item.htm?spm=a1z0d.6639537.1997196601.4.cwywJs&id=532166746631"},
{id: 10002,title: "MacBook Pro Retina 15英寸", price: 16088.00,quantity: 1,linkUrl: "https://detail.tmall.com/item.htm?spm=a1z0d.6639537.1997196601.26.cwywJs&id=45771116847"},
{id: 10003,title: "Surface Book I5 128G 獨(dú)顯",price: 11088.00, quantity: 1,linkUrl: "https://detail.tmall.com/item.htm?spm=a1z0d.6639537.1997196601.15.cwywJs&id=525614504276"},
{id: 10004, title: "Lenovo Yoga3Pro I5 4G",price: 7299.00, quantity: 1,linkUrl: "https://detail.tmall.com/item.htm?spm=a1z0d.6639537.1997196601.37.cwywJs&id=41541519814"} ];
$scope.add = function (id) {
angular.forEach($scope.items, function (item, index, array) {
if (item.id === id) {item.quantity++;} })
};
$scope.reduce = function (id) {
angular.forEach($scope.items, function (item, index, array) {
if (item.id === id) {item.quantity--; } })
};
//輸入框添加keydown事件涌萤,避免輸入非正整數(shù)
$scope.quantityKeydown = function (event) {
event = event || window.event;
var target=event.target||event.srcElement;
var keycode = event.keyCode;
if ((37 <= keycode && keycode <= 40)||(48 <= keycode && keycode <= 57) || (96 <= keycode && keycode <= 105) || keycode == 8) {
//方向鍵↑→ ↓←、數(shù)字鍵捍歪、backspace
}
else {
console.log(keycode);
event.preventDefault();
return false;
}
};
//keyup事件矾踱,當(dāng)輸入數(shù)字為0時(shí)恨狈,重新刷新文本框內(nèi)容
$scope.quantityKeyup = function (event) {
event = event || window.event;
var target=event.target||event.srcElement;
var keycode = event.keyCode;
if (48 === keycode || 96 === keycode ) {
target.value=parseInt(target.value);
}};
//刪除商品
$scope.delete = function (id) {
$scope.items.forEach(function (item, index) {
if (item.id == id) {
if (confirm("確定要從購(gòu)物車中刪除此商品?")) {
$scope.items.splice(index, 1);
return;
}
}
})
};
//計(jì)算已選商品數(shù)量
$scope.getQuantites = function () {
var quantities = 0;
angular.forEach($scope.items, function (item, index, array) {
if (item.quantity) {
quantities += parseInt(item.quantity);
}
});
return quantities;
};
//計(jì)算合計(jì)總金額
$scope.getTotalAmount = function () {
var totalAmount = 0;
angular.forEach($scope.items, function (item, index, array) {
totalAmount += item.quantity * item.price; });
return totalAmount;
};
$scope.alertSubmit = function () {alert("Angular實(shí)現(xiàn)購(gòu)物車"); }
}]);
</pre>
二呛讲、分析
請(qǐng)忽略bootstrap的樣式拴事,我們只關(guān)注Angular,代碼很簡(jiǎn)單圣蝎,我們來(lái)簡(jiǎn)單的分析一下:
1. 準(zhǔn)備
首先我們我們定義了一個(gè)cart模塊刃宵、cartCtr控制器,并將它們引入到了html代碼中徘公,同時(shí)我們還在js中定義了一個(gè)數(shù)組items用于模擬購(gòu)物車內(nèi)的東西牲证。
2. ng-repeat迭代器
為了將items里的數(shù)據(jù)動(dòng)態(tài)的遍歷加載出來(lái),我們使用Angular里的內(nèi)置指令ng-repeat关面,它可以非常方便的遍歷數(shù)組坦袍,生成DOM元素,在這里循環(huán)生成了4個(gè)<tr>標(biāo)簽:
<code><tr ng-repeat=" item in items"></code>
item就是items數(shù)組里面的某一個(gè)對(duì)象等太,是不是感覺這就是js中的for/in循環(huán)~~如果你是一名.net開發(fā)人員捂齐,用過asp.net mvc的Razor就對(duì)這種其他語(yǔ)言無(wú)縫操作DOM元素很熟悉了,至于java缩抡、PHP是否有沒有類似的語(yǔ)法我就不清楚了奠宜,我是一名苦逼的.net開發(fā)。
我們可以看到第一個(gè)td中用到了$index,這是ng-repeat內(nèi)的瞻想,并不是我們定義的压真,它的值是當(dāng)前item在items中的索引,從0開始蘑险,所以我們用$index+1作為序號(hào)滴肿,其他的(類似item.linkUrl)數(shù)據(jù)綁定在上一節(jié)中已經(jīng)介紹過了。
我們?cè)趩蝺r(jià)和金額兩列用到了{(lán){ xxx|number:2}}佃迄,這是Angular中的一種過濾器泼差,作用是將前面的值xxx保留兩位小數(shù)贵少,金額嘛,我們當(dāng)然要精確一些堆缘。剛才說了這是一種過濾器滔灶,那就還有其他的,比如currency套啤,可以在xxx前面添加一個(gè)$符號(hào)表示美元,可以自行百度其他過濾器用法随常。
3. 添加事件
當(dāng)前界面上分別有數(shù)量+潜沦、-按鈕、刪除按鈕绪氛,這幾個(gè)事件都比較簡(jiǎn)單唆鸡,利用ng-click給元素添加點(diǎn)擊事件。通過傳遞某個(gè)商品的id枣察,找到這個(gè)商品争占,對(duì)這個(gè)商品進(jìn)行加、減序目、刪除操作臂痕,只不過在“-”按鈕上有添加了一個(gè)ng-disabled標(biāo)簽,根據(jù)名字我們就可以很容易想到html的disabled屬性猿涨,它的作用就是當(dāng)ng-disabled的值為true時(shí)DOM元素禁用握童,同理,下面用到的ng-show也是一樣的叛赚,true時(shí)顯示澡绩,false時(shí)隱藏。如果是數(shù)字的話會(huì)自動(dòng)轉(zhuǎn)化為boolean值俺附,0是false肥卡,非0是true,注意負(fù)數(shù)也是true事镣!步鉴。這里我讓當(dāng)數(shù)量為1時(shí)就不能減少了,因?yàn)樵偕倬涂梢灾苯觿h除了呀~
然后在input元素添加ng-keydown事件璃哟,使其只能輸入方向鍵↑→ ↓←唠叛、數(shù)字鍵、backspace沮稚。然后我試了下確實(shí)到達(dá)了目的艺沼,但是卻可以輸入類似“00021”這種數(shù)字,顯然這并不能令人滿意蕴掏。我看了看淘寶的購(gòu)物車障般,發(fā)現(xiàn)當(dāng)在前面輸入0時(shí)调鲸,這個(gè)文本框的內(nèi)容會(huì)自動(dòng)刷新,去掉前面的0挽荡,于是我又添加了ng-keyup事件:
<pre>
$scope.quantityKeyup = function (event) {
event = event || window.event; //兼容IE8以下藐石,target也是
var target=event.target||event.srcElement;
var keycode = event.keyCode;
if (48 === keycode || 96 === keycode ) {
target.value=parseInt(target.value);
}};
</pre>
這時(shí)當(dāng)我輸入0時(shí),文本框值就會(huì)自動(dòng)刷新定拟,為什么不添加到keydown里面而要另外再加一個(gè)事件呢于微?那是因?yàn)?strong>觸發(fā)keydown事件時(shí)target.value的值還是原來(lái)的值,還沒有包含本次輸入的按鍵青自,而在keydown之后值就是新值了株依,這時(shí)候我們接著讓觸發(fā)keyup事件就可以達(dá)到目的了,可以對(duì)照看下淘寶購(gòu)物車的效果延窜,我覺得我的體驗(yàn)比它的更好恋腕,因?yàn)樗灰皇窃谧詈筝斎霐?shù)字文本框總是會(huì)失去焦點(diǎn)。逆瑞。荠藤。
4. 統(tǒng)計(jì)
統(tǒng)計(jì)數(shù)量就是直接綁定方法,遍歷數(shù)組返回值获高。
合計(jì)金額這塊哈肖,我做了個(gè)滿15000打9折的設(shè)計(jì)。利用ng-show隱藏顯示帶打折信息的合計(jì)金額念秧。
三牡彻、總結(jié)
js中用到了幾處forEach遍歷數(shù)組,ECMAScript5中原生的方法是array.forEach(function(item,index,array){});
angular中也封裝了出爹,angular.forEach(array,function(item,index,array){});
代碼中我兩種方法都用到了庄吼,也不知道那種性能好。严就。
至此总寻,購(gòu)物車就已經(jīng)完成了,利用Angular的雙向綁定梢为,可以快速的實(shí)現(xiàn)數(shù)量渐行、金額的聯(lián)動(dòng)改變。