列表篇-頁面邏輯處理
本文配套視訊地址: v.qq.com/x/page/z055…
開始前請把
ch3-2
分支中的code/
目錄匯入微信開發工具
修改 index.js
檔案,引入我們需要的外部資源
'use strict';
import util from '../../utils/index';
import config from '../../utils/config';
let app = getApp();
let isDEV = config.isDev;
// 後繼的程式碼都會放在此物件中
let handler = {
}
Page(handler)
複製程式碼
資料繫結
我們首先挖出和渲染相關的資料,並新增在 handler
物件的 data
欄位中(Model 層)
修改 index.js
中的 handler
物件:
// 此處省略部分程式碼
let handler = {
data: {
page: 1, //當前載入第幾頁的資料
days: 3,
pageSize: 4,
totalSize: 0,
hasMore: true,// 用來判斷下拉載入更多內容操作
articleList: [], // 存放文章列表資料,與檢視相關聯
defaultImg: config.defaultImg
},
}
複製程式碼
注意: 後續新增的程式碼都是放在 handler
物件中,它會傳遞到 Page
函式中用來初始化頁面元件
獲取資料
然後要做的就是獲取列表的資料,初始化資料的工作我們一般放在生命週期的 onLoad()
裡:
let handler = {
onLoad (options) {
this.requestArticle()
},
/*
* 獲取文章列表資料
*/
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 )
});
}
}
複製程式碼
資料載入完成之後,我們需要對介面返回的資料進行業務方面的容錯處理
修改 requestArticle
函式:
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 => {
// 資料正常返回
if (res && res.status === 0 && res.data && res.data.length) {
// 正常資料 do something
console.log(res)
}
/*
* 如果載入第一頁就沒有資料,說明資料存在異常情況
* 處理方式:彈出異常提示資訊(預設提示資訊)並設定下拉載入功能不可用
*/
else if (this.data.page === 1 && res.data && res.data.length === 0) {
util.alert();
this.setData({
hasMore: false
});
}
/*
* 如果非第一頁沒有資料,那說明沒有資料了,停用下拉載入功能即可
*/
else if (this.data.page !== 1 && res.data && res.data.length === 0) {
this.setData({
hasMore: false
});
}
/*
* 返回異常錯誤
* 展示後端返回的錯誤資訊,並設定下拉載入功能不可用
*/
else {
util.alert('提示', res);
this.setData({
hasMore: false
});
return null;
}
})
}
}
複製程式碼
上面我們把 wx.request
重新包裝成了 Promise
的形式,其實我們是請求的 mock 資料。但是介面請求到的資料絕大部分情況下都不會直接適用於 UI
展示,所以我們需要做一層資料轉換,把介面資料轉換成檢視資料。
格式化資料
先看下後端返回的資料結構
我們需要做兩件事情
- 遍歷
data
陣列,對返回的日期格式化,當天的顯示今天
,如果是今年的文章,顯示月日格式08-21
;如果是往年的文章,顯示標準的年月日格式2015-06-12
。 - 遍歷
articles
陣列,判斷此篇文章的contentId
是否已經在全域性變數visitedArticles
中,如果存在,說明已經訪問過。
修改 app.js
,增加全域性變數 visitedArticles
globalData: {
user: {
name: '',
avator: ''
},
visitedArticles: ''
}
複製程式碼
修改 index.js
中的 requestArticle
函式:
let handler = {
// 此處省略部分程式碼
requestArticle () {
// 注意:修改此處程式碼
if (res && res.status === 0 && res.data && res.data.length) {
let articleData = res.data;
//格式化原始資料
let formatData = this.formatArticleData(articleData);
console.log( formatData )
}
}
}
複製程式碼
增加對列表資料格式化的程式碼:
let handler = {
// 此處省略部分程式碼
/*
* 格式化文章列表資料
*/
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) => {
// 判斷是否已經訪問過
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;
},
/*
* 判斷文章是否訪問過
* @param contentId
*/
isVisited (contentId) {
let visitedArticles = app.globalData && app.globalData.visitedArticles || '';
return visitedArticles.indexOf(`${contentId}`) > -1;
},
}
複製程式碼
正常情況下,這個時候控制檯列印出來的資料,是經過格式化的標準資料了,下一步,我們需要把它新增到 data
中的 articleList
欄位裡面,這樣檢視才有了渲染的資料
修改 index.js
,增加 renderArticle
函式。由於每次請求的都是某一頁的資料,所以在函式中,我們需要把每次請求過來的列表資料都 concat
(拼接)到 articleList
中:
let handler = {
// 此處省略部分程式碼
renderArticle (data) {
if (data && data.length) {
let newList = this.data.articleList.concat(data);
this.setData({
articleList: newList
})
}
}
}
複製程式碼
在 requestArticle
函式中呼叫 renderArticle
:
let handler = {
// 此處省略部分程式碼
requestArticle () {
// 注意:修改此處程式碼
if (res && res.status === 0 && res.data && res.data.length) {
let articleData = res.data;
//格式化原始資料
let formatData = this.formatArticleData(articleData);
this.renderArticle( formatData )
}
}
}
複製程式碼
最終結果
最終的 index.js
檔案就是這樣的:
'use strict';
import util from '../../utils/index'
import config from '../../utils/config'
let app = getApp()
let isDEV = config.isDev
// 後繼的程式碼都會放在此物件中
let handler = {
data: {
page: 1, //當前的頁數
days: 3,
pageSize: 4,
totalSize: 0,
hasMore: true,// 用來判斷下拉載入更多內容操作
articleList: [], // 存放文章列表資料
defaultImg: config.defaultImg
},
onLoad(options) {
this.requestArticle();
},
/*
* 獲取文章列表資料
*/
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 => {
// 資料正常返回
if (res && res.status === 0 && res.data && res.data.length) {
let articleData = res.data;
//格式化原始資料
let formatData = this.formatArticleData(articleData);
this.renderArticle(formatData)
}
/*
* 如果載入第一頁就沒有資料,說明資料存在異常情況
* 處理方式:彈出異常提示資訊(預設提示資訊)並設定下拉載入功能不可用
*/
else if (this.data.page === 1 && res.data && res.data.length === 0) {
util.alert();
this.setData({
hasMore: false
});
}
/*
* 如果非第一頁沒有資料,那說明沒有資料了,停用下拉載入功能即可
*/
else if (this.data.page !== 1 && res.data && res.data.length === 0) {
this.setData({
hasMore: false
});
}
/*
* 返回異常錯誤
* 展示後端返回的錯誤資訊,並設定下拉載入功能不可用
*/
else {
util.alert('提示', res);
this.setData({
hasMore: false
});
return null;
}
})
},
/*
* 格式化文章列表資料
*/
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) => {
// 判斷是否已經訪問過
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;
},
/*
* 判斷文章是否訪問過
* @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)
複製程式碼
下一篇中,我們將會把資料與檢視層結合在一起,動態的展示檢視層
iKcamp官網:www.ikcamp.com
訪問官網更快閱讀全部免費分享課程:《iKcamp出品|全網最新|微信小程式|基於最新版1.0開發者工具之初中級培訓教程分享》。 包含:文章、視訊、原始碼
iKcamp原創新書《移動Web前端高效開發實戰》已在亞馬遜、京東、噹噹開售。
iKcamp最新活動
與
“天天練口語”
小程式總榜排名第四、教育類排名第一的研發團隊,面對面溝通交流。
2019年,iKcamp原創新書《Koa與Node.js開發實戰》已在京東、天貓、亞馬遜、噹噹開售啦!