1. 程式人生 > >[轉]微信小程序之加載更多(分頁加載)實例 —— 微信小程序實戰系列(2)

[轉]微信小程序之加載更多(分頁加載)實例 —— 微信小程序實戰系列(2)

是否 底部 watermark water ongl 小程序教程 所有 空數組 osi

本文轉自;http://blog.csdn.net/michael_ouyang/article/details/56846185

loadmore

加載更多(分頁加載)

當用戶打開一個頁面時,假設後臺數據量龐大時,一次性地返回所有數據給客戶端,頁面的打開速度就會有所下降,而且用戶只看上面的內容而不需要看後面的內容時,也浪費用戶流量,基於優化的角度來考慮,後臺不要一次性返回所有數據,當用戶有需要再往下翻的時候,再加載更加數據出來。

業務需求:

列表滾動到底部時,繼續往上拉,加載更多內容

必備參數:

(1)pageindex: 1 //第幾次加載

(2callbackcount: 15 //需要返回數據的個數

其他參數:

根據接口的所需參數

實現原理:

當第一次訪問接口時,傳遞2個必備參數(第1次加載,需要返回數據的個數為15個),和其他參數(需要搜索的字符串)給後臺,後臺返回第一次數據過來。在請求成功的的回調函數中,判斷返回的數據是否>0,是,則取出數據,渲染視圖層,並把“上拉加載”顯示在列表底部;否,則沒有數據可取,並把“沒有更多”顯示在列表底部,同時把“上拉加載”隱藏掉。

當用戶已經滾動到列表底部(這裏使用到小程序提供的scroll-view組件的bindscrolltolower事件),觸發bindscrolltolower事件,參數pageindex+1,再把2個必備參數(第2次加載,需要返回數據的個數為15個)和其他參數(需要搜索的字符串)給後臺,後臺把其余的數據返回給前臺,前臺在原來數據的基礎上添加數據。

示例:

wxml:

[html] view plain copy print?
  1. <view class="search">
  2. <view class="search-bar">
  3. <view class="search-wrap">
  4. <icon type="search" size="16" class="icon-search" />
  5. <input type="text" placeholder="請輸入搜索內容" class="search-input" name="searchKeyword" bindinput="bindKeywordInput" value="{{searchKeyword}}" />
  6. </view>
  7. <view class="search-cancel" bindtap="keywordSearch">搜索</view>
  8. </view>
  9. <view class="search-result">
  10. <scroll-view scroll-y="true" bindscrolltolower="searchScrollLower">
  11. <view class="result-item" wx:for="{{searchSongList}}" wx:key="unique" data-data="{{item}}" >
  12. <view class="icon{{item.isonly==‘0‘ ? ‘ nocopyright‘ : ‘‘}}"></view>
  13. <text class="title">{{item.songname}}</text>
  14. <view class="subtitle">
  15. <text wx:for="{{item.singer}}" wx:key="unique">{{item.name}}</text>
  16. </view>
  17. </view>
  18. <view class="loading" hidden="{{!searchLoading}}">正在載入更多...</view>
  19. <view class="loading complete" hidden="{{!searchLoadingComplete}}">已加載全部</view>
  20. </scroll-view>
  21. </view>
  22. </view>
<view class="search">
  <view class="search-bar">
    <view class="search-wrap">
        <icon type="search" size="16" class="icon-search" />
        <input type="text" placeholder="請輸入搜索內容" class="search-input" name="searchKeyword" bindinput="bindKeywordInput" value="{{searchKeyword}}" />
    </view>
    <view class="search-cancel" bindtap="keywordSearch">搜索</view>
  </view>
  <view class="search-result">
    <scroll-view scroll-y="true" bindscrolltolower="searchScrollLower">
      <view class="result-item" wx:for="{{searchSongList}}" wx:key="unique"  data-data="{{item}}" >
        <view class="icon{{item.isonly==‘0‘ ? ‘ nocopyright‘ : ‘‘}}"></view>
        <text class="title">{{item.songname}}</text>
        <view class="subtitle">
          <text wx:for="{{item.singer}}" wx:key="unique">{{item.name}}</text>
        </view>
      </view>
      <view class="loading" hidden="{{!searchLoading}}">正在載入更多...</view>
      <view class="loading complete" hidden="{{!searchLoadingComplete}}">已加載全部</view>
    </scroll-view>  
  </view>
</view>

js:

[javascript] view plain copy print?
  1. var util = require(‘../../utils/util.js‘)
  2. Page({
  3. data: {
  4. searchKeyword: ‘‘, //需要搜索的字符
  5. searchSongList: [], //放置返回數據的數組
  6. isFromSearch: true, // 用於判斷searchSongList數組是不是空數組,默認true,空的數組
  7. searchPageNum: 1, // 設置加載的第幾次,默認是第一次
  8. callbackcount: 15, //返回數據的個數
  9. searchLoading: false, //"上拉加載"的變量,默認false,隱藏
  10. searchLoadingComplete: false //“沒有數據”的變量,默認false,隱藏
  11. },
  12. //輸入框事件,每輸入一個字符,就會觸發一次
  13. bindKeywordInput: function(e){
  14. console.log("輸入框事件")
  15. this.setData({
  16. searchKeyword: e.detail.value
  17. })
  18. },
  19. //搜索,訪問網絡
  20. fetchSearchList: function(){
  21. let that = this;
  22. let searchKeyword = that.data.searchKeyword,//輸入框字符串作為參數
  23. searchPageNum = that.data.searchPageNum,//把第幾次加載次數作為參數
  24. callbackcount =that.data.callbackcount; //返回數據的個數
  25. //訪問網絡
  26. util.getSearchMusic(searchKeyword, searchPageNum,callbackcount, function(data){
  27. console.log(data)
  28. //判斷是否有數據,有則取數據
  29. if(data.data.song.curnum != 0){
  30. let searchList = [];
  31. //如果isFromSearch是true從data中取出數據,否則先從原來的數據繼續添加
  32. that.data.isFromSearch ? searchList=data.data.song.list : searchList=that.data.searchSongList.concat(data.data.song.list)
  33. that.setData({
  34. searchSongList: searchList, //獲取數據數組
  35. zhida: data.data.zhida, //存放歌手屬性的對象
  36. searchLoading: true //把"上拉加載"的變量設為false,顯示
  37. });
  38. //沒有數據了,把“沒有數據”顯示,把“上拉加載”隱藏
  39. }else{
  40. that.setData({
  41. searchLoadingComplete: true, //把“沒有數據”設為true,顯示
  42. searchLoading: false //把"上拉加載"的變量設為false,隱藏
  43. });
  44. }
  45. })
  46. },
  47. //點擊搜索按鈕,觸發事件
  48. keywordSearch: function(e){
  49. this.setData({
  50. searchPageNum: 1, //第一次加載,設置1
  51. searchSongList:[], //放置返回數據的數組,設為空
  52. isFromSearch: true, //第一次加載,設置true
  53. searchLoading: true, //把"上拉加載"的變量設為true,顯示
  54. searchLoadingComplete:false //把“沒有數據”設為false,隱藏
  55. })
  56. this.fetchSearchList();
  57. },
  58. //滾動到底部觸發事件
  59. searchScrollLower: function(){
  60. let that = this;
  61. if(that.data.searchLoading && !that.data.searchLoadingComplete){
  62. that.setData({
  63. searchPageNum: that.data.searchPageNum+1, //每次觸發上拉事件,把searchPageNum+1
  64. isFromSearch: false //觸發到上拉事件,把isFromSearch設為為false
  65. });
  66. that.fetchSearchList();
  67. }
  68. }
  69. })
var util = require(‘../../utils/util.js‘)
Page({
  data: {
    searchKeyword: ‘‘,  //需要搜索的字符
    searchSongList: [], //放置返回數據的數組
    isFromSearch: true,   // 用於判斷searchSongList數組是不是空數組,默認true,空的數組
    searchPageNum: 1,   // 設置加載的第幾次,默認是第一次
    callbackcount: 15,      //返回數據的個數
    searchLoading: false, //"上拉加載"的變量,默認false,隱藏
    searchLoadingComplete: false  //“沒有數據”的變量,默認false,隱藏
  },
  //輸入框事件,每輸入一個字符,就會觸發一次
  bindKeywordInput: function(e){
    console.log("輸入框事件")
    this.setData({
      searchKeyword: e.detail.value
    })
  },
  //搜索,訪問網絡
  fetchSearchList: function(){
    let that = this;
    let searchKeyword = that.data.searchKeyword,//輸入框字符串作為參數
        searchPageNum = that.data.searchPageNum,//把第幾次加載次數作為參數
        callbackcount =that.data.callbackcount; //返回數據的個數
    //訪問網絡
    util.getSearchMusic(searchKeyword, searchPageNum,callbackcount, function(data){
      console.log(data)
      //判斷是否有數據,有則取數據
      if(data.data.song.curnum != 0){
        let searchList = [];
        //如果isFromSearch是true從data中取出數據,否則先從原來的數據繼續添加
        that.data.isFromSearch ? searchList=data.data.song.list : searchList=that.data.searchSongList.concat(data.data.song.list)
        that.setData({
          searchSongList: searchList, //獲取數據數組
          zhida: data.data.zhida, //存放歌手屬性的對象
          searchLoading: true   //把"上拉加載"的變量設為false,顯示
        });
      //沒有數據了,把“沒有數據”顯示,把“上拉加載”隱藏
      }else{
        that.setData({
          searchLoadingComplete: true, //把“沒有數據”設為true,顯示
          searchLoading: false  //把"上拉加載"的變量設為false,隱藏
        });
      }
    })
  },
  //點擊搜索按鈕,觸發事件
  keywordSearch: function(e){
    this.setData({  
      searchPageNum: 1,   //第一次加載,設置1
      searchSongList:[],  //放置返回數據的數組,設為空
      isFromSearch: true,  //第一次加載,設置true
      searchLoading: true,  //把"上拉加載"的變量設為true,顯示
      searchLoadingComplete:false //把“沒有數據”設為false,隱藏
    })
    this.fetchSearchList();
  },
  //滾動到底部觸發事件
  searchScrollLower: function(){
    let that = this;
    if(that.data.searchLoading && !that.data.searchLoadingComplete){
      that.setData({
        searchPageNum: that.data.searchPageNum+1,  //每次觸發上拉事件,把searchPageNum+1
        isFromSearch: false  //觸發到上拉事件,把isFromSearch設為為false
      });
      that.fetchSearchList();
    }
  }
})

util.js:

[javascript] view plain copy print?
  1. function getSearchMusic(keyword, pageindex, callbackcount, callback){
  2. wx.request({
  3. url: ‘https://c.y.qq.com/soso/fcgi-bin/search_for_qq_cp‘,
  4. data: {
  5. g_tk: 5381,
  6. uin: 0,
  7. format: ‘json‘,
  8. inCharset: ‘utf-8‘,
  9. outCharset: ‘utf-8‘,
  10. notice: 0,
  11. platform: ‘h5‘,
  12. needNewCode: 1,
  13. w: keyword,
  14. zhidaqu: 1,
  15. catZhida: 1,
  16. t: 0,
  17. flag: 1,
  18. ie: ‘utf-8‘,
  19. sem: 1,
  20. aggr: 0,
  21. perpage: 20,
  22. n: callbackcount, //返回數據的個數
  23. p: pageindex,
  24. remoteplace: ‘txt.mqq.all‘,
  25. _: Date.now()
  26. },
  27. method: ‘GET‘,
  28. header: {‘content-Type‘: ‘application/json‘},
  29. success: function(res){
  30. if(res.statusCode == 200){
  31. callback(res.data);
  32. }
  33. }
  34. })
  35. }
  36. module.exports = {
  37. getSearchMusic: getSearchMusic
  38. }
function getSearchMusic(keyword, pageindex, callbackcount, callback){
  wx.request({
    url: ‘https://c.y.qq.com/soso/fcgi-bin/search_for_qq_cp‘,
    data: {
      g_tk: 5381,
      uin: 0,
      format: ‘json‘,
      inCharset: ‘utf-8‘,
      outCharset: ‘utf-8‘,
      notice: 0,
      platform: ‘h5‘,
      needNewCode: 1,
      w: keyword,
      zhidaqu: 1,
      catZhida: 1,
      t: 0,
      flag: 1,
      ie: ‘utf-8‘,
      sem: 1,
      aggr: 0,
      perpage: 20,
      n: callbackcount,  //返回數據的個數
      p: pageindex,
      remoteplace: ‘txt.mqq.all‘,
      _: Date.now()
    },
    method: ‘GET‘,
    header: {‘content-Type‘: ‘application/json‘},
    success: function(res){
      if(res.statusCode == 200){
        callback(res.data);
      }
    }
  })
}

module.exports = {
  getSearchMusic: getSearchMusic
}

wxss:

[css] view plain copy print?
  1. page{
  2. display: flex;
  3. flex-direction: column;
  4. height: 100%;
  5. }
  6. /*搜索*/
  7. .search{
  8. flex: auto;
  9. display: flex;
  10. flex-direction: column;
  11. background: #fff;
  12. }
  13. .search-bar{
  14. flex: none;
  15. display: flex;
  16. align-items: center;
  17. justify-content: space-between;
  18. padding: 20rpx;
  19. background: #f4f4f4;
  20. }
  21. .search-wrap{
  22. position: relative;
  23. flex: auto;
  24. display: flex;
  25. align-items: center;
  26. height: 80rpx;
  27. padding: 0 20rpx;
  28. background: #fff;
  29. border-radius: 6rpx;
  30. }
  31. .search-wrap .icon-search{
  32. margin-right: 10rpx;
  33. }
  34. .search-wrap .search-input{
  35. flex: auto;
  36. font-size: 28rpx;
  37. }
  38. .search-cancel{
  39. padding: 0 20rpx;
  40. font-size: 28rpx;
  41. }
  42. /*搜索結果*/
  43. .search-result{
  44. flex: auto;
  45. position: relative;
  46. }
  47. .search-result scroll-view{
  48. position: absolute;
  49. bottom: 0;
  50. left: 0;
  51. right: 0;
  52. top: 0;
  53. }
  54. .result-item{
  55. position: relative;
  56. display: flex;
  57. flex-direction: column;
  58. padding: 20rpx 0 20rpx 110rpx;
  59. overflow: hidden;
  60. border-bottom: 2rpx solid #e5e5e5;
  61. }
  62. .result-item .media{
  63. position: absolute;
  64. left: 16rpx;
  65. top: 16rpx;
  66. width: 80rpx;
  67. height: 80rpx;
  68. border-radius: 999rpx;
  69. }
  70. .result-item .title,
  71. .result-item .subtitle{
  72. overflow: hidden;
  73. text-overflow: ellipsis;
  74. white-space: nowrap;
  75. line-height: 36rpx;
  76. }
  77. .result-item .title{
  78. margin-bottom: 4rpx;
  79. color: #000;
  80. }
  81. .result-item .subtitle{
  82. color: #808080;
  83. font-size: 24rpx;
  84. }
  85. .result-item:first-child .subtitle text{
  86. margin-right: 20rpx;
  87. }
  88. .result-item:not(:first-child) .subtitle text:not(:first-child):before{
  89. content: ‘/‘;
  90. margin: 0 8rpx;
  91. }
  92. .loading{
  93. padding: 10rpx;
  94. text-align: center;
  95. }
  96. .loading:before{
  97. display: inline-block;
  98. margin-right: 5rpx;
  99. vertical-align: middle;
  100. content: ‘‘;
  101. width: 40rpx;
  102. height: 40rpx;
  103. background: url(../../images/icon-loading.png) no-repeat;
  104. background-size: contain;
  105. animation: rotate 1s linear infinite;
  106. }
  107. .loading.complete:before{
  108. display: none;
  109. }
page{
  display: flex;
  flex-direction: column;
  height: 100%;
}

/*搜索*/
.search{
  flex: auto;
  display: flex;
  flex-direction: column;
  background: #fff;
}
.search-bar{
  flex: none;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 20rpx;
  background: #f4f4f4;
}
.search-wrap{
  position: relative;
  flex: auto;
  display: flex;
  align-items: center;
  height: 80rpx;
  padding: 0 20rpx;
  background: #fff;
  border-radius: 6rpx;
}
.search-wrap .icon-search{
  margin-right: 10rpx;
}
.search-wrap .search-input{
  flex: auto;
  font-size: 28rpx;
}
.search-cancel{
  padding: 0 20rpx;
  font-size: 28rpx;
}

/*搜索結果*/
.search-result{
  flex: auto;
  position: relative;
}
.search-result scroll-view{
  position: absolute;
  bottom: 0;
  left: 0;
  right: 0;
  top: 0;
}
.result-item{
  position: relative;
  display: flex;
  flex-direction: column;
  padding: 20rpx 0 20rpx 110rpx;
  overflow: hidden;
  border-bottom: 2rpx solid #e5e5e5;
}

.result-item .media{
  position: absolute;
  left: 16rpx;
  top: 16rpx;
  width: 80rpx;
  height: 80rpx;
  border-radius: 999rpx;
}
.result-item .title,
.result-item .subtitle{
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  line-height: 36rpx;
}
.result-item .title{
  margin-bottom: 4rpx;
  color: #000;
}
.result-item .subtitle{
  color: #808080;
  font-size: 24rpx;
}
.result-item:first-child .subtitle text{
  margin-right: 20rpx;
}
.result-item:not(:first-child) .subtitle text:not(:first-child):before{
  content: ‘/‘;
  margin: 0 8rpx;
}
.loading{
  padding: 10rpx;
  text-align: center;
}
.loading:before{
  display: inline-block;
  margin-right: 5rpx;
  vertical-align: middle;
  content: ‘‘;
  width: 40rpx;
  height: 40rpx;
  background: url(../../images/icon-loading.png) no-repeat;
  background-size: contain;
  animation: rotate 1s linear infinite;
}
.loading.complete:before{
  display: none;
}

運行:

技術分享

微信小程序教程系列

相關連接:http://blog.csdn.net/michael_ouyang/article/details/54700871

基礎篇

------------------------------------------------------------

微信開發者工具的快捷鍵

微信小程序的文件結構 —— 微信小程序教程系列(1)

微信小程序的生命周期實例演示 —— 微信小程序教程系列(2)

微信小程序的動態修改視圖層的數據 —— 微信小程序教程系列(3)

微信小程序的新建頁面 —— 微信小程序教程系列(4)

微信小程序的如何使用全局屬性 —— 微信小程序教程系列(5)

微信小程序的頁面跳轉 —— 微信小程序教程系列(6)

微信小程序標題欄和導航欄的設置 —— 微信小程序教程系列(7)

微信小程序的作用域和模塊化 —— 微信小程序教程系列(8)

微信小程序視圖層的數據綁定 —— 微信小程序教程系列(9)

微信小程序視圖層的條件渲染 —— 微信小程序教程系列(10)

微信小程序視圖層的列表渲染 —— 微信小程序教程系列(11)

微信小程序視圖層的模板 —— 微信小程序教程系列(12)

微信小程序之wxss —— 微信小程序教程系列(13)

微信小程序的網絡請求 —— 微信小程序教程系列(14)

微信小程序的百度地圖獲取地理位置 —— 微信小程序教程系列(15)

微信小程序使用百度api獲取天氣信息 —— 微信小程序教程系列(16)

微信小程序獲取系統日期和時間 —— 微信小程序教程系列(17)

微信小程序之上拉加載和下拉刷新 —— 微信小程序教程系列(18)

微信小程序之組件 —— 微信小程序教程系列(19)

微信小程序之微信登陸 —— 微信小程序教程系列(20)

實戰篇

------------------------------------------------------------

微信小程序之頂部導航欄實例 —— 微信小程序實戰系列(1)

微信小程序之上拉加載(分頁加載)實例 —— 微信小程序實戰系列(2)

微信小程序之輪播圖實例 —— 微信小程序實戰系列(3)

微信小程序之仿android fragment之可滑動的底部導航欄實例 —— 微信小程序實戰系列(4)

微信小程序之登錄頁實例 —— 微信小程序實戰系列(5)

微信小程序之自定義toast實例 —— 微信小程序實戰系列(6)

微信小程序之自定義抽屜菜單(從下拉出)實例 —— 微信小程序實戰系列(7)

微信小程序之自定義模態彈窗(帶動畫)實例 —— 微信小程序實戰系列(8)

電商篇

------------------------------------------------------------

微信小程序之側欄分類 —— 微信小程序實戰商城系列(1)

微信小程序之仿淘寶分類入口 —— 微信小程序實戰商城系列(2)

微信小程序之購物數量加減 —— 微信小程序實戰商城系列(3)

微信小程序之商品屬性分類 —— 微信小程序實戰商城系列(4)

微信小程序之購物車 —— 微信小程序實戰商城系列(5)

未完待續。。。

更多小程序的教程:http://blog.csdn.net/column/details/14653.html

謝謝觀看,不足之處,敬請指導

附:項目下載地址 http://download.csdn.net/detail/michael_ouyang/9773794

[轉]微信小程序之加載更多(分頁加載)實例 —— 微信小程序實戰系列(2)