§ 页面逻辑处理
本文配套视频地址:
v.qq.com/x/page/n055…
开始前请把 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较新活动
报名地址: www.huodongxing.com/event/54099…
与 “天天练口语”
小程序总榜排名第四、教育类排名先进的研发团队,面对面沟通交流。