八,food組件實現(xiàn)
1. 商品詳情頁
一個命名規(guī)范:methods命名的函數(shù)如果實在組件內(nèi)部私有的讼载,命名前加一個下劃線痕檬,如果是外部能調(diào)用的不用。
由于food圖片(image-header)大小不一致毅该,為了給food框定一個大小限制的寬高(圖片加載前也要留好空間),這里用一個黑科技:padding-top: 100% 相對于寬度來計算padding
潦牛。其實可以用width:100vw眶掌;height:100vw來實現(xiàn)啊,很優(yōu)雅巴碗,但是為了考慮到兼容性問題朴爬。
.image-header
position: relative
width: 100%
height: 0
padding-top: 100%
img
position: absolute
top: 0
left: 0
width: 100%
height: 100%
在做“加入購物車”和cartcontrol動畫的時候,注意第一次點擊加入購物車后這個div就消失了橡淆,所以getBoundingClientRect拿不到所在位置召噩。解決方法如下:給“加入購物車”加一個消失fade的動畫母赵。
記得給cartcontrol組件里面點擊事件加阻止冒泡哦。
現(xiàn)在在goods頁面點擊一個商品的+號按鈕蚣常,再進入第一個商品的商品詳情頁市咽,不管怎么點擊+號按鈕或者是點擊-號按鈕,數(shù)字一直是1抵蚊,并且有小球動畫。bug修復(fù)溯革。贞绳。,
2. split組件
教程中做了一個組件致稀。
split組件很小冈闭,而且沒有內(nèi)容,只有樣式抖单,其實也可以直接寫成一個公共樣式放在base文件里萎攒,然后通過類名直接調(diào)用,可以省去引用組件矛绘、注冊組件的環(huán)節(jié)耍休。
3. ratingselect組件
ratingselect組件是用在food組件里面以及評價路由中的。兩者的desc不太一樣货矮,結(jié)構(gòu)一樣羊精。
food中要在show函數(shù)里面初始化設(shè)定值,因為從good里面進去的不同的食物應(yīng)該都要初始化囚玫。
ratingselect組件中的點擊事件要傳給父組件喧锦,由于都是基礎(chǔ)類型(Number,Boolean)抓督,所以只能dispatch事件燃少。對應(yīng)到父組件food里面定義events。
events: {
'ratingtype.select'(type) {
this.selectType = type;
this.$nextTick(() => {
this.scroll.refresh();
});
},
'content.toggle'(onlyContent) {
this.onlyContent = onlyContent;
this.$nextTick(() => {
this.scroll.refresh();
});
}
}
注意要更新scrollDOM和刷新铃在,不然有回彈效果阵具。
4. 評價列表
v-show也可以綁定一個表達式,表達式是一個函數(shù)計算的結(jié)構(gòu)涌穆。
<li v-show="needShow(rating.rateType,rating.text)" v-for="rating in food.ratings" class="rating-item border-1px-dpr">...</li>
needShow(type, text) {
if (this.onlyContent && !text) {
return false;
}
if (this.selectType === ALL) {
return true;
} else {
return type === this.selectType;
}
}
評價item中的時間要從時間戳格式化怔昨。方法為用vue的filter方法。
filter在template中的寫法: <div class="time">{{rating.rateTime | formatDate}}</div>
宿稀。第一個參數(shù)是這個message趁舀,| 豎線后面是函數(shù),函數(shù)可以帶參數(shù)祝沸。
filters: {
formatDate(time) {
let date = new Date(time);
return formatDate(date, 'yyyy-MM-dd hh:mm');
}
}
filters函數(shù)中引用一個我們自定義的公用方法common/js/date.js
矮烹。模塊化編程的思想:
//common/js/date.js
export function formatDate(date, fmt) {
if (/(y+)/.test(fmt)) {
fmt = fmt.replace(RegExp.$1, date.getFullYear() + '').substr(4 - RegExp.$1.length);
}
let obj = {
'M+': date.getMonth() + 1,
'd+': date.getDate(),
'h+': date.getHours(),
'm+': date.getMinutes(),
's+': date.getSeconds()
};
for (let key in obj) {
if (new RegExp(`(${key})`).test(fmt)) {
let str = obj[key] + '';
fmt = fmt.replace(RegExp.$1, (RegExp.$1.length === 1) ? str : padLeftZero(str));
}
}
return fmt;
};
function padLeftZero(str) {
return ('00' + str).substr(str.length);
}
這里的寫法很巧妙越庇,注意學(xué)習。不帶花擴號的一般用于export default
; 帶花括號的用于export function XX
奉狈,花括號內(nèi)可以引多個不同的函數(shù)名字卤唉。
這一章最后老師發(fā)現(xiàn)了了一個報錯信息提示better-scroll傳進來的是null。分析是因為執(zhí)行router.go('/goods')的時候ratings頁面已經(jīng)沒有dom了仁期,但是betterscroll異步執(zhí)行拿不到數(shù)據(jù)桑驱。解決方法就是注釋掉router.go。
九跛蛋,seller組件實現(xiàn)
大部分內(nèi)容都和之前做過的知識點重復(fù)熬的。
這里的betterscroll用一個hack的方式實現(xiàn)。
首先嘗試在ready()的鉤子中初始化赊级,因為created不能保證DOM已經(jīng)渲染好押框,ready的時候渲染好了。然而這樣并不能滾動理逊,原因是ready的時候seller這個異步數(shù)據(jù)還沒有傳過來橡伞,并不能把高度撐開。接著我們嘗試把初始化代碼放在watch中晋被,watch觀測seller的變化從而執(zhí)行初始化滾動兑徘。然而又有一個問題出現(xiàn)了,在seller/goods/ratings導(dǎo)航欄切換的時候dom會重新渲染走一遍墨微,此時watch觀測的seller后端數(shù)據(jù)不會改變函數(shù)不起作用道媚。解決方法是在ready和watch中都寫上初始化代碼,切換導(dǎo)航欄的時候通過ready的refresh實現(xiàn)滾動翘县。
在實現(xiàn)商家實景圖的橫向滾動時最域,方法和前面的一樣,watch和ready中都要寫上初始化函數(shù)锈麸。better-srcoll橫向滾動的參數(shù)設(shè)置:scroll:true, eventPassthrough:'vertical'
注意這里ul的寬度沒有撐開镀脂,所以要手動在代碼里賦值真實高度。課程有人在提問里說只要觸發(fā)BFC就可以無需計算ul寬度忘伞。
這里唯一的和用戶交互的地方是“收藏商家”薄翅。絕對定位收藏div,注意給定一個width氓奈,這樣位置可以固定不會由于文字長度改變而改變翘魄。給這個favorite值做localstorage緩存。
在common/js中寫兩個文件舀奶。
// store.js
export function saveToLocal(id, key, value) {
let seller = window.localStorage.__seller__;
if (!seller) {
seller = {};
seller[id] = {};
} else {
seller = JSON.parse(seller);
if (!seller[id]) {
seller[id] = {};
}
}
seller[id][key] = value;
window.localStorage.__seller__ = JSON.stringify(seller);
};
export function loadFromLocal(id, key, def) {
let seller = window.localStorage.__seller__;
if (!seller) {
return def;
}
seller = JSON.parse(seller)[id];
if (!seller) {
return def;
}
let ret = seller[key];
return ret || def;
};
// util.js
/**
* 解析url參數(shù)
* @example ?id=12345&a=b
* @return Object {id:12345,a:b}
*/
export function urlParse() {
let url = window.location.search;
let obj = {};
let reg = /[?&][^?&]+=[^?&]+/g;
let arr = url.match(reg);
// ['?id=12345', '&a=b']
if (arr) {
arr.forEach((item) => {
let tempArr = item.substring(1).split('=');
let key = decodeURIComponent(tempArr[0]);
let val = decodeURIComponent(tempArr[1]);
obj[key] = val;
});
}
return obj;
};
修改App.vue暑竟。 為了router切換的時候避免DOM重新渲染,記住購物車信息等育勺,我們使用keep-alive但荤。Vue中推薦我們用Object.assign({},this.seller,response.data)
給對象擴展屬性的方法罗岖,這樣不會覆蓋本身的屬性。這里seller有id信息并顯示在url中腹躁。data中用立即執(zhí)行函數(shù)桑包。
// App.vue
<router-view :seller="seller" keep-alive></router-view>
...
<script type="text/ecmascript-6">
import {urlParse} from 'common/js/util';
import header from 'components/header/header.vue';
const ERR_OK = 0;
export default {
data() {
return {
seller: {
id: (() => {
let queryParam = urlParse();
return queryParam.id;
})()
}
};
},
created() {
this.$http.get('/api/seller?id=' + this.seller.id).then((response) => {
response = response.body;
if (response.errno === ERR_OK) {
this.seller = Object.assign({}, this.seller, response.data);
}
});
},
components: {
'v-header': header
}
};
</script>
在seller.vue中觀測改變favorite的localstorage存儲。
data() {
return {
favorite: (() => {
return loadFromLocal(this.seller.id, 'favorite', false);
})()
};
},
methods: {
toggleFavorite(event) {
if (!event._constructed) {
return;
}
this.favorite = !this.favorite;
saveToLocal(this.seller.id, 'favorite', this.favorite);
},
...
十纺非,項目編譯打包
**webpack **
npm run build 生成的東西在 dist文件夾中哑了。
extract-text-webpack-plugin可以把打包過程中的css提取出來生成獨立的文件。
打包后dist靜態(tài)資源交給后端或者cdn铐炫,后端需要實現(xiàn)ajax接口垒手。就是說dist 目錄可以發(fā)布到 cdn 源站,配置 webpack 的 publicpath 指定域名生成絕對路徑訪問倒信,也可以發(fā)布到后端服務(wù)器,通過相對路徑訪問泳梆。
souremap啟動是為了方便調(diào)試(配置config/index.js
中可以更改)鳖悠,真實生產(chǎn)環(huán)境中不讓調(diào)試的。
因為我們不能只做靜態(tài)文件优妙,這里教程中寫一個文件prod.server.js
做簡單的express起HTTP server乘综。從之前dev-server.js里面拷貝異步router。最后命令行中運行node prod.server.js
套硼。
記得在config/index.js
中寫上build環(huán)境下的端口號port卡辰。
代碼中配置請求的 ajax 地址,可以有類似如下的代碼:const debug = process.env.NODE_ENV !== 'production'
, const apiUrl = debug ? '線下ajax地址' : '線上ajax地址'
邪意。
app 可以通過 webview 渲染 h5 頁面九妈。
十二,vue1.0升級2.0
配置文件的修改
package.json, build目錄, config目錄雾鬼。
vue以及vue-router等都要變成2.0的萌朱。
幾個修改注意的地方
//webpack.base.conf.js
postcss: [
require('autoprefixer')({
browsers: ['last 2 versions', 'Android >= 4.0']
})
]
build目錄下多了一個check-versions.js,未來檢測當前npm和node版本策菜。
vue-router API
- 初始化路由變化晶疼。(看官網(wǎng)) render等
- v-link指令替換為<router-link>組件。
vue2.0 語法變化
- v-for又憨。 index翠霍、key
- v-el、v-ref蠢莺。替換為ref屬性
- 模版變化寒匙,組件只允許一個根元素。
- 組件通信變化浪秘,¥dispatch廢除蒋情。dispatch為子組件向父組件不斷冒泡埠况,而替換為emit在當前組件監(jiān)聽,即現(xiàn)在子組件上監(jiān)聽棵癣,父組件上定義辕翰,一種變通做法。
- 實踐監(jiān)聽變化狈谊,廢除events屬性喜命。
- 不能在子組件直接修改父組件傳入的prop。解決方法是用data或計算屬性修改河劝,或者像ratingselect組件那樣emit事件然后在父組件修改壁榕。
- 過渡的變化,transition組件赎瞎。視頻講解很詳細
- 小球下落動畫實現(xiàn)的變化牌里。有@before-enter,@enter,@after-enter幾個事件
- keep-alive屬性變?yōu)?lt;keep-alive>組件