资讯专栏INFORMATION COLUMN

微信小程序教学第三章(含视频):小程序中级实战教程:列表-页面逻辑处理

阿罗 / 2743人阅读

摘要:包含文章视频源代码原创新书移动前端高效开发实战已在亚马逊京东当当开售。最新活动报名地址与天天练口语小程序总榜排名第四教育类排名第一的研发团队,面对面沟通交流。

§ 页面逻辑处理

本文配套视频地址:
https://v.qq.com/x/page/n0554...

开始前请把 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官网:http://www.ikcamp.com

访问官网更快阅读全部免费分享课程:《iKcamp出品|全网最新|微信小程序|基于最新版1.0开发者工具之初中级培训教程分享》。
包含:文章、视频、源代码

iKcamp原创新书《移动Web前端高效开发实战》已在亚马逊、京东、当当开售。

iKcamp最新活动

报名地址:http://www.huodongxing.com/ev...

“天天练口语”小程序总榜排名第四、教育类排名第一的研发团队,面对面沟通交流。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/115572.html

相关文章

  • 程序教学三章第三节(视频):程序中级实战教程:视图与数据关联

    摘要:因为循环中当前项的下标变量名默认为,当前项的变量名默认为。包含文章视频源代码原创新书移动前端高效开发实战已在亚马逊京东当当开售。最新活动报名地址与天天练口语小程序总榜排名第四教育类排名第一的研发团队,面对面沟通交流。 § 视图与数据关联 本文配套视频地址:https://v.qq.com/x/page/z0554... 开始前请把 ch3-3 分支中的 code/ 目录导入微信开发工...

    haitiancoder 评论0 收藏0
  • 程序教学三章第三节(视频):程序中级实战教程:视图与数据关联

    摘要:因为循环中当前项的下标变量名默认为,当前项的变量名默认为。包含文章视频源代码原创新书移动前端高效开发实战已在亚马逊京东当当开售。最新活动报名地址与天天练口语小程序总榜排名第四教育类排名第一的研发团队,面对面沟通交流。 § 视图与数据关联 本文配套视频地址:https://v.qq.com/x/page/z0554... 开始前请把 ch3-3 分支中的 code/ 目录导入微信开发工...

    scola666 评论0 收藏0
  • 程序教学三章第三节(视频):程序中级实战教程:视图与数据关联

    摘要:因为循环中当前项的下标变量名默认为,当前项的变量名默认为。包含文章视频源代码原创新书移动前端高效开发实战已在亚马逊京东当当开售。最新活动报名地址与天天练口语小程序总榜排名第四教育类排名第一的研发团队,面对面沟通交流。 § 视图与数据关联 本文配套视频地址:https://v.qq.com/x/page/z0554... 开始前请把 ch3-3 分支中的 code/ 目录导入微信开发工...

    Nekron 评论0 收藏0
  • iKcamp出品程序教学共5章16节汇总(视频)

    摘要:微信小程序课程,面向所有具备前端基础知识的同学阅读要求读者需要具备但不限于以下技能更佳一共四部分十五小节,适合七天的训练营。 ?? 微信小程序课程,面向所有具备前端基础知识的同学 ?? 阅读要求 读者需要具备但不限于以下技能 HTML JavaScript es6更佳 CSS 一共四部分十五小节,适合七天的训练营。 从现在开始,我假装你已经掌握了 html、 css以及 ES6...

    elliott_hu 评论0 收藏0
  • iKcamp出品程序教学共5章16节汇总(视频)

    摘要:微信小程序课程,面向所有具备前端基础知识的同学阅读要求读者需要具备但不限于以下技能更佳一共四部分十五小节,适合七天的训练营。 ?? 微信小程序课程,面向所有具备前端基础知识的同学 ?? 阅读要求 读者需要具备但不限于以下技能 HTML JavaScript es6更佳 CSS 一共四部分十五小节,适合七天的训练营。 从现在开始,我假装你已经掌握了 html、 css以及 ES6...

    paney129 评论0 收藏0
  • iKcamp出品程序教学共5章16节汇总(视频)

    摘要:微信小程序课程,面向所有具备前端基础知识的同学阅读要求读者需要具备但不限于以下技能更佳一共四部分十五小节,适合七天的训练营。 ?? 微信小程序课程,面向所有具备前端基础知识的同学 ?? 阅读要求 读者需要具备但不限于以下技能 HTML JavaScript es6更佳 CSS 一共四部分十五小节,适合七天的训练营。 从现在开始,我假装你已经掌握了 html、 css以及 ES6...

    lmxdawn 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<