微信小程序教學(xué)第三章(含視頻):小程序中級(jí)實(shí)戰(zhàn)教程:列表-頁(yè)面邏輯處理

<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)

我們需要做兩件事情

  1. 遍歷 data 數(shù)組,對(duì)返回的日期格式化,當(dāng)天的顯示 今天,如果是今年的文章,顯示月日格式 08-21 ;如果是往年的文章,顯示標(biāo)準(zhǔn)的年月日格式 2015-06-12
  2. 遍歷 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)

報(bào)名地址:http://www.huodongxing.com/event/5409924174200

“天天練口語(yǔ)”小程序總榜排名第四、教育類排名第一的研發(fā)團(tuán)隊(duì),面對(duì)面溝通交流。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 179,137評(píng)論 25 708
  • 上一篇《WEB請(qǐng)求處理一:瀏覽器請(qǐng)求發(fā)起處理》,我們講述了瀏覽器端請(qǐng)求發(fā)起過(guò)程,通過(guò)DNS域名解析服務(wù)器IP,并建...
    七寸知架構(gòu)閱讀 81,772評(píng)論 21 356
  • 鉆石?對(duì),沒(méi)看錯(cuò),鉆石。為啥叫鉆石,老大給出金句:擁有一串珍珠項(xiàng)鏈,不如擁有一顆鉆石。so,知道了此次活動(dòng)巨大價(jià)值...
    諾布_fb1a閱讀 310評(píng)論 0 0
  • 與某些文字相遇,我想那是一種緣分。 第一位留言讀者說(shuō)我的文字真誠(chéng),所謂‘當(dāng)局者迷旁觀者清’‘不識(shí)廬山真面目,只緣身...
    fall_in_love閱讀 275評(píng)論 0 0
  • 高效溝通和工作: 會(huì)議效率 溝通效率 1.有人R,轉(zhuǎn)給負(fù)責(zé)人【具體事情不溝通】; 比如今天和亞軍溝通推廣計(jì)劃,應(yīng)...
    liuqin閱讀 183評(píng)論 0 0

友情鏈接更多精彩內(nèi)容