主要頁(yè)面
分別是主頁(yè)流行,書單,書單詳情,我的頁(yè)面(喜歡)
項(xiàng)目gif圖部分展示
gif圖太大,不好一一做展示
對(duì)整個(gè)項(xiàng)目做一個(gè)回顧和復(fù)盤總結(jié),整個(gè)項(xiàng)目是由12個(gè)組件,4個(gè)頁(yè)面構(gòu)成,我們就按頁(yè)面的構(gòu)成來(lái)復(fù)盤整個(gè)項(xiàng)目
首先是首頁(yè)(流行):
首頁(yè)主要由like(喜歡)組件,epsoid(月份),classic(電影,音樂(lè),詩(shī)歌)組件構(gòu)成;
like(喜歡)組件:
1.組件主要是接收外部傳過(guò)來(lái)的2個(gè)參數(shù),一個(gè)是喜歡的狀態(tài),一個(gè)是喜歡的數(shù)量,拿到后在組件內(nèi)直接進(jìn)行渲染
2.重點(diǎn)是點(diǎn)擊事件的邏輯要在父組件進(jìn)行處理,子組件只負(fù)責(zé)觸發(fā)點(diǎn)擊事件,并且把當(dāng)前的狀態(tài)傳給父組件,如果放在組件里面進(jìn)行業(yè)務(wù)邏輯處理,那這個(gè)組件的復(fù)用性就會(huì)比較差
//喜歡組件的點(diǎn)擊事件處理
methods: {
typeoff: function(event) {
//喜歡的數(shù)量
let num = this.data.num;
//根據(jù)當(dāng)前l(fā)ike的狀態(tài)判斷是加1還是減1
num = this.data.like ? num - 1 : num + 1;
this.setData({
num: num,
like: !this.properties.like
})
//當(dāng)前l(fā)ike組件的狀態(tài)
let behavier = this.properties.like ? 'like' : 'cancel'
//激活事件,把like狀態(tài)傳給父組件
this.triggerEvent('like',{
behavier:behavier
},{})
}
當(dāng)前月份組件:
1.主要接收外部穿過(guò)來(lái)的當(dāng)前書刊序號(hào),接口返回的數(shù)據(jù)是中文月份,主要實(shí)現(xiàn)的方式通過(guò)私有組件中的observer屬性實(shí)現(xiàn)屬性計(jì)算,并返回對(duì)應(yīng)的月份
2.observer每當(dāng)接收數(shù)值的這個(gè)值發(fā)生了變化,他就會(huì)執(zhí)行一次
Component({
properties: {
index: {
type: String,
//observer類似于vue中的wacth,每當(dāng)這個(gè)index的值發(fā)生改變,這個(gè)ob函數(shù)就會(huì)執(zhí)行
//無(wú)限遞歸的原因,不斷的執(zhí)行ob函數(shù)
observer:function(newVal,odlVal){
let val = newVal < 10? '0'+ newVal : newVal;
this.setData({
_index:val
})
}
},
},
/**
* 頁(yè)面的初始數(shù)據(jù)
*/
data: {
arr: ['一月', '二月', '三月', '四月', '五月', '六月', '七月', '八月', '九月', '十月', '十一月','十二月'],
year:'',
month:'',
_index:''
},
//第一次加載的時(shí)候會(huì)執(zhí)行,在attached加載后就加載onload
attached:function(){
let time = new Date();
this.setData({
year: time.getFullYear(),
month: this.data.arr[time.getMonth()]
})
console.log(this.data);
},
})
頁(yè)面展示組件(電影,詩(shī)歌,音樂(lè))
包括三個(gè)子組件音樂(lè),詩(shī)歌,電影,他們都有自己的公用屬性,img,center屬性,后臺(tái)會(huì)根據(jù)類容的不同返回不同的type值
在首頁(yè)接收到返回的數(shù)據(jù)的時(shí)候,通過(guò)返回?cái)?shù)據(jù)中的type值,就可以判斷是什么類型
<move wx:if="{{classic.type===100}}" img="{{classic.image}}" centent="{{classic.content}}" />
<music wx:if="{{classic.type===200}}" img="{{classic.image}}" centent="{{classic.content}}" src="{{classic.url}}" />
<essay wx:if="{{classic.type===300}}" img="{{classic.image}}" centent="{{classic.content}}" />
重點(diǎn):當(dāng)每次點(diǎn)擊的時(shí)候都需要發(fā)送一次請(qǐng)求,于是想到用本地緩存來(lái)進(jìn)行優(yōu)化
思路:
1.當(dāng)每次點(diǎn)擊都會(huì)發(fā)送一次新的請(qǐng)求,把這次的請(qǐng)求數(shù)據(jù)存在,通過(guò)每次請(qǐng)求后返回?cái)?shù)據(jù)中的index去做為key
2.每次點(diǎn)擊的的時(shí)候,都會(huì)傳入一個(gè)index到一個(gè)方法中,這個(gè)方法會(huì)根據(jù)當(dāng)前的index的值作為參數(shù)去本地緩存中拿數(shù)據(jù),如果拿到的數(shù)據(jù)不為空,就直接把拿到的數(shù)據(jù)作為參數(shù)返回
3.如果拿到的數(shù)據(jù)為空就發(fā)送請(qǐng)求,并且把這次請(qǐng)求存到本次緩存中
class ClassicModel extends HTTP{
//獲取最新的樣刊,頁(yè)面加載的時(shí)候
getlatest(callback){
this.request({
url: 'classic/latest',
success: (data) => {
callback(data);
//把最新期刊加載的key存入
let key = this._name(data.data.index);
//設(shè)置本地存儲(chǔ),把當(dāng)前最新的的key存入一個(gè)data
wx.setStorageSync(key,data);
//把當(dāng)前的index傳入方法,方法會(huì)根據(jù)傳入的最新期刊的index,在緩存中設(shè)置一個(gè)當(dāng)前的最新期刊對(duì)應(yīng)的index值
this._setindex(data.data.index);
}
})
}
//每當(dāng)點(diǎn)擊下一頁(yè)或者上一頁(yè)
_getClassic(index,name,callback){
// 1.key的名字,如果是向左名字就是class拼接index+1,否則就是減1
// let key = name == 'next' ? 'classic' + (index + 1) : 'classic'+ (index-1);
let key = name == 'next' ? this._name(index + 1) : this._name(index-1);
//取出本地的緩存數(shù)據(jù)
let classic = wx.getStorageSync(key);
//如果取出來(lái)的數(shù)據(jù)是undefined
if(!classic){
//發(fā)送請(qǐng)求
this.request({
url:'classic/'+ index + '/'+ name,
success:(data=>{
//請(qǐng)求成功后
//1.記錄當(dāng)前寫入的數(shù)據(jù)名稱
let key = this._name(data.data.index);
//2.寫入數(shù)據(jù)
wx.setStorageSync(key,data)
//3.把data作為參數(shù)傳入
callback(data)
})
})
//如果取出來(lái)的不是空,就直接把取出來(lái)的classic數(shù)據(jù)傳入
}else{
callback(classic)
}
}
}
由于加入緩存出現(xiàn)的bug
由于like(點(diǎn)贊)組件是通過(guò)首頁(yè)請(qǐng)求的數(shù)據(jù)進(jìn)行賦值,而首頁(yè)的切換后續(xù)拿到的是緩存中的數(shù)據(jù),所以like組件渲染的就一直是緩存的數(shù)據(jù)
解決方案:定義一個(gè)新的中間變量去給like組件賦值,第一次請(qǐng)求到的參數(shù)作為默認(rèn)值傳給這個(gè)新變量,每次like組件被點(diǎn)擊的時(shí)候,再把新的返回?cái)?shù)據(jù)覆蓋這個(gè)新變量
//綁定新的變量,而不是直接綁定之前的變量
<like-cmp bind:like="onlike" like="{{likeType}}" num="{{likeNum}}" />
書單頁(yè)面
book組件
接收兩個(gè)參數(shù):
1.Obj:book的基本信息(img,title,text)
2.Num:書本喜歡的人數(shù)
直接書寫html,css然后父組件發(fā)送請(qǐng)求后傳參數(shù)進(jìn)行渲染
搜索組件
歷史搜索(注釋寫的非常詳細(xì)了)
//回車搜索與點(diǎn)擊搜索
onSearch(event) {
//組件被點(diǎn)擊輸入的值
//回車輸入的值
let text = event.detail.text || event.detail.value;
//更改頁(yè)面開關(guān)和vulae值雙向綁定
this.setData({
searchoff: true,
q: text,
searchBook:[]
})
//加載
this._loadingT();
//獲取最新的value值
//將數(shù)據(jù)讀入到緩存中(接收text讀入緩存)
keyword.sethistory(text);
//書籍搜索的請(qǐng)求
books.getbook(0, text)
.then(res => {
this.setData({
searchoff: true,
searchBook: res.data.books
})
//沒有加載到書籍的
if (this.data.searchBook.length === 0) {
this.setData({
empty: true
})
}
//加載開關(guān)
this._loadingF();
})
},
熱門搜索
1.請(qǐng)求熱門搜索接口后,拿到數(shù)據(jù)直接渲染短評(píng)組件
搜索后的書單懶加載
思路:
頁(yè)面下拉到底部,
/**
* 頁(yè)面下拉觸底事件的處理函數(shù)
*/
onReachBottom: function () {
console.log('我被觸發(fā)了')
//more是自定義的一個(gè)變量,每次觸發(fā)都進(jìn)行累加,這樣就可以重復(fù)觸發(fā)子組件的observer
this.data.more +=1;
this.setData({
more: this.data.more
})
console.log(this.data.more)
},
主要問(wèn)題:
如何避免父組件下拉發(fā)送多次請(qǐng)求-----通過(guò)設(shè)置Boolean值來(lái)控制請(qǐng)求的狀態(tài)
如何避免請(qǐng)求數(shù)量完成,發(fā)送無(wú)效請(qǐng)求 ----- 記錄當(dāng)前書籍?dāng)?shù)量和當(dāng)前書籍總數(shù)量,再加入判斷
//監(jiān)控父組件的下拉事件
more: {
type: String,
observer: function() {
//頁(yè)面滾到底部
//父組件的值改變觸發(fā)子組件的observer方法
//請(qǐng)求參數(shù)1:從哪里開始搜索(從當(dāng)前數(shù)組的最后一個(gè)下標(biāo)開始)
//請(qǐng)求參數(shù)2:搜索的內(nèi)容
let q = this.data.q;
let length = this.properties.searchBook.length;
//請(qǐng)求的開關(guān)(避免無(wú)效請(qǐng)求)
console.log(this.properties.searchbuttom)
//如果開關(guān)為trun就可以發(fā)送請(qǐng)求
if (this.properties.searchbuttom) {
//發(fā)送請(qǐng)求后立馬改為false
this.properties.searchbuttom = false;
//當(dāng)前的請(qǐng)求數(shù)量是否等于數(shù)組返回最大的響應(yīng)數(shù)量
if (this.properties.start == this.properties.total || length ==0) {
//如果相等就不要再發(fā)送無(wú)效的請(qǐng)求了
//同時(shí)把請(qǐng)求的開關(guān)改為true
this.properties.searchbuttom = true;
return;
} else {
//正在加載中
this.loadingCenterT();
books.getbook(length, q)
.then(res => {
console.log('我發(fā)送了一次請(qǐng)求')
//1.拼接數(shù)組返回給searchbook
console.log(res)
let newarr = res.data.books;
//2.數(shù)組的拼接
let arr = this.properties.searchBook.concat(newarr)
//3.避免多次無(wú)效請(qǐng)求,記錄當(dāng)前的書籍?dāng)?shù)量和總數(shù)量
this.properties.start = res.data.start;
this.properties.total = res.data.total;
//把拼接的數(shù)組傳給searchBook,渲染頁(yè)面
this.setData({
searchBook: arr
})
//加載結(jié)束
this.loadingCenterF()
this.properties.searchbuttom = true;
})
}
} else {
return
}
}
}
頁(yè)面優(yōu)化
書單詳情頁(yè)總共發(fā)送了3次請(qǐng)求,但是短評(píng)的響應(yīng)速度較慢,頁(yè)面渲染的速度不統(tǒng)一,
采用promise.all()方法進(jìn)行優(yōu)化
promise.all()接收一個(gè)數(shù)組,數(shù)組中傳入promise實(shí)例,當(dāng)數(shù)組中所有的promise實(shí)例都請(qǐng)求成功后,才能進(jìn)行調(diào)用
與之對(duì)應(yīng)的還有一個(gè)promise.race(),他接收的promise實(shí)例只要有一個(gè)成功后他就會(huì)調(diào)用
調(diào)用成功的參數(shù)中通過(guò)下標(biāo)就可以拿到傳入的promise實(shí)例調(diào)用成功后的數(shù)據(jù)
//獲取詳情
const getinfo = books.getinfo(id);
//獲取點(diǎn)贊
const getfavor = books.getfavor(id);
//獲取短評(píng)
const getshort = books.getshort(id);
/**
* 接收一個(gè)參數(shù)array
* array中存放promise實(shí)例
* res返回的是實(shí)例對(duì)象中的res數(shù)據(jù),根據(jù)對(duì)應(yīng)的下標(biāo)可以取到
*/
Promise.all([getinfo,getfavor,getshort])
.then(res=>{
this.setData({
info: res[0].data,
favor:res[1].data,
count:res[1].data.fav_nums,
short:res[2].data.comments
})
//停止加載
wx.hideLoading()
})
書單詳情頁(yè)
短評(píng)組件:實(shí)現(xiàn)輸入短評(píng)后渲染用戶輸入的value,如果點(diǎn)擊是舊值,就直接進(jìn)行加1渲染
1.短評(píng)組件
1.考慮到要在搜索組件進(jìn)行復(fù)用,在這個(gè)組件中啟用了插槽,啟用插槽,要在組件的js文件中加入這一段代碼
//支持插槽
options:{
multipleSlots:true
},
2.當(dāng)短評(píng)被點(diǎn)擊的時(shí)候,把當(dāng)前的短評(píng)text作為參數(shù)傳給父組件去做業(yè)務(wù)處理
onTap(event){
this.triggerEvent('gettext', {
text: this.properties.text
})
},
喜歡頁(yè)面
用戶授權(quán)組件
需要用戶點(diǎn)擊按鈕后才能拉起授權(quán)彈窗,但是微信提供的默認(rèn)按鈕的樣式是固定的
思路:
1.讓子組件來(lái)拉起授權(quán),button需要傳入的參數(shù)open-type讓父組件給他
2.當(dāng)子組件拉起授權(quán)后,把授權(quán)的用戶信息通過(guò)自定義事件作為參數(shù)傳給父組件進(jìn)行業(yè)務(wù)處理
1.子組件觸發(fā)
<button bind:getuserinfo="onGetUserInfo" open-type='{{openType}}' plain='{{true}}' class="container">
<slot name="img"></slot>
</button>
methods: {
onGetUserInfo(event) {
//授權(quán)的信息
console.log(event.detail)
this.triggerEvent('getuserinfo', event.detail, {})
},
}
2.父組件的業(yè)務(wù)處理
//子組件監(jiān)聽授權(quán)點(diǎn)擊函數(shù)
onGetUserInfo: function (event) {
//獲取用戶信息
let userInfo = event.detail.userInfo
//如果信息不為空,則已經(jīng)授權(quán),把信息傳入userinfo中
if (userInfo) {
this.setData({
hasUserInfo: true,
userInfo: userInfo
})
}
},
用戶授權(quán)檢查
onLoad: function (options) {
//查看用戶是否已經(jīng)授權(quán)
this.getUserInfo();
//加載用戶喜歡的書籍?dāng)?shù)
this.getMyBook();
//獲取用戶喜歡的書刊
this.GetMyfavor();
},
//獲取用戶信息
getUserInfo(){
wx.getSetting({
success: (res) => {
console.log(res);
if (res.authSetting['scope.userInfo']) {
//這里表示已經(jīng)授權(quán)成功了
wx.getUserInfo({
success: (res) => {
this.setData({
hasUserInfo: true,
userInfo: res.userInfo
})
}
})
//沒有授權(quán)成功的話
} else {
this.setData({
hasUserInfo: false,
})
}
}
})
},
本文正在參加“寫編程博客瓜分千元現(xiàn)金”活動(dòng)飒炎,關(guān)注公眾號(hào)“饑人谷”回復(fù)“編程博客”參與活動(dòng)粘驰。