美文网首页前端跟我学Web前端之路让前端飞
微信小程序教学第三章(含视频):小程序中级实战教程:列表-页面逻

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

作者: iKcamp | 来源:发表于2017-10-25 12:08 被阅读29次

    <a>§ 页面逻辑处理</a>

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


    开始前请把 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 展示,所以我们需要做一层数据转换,把接口数据转换成视图数据。

    格式化数据

    先看下后端返回的数据结构

    我们需要做两件事情

    1. 遍历 data 数组,对返回的日期格式化,当天的显示 今天,如果是今年的文章,显示月日格式 08-21 ;如果是往年的文章,显示标准的年月日格式 2015-06-12
    2. 遍历 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/event/5409924174200

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

    相关文章

      网友评论

        本文标题:微信小程序教学第三章(含视频):小程序中级实战教程:列表-页面逻

        本文链接:https://www.haomeiwen.com/subject/qokqpxtx.html