笔记内容:最后一个页面:构建电影详情页面
笔记日期: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" >
<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,
});
},
所有的代码编写完成后,运行效果如下:
到目前为止,整个小程序的开发就告一段落了,这个笔记的目的也只是为了记录一下开发的过程,所以其中对细节没有过多的介绍,不过基本上代码也都注释了,也是为了方便以后遇到类似的功能可以参考实现思路,毕竟像我这种代码写完就忘的人。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。