1. 程式人生 > >最後一個頁面:構建電影詳情頁面

最後一個頁面:構建電影詳情頁面

ons 基本上 webkit style 所有 idt for 換行 lur

筆記內容:最後一個頁面:構建電影詳情頁面
筆記日期:2018-02-02


電影搜索頁面構建

我們想要有一個搜索電影的功能,需要在電影資訊頁面頂部編寫一個搜索框,當我們的鼠標焦點位於該搜索框時,就會顯示出電影搜索頁面,而點擊搜索框的關閉圖標時,需要隱藏電影搜索頁面。所以這個電影搜索頁面不是一個單獨的頁面文件,而是用隱/顯的方式來做。

搜索框效果圖:
技術分享圖片

要實現這個搜索框,我們首先需要一個表單組件:input,該組件的官方說明文檔地址如下:

https://mp.weixin.qq.com/debug/wxadoc/dev/component/input.html

然後還需要用到icon組件,該組件的官方說明文檔地址如下:

https://mp.weixin.qq.com/debug/wxadoc/dev/component/icon.html

1.編輯movies.wxml代碼如下:

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

<view class="search">
  <icon type=‘search‘ class=‘search-img‘ size=‘13‘ color=‘#405f80‘></icon>
  <input type=‘text‘ placeholder=‘{{placeholder}}‘ placeholder-class=‘placeholder‘ bindfocus=‘onBindFocus‘ bindconfirm=‘onBindFirm‘ value="{{cleanValue}}" />
  <image wx:if=‘{{searchPanelShow}}‘ src=‘/images/icon/xx.png‘ class=‘xx-img‘ catchtap=‘onCancelImgTap‘></image>
</view>
<view class=‘container‘ wx:if=‘{{containerShow}}‘>
  <view>
    <template is="movieListTemplate" data=‘{{...inTheaters}}‘ />
  </view>
  <view>
    <template is="movieListTemplate" data=‘{{...comingSoon}}‘ />
  </view>
  <view>
    <template is="movieListTemplate" data=‘{{...top250}}‘ />
  </view>
</view>

<view class=‘search-panel‘ wx:if=‘{{searchPanelShow}}‘>
  <template is=‘movieGridTemplate‘ data=‘{{...searchResult}}‘ />
</view>

2.編輯movies.wxss代碼如下:

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

.container{
  background-color: #f2f2f2;
}

.container view{
  margin-bottom: 30rpx;
}

.search{
  background-color: #f2f2f2;
  height: 80rpx;
  width: 100%;
  display: flex;
  flex-direction: row;
}

.search-img{
  margin: auto 0 auto 20rpx;
}

.search input{
  height: 100%;
  width: 600rpx;
  margin-left: 20px;
  font-size: 28rpx;
}

.placeholder{
  font-size: 14px;
  color: #d1d1d1;
  margin-left: 20rpx;
}

.search-panel{
  position: absolute;
  top: 80rpx;
}
.xx-img{
  height: 30rpx;
  width: 30rpx;
  margin: auto 0 auto 10rpx;
}

3.編輯movies.js代碼如下:

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

Page({
  data: {
    // 需要有一個初始值
    inTheaters: {},
    comingSoon: {},
    top250: {},
    searchResult: {},
    containerShow: true,
    searchPanelShow: false,
  },
  onLoad: function (event) {
    var inTheatersUrl = app.globalData.doubanBase + ‘/v2/movie/in_theaters?start=0&count=3‘;
    var comingSoonUrl = app.globalData.doubanBase + ‘/v2/movie/coming_soon?start=0&count=3‘;
    var top250Url = app.globalData.doubanBase + ‘/v2/movie/top250?start=0&count=3‘;

    this.getMovieListData(inTheatersUrl, "inTheaters", "正在熱映");
    this.getMovieListData(comingSoonUrl, "comingSoon", "即將上映");
    this.getMovieListData(top250Url, "top250", "豆瓣電影Top250");
  },

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

  // 請求API的數據
  getMovieListData: function (url, settedkey, categoryTitle) {
    var that = this;
    // 通過reques來發送請求
    wx.request({
      url: url,
      method: ‘GET‘,
      header: {
        "Content-Type": "application/json"
      },
      success: function (res) {
        that.processDoubanData(res.data, settedkey, categoryTitle);
      },
      fail: function () {
        console.log("API請求失敗!請檢查網絡!");
      }
    });
  },

  // 關閉電影搜索頁面
  onCancelImgTap: function (event) {
    this.setData({
      containerShow: true,
      searchPanelShow: false,
      searchResult: {},
      cleanValue: ‘‘,
    });

  },

  // 顯示電影搜索頁面
  onBindFocus: function (event) {
    this.setData({
      containerShow: false,
      searchPanelShow: true,
    });
  },

  // 搜索電影數據
  onBindFirm: function (event) {
    var text = event.detail.value;
    var searchUrl = app.globalData.doubanBase + "/v2/movie/search?q=" + text;
    this.getMovieListData(searchUrl, "searchResult", "");
  },

  // 處理API返回的數據
  processDoubanData: function (moviesDouban, settedkey, categoryTitle) {
    // 存儲處理完的數據
    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);
    }

    if (categoryTitle == ‘正在熱映‘) {
      this.setData({
        placeholder: movies[0][‘title‘]
      });
    }

    // 動態賦值
    var readyData = {};
    readyData[settedkey] = {
      categoryTitle: categoryTitle,
      movies: movies
    };
    this.setData(readyData);
  },

})

運行效果:
技術分享圖片
技術分享圖片


編寫電影詳情頁面

以上我們已經完成了大部分的頁面了,現在我們來完成最後一個影詳情頁面,我們希望在電影資訊頁面上點擊某一部電影時,要能跳轉到該電影的詳情頁面,所以這是一個新的頁面,我們首先要做的事情就是創建這個頁面的目錄及文件:
技術分享圖片

然後首先是在movie-template.wxml文件中加上一個點擊事件:

<import src=‘../stars/stars-template.wxml‘ />
<template name=‘movieTemplate‘>
  <view class=‘movie-container‘ catchtap=‘onMovieTap‘ data-movieId=‘{{movieId}}‘ style=‘margin:0‘>
    <image class=‘movie-img‘ src=‘{{coverageUrl}}‘></image>
    <text class=‘movie-title‘>{{title}}</text>
    <template is=‘starsTemplate‘ data="{{stars:stars, score: average}}" />
  </view>
</template>

接著在movies.js文件中編寫一段跳轉頁面的邏輯代碼:

  // 跳轉到電影詳情頁面
  onMovieTap:function(event){
    // 獲得電影的id
    var movieId = event.currentTarget.dataset.movieid;
    wx.navigateTo({
      // 通過參數把電影的subject id傳遞過去
      url: ‘movie-detail/movie-detail?id=‘ + movieId,
    });
  },

然後在movie-detail.js裏接收id參數,向API請求數據,把服務器返回的數據在控制臺中打印出來:

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

Page({

  data: {

  },

  onLoad: function (options) {
    var movieId = options.id;
    var url = app.globalData.doubanBase + "/v2/movie/subject/" + movieId;
    util.http(url, this.processDoubanData);
  },

  processDoubanData:function(data){
    console.log(data)
  },

})

確定能正常獲取到數據後,就可以開始處理數據了,主要的邏輯是做數據的篩選及判空容錯,編寫movie-detail.js代碼如下:

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

Page({

  data: {
    movie: {},
  },

  onLoad: function (options) {
    var movieId = options.id;
    var url = app.globalData.doubanBase + "/v2/movie/subject/" + movieId;
    util.http(url, this.processDoubanData);
  },

  // 處理API返回的數據
  processDoubanData: function (data) {
    // 初始一些數據的默認值
    var director = {
      avatar: "",
      name: "",
      id: ""
    }

    // 處理可能會出現的空值
    if (data.directors[0] != null) {
      if (data.directors[0].avatars != null) {
        director.avatar = data.directors[0].avatars.large;
      }
      director.name = data.directors[0].name;
      director.id = data.directors[0].id;
    }

    // 填充數據
    var movie = {
      movieImg: data.images ? data.images.large : "",  // 處理可能會出現的空值
      country: data.countries[0],
      title: data.title,
      originalTitle: data.original_title,
      wishCount: data.wish_count,
      commentCount: data.comments_count,
      year: data.year,
      generes: data.genres.join("、"),  // 把數組轉化成用 、分割的字符串
      stars: util.convertToStarsArray(data.rating.stars),
      score: data.rating.average,
      director: director,
      casts: util.convertToCastString(data.casts),
      castsInfo: util.convertToCastInfos(data.casts),
      summary: data.summary,
    }
    console.log(movie)
    // 綁定數據
    this.setData({
      movie: movie
    });
  },

})

接著util.js代碼如下:

            // 以上代碼略

// 把演員的名字用斜杠分割
function convertToCastString(casts) {
  var castsjoin = "";
  for (var idx in casts) {
    castsjoin = castsjoin + casts[idx].name + "/";
  }
  return castsjoin.substring(0, castsjoin.length - 2);
}

// 處理演員的名稱與照片
function convertToCastInfos(casts) {
  var castsArray = []
  for (var idx in casts) {
    var cast = {
      img: casts[idx].avatars ? casts[idx].avatars.large : "", // 處理可能會出現的空值
      name: casts[idx].name
    }
    castsArray.push(cast);
  }
  return castsArray;
}

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

然後編譯運行看看控制臺裏是否有正常打印出數據。


以上我們完成了數據獲取以及處理,現在我們就可以開始編寫頁面上的代碼了。首先編寫電影詳情頁面的骨架代碼,這個頁面的代碼還挺多的,不過並不復雜:

movie-detail.wxml骨架代碼:

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

<view class=‘container‘>
  <image class=‘head-img‘ src=‘{{movie.movieImg}}‘ mode=‘aspectFill‘ />
  <view class=‘head-img-hover‘>
    <text class=‘main-title‘>{{movie.title}}</text>
    <text class=‘sub-title‘>{{movie.country + " . " + movie.year}}</text>
    <view class=‘like‘>
      <text class=‘highlight-font‘>
        {{movie.wishCount}}
      </text>
      <text class=‘plain-font‘>
        人喜歡
      </text>
      <text class=‘highlight-font‘>
        {{movie.commentCount}}
      </text>
      <text class=‘plain-font‘>
        條評論
      </text>
    </view>
  </view>
  <image class=‘movie-img‘ src=‘{{movie.movieImg}}‘ data-src="{{movie.movieImg}}" catchtap=‘viewMoviePostImg‘ />
  <view class=‘summary‘>
    <view class=‘original-title‘>
      <text>{{movie.originalTitle}}</text>
    </view>
    <view class="flex-row">
      <text class="mark">評分</text>
      <template is="starsTemplate" data="{{stars:movie.stars, score:movie.score}}" />
    </view>
    <view class="flex-row">
      <text class="mark">導演</text>
      <text>{{movie.director.name}}</text>
    </view>
    <view class="flex-row">
      <text class="mark">影人</text>
      <text>{{movie.casts}}</text>
    </view>
    <view class="flex-row">
      <text class="mark">類型</text>
      <text>{{movie.generes}}</text>
    </view>
  </view>
  <view class="hr"></view>
  <view class="synopsis">
    <text class="synopsis-font">劇情簡介</text>
    <text class="summary-content">{{movie.summary}}</text>
  </view>
  <view class="hr"></view>
  <view class="cast">
    <text class="cast-font"> 影人</text>
    <scroll-view class="cast-imgs" scroll-x="true" style="width:100%">
      <block wx:for="{{movie.castsInfo}}" wx:for-item="item">
        <view class="cast-container">
          <image class="cast-img" src="{{item.img}}"></image>
          <text class="cast-name">{{item.name}}</text>
        </view>
      </block>
    </scroll-view>
  </view>
</view>

movie-detail.wxss樣式代碼:

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

.container {
  display: flex;
  flex-direction: column;
}

.head-img {
  width: 100%;
  height: 320rpx;
  /* 圖片模糊效果 */
  -webkit-filter: blur(20px);
}

.head-img-hover {
  width: 100%;
  height: 320rpx;
  position: absolute;
  top: 0;
  left: 0;
  display: flex;
  flex-direction: column;
}

.main-title {
  font-size: 19px;
  color: #fff;
  font-weight: bold;
  margin-top: 50rpx;
  margin-left: 40rpx;
  letter-spacing: 2px;
}

.sub-title {
  font-size: 28rpx;
  color: #fff;
  margin-left: 40rpx;
  margin-top: 30rpx;
}

.like {
  display: flex;
  flex-direction: row;
  margin-top: 30rpx;
  margin-left: 40rpx;
}

.highlight-font {
  color: #f21146;
  font-size: 22rpx;
  margin-right: 10rpx;
}

.plain-font {
  color: #666;
  font-size: 22rpx;
  margin-right: 30rpx;
}

.movie-img {
  height: 238rpx;
  width: 175rpx;
  position: absolute;
  top: 160rpx;
  right: 30rpx;
}

.summary {
  margin-left: 40rpx;
  margin-top: 40rpx;
  color: #777;
}

.original-title {
  color: #1f3463;
  font-size: 24rpx;
  font-weight: bold;
  margin-bottom: 40rpx;
}

.flex-row {
  display: flex;
  flex-direction: row;
  margin-bottom: 10rpx;
}

.mark {
  margin-right: 30rpx;
  white-space: nowrap;
  color: #999;
}

.hr {
  margin-top: 45rpx;
  height: 1px;
  width: 100%;
  background-color: #d9d9d9;
}

.synopsis {
  margin-left: 40rpx;
  display: flex;
  flex-direction: column;
  margin-top: 50rpx;
}

.synopsis-font {
  color: #999;
}

.summary-content {
  margin-top: 20rpx;
  margin-right: 40rpx;
  line-height: 40rpx;
  letter-spacing: 1px;
}

.cast {
  margin-left: 40rpx;
  display: flex;
  flex-direction: column;
  margin-top: 50rpx;
}

.cast-font {
  color: #999;
  margin-bottom: 40rpx;
}

.cast-container {
  display: inline-flex;
  flex-direction: column;
  margin-bottom: 50rpx;
  margin-right: 40rpx;
  width: 170rpx;
  text-align: center;
  /* 正常換行 */
  white-space: normal;
}

.cast-imgs {
  /* 禁止自動換行 */
  white-space: nowrap;
}

.cast-img {
  width: 170rpx;
  height: 210rpx;
}

.cast-name {
  margin: 10rpx auto 0;
}

movie-detail.js裏增加以下代碼:

  // 查看圖片
  viewMoviePostImg: function (event) {
    var src = event.currentTarget.dataset.src;
    wx.previewImage({
      current: src,   // 當前顯示圖片的http鏈接
      urls: [src],  // 需要預覽的圖片的http鏈接
    })
  },

其中用到的image組件的官方說明文檔地址如下:

https://mp.weixin.qq.com/debug/wxadoc/dev/component/image.html

然後我們希望更多電影頁面中也能夠跳轉到電影詳情頁,所以需要在more-movie.js文件中增加以下代碼:

  // 跳轉到電影詳情頁面
  onMovieTap: function (event) {
    // 獲得電影的id
    var movieId = event.currentTarget.dataset.movieid;
    wx.navigateTo({
      // 通過參數把電影的subject id傳遞過去
      url: ‘../movie-detail/movie-detail?id=‘ + movieId,
    });
  },

所有的代碼編寫完成後,運行效果如下:
技術分享圖片


到目前為止,整個小程序的開發就告一段落了,這個筆記的目的也只是為了記錄一下開發的過程,所以其中對細節沒有過多的介紹,不過基本上代碼也都註釋了,也是為了方便以後遇到類似的功能可以參考實現思路,畢竟像我這種代碼寫完就忘的人。

最後一個頁面:構建電影詳情頁面