当前位置:   article > 正文

微信小程序一星期入门-完结篇--电影详情页的制作_微信小程序电影详情页

微信小程序电影详情页


前文
微信小程序学习之旅–第一个页面的制作
微信小程序学习之旅–零基础制作自己的小程序–第二个页面的制作
微信小程序学习之旅–完善pages页面–字体图标,数据绑定,条件/列表渲染,事件/catch/bind以及路由的学习
微信小程序学习之旅–零基础制作自己的小程序-完成文章详情页–自定义属性/页面通信/缓存机制/异步API/async/await
微信小程序学习之旅–零基础制作自己的小程序-文章详情页音乐播放功能的实现-背景音频/全局App/页面的bug修改和优化
微信小程序入门之旅-第六天-自定义组件及request的使用-制作电影页面

微信小程序入门(七)–入门篇完结

实现电影页面按钮的更多功能

image-20210901094428669

点击更多按钮,进入电影的更多页面。

所以我们接下来就先获取到请求的数据,来构建更多电影页面。

获取数据

image-20210901105620511

/**
   * 页面的初始数据
   */
  data: {
    // 电影集合
    movies:[]
  },

  /**
   * 生命周期函数--监听页面加载
   */
  onLoad: function (options) {
    // 请求服务器数据 获取正在热映的电影
    wx.request({
      // 请求地址
      url: app.gBaseUrl + 'in_theaters',
      method: "GET",
      // 参数 在get请求中为查询字符串
      data: {
        // 电影的起始索引
        start: 0,
        // 电影的总条数
        count: 12
      },
      success: (res) => { // 使用箭头函数解决this指向问题
        // 电影数据
        console.log(res.data.subjects);
        this.setData({
          movies: res.data.subjects
        })
      }
    });
  },
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33

image-20210901132458764

more-movie页面布局

image-20210901134323343

/* pages/more-movie/more-movie.wxss */
/* 容器 */
.container {
  display: flex;
  flex-direction: row;
  /* 排列不下的时候,自动换行 */
  flex-wrap: wrap;
  padding: 30rpx 28rpx;
  justify-content: space-between;
}

.movie {
  margin-bottom: 26rpx;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

这里,我们可以发现,并没有用外部样式类来设置组件的样式,而是直接给组件添加样式类,设置的样式也生效。这里的生效原因应该是这个组件被view标签进行了包裹,所以设置的样式才会生效,如果没有被其他标签包裹,而是一个单独的标签,应该是设置样式不会生效,除非使用外部样式类。

像下面这种就不会生效。

<movie class="movie" movie="{{movie}}" />
  • 1
movies页面更多按钮绑定事件

image-20210901135014871

在每个电影列表上都绑定好当前所属的列表类型。用自定义属性进行绑定。

image-20210901135603377

更多按钮的事件

通过event事件属性取到我们在当前元素上自定义的属性,进行页面跳转的时候,将电影类型一并传过去,方法更多电影页面发起请求。

/**
   * 页面跳转
   * @param {*} event 
   */
  onGoToMore(event) {
    // 类型
    const type = event.currentTarget.dataset.type;
    // 跳转到更多页面 以子页面的形式打开
    wx.navigateTo({
      url: "/pages/more-movie/more-movie?type="+type
    })
  }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
更多页面onLoad的更改

需要请求的具体电影列表,通过type属性进行接收。

/**
   * 生命周期函数--监听页面加载
   */
  onLoad: function (options) {
    // 获取电影列表类型
    const type = options.type;
    // 请求服务器数据 获取正在热映的电影
    wx.request({
      // 请求地址
      url: app.gBaseUrl + type,
      method: "GET",
      // 参数 在get请求中为查询字符串
      data: {
        // 电影的起始索引
        start: 0,
        // 电影的总条数
        count: 12
      },
      success: (res) => { // 使用箭头函数解决this指向问题
        // 电影数据
        console.log(res.data.subjects);
        this.setData({
          movies: res.data.subjects
        })
      }
    });
  },
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
实现movies电影页面的搜索功能

直接使用lin-ui小程序组件库进行开发。方便快捷,没什么写的必要。

注册组件
{
  "usingComponents": {
    "movie-list":"/components/movie-list/index",
    "l-search-bar":"/miniprogram_npm/lin-ui/search-bar/index"
  }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
使用
<!-- 搜索栏 -->
<!-- bg-color属性 更改背景颜色 -->
<!-- 我们这里使用该组件提供好的外部样式类,进行样式的更改,修改高度 -->
<!-- 这些东西官网都有说明 -->
<!-- 使用show-cancel属性 可以取消 右侧的取消按钮及其事件 -->
<l-search-bar l-class="ex-search-bar" placeholder="请输入您想看的电影" />
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
/* 外部样式类 */
.ex-search-bar {
  /* 可能发生了样式冲突,所以我们需要提高优先级 */
  height: 90rpx !important;
}
  • 1
  • 2
  • 3
  • 4
  • 5

image-20210901141433978

image-20210901141517765

上滑加载更多电影数据

我们每次请求的数据,默认的条数都是12条,所以用户可能一会就滑到了最底部,其实,小程序的生命周期里面,提供的有关于滑到到页面底部的回调函数。

image-20210901142611984

可以看见,只要你滑动到最底部,我们在这个函数里面写的代码就会被打印。说明该函数的确是执行了。

image-20210901142725171

所以我们可以在这个函数里面书写继续发起请求电影列表的代码。

加载更多电影数据

将前面我们在onLoad方法里面拿到的type值,也就是电影列表的类型进行保存。

image-20210901144912320

发起请求获取数据

代码逻辑都写在页面上啦触底事件的生命周期函数中。

/**
   * 页面上拉触底事件的处理函数
   */
  onReachBottom: function () {
    // 请求服务器数据 获取正在热映的电影
    wx.request({
      // 请求地址
      url: app.gBaseUrl + this.data._type,
      method: "GET",
      // 参数 在get请求中为查询字符串
      data: {
        // 电影的起始索引
        start: this.data.movies.length,
        // 电影的总条数
        count: 12
      },
      success: (res) => { // 使用箭头函数解决this指向问题
        // 电影数据
        this.setData({
          // 追加数据
          movies: [...this.data.movies, ...res.data.subjects]
        });
      }
    });
  }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

提示用户数据请求中

我们在发起请求获取新的电影数据的时候,很可能出现用户多次发起请求,但是此时网络情况并不好,这时候页面的刷新就比较慢,这时候我们就需要提醒用户页面数据正在刷新。用小程序的内置组件就可以完成这种轻提示。

我们的目的就是,数据请求过程中,页面还没刷新完毕的时候,提示用户正在加载,一旦数据请求成功并且页面开始刷新了,就不应该还继续提示用户正在加载数据。

image-20210901150131517

只需要添加显示和隐藏加载动画的提示框即可。

/**
   * 页面上拉触底事件的处理函数
   */
  onReachBottom: function () {
    // 请求数据前 提示用户正在加载数据 刷新页面 显示加载动画
    wx.showNavigationBarLoading();

    // 请求服务器数据 获取正在热映的电影
    wx.request({
      // 请求地址
      url: app.gBaseUrl + this.data._type,
      method: "GET",
      // 参数 在get请求中为查询字符串
      data: {
        // 电影的起始索引
        start: this.data.movies.length,
        // 电影的总条数
        count: 12
      },
      success: (res) => { // 使用箭头函数解决this指向问题
        // 电影数据
        this.setData({
          // 追加数据
          movies: [...this.data.movies, ...res.data.subjects]
        });

        // 电影数据请求完毕了,隐藏正在加载的提示框动画
        wx.hideNavigationBarLoading()
      }
    });
  },
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31

image-20210901150318850

下拉刷新数据

开启页面的下拉刷新

{
  "usingComponents": {
    "movie":"/components/movie/index"
  },
    // 开启下拉刷新
  "enablePullDownRefresh": true
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

如果在app.json里面配置这个的话,那么在所有的页面都可以进行下来是刷新了。

image-20210901152450885

监听用户下拉动作

小程序默认给我们提供好的有小程序页面监听下拉动作的函数。

image-20210901153626697

实现下拉刷新

这个就比较简单了,直接一段代码搞定。获取数据以后,调用wx.stopPullDownRefresh()方法,停止下拉的动作。

/**
   * 页面相关事件处理函数--监听用户下拉动作
   */
  onPullDownRefresh: function () {
    // 用户进行下拉以后,我们就刷新数据
    wx.request({
      url: app.gBaseUrl + this.data._type,
      data: {
        start: 0,
        count: 12
      },
      success: (res) => {
        this.setData({
          movies: res.data.subjects
        })
        // 关闭我们的下拉刷新动画
        wx.stopPullDownRefresh();
      }
    })
  }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

增强阅读页面效果

配置标题与动态配置标题

配置标题

**使用小程序全局的window对象里面的navigationBarTitleText属性,**设置导航栏的标题。

"navigationBarTitleText": "光与影"
  • 1

但是这样配置的标题是死标题,而且,还不能动态的改变,对于组件来说,这样配置无疑是没什么用的。我们应该让这个标题是动态的。

image-20210901161053852

动态配置标题

很明显,动态配置标题是不可获取的,对于这种常用的功能,小程序基本都帮我们提供好了。

使用小程序的wx.setNavigationBarTitle方法就可以动态的设置我们想设置的标题了。

image-20210901161503637

我们将这部分动态设置标题的代码写在onReady生命周期中,页面只有第一次加载才需要设置标题的。

/**
   * 生命周期函数--监听页面初次渲染完成
   */
  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
    })
  }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

电影详情页

组件的独立性

对post组件进行改进

开始,我们是将点击文章,去文章详情页的点击事件的回调函数,直接写死在了组件上,这肯定是不合理的。因为不可能每个人用组件,点击之后的操作都是同样的。所以回调函数的执行应该让外界传递。提高组件的复用性,让组件与事件的具体执行操作独立开来。这就是组件的独立性。

发射事件

image-20210901172629488

当然,携带的参数也不一定非要通过当前事件的目标对象身上的属性来获取,毕竟我们组件上其实已经有这一篇文章的全部信息了。

image-20210901173604854

接收事件

image-20210901172743182

这种做功能一样还是正常实现,但是提高了组件的可复用性。

文章页面问题修正

虽然我们上面那种做法,提高了组件的复用性。但是现在带来了新的问题,那就是我们点击图片是无法完成跳转了。

方式一

最简单的方式当然是直接在写一个方法,按照之前的逻辑就完事。简单易懂。

方式二

我们可以还是在一个方法里面实现点击上面轮播图实现正常跳转。

// event  事件
  onGoToDetail(event) {
    // console.log(event.type); // 可以获取触发的事件类型
    let pid = event.currentTarget.dataset.postId;
    if (!pid) {
      // 没有获取到,说明是点击文章进行跳转的
      pid = event.detail.pid;
    }
    wx.navigateTo({
      // 跳转文章详情页 event.detail.pid 可以拿到我们组件发射事件时携带的参数
      url: "/pages/post-detail/post-detail?pid=" + pid,
    })
  }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

电影详情页的制作

给自定义组件movie绑定事件

为了开发方便,这里我是讲业务代码封装了一部分在组件上,实际上一个好的组件不应该这样,这里是因为这是我们自己写的业务组件,纯粹是为了自己方便,所以可以这样做。

image-20210901191651266

在点击每个电影,都可以去往电影详情页。而且携带了当前电影的id号。

image-20210901191749501

根据id请求电影数据

根据mid,向服务器发起请求,获取当前电影的详情数据。

image-20210901192622268

绑定数据

image-20210901192823290

详情页的制作
详情页头部区域

前面我们已经获取到每个电影详情页的电影详情数据。接下来开始电影详情的头部制作。

骨架

<!--pages/movie-detail/movie-detail.wxml-->
<view class="container">
  <!-- 头部大图(做模糊效果) -->
  <image class="head-img" src="{{movie.images.large}}"></image>
  <!-- 头部标题,副标题 -->
  <view class="head-image-hover">
    <text class="main-title">{{movie.title}}</text>
    <text class="sub-title">{{movie.countries[0] + " · " +movie.year}}</text>

    <!-- 多少人想看,多少人喜欢 -->
    <view class="like">
      <text class="highlight-font">{{movie.wish_count}}</text>
      <text class="plain-font">人喜欢</text>
      <text class="highlight-font">{{movie.comments_count}}</text>
      <text class="plain-font">条评论</text>
    </view>
    <!-- 电影海报 -->
    <image class="movie-image" src="{{movie.images.large}}"></image>
  </view>

</view>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

样式

/* pages/movie-detail/movie-detail.wxss */

/* 容器 */
.container {
  display: flex;
  flex-direction: column;
}

/* 头部海报 做模糊效果图 */
.head-img {
  width: 100%;
  height: 320rpx;
  /* 模糊效果 */
  filter: blur(18px);
}
/* 标题 */
.head-image-hover{
  display: flex;
  flex-direction: column;
  width: 100%;
  height: 320rpx;
  position: absolute;
}
.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-top: 30rpx;
  margin-left: 40rpx;
}
.like{
  display: flex;
  flex-direction: row;
  margin-top: 30rpx;
  margin-left: 40rpx;
}
/* 数字高亮 */
.highlight-font{
  color:#f21146;
  font-size: 22rpx;
  font-weight: 600;
  margin-right: 10rpx;
}
.plain-font{
  color:#666;
  font-size: 22rpx;
  margin-right: 30rpx;
}


/* 电影海报 */
.movie-image {
  position: absolute;
  top: 160rpx;
  right: 30rpx;
  height: 238rpx;
  width: 175rpx;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65

效果

image-20210901205540785

没错,是我要的。

头部电影海报(预览)

做小程序的海报放大方式,也就是我们所说的预览。小程序原生给我们提供的有这种方法。

image-20210901211056877

/**
   * 图片预览
   * @param {*} event 
   */
  onViewPost(event) {
    wx: wx.previewImage({
      // 预览的图片,可以有多个 值是src的值 也就是链接地址
      urls: [this.data.movie.images.large],
      // 当前预览的第一张图片
      current: this.data.movie.images.large
    })
  }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

大部分功能基本上小程序都内置过了。想要做什么效果,建议第一件事是去文档查一下有没有。

image-20210901211352153

图片的mode模式

图片的mode模式,懂的都懂

默认不设置的模式:

image-20210901212027581

设置mode模式为aspectFill时:

image-20210901212121039

很明显,可以看出图片没有被拉伸。

当然,mode模式的值很多,可以去官网多看看

image-20210901212313363

电影详情页建议简介部分
数据的预处理

image-20210901213932843

可以看见,我们获取到数据,很多都是数组,不便于页面的数据展示,所以需要对数据进行预处理。

封装一个工具函数

该函数用来处理导演和演员数组,拼接元素的name属性。

/**
 * 将数组元素里面的name属性转为字符串拼接 
 * @param {*} casts 数组 可以拼接演员和导演数组的name
 */
export function convertToCastString(casts) {
  const names = [];
  casts.forEach(item => {
    names.push(item.name);
  })
  return names.join(" / ");
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
数据的处理

对数据进行预处理,方便页面进行更好的展示

// pages/movie-detail/movie-detail.js
// 导入util工具
import { convertToCastString } from "../../utils/util.js"
const app = getApp()
Page({

  /**
   * 页面的初始数据
   */
  data: {
    // 电影详情数据
    movie: {}
  },

  /**
   * 生命周期函数--监听页面加载
   */
  onLoad: function (options) {
    wx.request({
      // 获取电影详细数据
      url: app.gBaseUrl + "subject/" + options.mid,
      method: "GET",
      success: (res) => {
        console.log(res.data);
        // 电影数据预处理
        this.processMovieData(res.data);
        // 数据绑定 方法处理好数据以后,内部绑定
      }
    })
  },
  /**
   * 图片预览
   * @param {*} event 
   */
  onViewPost(event) {
    wx: wx.previewImage({
      // 预览的图片,可以有多个 值是src的值 也就是链接地址
      urls: [this.data.movie.image],
      // 当前预览的第一张图片
      current: this.data.movie.image
    })
  },
  /**
   * 对请求的电影数据进行预处理
   * @param {*} movie 电影数据
   */
  processMovieData(movie) {
    // 处理后的数据
    const movieData = {};
    // 处理导演和演员数组
    movieData.directorsStr = convertToCastString(movie.directors);
    movieData.castsStr = convertToCastString(movie.casts);
    // 图片处理一下
    movieData.image = movie.images.large;
    // 标题处理
    movieData.title = movie.title;
    // 副标题
    movieData.sub_title = movie.countries[0] + " · " + movie.year;
    movieData.wishCount = movie.wish_count;
    movieData.commentsCount = movie.comments_count;
    movieData.originalTitle = movie.original_title;
    // 评分
    movieData.score = movie.rating.stars / 10;
    movieData.average = movie.rating.average;
    movieData.genresStr = movie.genres.join(" / ");
    // 数据绑定
    this.setData({
      movie: movieData
    })
  }
})
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
页面数据展示

这里只截取了其中的电影简介部分。也就是我们当前写的这一部分。

 <!-- 电影简介 -->
  <view class="summary">
    <!-- 起始标题 -->
    <view class="orgin-title">
      <text>{{movie.originalTitle}}</text>
    </view>
    <view class="flex-row">
      <text class="mark">评分</text>
      <!-- lin-ui的评分组件 -->
      <view class="score-container">
        <l-rate size="22" disabled="{{true}}" score="{{movie.score}}"></l-rate>
        <text class="average">{{movie.average}}</text>
      </view>
    </view>
    <view class="flex-row">
      <text class="mark">导演</text>
      <!-- 导演可能有多个,需要进行数据处理 -->
      <text>{{movie.directorsStr}}</text>
    </view>
    <view class="flex-row">
      <text class="mark">影人</text>
      <!-- 影人也需要进行数据处理,也是数组 -->
      <text>{{movie.castsStr}}</text>
    </view>
    <view class="flex-row">
      <text class="mark">类型</text>
      <!-- 一般类型也是数组,都需要进行对原始处理 -->
      <text>{{movie.genresStr}}</text>
    </view>
  </view>
<!-- 分割线 -->
<view class="hr"></view>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
电影简介的样式书写
/* 电影简介 */
.summary {
  margin-left: 40rpx;
  margin-top: 40rpx;
  color: #777;
}

.orginal-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;
}
.score-container {
  display: flex;
  flex-direction: row;
  align-items: baseline;
}
.average{
  margin-left: 20rpx;
}


.mark {
  margin-right: 30rpx;
  /* 不换行 */
  white-space: nowrap;
  color: #999;
}
/* 水平线 */
.hr{
  width: 100%;
  height: 1px;
  margin-top: 50rpx;
  background-color: #d9d9d9;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
效果

image-20210901223856720

电影剧情简介

没啥好说的,都简单了

结构
  <!-- 剧情简介 -->
  <view class="synopsis">
    <text class="synopsis-font">剧情简介</text>
    <text class="summary-content">{{movie.summary}}</text>
  </view>
  <view class="hr"></view>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
样式
/* 剧情简介样式 */
.synopsis{
  margin-left: 40rpx;
  display: flex;
  flex-direction: column;
  margin-top: 50rpx;
}
.synopsis-font{
  font-size: 32rpx;
  color:#999;
}

.summary-content{
  margin-top: 20rpx;
  margin-right: 40rpx;
  line-height: 40rpx;
  letter-spacing: 1px;
  text-indent: 2em;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
影人部分制作

这个部分其实有点难。好好看好好学

增加的数据预处理部分
/**
 * 将数组元素里面的name属性转为字符串拼接 
 * @param {*} casts 数组 可以拼接演员和导演数组的name
 */
export function convertToCastString(casts) {
  const names = [];
  casts.forEach(item => {
    names.push(item.name);
  })
  return names.join(" / ");
}
/**
 * 整合影人的信息 图片和名字
 * @param {*} casts 
 */
export function convertToCastInfos(casts) {
  const castsArray = [];
  casts.forEach(item => {
    castsArray.push({
      img: item.avatars?.large,
      name: item.name
    })
  })
  return castsArray;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
/**
   * 对请求的电影数据进行预处理
   * @param {*} movie 电影数据
   */
  processMovieData(movie) {
    // 处理后的数据
    const movieData = {};
    // 处理导演和演员数组
    movieData.directorsStr = convertToCastString(movie.directors);
    movieData.castsStr = convertToCastString(movie.casts);
    // 图片处理一下
    movieData.image = movie.images.large;
    // 标题处理
    movieData.title = movie.title;
    // 副标题
    movieData.sub_title = movie.countries[0] + " · " + movie.year;
    movieData.wishCount = movie.wish_count;
    movieData.commentsCount = movie.comments_count;
    movieData.originalTitle = movie.original_title;
    // 评分
    movieData.score = movie.rating.stars / 10;
    movieData.average = movie.rating.average;
    movieData.genresStr = movie.genres.join(" / ");
    movieData.summary = movie.summary;
    // 处理影人数据
    movieData.castsInfo = convertToCastInfos(movie.casts);
    // 数据绑定
    this.setData({
      movie: movieData
    })
  }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
结构
<!-- 影人简介 -->
  <view class="casts">
    <!-- 标题 -->
    <text class="cast-font">影人</text>
    <view 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>
    </view>
  </view>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
样式
/* 影人简介布局 */
.casts{
  display: flex;
  flex-direction: column;
  margin-top: 50rpx;
  margin-left: 40rpx;

}
.casts-container{
  display: flex;
  flex-direction: row;
}
.cast-container{
  display: flex;
  flex-direction: column;
  align-items: center;
  margin-right: 40rpx;
  margin-bottom: 60rpx;
}
.cast-img{
  width: 170rpx;
  height: 210rpx;
  margin-bottom: 12rpx;
}
.cast-font{
  color:#999;
  margin-bottom: 40rpx;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
滑动效果
小程序的滑动组件

小程序提供的内置组件里面有scroll-view组件,可以用来替换view组件。

提供这个标签,可以进行横向的滑动,做成可滚动的视图区域。

你想要的scroll-view这都有

image-20210901232227835

效果

image-20210901232321718

电影详情页完整代码

结构
<!--pages/movie-detail/movie-detail.wxml-->
<view class="container">
  <!-- 头部大图(做模糊效果) -->
  <!-- 图片的填充模式,默认的填充模式,在我们不知道图片比例的情况下,一般设置宽高撑满,容易出现变形。拉伸 -->
  <!-- mode="aspectFill" 设置这个值,会保持原来图片的比例进行缩放,可以保证某一个方向是完整的,另一个方向被裁减 -->
  <image mode="aspectFill" class="head-img" src="{{movie.image}}"></image>
  <!-- 头部标题,副标题 -->
  <view class="head-image-hover">
    <text class="main-title">{{movie.title}}</text>
    <text class="sub-title">{{movie.sub_title}}</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-image" src="{{movie.image}}"></image>
  </view>

  <!-- 电影简介 -->
  <view class="summary">
    <!-- 起始标题 -->
    <view class="orgin-title">
      <text>{{movie.originalTitle}}</text>
    </view>
    <view class="flex-row">
      <text class="mark">评分</text>
      <!-- lin-ui的评分组件 -->
      <view class="score-container">
        <l-rate size="22" disabled="{{true}}" score="{{movie.score}}"></l-rate>
        <text class="average">{{movie.average}}</text>
      </view>
    </view>
    <view class="flex-row">
      <text class="mark">导演</text>
      <!-- 导演可能有多个,需要进行数据处理 -->
      <text>{{movie.directorsStr}}</text>
    </view>
    <view class="flex-row">
      <text class="mark">影人</text>
      <!-- 影人也需要进行数据处理,也是数组 -->
      <text>{{movie.castsStr}}</text>
    </view>
    <view class="flex-row">
      <text class="mark">类型</text>
      <!-- 一般类型也是数组,都需要进行对原始处理 -->
      <text>{{movie.genresStr}}</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-x="{{true}}" 表示进行横向滚动 -->
    <!-- enable-flex = {{true}} 表示重新支持flex布局,scroll-view组件默认是不支持flex布局的,需要开启 -->
    <scroll-view enable-flex="{{true}}" scroll-x="{{true}}" 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>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
样式
/* pages/movie-detail/movie-detail.wxss */

/* 容器 */
.container {
  display: flex;
  flex-direction: column;
}

/* 头部海报 做模糊效果图 */
.head-img {
  width: 100%;
  height: 320rpx;
  /* 模糊效果 */
  filter: blur(18px);
}

/* 标题 */
.head-image-hover {
  display: flex;
  flex-direction: column;
  width: 100%;
  height: 320rpx;
  position: absolute;
}

.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-top: 30rpx;
  margin-left: 40rpx;
}

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

/* 数字高亮 */
.highlight-font {
  color: #f21146;
  font-size: 22rpx;
  font-weight: 600;
  margin-right: 10rpx;
}

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


/* 电影海报 */
.movie-image {
  position: absolute;
  top: 160rpx;
  right: 30rpx;
  height: 238rpx;
  width: 175rpx;
}

/* 电影简介 */
.summary {
  margin-left: 40rpx;
  margin-top: 40rpx;
  color: #777;
}

.orginal-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;
}
.score-container {
  display: flex;
  flex-direction: row;
  align-items: baseline;
}
.average{
  margin-left: 20rpx;
}


.mark {
  margin-right: 30rpx;
  /* 不换行 */
  white-space: nowrap;
  color: #999;
}
/* 水平线 */
.hr{
  width: 100%;
  height: 1px;
  margin-top: 50rpx;
  background-color: #d9d9d9;
}

/* 剧情简介样式 */
.synopsis{
  margin-left: 40rpx;
  display: flex;
  flex-direction: column;
  margin-top: 50rpx;
}
.synopsis-font{
  font-size: 32rpx;
  color:#999;
}

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

/* 影人简介布局 */
.casts{
  display: flex;
  flex-direction: column;
  margin-top: 50rpx;
  margin-left: 40rpx;

}
.casts-container{
  display: flex;
  flex-direction: row;
  /* margin-bottom: 50rpx; */
  height: 300rpx;
}
.cast-container{
  display: flex;
  flex-direction: column;
  align-items: center;
  margin-right: 40rpx;
  margin-bottom: 40rpx;
}
.cast-img{
  width: 170rpx;
  height: 210rpx;
  margin-bottom: 12rpx;
}
.cast-font{
  color:#999;
  margin-bottom: 40rpx;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
行为
// pages/movie-detail/movie-detail.js
// 导入util工具
import { convertToCastString,convertToCastInfos } from "../../utils/util.js"
const app = getApp()
Page({

  /**
   * 页面的初始数据
   */
  data: {
    // 电影详情数据
    movie: {}
  },

  /**
   * 生命周期函数--监听页面加载
   */
  onLoad: function (options) {
    wx.request({
      // 获取电影详细数据
      url: app.gBaseUrl + "subject/" + options.mid,
      method: "GET",
      success: (res) => {
        console.log(res.data);
        // 电影数据预处理
        this.processMovieData(res.data);
        // 数据绑定 方法处理好数据以后,内部绑定
        // this.setData({
        //   movie: res.data
        // })
      }
    })
  },
  /**
   * 图片预览
   * @param {*} event 
   */
  onViewPost(event) {
    wx: wx.previewImage({
      // 预览的图片,可以有多个 值是src的值 也就是链接地址
      urls: [this.data.movie.image],
      // 当前预览的第一张图片
      current: this.data.movie.image
    })
  },
  /**
   * 对请求的电影数据进行预处理
   * @param {*} movie 电影数据
   */
  processMovieData(movie) {
    // 处理后的数据
    const movieData = {};
    // 处理导演和演员数组
    movieData.directorsStr = convertToCastString(movie.directors);
    movieData.castsStr = convertToCastString(movie.casts);
    // 图片处理一下
    movieData.image = movie.images.large;
    // 标题处理
    movieData.title = movie.title;
    // 副标题
    movieData.sub_title = movie.countries[0] + " · " + movie.year;
    movieData.wishCount = movie.wish_count;
    movieData.commentsCount = movie.comments_count;
    movieData.originalTitle = movie.original_title;
    // 评分
    movieData.score = movie.rating.stars / 10;
    movieData.average = movie.rating.average;
    movieData.genresStr = movie.genres.join(" / ");
    movieData.summary = movie.summary;
    // 处理影人数据
    movieData.castsInfo = convertToCastInfos(movie.casts);
    // 数据绑定
    this.setData({
      movie: movieData
    })
  },
  /**
   * 生命周期函数--监听页面初次渲染完成
   */
  onReady: function () {

  },

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

  },

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

  },

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

  },

  /**
   * 页面相关事件处理函数--监听用户下拉动作
   */
  onPullDownRefresh: function () {

  },

  /**
   * 页面上拉触底事件的处理函数
   */
  onReachBottom: function () {

  },

  /**
   * 用户点击右上角分享
   */
  onShareAppMessage: function () {

  }
})
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125

入门篇完结

小程序相对于vue或者react来说还是比较简单的。入门容易。

完整项目代码

完整项目代码放在csdn博客上,也可以去我的github上下载。

github地址

first_mini_program

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/空白诗007/article/detail/784398
推荐阅读
相关标签
  

闽ICP备14008679号