微信小程式教學第三章(含視訊):小程式中級實戰教程:列表篇-頁面邏輯處理

iKcamp發表於2017-10-25

列表篇-頁面邏輯處理

本文配套視訊地址: 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 展示,所以我們需要做一層資料轉換,把介面資料轉換成檢視資料。


格式化資料

先看下後端返回的資料結構

微信小程式教學第三章(含視訊):小程式中級實戰教程:列表篇-頁面邏輯處理

我們需要做兩件事情

  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官網:www.ikcamp.com

訪問官網更快閱讀全部免費分享課程:《iKcamp出品|全網最新|微信小程式|基於最新版1.0開發者工具之初中級培訓教程分享》。 包含:文章、視訊、原始碼

微信小程式教學第三章(含視訊):小程式中級實戰教程:列表篇-頁面邏輯處理

iKcamp原創新書《移動Web前端高效開發實戰》已在亞馬遜、京東、噹噹開售。

iKcamp最新活動

微信小程式教學第三章(含視訊):小程式中級實戰教程:列表篇-頁面邏輯處理

報名地址:www.huodongxing.com/event/54099…

“天天練口語”小程式總榜排名第四、教育類排名第一的研發團隊,面對面溝通交流。


微信小程式教學第三章(含視訊):小程式中級實戰教程:列表篇-頁面邏輯處理

2019年,iKcamp原創新書《Koa與Node.js開發實戰》已在京東、天貓、亞馬遜、噹噹開售啦!

相關文章