<a>§ 頁(yè)面邏輯處理</a>
本文配套視頻地址:
https://v.qq.com/x/page/n0554dndrez.html
開始前請(qǐng)把
ch3-2分支中的code/目錄導(dǎo)入微信開發(fā)工具
修改 index.js 文件,引入我們需要的外部資源
'use strict';
import util from '../../utils/index';
import config from '../../utils/config';
let app = getApp();
let isDEV = config.isDev;
// 后繼的代碼都會(huì)放在此對(duì)象中
let handler = {
}
Page(handler)
數(shù)據(jù)綁定
我們首先挖出和渲染相關(guān)的數(shù)據(jù),并添加在 handler 對(duì)象的 data 字段中(Model 層)
修改 index.js 中的 handler 對(duì)象:
// 此處省略部分代碼
let handler = {
data: {
page: 1, //當(dāng)前加載第幾頁(yè)的數(shù)據(jù)
days: 3,
pageSize: 4,
totalSize: 0,
hasMore: true,// 用來(lái)判斷下拉加載更多內(nèi)容操作
articleList: [], // 存放文章列表數(shù)據(jù),與視圖相關(guān)聯(lián)
defaultImg: config.defaultImg
},
}
注意: 后續(xù)添加的代碼都是放在 handler 對(duì)象中,它會(huì)傳遞到 Page 函數(shù)中用來(lái)初始化頁(yè)面組件
獲取數(shù)據(jù)
然后要做的就是獲取列表的數(shù)據(jù),初始化數(shù)據(jù)的工作我們一般放在生命周期的 onLoad() 里:
let handler = {
onLoad (options) {
this.requestArticle()
},
/*
* 獲取文章列表數(shù)據(jù)
*/
requestArticle () {
util.request({
url: 'list',
mock: true,
data: {
tag:'微信熱門',
start: this.data.page || 1,
days: this.data.days || 3,
pageSize: this.data.pageSize,
langs: config.appLang || 'en'
}
})
.then(res => {
console.log( res )
});
}
}
數(shù)據(jù)加載完成之后,我們需要對(duì)接口返回的數(shù)據(jù)進(jìn)行業(yè)務(wù)方面的容錯(cuò)處理
修改 requestArticle 函數(shù):
let handler = {
// 此處省略部分代碼
requestArticle () {
util.request({
url: 'list',
mock: true,
data: {
tag:'微信熱門',
start: this.data.page || 1,
days: this.data.days || 3,
pageSize: this.data.pageSize,
langs: config.appLang || 'en'
}
})
.then(res => {
// 數(shù)據(jù)正常返回
if (res && res.status === 0 && res.data && res.data.length) {
// 正常數(shù)據(jù) do something
console.log(res)
}
/*
* 如果加載第一頁(yè)就沒(méi)有數(shù)據(jù),說(shuō)明數(shù)據(jù)存在異常情況
* 處理方式:彈出異常提示信息(默認(rèn)提示信息)并設(shè)置下拉加載功能不可用
*/
else if (this.data.page === 1 && res.data && res.data.length === 0) {
util.alert();
this.setData({
hasMore: false
});
}
/*
* 如果非第一頁(yè)沒(méi)有數(shù)據(jù),那說(shuō)明沒(méi)有數(shù)據(jù)了,停用下拉加載功能即可
*/
else if (this.data.page !== 1 && res.data && res.data.length === 0) {
this.setData({
hasMore: false
});
}
/*
* 返回異常錯(cuò)誤
* 展示后端返回的錯(cuò)誤信息,并設(shè)置下拉加載功能不可用
*/
else {
util.alert('提示', res);
this.setData({
hasMore: false
});
return null;
}
})
}
}
上面我們把 wx.request 重新包裝成了 Promise 的形式,其實(shí)我們是請(qǐng)求的 mock 數(shù)據(jù)。但是接口請(qǐng)求到的數(shù)據(jù)絕大部分情況下都不會(huì)直接適用于 UI 展示,所以我們需要做一層數(shù)據(jù)轉(zhuǎn)換,把接口數(shù)據(jù)轉(zhuǎn)換成視圖數(shù)據(jù)。
格式化數(shù)據(jù)
先看下后端返回的數(shù)據(jù)結(jié)構(gòu)
我們需要做兩件事情
- 遍歷
data數(shù)組,對(duì)返回的日期格式化,當(dāng)天的顯示今天,如果是今年的文章,顯示月日格式08-21;如果是往年的文章,顯示標(biāo)準(zhǔn)的年月日格式2015-06-12。 - 遍歷
articles數(shù)組,判斷此篇文章的contentId是否已經(jīng)在全局變量visitedArticles中,如果存在,說(shuō)明已經(jīng)訪問(wèn)過(guò)。
修改 app.js,增加全局變量 visitedArticles
globalData: {
user: {
name: '',
avator: ''
},
visitedArticles: ''
}
修改 index.js 中的 requestArticle 函數(shù):
let handler = {
// 此處省略部分代碼
requestArticle () {
// 注意:修改此處代碼
if (res && res.status === 0 && res.data && res.data.length) {
let articleData = res.data;
//格式化原始數(shù)據(jù)
let formatData = this.formatArticleData(articleData);
console.log( formatData )
}
}
}
增加對(duì)列表數(shù)據(jù)格式化的代碼:
let handler = {
// 此處省略部分代碼
/*
* 格式化文章列表數(shù)據(jù)
*/
formatArticleData (data) {
let formatData = undefined;
if (data && data.length) {
formatData = data.map((group) => {
// 格式化日期
group.formateDate = this.dateConvert(group.date);
if (group && group.articles) {
let formatArticleItems = group.articles.map((item) => {
// 判斷是否已經(jīng)訪問(wèn)過(guò)
item.hasVisited = this.isVisited(item.contentId);
return item;
}) || [];
group.articles = formatArticleItems;
}
return group
})
}
return formatData;
},
/*
* 將原始日期字符串格式化 '2017-06-12'
* return '今日' / 08-21 / 2017-06-12
*/
dateConvert (dateStr) {
if (!dateStr) {
return '';
}
let today = new Date(),
todayYear = today.getFullYear(),
todayMonth = ('0' + (today.getMonth() + 1)).slice(-2),
todayDay = ('0' + today.getDate()).slice(-2);
let convertStr = '';
let originYear = +dateStr.slice(0,4);
let todayFormat = `${todayYear}-${todayMonth}-${todayDay}`;
if (dateStr === todayFormat) {
convertStr = '今日';
} else if (originYear < todayYear) {
let splitStr = dateStr.split('-');
convertStr = `${splitStr[0]}年${splitStr[1]}月${splitStr[2]}日`;
} else {
convertStr = dateStr.slice(5).replace('-', '月') + '日'
}
return convertStr;
},
/*
* 判斷文章是否訪問(wèn)過(guò)
* @param contentId
*/
isVisited (contentId) {
let visitedArticles = app.globalData && app.globalData.visitedArticles || '';
return visitedArticles.indexOf(`${contentId}`) > -1;
},
}
正常情況下,這個(gè)時(shí)候控制臺(tái)打印出來(lái)的數(shù)據(jù),是經(jīng)過(guò)格式化的標(biāo)準(zhǔn)數(shù)據(jù)了,下一步,我們需要把它添加到 data 中的 articleList 字段里面,這樣視圖才有了渲染的數(shù)據(jù)
修改 index.js,增加 renderArticle 函數(shù)。由于每次請(qǐng)求的都是某一頁(yè)的數(shù)據(jù),所以在函數(shù)中,我們需要把每次請(qǐng)求過(guò)來(lái)的列表數(shù)據(jù)都 concat(拼接)到 articleList中:
let handler = {
// 此處省略部分代碼
renderArticle (data) {
if (data && data.length) {
let newList = this.data.articleList.concat(data);
this.setData({
articleList: newList
})
}
}
}
在 requestArticle 函數(shù)中調(diào)用 renderArticle:
let handler = {
// 此處省略部分代碼
requestArticle () {
// 注意:修改此處代碼
if (res && res.status === 0 && res.data && res.data.length) {
let articleData = res.data;
//格式化原始數(shù)據(jù)
let formatData = this.formatArticleData(articleData);
this.renderArticle( formatData )
}
}
}
最終結(jié)果
最終的 index.js 文件就是這樣的:
'use strict';
import util from '../../utils/index'
import config from '../../utils/config'
let app = getApp()
let isDEV = config.isDev
// 后繼的代碼都會(huì)放在此對(duì)象中
let handler = {
data: {
page: 1, //當(dāng)前的頁(yè)數(shù)
days: 3,
pageSize: 4,
totalSize: 0,
hasMore: true,// 用來(lái)判斷下拉加載更多內(nèi)容操作
articleList: [], // 存放文章列表數(shù)據(jù)
defaultImg: config.defaultImg
},
onLoad(options) {
this.requestArticle();
},
/*
* 獲取文章列表數(shù)據(jù)
*/
requestArticle() {
util.request({
url: 'list',
mock: true,
data: {
tag: '微信熱門',
start: this.data.page || 1,
days: this.data.days || 3,
pageSize: this.data.pageSize,
langs: config.appLang || 'en'
}
})
.then(res => {
// 數(shù)據(jù)正常返回
if (res && res.status === 0 && res.data && res.data.length) {
let articleData = res.data;
//格式化原始數(shù)據(jù)
let formatData = this.formatArticleData(articleData);
this.renderArticle(formatData)
}
/*
* 如果加載第一頁(yè)就沒(méi)有數(shù)據(jù),說(shuō)明數(shù)據(jù)存在異常情況
* 處理方式:彈出異常提示信息(默認(rèn)提示信息)并設(shè)置下拉加載功能不可用
*/
else if (this.data.page === 1 && res.data && res.data.length === 0) {
util.alert();
this.setData({
hasMore: false
});
}
/*
* 如果非第一頁(yè)沒(méi)有數(shù)據(jù),那說(shuō)明沒(méi)有數(shù)據(jù)了,停用下拉加載功能即可
*/
else if (this.data.page !== 1 && res.data && res.data.length === 0) {
this.setData({
hasMore: false
});
}
/*
* 返回異常錯(cuò)誤
* 展示后端返回的錯(cuò)誤信息,并設(shè)置下拉加載功能不可用
*/
else {
util.alert('提示', res);
this.setData({
hasMore: false
});
return null;
}
})
},
/*
* 格式化文章列表數(shù)據(jù)
*/
formatArticleData(data) {
let formatData = undefined;
if (data && data.length) {
formatData = data.map((group) => {
// 格式化日期
group.formateDate = this.dateConvert(group.date);
if (group && group.articles) {
let formatArticleItems = group.articles.map((item) => {
// 判斷是否已經(jīng)訪問(wèn)過(guò)
item.hasVisited = this.isVisited(item.contentId);
return item;
}) || [];
group.articles = formatArticleItems;
}
return group
})
}
return formatData;
},
/*
* 將原始日期字符串格式化 '2017-06-12'
* return '今日' / 08-21 / 2017-06-12
*/
dateConvert(dateStr) {
if (!dateStr) {
return '';
}
let today = new Date(),
todayYear = today.getFullYear(),
todayMonth = ('0' + (today.getMonth() + 1)).slice(-2),
todayDay = ('0' + today.getDate()).slice(-2);
let convertStr = '';
let originYear = +dateStr.slice(0, 4);
let todayFormat = `${todayYear}-${todayMonth}-${todayDay}`;
if (dateStr === todayFormat) {
convertStr = '今日';
} else if (originYear < todayYear) {
let splitStr = dateStr.split('-');
convertStr = `${splitStr[0]}年${splitStr[1]}月${splitStr[2]}日`;
} else {
convertStr = dateStr.slice(5).replace('-', '月') + '日'
}
return convertStr;
},
/*
* 判斷文章是否訪問(wèn)過(guò)
* @param contentId
*/
isVisited(contentId) {
let visitedArticles = app.globalData && app.globalData.visitedArticles || '';
return visitedArticles.indexOf(`${contentId}`) > -1;
},
renderArticle(data) {
if (data && data.length) {
let newList = this.data.articleList.concat(data);
this.setData({
articleList: newList
})
}
}
}
Page(handler)
下一篇中,我們將會(huì)把數(shù)據(jù)與視圖層結(jié)合在一起,動(dòng)態(tài)的展示視圖層
iKcamp官網(wǎng):http://www.ikcamp.com
訪問(wèn)官網(wǎng)更快閱讀全部免費(fèi)分享課程:《iKcamp出品|全網(wǎng)最新|微信小程序|基于最新版1.0開發(fā)者工具之初中級(jí)培訓(xùn)教程分享》。
包含:文章、視頻、源代碼
iKcamp原創(chuàng)新書《移動(dòng)Web前端高效開發(fā)實(shí)戰(zhàn)》已在亞馬遜、京東、當(dāng)當(dāng)開售。
iKcamp最新活動(dòng)
與
“天天練口語(yǔ)”小程序總榜排名第四、教育類排名第一的研發(fā)團(tuán)隊(duì),面對(duì)面溝通交流。