小程序项目文字与电影(二)

一,电影页面功能

 功能分析,1.点击搜索关键字,搜索电影

2.点击更多按钮,跳转到更多电影页面

3.点击电影图片,跳转到电影详情页

逻辑分析,1.在movies页面分别发送三个请求,获取正在上映的,不久上映的,top250的数据,传递给电影列表movie-list子组件

2.从lin-ui映入搜索组件l-search-bar, 

 3.点击更多,跳转到更多页面

4.引入movie-list组件

pages-->movies->movies

movies.wxml

在movie-lilst设置组件外链样式类

<l-search-bar bind:lincancel="onSearchCancel" bind:linconfirm="onConfirm" l-class="ex-search-bar" placeholder="盗梦空间、你的名字"/>

<view wx:if="{{!searchResult}}">
电影列表 <movie-list data-type="in_theaters" bind:tap="onGotoMore" movies="{{inTheaters}}" title="正在热映" f-class="movie-list" /> <movie-list data-type="coming_soon" bind:tap="onGotoMore" movies="{{comingSoon}}" title="即将上映" f-class="movie-list" /> <movie-list data-type="top250" bind:tap="onGotoMore" movies="{{top250}}" title="豆瓣Top250" f-class="movie-list" /> </view> <!-- 搜索的结构 ,默认遍历每项为item--> <view class="search-container" wx:else> <block wx:for="{{searchData}}" wx:key="index"> <movie class="movie" movie="{{item}}" /> </block> </view>

movies.wxss

/* pages/movies/movies.wxss */
//movie-list组件的外链样式 .movie-list{ margin-bottom: 30rpx; /* background-color: teal !important; */ } //组件外链样式 .ex-search-bar{ height: 90rpx !important; } .search-container{ display: flex; flex-direction: row;
//换行,开启flex,不会自动换行 flex
-wrap: wrap; padding: 30rpx 28rpx; justify-content: space-between; } /* 解决两端对齐的bug 每个电影图像宽200rpx*/ .search-container::after{ content:''; 200rpx; } page{ background-color: #f2f2f2; /* background-color: teal; */ }

movies.js, 从app.js中引入全局变量app.gBaseUrl,

ongotomore函数,跳转到更多页面,把电影类型参数传递到more-movie页面
// pages/movies/movies.js

const app = getApp()
Page({

  /**
   * 页面的初始数据
   */
  data: {
    // 正在上映数据
    inTheaters:[],
    // 不就上映数据
    comingSoon:[],
    // top250数据
    top250:[],
    // 搜索状态,影响结构
    searchResult:false,
    // 搜索后的数据
    searchData:[]
  },

  /**
   * 生命周期函数--监听页面加载
   */
  onLoad: function (options) {
    // 不可用async, await,默认get请求,类型in_theaters(正在上映)
    wx.request({
      url: app.gBaseUrl + 'in_theaters',
      // 请求参数,第0条开始加载,三条数据,问号?后的参数
      data:{
        start:0,
        count:3
      },
      // 箭头函数,this指向
      success:(res)=>{
        this.setData({
          inTheaters:res.data.subjects
        })
      }
    })   
  
    wx.request({
      // 类型coming_soon(不久上映)
      url: app.gBaseUrl + 'coming_soon',
      data:{
        start:0,
        count:3
      },
      success:(res)=>{
        this.setData({
          comingSoon:res.data.subjects
        })
      }
    })
    wx.request({
      // 类型top250(top250)
      url: app.gBaseUrl + 'top250',
      data:{
        start:0,
        count:3
      },
      success:(res)=>{
        this.setData({
          top250:res.data.subjects
        })
      }
    })
  },

  // 去更多电影页面
  onGotoMore(event){
    console.log(event)
    // 获取自定义属性,作为参数
    const type = event.currentTarget.dataset.type
    wx.navigateTo({
      url: '/pages/more-movie/more-movie?type=' + type,
    })
  },

  // 真实机型输入框点击确定触发,小程序模拟器enter键触发,kin-ui的事件,event.detail.value可获取到输入字
  onConfirm(event){
    // 正在搜索
    this.setData({
      searchResult:true
    })
    wx.request({
      url: app.gBaseUrl + 'search',
      // 查询参数,?后的参数
      data:{
        q:event.detail.value
      },
      success:(res)=>{
        this.setData({
          searchData:res.data.subjects
        })
      },
    })
  },

  // 取消搜索触发,
  onSearchCancel(event){
    this.setData({
      searchResult:false
    })
  },


})

注册movies-list子组件,movies.json

{
  "usingComponents": {
    "movie-list":"/components/movie-list/index",
    "l-search-bar":"/miniprogram_npm/lin-ui/search-bar/index"
  },
  "navigationBarTitleText":"光与影"
}

部分电影数据

{
"count": 20,
"start": 0,
"subjects": [
{
    "casts": [
        {
            "avatars": {
                "large": "https://img3.doubanio.com/view/celebrity/s_ratio_celebrity/public/p230.jpg"
            },
            "name": "弗兰克·德拉邦特"
        },
        {
            "avatars": {
                "large": "https://img3.doubanio.com/view/celebrity/s_ratio_celebrity/public/p17525.jpg"
            },
            "name": "蒂姆·罗宾斯"
        },
        {
            "avatars": {
                "large": "https://img3.doubanio.com/view/celebrity/s_ratio_celebrity/public/p34642.jpg"
            },
            "name": "摩根·弗里曼"
        }
    ],
    "comments_count": 222527,
    "countries": [
        "美国"
    ],
    "directors": [
        {
            "avatars": {
                "large": null
            },
            "name": "弗兰克·德拉邦特"
        }
    ],
    "genres": [
        "剧情",
        "犯罪"
    ],
    "id": 3,
    "images": {
        "large": "https://img3.doubanio.com/view/photo/s_ratio_poster/public/p480747492.jpg"
    },
    "original_title": "肖申克的救赎 The Shawshank Redemption",
    "rating": {
        "average": 9.6,
        "max": 10,
        "min": 0,
        "stars": "50"
    },
    "reviews_count": 5794,
    "summary": "",
    "title": "肖申克的救赎 The Shawshank Redemption",
    "warning": "数据来源于网络整理,仅供学习,禁止他用。如有侵权请联系公众号:小楼昨夜又秋风。我将及时删除。",
    "wish_count": 98814,
    "year": 1994
}

引入movie-list组件,电影列表 

components--> movie-llist-->movie-llist

<view class="container f-class">
  <view class="title-container">
    <text>{{title}}</text>
    <text class="more-text">更多 ></text>
  </view>
  <view class="movie-container">
    <block wx:for="{{movies}}" wx:key="index">
      <movie movie="{{item}}" />
    </block>
  </view>
</view>
/* components/movie-list/index.wxss */

.container{
  padding: 36rpx 36rpx;
  background-color: #ffffff;
}

.title-container{
  display: flex;
  flex-direction: row;
  justify-content: space-between;
  margin-bottom: 28rpx;
}

.movie-container{
  display: flex;
  flex-direction: row;
  justify-content: space-between;
}

.more-text{
  color: #1f4ba5;
}

movie-lilst.js

// components/movie-list/index.js
Component({
  /**
   * 组件的属性列表
   */
  // 设置组件外链样式类
  externalClasses:['f-class'],

  properties: {
    title:String,
    movies:Array
  },

  /**
   * 组件的初始数据
   */
  data: {

  },

  /**
   * 组件的方法列表
   */
  methods: {

  }
})

注册movie组件

movie-list.json

{
  "component": true,
  "usingComponents": {
    "movie": "/components/movie/index"
  }
}

引入movie组件,电影卡片

components--> movie-->movie

<view catch:tap="onGoToDetail" class="container">
    <image class="poster" src="{{movie.images.large}}"></image>
    <text class="title">{{movie.title}}</text>
    <view class="rate-container">
    <l-rate disabled="{{true}}" size="22" score="{{movie.rating.stars/10}}" />

    <text class="score">{{movie.rating.average}}</text>
    </view>
</view>
.container{
  display: flex;
  flex-direction: column;
   200rpx;
}

.poster{
   100%;
  height: 270rpx;
  margin-bottom: 22rpx;
}

.title{
  white-space: nowrap;
  text-overflow: ellipsis;
  overflow: hidden;
  word-break: break-all;
}

.rate-container{
  margin-top:6rpx;
  display: flex;
  flex-direction: row;
  /* 基线对齐 */
  align-items: baseline;
}

.score{
  margin-left:20rpx;
  font-size:24rpx;
}

movie.js

点击电影卡片,跳转到电影详情页面,携带id参数

// components/movie/index.js
Component({
  /**
   * 组件的属性列表
   */


  properties: {
    movie:Object
  },

  /**
   * 组件的初始数据
   */
  data: {

  },

  /**
   * 组件的方法列表
   */
  methods: {
    onGoToDetail(event){
      // console.log(this.properties.movie)
      const mid = this.properties.movie.id
      wx.navigateTo({
        url: '/pages/movie-detail/movie-detail?mid=' + mid
      })
    }
  }
})

跳转到更多电影页面

pages-->more-movie-->more-movie

<view class="container">
    <block wx:for="{{movies}}" wx:key="index">
        <movie class="movie" movie="{{item}}" />
    </block>
</view>
/* pages/more-movie/more-movie.wxss */

.container{
  display: flex;
  flex-direction: row;
  /* 换行,用flex布局不会自动换行 */
  flex-wrap: wrap;
  padding: 30rpx 28rpx;
  justify-content: space-between;
}

.movie{
  margin-bottom: 30rpx;
}

more-movie.js

1.触顶下拉加载数据动画,要在json文件中引入enablePullDownRefresh属性,然后在函数中,调用小程序的方法wx.showNavigationBarLoading()

2.不同类型的更多电影,顶部标题不一样,需要在onready中动态设置,调用小程序的 wx.setNavigationBarTitle函数
 
3.触底上拉一次,加载12条数据,是个追加过程,每次下拉,还有个动态加载状态,小程序调用wx.hideNavigationBarLoading()函数
 
 
// pages/more-movie/more-movie.js
const app = getApp()

Page({

  /**
   * 页面的初始数据
   */
  data: {
    movies:[],
    _type:''
  },

  /**
   * 生命周期函数--监听页面加载
   */
  onLoad: function (options) {
    // 获取自定义type属性,作为请求路劲
    const type = options.type
    this.data._type = type
    wx.request({
      url: app.gBaseUrl + type,
      // 从第0条开始加载,请求12条数据
      data:{
        start:0,
        count:12
      },
      success:(res)=>{
        console.log(res)
        this.setData({
          movies:res.data.subjects
        })
      }
    }) 
  },

  /**
   * 生命周期函数--监听页面初次渲染完成
   */
  onReady: function () {
    let title = '电影'
    switch(this.data._type){
      case 'in_theaters':
        title='正在热映'
        break
      case 'coming_soon':
        title = '即将上映'
        break
      case 'top250':
        title = '豆瓣Top250'
        break
    }
    // 动态设置顶部标题
    wx.setNavigationBarTitle({
      title: title,
    })
  },

  /**
   * 生命周期函数--监听页面显示
   */
  onShow: function () {

  },

  /**
   * 生命周期函数--监听页面隐藏
   */
  onHide: function () {
   
  },

  /**
   * 生命周期函数--监听页面卸载
   */
  onUnload: function () {

  },

  /**
   * 页面相关事件处理函数--监听用户下拉动作
   */
  onPullDownRefresh: function () {
    wx.request({
      url: app.gBaseUrl + this.data._type,
      // 页面下拉,获取最新的12条数据
      data:{
        start:0,
        count:12,
      },
      success:(res)=>{
        this.setData({
          movies:res.data.subjects
        })
        // 下拉效果停止
        wx.stopPullDownRefresh()
      }
    })
  },

  /**
   * 页面上拉触底事件的处理函数
   */
  onReachBottom: function () {
    // [1,2,3...... 12,13,]
    // [0,1,2....11] + [12,13....23] + [24...35] + [36...47]
//每次上拉加载出来加载动画
wx.showNavigationBarLoading() wx.request({ url: app.gBaseUrl + this.data._type, // 从每次请求数据的最后一条开始加载,12条数据 data:{ start: this.data.movies.length, count:12 }, success:(res)=>{ console.log(res) this.setData({ // 数组追加合并 movies:this.data.movies.concat(res.data.subjects) }) // 每次追加数据后,顶部添加加载转圈效果 wx.hideNavigationBarLoading() } }) }, /** * 用户点击右上角分享 */ onShareAppMessage: function () { } })

json文件

{
  "usingComponents": {
    "movie":"/components/movie/index"
  },
  "enablePullDownRefresh":true
}

跳转到电影详情页面

实现影人中图片左右滚动效果,引入小程序组件scroll-view组件,但是会放flex布局失效,需要添加enable-flex 让其生效,并且会是容器留有很大高度,给容器高度重新设置下

图片的mode模式,给image标签添加mode="aspectFill"缩放模式,官网https://developers.weixin.qq.com/miniprogram/dev/component/image.html

给图片添加模糊效果,-webkit-filter:blur(20px); 

 

pages-->movie-detail-->movie-detail

<view class="container">
  <image mode="aspectFill" class="head-img" src="{{movie.image}}"></image>
  <view class="head-img-hover">
    <text class="main-title">{{movie.title}}</text>
    <text class="sub-title">{{movie.subtitle}}</text>
    <view class="like">
      <text class="highlight-font">{{movie.wishCount}}</text>
      <text class="plain-font">人喜欢</text>
      <text class="highlight-font">{{movie.commentsCount}}</text>
      <text class="plain-font">条评论</text>
    </view>
    <image bind:tap="onViewPost" class="movie-img" src="{{movie.image}}"></image>
  </view>
  <view class="summary">
    <view class="original-title">
      <text>{{movie.title}}</text>
    </view>
    <view class="flex-row">
      <text class="mark">评分</text>
      <view class="score-container">
        <l-rate disabled="{{true}}" size="22" score="{{movie.rating}}" />
        <text class="average">{{movie.average}}</text>
      </view>
    </view>
    <view class="flex-row">
      <text class="mark">导演</text>
      <text>{{movie.directors}}</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.genres}}</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="casts">
    <text class="cast-font">影人</text>
    <scroll-view enable-flex scroll-x class="casts-container">
      <block wx:for="{{movie.castsInfo}}" wx:key="index">
        <view class="cast-container">
          <image class="cast-img" src="{{item.img}}"></image>
          <text>{{item.name}}</text>
        </view>
        <view class="cast-container">
          <image class="cast-img" src="{{item.img}}"></image>
          <text>{{item.name}}</text>
        </view>
        <view class="cast-container">
          <image class="cast-img" src="{{item.img}}"></image>
          <text>{{item.name}}</text>
        </view>
      </block>
    </scroll-view>
  </view>
</view>
.container{
  display: flex;
  flex-direction: column;
}

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

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

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

.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;
   175rpx;
  position: absolute;
  top:160rpx;
  right: 30rpx;
}

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

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

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

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

.score-container{
  display: flex;
  flex-direction: row;
  align-items: baseline;
}

.average{
  margin-left:20rpx;
  margin-top:4rpx;
}

.hr{
  margin-top:45rpx;
   100%;
  height: 1px;
  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;
}

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

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

.cast-img{
   170rpx;
  height: 210rpx;
  margin-bottom: 10rpx;
}

.casts-container{
  display: flex;
  flex-direction: row;
  margin-bottom: 50rpx;
  margin-right: 40rpx;
  height: 300rpx;
}

.cast-container{
  display: flex;
  flex-direction: column;
  align-items: center;
  margin-right: 40rpx;
}

movie-detail.js

请求获取的电影详情数据,需要预处理

{
    "casts": [
        {
            "avatars": {
                "large": "https://img1.doubanio.com/view/celebrity/s_ratio_celebrity/public/p1470662353.8.jpg"
            },
            "name": "约翰·卡尼"
        },
        {
            "avatars": {
                "large": "https://img3.doubanio.com/view/celebrity/s_ratio_celebrity/public/p49301.jpg"
            },
            "name": "格伦·汉塞德"
        },
        {
            "avatars": {
                "large": "https://img3.doubanio.com/view/celebrity/s_ratio_celebrity/public/p40505.jpg"
            },
            "name": "玛可塔·伊尔格洛娃"
        }
    ],
    "comments_count": 61027,
    "countries": [
        "爱尔兰"
    ],
    "directors": [
        {
            "avatars": {
                "large": null
            },
            "name": "约翰·卡尼"
        }
    ],
    "genres": [
        "剧情",
        "爱情",
        "音乐"
    ],
    "id": 1,
    "images": {
        "large": "https://img3.doubanio.com/view/photo/s_ratio_poster/public/p2173720203.jpg"
    },
    "original_title": "曾经 Once",
    "rating": {
        "average": 8.3,
        "max": 10,
        "min": 0,
        "stars": "40"
    },
    "reviews_count": 2232,
    "summary": "",
    "title": "曾经 Once",
    "warning": "数据来源于网络整理,仅供学习,禁止他用。如有侵权请联系公众号:小楼昨夜又秋风。我将及时删除。",
    "wish_count": 96885,
    "year": 2007
}

1. 点击电影图片,有放大效果,调用小程序wx.previewImage预览函数

 
// pages/movie-detail/movie-detail.js
import {convertToCastString, convertToCastInfos} from '../../utils/util.js'
const app = getApp()
Page({

  /**
   * 页面的初始数据
   */
  data: {
    movie:{}
  },

  /**
   * 生命周期函数--监听页面加载
   */
  onLoad: function (options) {
    const mid = options.mid
    wx.request({
      url: app.gBaseUrl + 'subject/' + mid,
      success:(res)=>{
        console.log(res.data)
        this.processMovieData(res.data)
        // this.setData({
        //   movie:res.data
        // })
      }
    })
  },

  processMovieData(movie){
    const data = {}
    // 前端字段与后台字段映射,数据预处理
    // 处理小明 / 小红 / 小李 这种字符串,movie.directors是个数组
    data.directors = convertToCastString(movie.directors)
    // movie.casts是个数组
    data.casts = convertToCastString(movie.casts)
    data.image = movie.images.large
    data.title = movie.title
    data.subtitle = movie.countries[0]+'·'+movie.year
    data.wishCount = movie.wish_count
    data.commentsCount = movie.comments_count
    data.rating = movie.rating.stars/10
    data.average = movie.rating.average
    // movie.genres是个数组,join() 方法用于把数组中的所有元素放入一个字符串,元素是通过指定的分隔符进行分隔的
    data.genres = movie.genres.join('')
    data.summary = movie.summary
    // movie.casts是个数组
    data.castsInfo = convertToCastInfos(movie.casts)
    this.setData({
      movie:data
    })
  },

  // 点击图片放大功能
  onViewPost(event){
    wx.previewImage({
      urls: [this.data.movie.images.large],
    })
  },


})

引入的utils.js工具

function convertToCastString(casts){
  var castsjoin = "";
  for (var idx in casts) {
    castsjoin = castsjoin + casts[idx].name + " / ";
  }
  // substring() 方法用于提取字符串中介于两个指定下标之间的字符。
  return castsjoin.substring(0, castsjoin.length - 2);
}

function convertToCastInfos(casts) {
  var castsArray = []
  for (var idx in casts) {
    // 过滤掉原来的avatars属性
    var cast = {
      img: casts[idx].avatars ? casts[idx].avatars.large : "",
      name: casts[idx].name
    }
    castsArray.push(cast);
  }
  return castsArray;
}

export {
  convertToCastString,
  convertToCastInfos
}
原文地址:https://www.cnblogs.com/fsg6/p/14464168.html