視頻學習網址:http://www.imooc.com/learn/796javascript
源碼打包:https://codeload.github.com/fachaoshao/Vue-ShoppingCart/zip/master(before爲老師未寫功能的源碼,after爲實現功能後的源碼);html
注意:以上源碼請在 Apache 打開狀態打開瀏覽;前端
該教程在功能上實現了:vue
1)將 .json文件數據發送http請求,經過遍歷數組將數據渲染到頁面;java
2)建立過濾器實現了價格加「¥」和保留2位小數,分局部過濾器和全局過濾器;
3)實現了全選和取消全選的功能,經過v-bind:class
4)實現商品金額的計算和刪除功能;
5)收貨地址的卡片選擇和設置默認地址;react
下面說說我在該課程中get到的知識jquery
在近期對 Vue 2.0 輪番轟炸般的學習以後,瞭解到 vue 這個框架是一個輕量級、高性能的js框架,在處理高併發的事件時vue較原生js或者jquery具備很是好的優點,由於他是一個MVVM模式(Model-View-ViewModel)的一個設計模式,以數據驅動爲爲核心思想,當數據發生變化的時候,用戶界面發生相應的變化,開發者不須要手動的去修改dom.也就是說,vuejs幫咱們封裝了數據和dom對象操做的映射,咱們只須要關心數據的邏輯處理,數據的變化就可以天然的通知頁面進行頁面的從新渲染。git
MVVM框架angularjs
Vuejs的數據驅動是經過MVVM這種框架來實現的。MVVM框架主要包含3個部分:model、view和 viewmodel。es6
Model:指的是數據部分,對應到前端就是javascript對象
View:指的是視圖部分,對應前端就是dom
Viewmodel:就是鏈接視圖與數據的中間件
數據(Model)和視圖(View)是不能直接通信的,而是須要經過ViewModel來實現雙方的通信。當數據變化的時候,viewModel可以監聽到這種變化,並及時的通知view作出修改。一樣的,當頁面有事件觸發時,viewMOdel也可以監聽到事件,並通知model進行響應。Viewmodel就至關於一個觀察者,監控着雙方的動做,並及時通知對方進行相應的操做,這樣就造成了以數據的雙向綁定。
數據響應原理
數據(model)改變 驅動 視圖(view)自動更新
首先,vuejs在實例化的過程當中,會對遍歷傳給實例化對象選項中的data 選項,遍歷其全部屬性並使用 Object.defineProperty 把這些屬性所有轉爲 getter/setter。
同時每個實例對象都有一個watcher實例對象,他會在模板編譯的過程當中,用getter去訪問data的屬性,watcher此時就會把用到的data屬性記爲依賴,這樣就創建了視圖與數據之間的聯繫。當以後咱們渲染視圖的數據依賴發生改變(即數據的setter被調用)的時候,watcher會對比先後兩個的數值是否發生變化,而後肯定是否通知視圖進行從新渲染。
這樣就實現了所謂的數據對於視圖的驅動。
下面詳細說下慕課網《使用vue2.0實現購物車和地址選配功能》功能實現的總結
1)將 .json文件數據發送http請求,經過遍歷數組將數據渲染到頁面;
在methods:裏面定義方法:發送http請求,得到json數據
cartView: function () {
// var _this = this;
this.$http.get('data/cartData.json').then(res=>{
//此處使用了箭頭函數,使得內部的this與外部this保持一致,能夠不用上面聲明的
//_this了
this.productList = res.data.result.list;
// this.totalMoney = res.data.result.totalMoney;
})
},
使用了v-for,v-model,v-bind(:),v-if,v-on(@click)等基本api指令,將數據渲染到頁面
2)建立過濾器實現了價格加「¥」和保留2位小數,分局部過濾器和全局過濾器;
局部過濾器,寫在new Vue({})的 選項 裏面
filters:{// 局部過濾器,在做用域內調用 formatMoney:function(value){ return "¥"+value.toFixed(2)+ '元' } }
經過管道符號改變數據內容 {{ item.productPrice | formatMoney }} ¥19.00元
全局過濾器
Vue.filter('money',function(value,type) {// 全局過濾器,在全局範圍內可用 return "¥"+value.toFixed(2) + type; });經過管道符號改變數據內容 {{totalMoney | money('元')}} ¥256.00元 區別於局部過濾器,在vue2.0中,定義的全局過濾器是一個函數,money中傳入的參數 「元」 是第二個參數 type,
參考(https://cn.vuejs.org/v2/guide/migration.html#過濾器參數符號-變動)
3)實現了全選和取消全選的功能,經過v-bind:class
單選按鈕:
<a href="javascript:;" class="item-check-btn" v-bind:class="{'check':item.checked}"
v-on:click="selectedProduct(item)" >
selectedProduct: function (item) { if(typeof item.checked == "undefined"){ // Vue.set(item,'checked',true); // 全局註冊 this.$set(item,'checked',true) }else{ item.checked = !item.checked; }; this.calcTotalPrice(); },若是item裏面的checked不存在,就給他註冊一個變量(通常都是在data裏面註冊一個變量的),而且設置值爲true,這樣在頁面就能夠顯示被選中狀態;
全選/取消全選按鈕:
綁定一個點擊函數,傳值爲true,就全選,false就取消全選
注意到:var _this = this;是es5的語法。要是採用es6的箭頭函數,內部this就和外部this保持一致了
這裏的思路是:傳入的flag(true/false)保存在checkAllFlag中,遍歷productList item.checked沒被建立,我建立一個,設置他們的值都爲checkAllFlag,若建立了,直接設置爲checkAllFlag。這個遍歷的過程就達到了一個 全選/取消全選 的目的。
<span class="item-check-btn" :class="{'check':checkAllFlag}" @click="checkAll(true)">全選按鈕
<a href="javascript:void 0" class="item-del-btn" @click="checkAll(false)">取消全選按鈕
checkAll: function (flag) { this.checkAllFlag = flag; var _this = this; this.productList.forEach(function(item,index){ if(typeof item.checked == "undefined"){ // Vue.set(item,'checked',true); // 全局註冊 _this.$set(item,'checked',_this.checkAllFlag) }else{ item.checked = _this.checkAllFlag } }); this.calcTotalPrice(); },
這裏有單個商品的金額計算和總金額的計算
單個商品的金額計算:{{ item.productPrice * item.productQuantity | money('元')}}
總金額的計算:{{totalMoney | money('元')}}
而後就是改變單個商品數量以及選中商品或者全選商品,要是的總金額動態改變
首先定義一個函數:calcTotalPrice,設置this.totalMoney = 0;爲何呢?由於你每次金額變動前都得把總金額設置爲0吧,否則在前面的基礎上運算,好比我前面點擊選中了,總金額變了,而後我取消了,總金額依然是以前的,因此得設置this.totalMoney = 0,每次計算前清0;
遍歷數組productList
_this.totalMoney += item.productPrice*item.productQuantity; 疊加數組紅全部商品金額就是總金額了
以後考慮選中與未選中以及全選和取消全選致使的總金額變化,因此他們都得調一次this.calcTotalPrice();實現總金額的計算;
changeMoney:function (product,way) { if(way>0){ product.productQuantity++; }else{ product.productQuantity--; if(product.productQuantity < 1){ product.productQuantity = 1 } }; this.calcTotalPrice(); }, selectedProduct: function (item) { if(typeof item.checked == "undefined"){ // Vue.set(item,'checked',true); // 全局註冊 this.$set(item,'checked',true) }else{ item.checked = !item.checked; }; this.calcTotalPrice(); }, checkAll: function (flag) { this.checkAllFlag = flag; var _this = this; this.productList.forEach(function(item,index){ if(typeof item.checked == "undefined"){ // Vue.set(item,'checked',true); // 全局註冊 _this.$set(item,'checked',_this.checkAllFlag) }else{ item.checked = _this.checkAllFlag } }); this.calcTotalPrice(); }, calcTotalPrice:function(){ var _this = this; this.totalMoney = 0; this.productList.forEach(function(item,index){ if(item.checked){ _this.totalMoney += item.productPrice*item.productQuantity; } }); },
首先依然是遍歷出 .json裏面的地址,注意到這裏的 v-for="(address,index) in filterAddress",相比angular中的ng-repeat = "(index,address) in filterAddress" , angularjs是先寫下標,再寫值,注意啊,正好相反。vue 1.0中也是(index,address)與angualr相同;
這裏我就把js代碼都放上來了,不分段截取了
能夠看到也是先發送$http請求,獲取數據,注意獲取的數據保存在response.data中,而不是子response中,作項目是能夠查看下;
爲了作加載更多,咱們先讓它顯示3條數據,因此咱們設置limitNum:3, 在computed中 return this.addressList.slice(0,this.limitNum),全部咱們得遍歷filterAddress 的數據,當咱們點擊more時,@click="loadMore",觸發loadMore函數,this.limitNum = this.addressList.length,就能夠加載addressList中全部的地址了
卡片地址選擇:把點擊的index賦值給currentIndex,當index==currentIndex時,顯示被選中,這個挺重要的
<li v-for="(address,index) in filterAddress" :class="{'check':index == currentIndex}"
@click="currentIndex = index">
new Vue({
el:'.container',
data:{
addressList:[],
limitNum:3,
currentIndex:0,
shippingMethods:1
},
mounted: function () {
this.$nextTick(function () {
this.getAddressList()
})
},
methods:{
getAddressList:function(){
this.$http.get("data/address.json").then(response=>{
console.log(response)
var res = response.data;
this.addressList = res.result;
})
},
loadMore:function(){
this.limitNum = this.addressList.length
},
setDefault:function(addressId){
this.addressList.forEach(function(address,index){
if(address.addressId == addressId){
address.isDefault = true;
}else{
address.isDefault = false;
}
})
}
},
computed:{
filterAddress:function(){
return this.addressList.slice(0,this.limitNum)
}
}
})
設置默認地址:
v-if="!address.isDefault" @click="setDefault(address.addressId)">設爲默認
<div class="addr-opration addr-default" v-if="address.isDefault">默認地址
v-if控制顯示與隱藏,當點擊設爲默認觸發setDefault,傳的addressId值,設置當前點擊的addressId爲默認地址
<li v-bind:class="{'check':shippingMethods == 1}" @click="shippingMethods=1">標準配送
<li class="name" v-bind:class="{'check':shippingMethods == 2}" @click="shippingMethods=2">高級配送
選中狀態爲check,標準配送 shippingMethods == 1決定check顯示選中,當點擊標準配送時
shippingMethods == 1,
當點擊高級配送時shippingMethods == 2,經過修改shippingMethods值決定顯示誰!
上述文字都是我的看法,不當之處,還請各位指正!
參考文獻:
https://cn.vuejs.org/v2/guide/reactivity.html
http://www.cnblogs.com/caizhenbo/p/6418284.html
http://www.cnblogs.com/caizhenbo/p/6710174.html