1. 程式人生 > >第五個頁面:更多電影頁面

第五個頁面:更多電影頁面

動態 導致 isempty 創建模板 start 小問題 empty 可復用 並且

筆記內容:第五個頁面:更多電影頁面
筆記日期:2018-01-27


跳轉到更多電影頁面以及獲取電影類型

因為要編寫一個新的頁面,所以第一件事情就是創建好目錄以及文件:
技術分享圖片

我們需要實現兩個功能,一是點擊電影資訊頁面上的 “更多” 時,跳轉到更多電影頁面中,二是跳轉時要獲取相應的電影類型。

編輯movie-list-template.wxml,修改內容如下:

<import src=‘../movie/movie-template.wxml‘ />

<template name=‘movieListTemplate‘>
  <view class=‘movie-list-container‘ style=‘margin: 0;‘>
    <view class=‘inner-container‘ style=‘margin: 0;‘>
      <view class=‘movie-head‘>
        <text class=‘slogan‘>{{categoryTitle}}</text>
        <!-- 添加點擊事件,並且把電影類型存儲在自定義屬性裏 -->
        <view catchtap=‘onMoreTap‘ class=‘more‘ data-category="{{categoryTitle}}">
          <text class=‘more-text‘>更多</text>
          <image class=‘more-img‘ src=‘/images/icon/arrow-right.png‘></image>
        </view>
      </view>
      <view class=‘movies-container‘>
        <block wx:for=‘{{movies}}‘ wx:for-item=‘movie‘>
          <template is=‘movieTemplate‘ data=‘{{...movie}}‘ />
        </block> 
      </view>
    </view>
  </view>
</template>

在movie.js文件中增加一個事件方法,內容如下:

  // 跳轉到更多電影頁面
  onMoreTap: function (event) {
    // 獲得電影類型
    var category = event.currentTarget.dataset.category;
    wx.navigateTo({
      // 通過參數把電影類型傳遞過去
      url: ‘more-movie/more-movie?category=‘ + category,
    });
  },

最後是在more-movie.js中測試一下是否能成功獲取相應的電影類型:

Page({

  onLoad: function (options) {
    // 接收傳遞過來的參數
    var category = options.category;
    console.log(category);
  },

})

分別點擊不同的電影類型上的 “更多“ ,看看控制臺的輸出是否對得上:
技術分享圖片


動態設置導航欄標題

以上我們完成了電影類型的獲得,在這之後就需要動態的把獲得的數據設置為導航欄標題,這樣點擊不同的電影類型時就能在更多電影頁面的導航欄上顯示不同的標題。

官方給出的設置導航欄文檔地址如下:

https://mp.weixin.qq.com/debug/wxadoc/dev/api/ui.html#wxsettopbartextobject

編輯more-movie.js文件內容如下:

Page({

  onLoad: function (options) {
    // 接收傳遞過來的參數
    var category = options.category;

    // 設置成變量才能在方法之間使用
    this.setData({
      navigateTitle: category,
    });
  },

  onReady: function (event) {
    // 動態設置導航欄標題
    wx.setNavigationBarTitle({
      title: this.data.navigateTitle,
    })
  }

})

以上新增的代碼就簡單的實現了動態設置導航欄標題。


在更多電影頁面上加載數據

這一步我們需要實現在更多電影頁面上,根據電影類型來向服務器加載不同電影類型的數據,由於這個請求API數據的方法挺通用的,所以我把它放到了util.js下,到時候就可以全局調用了,提高代碼的復用性。

編輯util.js代碼如下:

// 請求API的數據
function http (url, callBack) {

  // 通過reques來發送請求
  wx.request({
    url: url,
    method: ‘GET‘,
    header: {
      "Content-Type": "application/json"
    },
    success: function (res) {
      callBack(res.data);
    },
    fail: function (error) {
      console.log("API請求失敗!請檢查網絡!" + error);
    }
  });
}

module.exports={
  convertToStarsArray: convertToStarsArray,
  http: http
}

編輯more-movie.js代碼如下:

var app = getApp();
var util = require(‘../../../utils/util.js‘);

Page({
  data:{
    movies:{}
  },
  onLoad: function (options) {
    // 接收傳遞過來的參數
    var category = options.category;

    // 設置成變量才能在方法之間使用
    this.setData({
      navigateTitle: category,
    });

    var dataUrl = "";
    switch (category) {
      case "正在熱映":
        dataUrl = app.globalData.doubanBase + ‘/v2/movie/in_theaters‘;
        break;
      case "即將上映":
        dataUrl = app.globalData.doubanBase + ‘/v2/movie/coming_soon‘;
        break;
      case "豆瓣電影Top250":
        dataUrl = app.globalData.doubanBase + ‘/v2/movie/top250‘;
        break;
    }
    util.http(dataUrl, this.processDoubanData)
  },

  // 處理API返回的數據,並綁定到數據集裏
  processDoubanData: function (moviesDouban) {
    console.log(moviesDouban)
    // 存儲處理完的數據
    var movies = [];
    for (var idx in moviesDouban.subjects) {
      var subject = moviesDouban.subjects[idx];
      var title = subject.title;
      // 處理標題過長
      if (title.length >= 6) {
        title = title.substring(0, 6) + "...";
      }

      var temp = {
        stars: util.convertToStarsArray(subject.rating.stars),
        title: title,
        average: subject.rating.average,
        coverageUrl: subject.images.large,
        movieId: subject.id
      };
      movies.push(temp);
    }

    this.setData({
      movies: movies
    });
  },

  onReady: function (event) {
    // 動態設置導航欄標題
    wx.setNavigationBarTitle({
      title: this.data.navigateTitle,
    })
  }

})

實現movie-grid template

以上我們已經完成了數據的處理,現在只需要完成頁面代碼即可因為這個更多電影頁面的結構以及樣式都需要進行復用,所以我們還是使用template把這些代碼作為模板代碼。

創建模板文件:
技術分享圖片

movie-grid-template.wxml文件內容:

<import src="../movie/movie-template.wxml" />

<template name="movieGridTemplate">
  <view class=‘grid-container‘>
    <block wx:for="{{movies}}" wx:for-item="movie">
      <view class=‘single-view-container‘>
        <template is="movieTemplate" data="{{...movie}}" />
      </view>
    </block>
  </view>
</template>

movie-grid-template.wxss文件內容:

@import "../movie/movie-template.wxss";

.single-view-container{
  float: left; 
  margin-bottom: 40rpx;
}

.grid-container{
  margin: 40rpx 0 40rpx 6rpx;
}

more-movie.wxml就只需要引用模板即可,代碼的可復用性越高,需要寫的代碼就越少:

<import src="../movie-grid/movie-grid-template.wxml" />
<template is="movieGridTemplate" data="{{movies}}" />

more-movie.wxss也是只需要引用模板即可:

@import "../movie-grid/movie-grid-template.wxss";

運行效果:
技術分享圖片


實現上滑加載更多數據

以上我們實現了更多電影頁面,但是每次只能加載20條電影數據,我們希望能夠有一個上滑加載更多數據的功能,所以本節就是演示如何實現這樣一個功能。

實現這樣一個功能我們需要使用到scroll-view組件,該組件的官方說明文檔地址如下:

https://mp.weixin.qq.com/debug/wxadoc/dev/component/scroll-view.html

編輯movie-grid-template.wxml文件內容,將view換成scroll-view:

<import src="../movie/movie-template.wxml" />

<template name="movieGridTemplate">
  <scroll-view scroll-y="true" scroll-x="false" bindscrolltolower="onScrollLower" class=‘grid-container‘>
    <block wx:for="{{movies}}" wx:for-item="movie">
      <view class=‘single-view-container‘>
        <template is="movieTemplate" data="{{...movie}}" />
      </view>
    </block>
  </scroll-view>
</template>

編輯movie-grid-template.wxss文件內容,給grid-container設置一個固定的高度,因為需要有一個固定的高度才知道是否已經滾動到底部了:

@import "../movie/movie-template.wxss";

.single-view-container{
  float: left; 
  margin-bottom: 40rpx;
}

.grid-container{
  /*必須要給一個固定的高度*/
  height: 1300rpx;
  margin: 40rpx 0 40rpx 6rpx;
}

最後是編輯more-movie.js文件,這一步我們需要完成三件事情:

1.實現事件方法,當觸發bindscrolltolower時向API請求更多的數據

2.我們都知道第一次請求API時默認是請求0-19條數據,所以我們需要有一個變量充當計數器,讓這個變量的值在每一次請求成功後都進行累加,這樣才能讓start參數的值進行一個遞增,例如第一次是0-19,第二次就得是20-39,第三次就是40-59......以此類推

3.能夠實現不斷的往後加載數據之後,我們需要將這些數據都整合起來,不然的話數據會進行覆蓋,那麽每一次加載都只能顯示20條數據,這顯然不是我們想要的效果。我們想要的是數據進行疊加,第一次顯示20條數據,第二次顯示40條數據,第三次顯示60條數據......以此類推

理清思路後,編輯more-movie.js文件內容如下:

var app = getApp();
var util = require(‘../../../utils/util.js‘);

Page({
  data: {
    movies: {},
    totalCount: 0,
    isEmpty:true,  // 用於判斷movies是否為空,是的話就是第一次請求數據
  },
  onLoad: function (options) {
    // 接收傳遞過來的參數
    var category = options.category;

    // 設置成變量才能在方法之間使用
    this.setData({
      navigateTitle: category,
    });

    var dataUrl = "";
    switch (category) {
      case "正在熱映":
        dataUrl = app.globalData.doubanBase + ‘/v2/movie/in_theaters‘;
        break;
      case "即將上映":
        dataUrl = app.globalData.doubanBase + ‘/v2/movie/coming_soon‘;
        break;
      case "豆瓣電影Top250":
        dataUrl = app.globalData.doubanBase + ‘/v2/movie/top250‘;
        break;
    }
    this.setData({
      requestUrl: dataUrl
    });
    util.http(dataUrl, this.processDoubanData)
  },

  // 觸發bindscrolltolower事件時加載更多數據
  onScrollLower: function (event) {
    var nextUrl = this.data.requestUrl + "?start=" + this.data.totalCount + "&count=20";
    util.http(nextUrl, this.processDoubanData)
  },

  // 處理API返回的數據,並綁定到數據集裏
  processDoubanData: function (moviesDouban) {
    console.log(moviesDouban)
    // 存儲處理完的數據
    var movies = [];
    for (var idx in moviesDouban.subjects) {
      var subject = moviesDouban.subjects[idx];
      var title = subject.title;
      // 處理標題過長
      if (title.length >= 6) {
        title = title.substring(0, 6) + "...";
      }

      var temp = {
        stars: util.convertToStarsArray(subject.rating.stars),
        title: title,
        average: subject.rating.average,
        coverageUrl: subject.images.large,
        movieId: subject.id
      };
      movies.push(temp);
    }
    // 將新舊數據進行整合在一起
    var totalMovies={};
    if(!this.data.isEmpty){
      // 不為空代表不是第一次請求才進行整合
      totalMovies=this.data.movies.concat(movies);
    }else{
      // 第一次請求則需要不需要整合,並且需要改變isEmpty的狀態
      totalMovies = movies;
      this.data.isEmpty=false;
    }
    this.setData({
      movies: totalMovies
    });
    // 計數器,數據綁定成功後才進行累加
    this.data.totalCount += 20;
  },

  onReady: function (event) {
    // 動態設置導航欄標題
    wx.setNavigationBarTitle({
      title: this.data.navigateTitle,
    })
  }
})

設置loading狀態

以上我們完成了更多數據的加載,但是只是這樣的話,體驗還不夠良好,我們需要在數據加載時提示用戶一個loading狀態,這樣體驗起來就沒那麽生硬。

有幾個API都可以實現這個loading的效果,我這裏使用的是wx.showNavigationBarLoading(),以下是關於交互反饋API的官方文檔地址:

https://mp.weixin.qq.com/debug/wxadoc/dev/api/ui.html#wxshownavigationbarloading

編輯more-movie.js文件中的onScrollLower以及processDoubanData方法,在方法代碼的末尾加上以下內容:

onScrollLower: function (event) {
            // 其他代碼忽略

    // 設置loading狀態
    wx.showNavigationBarLoading();
},

processDoubanData: function (moviesDouban) {
            // 其他代碼忽略

    // 結束loading狀態
    wx.hideNavigationBarLoading();
},

通過這兩個API就簡單的實現了數據加載時提示loading狀態。


實現下拉頁面重新刷新數據

幾乎所有的app裏都有下拉頁面重新刷新數據的功能,所以我們也希望有一個這樣的功能。不過目前有一個小問題,我們是使用scroll-view組件來實現下滑加載更多數據的,但是130400版本更新後卻導致下拉刷新和scroll-view不能同時使用。

導致onPullDownRefresh事件函數無法執行的原因是頁面裏包含一個scroll-view組件。而scroll-view組件和onPullDownRefresh在130400版本裏是沖突的。當我們在頁面裏滑動scroll-view時,只是滑動這個組件,不再可以觸發onPullDownRefresh。當然,你還是可以在scroll-view區域外滑動頁面執行onPullDownRefresh。什麽意思呢?看下面的圖:
技術分享圖片

點擊箭頭那塊兒的空白部分依然可以執行onPullDownRefresh,但除此之外任何位置都不可以執行刷新事件。原因是因為,箭頭的空白部分不屬於scroll-view這個組件的區域,它是屬於page頁面的區域,page頁面依然可以執行onPullDownRefresh。但如果是在scroll-view組件內部去拉動頁面,則滑動的動作只對scroll-view組件有效,不再對page頁面有效,自然就不會再觸發頁面的onPullDownRefresh。

解決方案如下(下拉刷新和加載更多同時存在的方法):

放棄使用scroll-view組件,改用view組件。那麽既然放棄了scroll-view組件,上滑加載更多就不能再使用scroll-view的bindscrolltolower="onScrollLower"事件。

那麽view組件如何監控上滑到底的事件?MINA在Page裏還提供了一個onReachBottom事件,使用這個事件來監聽頁面上滑到底。

具體改動:

more-movie.js文件:

// 觸發onReachBottom事件時加載更多的數據
  onReachBottom: function (event) {
    var nextUrl = this.data.requestUrl + "?start=" + this.data.totalCount + "&count=20";
    util.http(nextUrl, this.processDoubanData);

    // 設置loading狀態
    wx.showNavigationBarLoading();
  },

將原本的onScrollLower方法更名成onReachBottom,方法的內容無需任何改動。

movie-grid-template.wxml文件:

<import src="../movie/movie-template.wxml" />

<template name="movieGridTemplate">
  <view class=‘grid-container‘>
    <block wx:for="{{movies}}" wx:for-item="movie">
      <view class=‘single-view-container‘>
        <template is="movieTemplate" data="{{...movie}}" />
      </view>
    </block>
  </view>
</template>

完成以上的修改後,才能開始著手開始實現我們的下拉頁面重新刷新數據的功能,首先我們需要編輯more-movie.json文件,增加如下內容,以開啟下拉刷新功能:

{
  "enablePullDownRefresh": "true"
}

該配置語句的官網說明文檔地址:

https://mp.weixin.qq.com/debug/wxadoc/dev/framework/config.html

當下拉頁面下拉刷新時會觸發onPullDownRefresh事件方法,所以最後就是編輯more-movie.js文件,實現onPullDownRefresh方法,以及在processDoubanData方法裏需要添加一句代碼:

  // 當下拉刷新時會觸發onPullDownRefresh方法,所以我們要實現它
  onPullDownRefresh: function (event) {
    var refreshUrl = this.data.requestUrl + "?start=0&count=20";
    util.http(refreshUrl, this.processDoubanData);

    // 清空movies裏的數據
    this.data.movies = {};
    // 將totalCount歸零
    this.data.totalCount = 0;
    // 並且改變isEmpty狀態
    this.data.isEmpty = true;

    // 設置loading狀態
    wx.showNavigationBarLoading();
  },

  processDoubanData: function (moviesDouban) {
          // 其他代碼忽略

    // 停止刷新數據
    wx.stopPullDownRefresh();
  },

關於backgroundColor 到底設置的是哪裏的顏色

很多人以為 backgroundColor 設置的是頁面的背景顏色,而且官方文檔上寫的也不是很清楚,就寫了個 “窗口的背景色” 。經過試驗發現實際上 backgroundColor 設置的是我們下拉頁面時的那個背景顏色,我們可以做一個簡單的小實驗,在more-movie.json文件中增加一行配置:

{
  "enablePullDownRefresh": "true",
  "backgroundColor":"red"
}

然後到more-movie頁面中,然後下拉頁面,可以看到背景顏色是我們設置的red紅色:
技術分享圖片

或許不能說是下拉頁面時的背景顏色,嚴格來說是Page頁面底層下的背景顏色,也就是脫離了Page頁面時裸露出來的頁面背景。

第五個頁面:更多電影頁面