记内容:第四个页面:制作电影资讯页面 笔记日期:2018-01-18
之前的文章列表页面还有一个小功能没有实现,就是点击点击轮播图就能跳转到相应的文章详情页面,这个和点击文章列表跳转到文章详情页面的实现方式是一样的。
post.wxml修改轮播图代码如下:
<!-- 添加点击事件,这里利用了事件冒泡的机制 -->
<swiper catchtap='onSwiperTap' indicator-dots='true' autoplay='true' interval='5000'>
<!-- 每一项里都放了一个图片 -->
<swiper-item>
<!-- data-postId对应的是需要跳转的文章id -->
<image src='/images/wx.png' data-postId="3"></image>
</swiper-item>
<swiper-item>
<image src='/images/vr.png' data-postId="4"></image>
</swiper-item>
<swiper-item>
<image src='/images/iqiyi.png' data-postId="5"></image>
</swiper-item>
</swiper>
post.js文件增加如下代码:
onSwiperTap:function(event){
// target和currentTarget的区别在于,前者代表的是当前点击的组件,后者代表的是事件捕获的组件
// 在这段代码里,target代表image组件,currentTarget代表swiper组件
var postId = event.target.dataset.postid;
wx.navigateTo({
url: 'post-detail/post-detail?id=' + postId,
});
},
现在我们就可以开始编写电影资讯页面了,为此我们需要给我们的小程序加入一个tab选项卡,这样才能够方便的切换到不同的主题页面上。像这个tab选项卡这种常用的组件,微信已经提供了现成的,无需我们自己去实现。
如果小程序是一个多 tab 应用(客户端窗口的底部或顶部有 tab 栏可以切换页面),可以通过 tabBar 配置项指定 tab 栏的表现,以及 tab 切换时显示的对应页面。
官方的说明文档如下:
https://mp.weixin.qq.com/debug/wxadoc/dev/framework/config.html
注:tabBar 中的 list 属性是一个数组,只能配置最少2个、最多5个 tab,tab 按数组的顺序排序。
首先我们需要构建电影资讯页面的目录、文件,在pages目录下创建movies目录并在该目录下创建相应的文件:
在app.json里配置movies页面以及tabBar:
{
"pages": [
"pages/welcome/welcome",
"pages/posts/post",
"pages/posts/post-detail/post-detail",
"pages/movies/movies" // 配置movies页面
],
"window": {
"navigationBarBackgroundColor": "#405f80"
},
"tabBar": {
"list": [
{
"pagePath": "pages/posts/post", // 跳转的页面
"text": "阅读" // 选项卡的文本内容
},
{
"pagePath": "pages/movies/movies",
"text": "电影"
}
]
}
}
配置完app.json后还需要修改welcome.js代码中的跳转方法,需要将原本的redirectTo方法修改成switchTab方法来实现页面的跳转。switchTab方法用于跳转到有 tabBar 选项卡的页面,并关闭其他所有非 tabBar 页面。修改代码如下:
Page({
onTap:function(){
wx.switchTab({
url: "../posts/post",
});
},
})
官方文档如下:
https://mp.weixin.qq.com/debug/wxadoc/dev/api/ui-navigate.html#wxswitchtabobject
完成以上修改后,编译运行效果如下:
注:选项卡的顺序是与list里的元素顺序一致的。
虽然我们已经完成了简单的选项卡效果,可是默认的样式实在不忍直视,所以我们还得完善这个tab选项卡。其实也很简单,加上两张图片就好了:
"tabBar": {
"borderStyle":"white",
"list": [
{
"pagePath": "pages/posts/post",
"text": "阅读",
"iconPath":"images/tab/yuedu.png", // 没被选中时显示的图片
"selectedIconPath":"images/tab/yuedu_hl.png" // 被选中时显示的图片
},
{
"pagePath": "pages/movies/movies",
"text": "电影",
"iconPath": "images/tab/dianying.png",
"selectedIconPath": "images/tab/dianying_hl.png"
}
]
}
tabBar里还有一个position属性,该属性可以设置选项卡居顶部或居底部,例如我要选项卡居顶部,就可以在app.json文件中加上这一句配置:
"position":"top",
完成效果:
我们需要做一个这样的电影资讯页面:
根据分析效果图,可以看到页面的布局是一排一排重复的的,每一排里都有三个电影,所以这样的重复性的布局以及样式我们可以做成一个template进行复用:
当点击 “更多” 时进入的页面效果图如下:
从效果图,可以看到图片、电影名称以及评分都是和电影资讯页面上的布局以及样式是重复的,所以我们还需要把这部分做成第二个template进行复用:
再来看一张效果图:
这是电影的详情页面,这里也用到了一个评分样式,这个样式也是重复的,所以我们还需要把这个样式做成第三个template进行复用。
先创建好各个template的目录结构:
我这里是先实现评分样式的template:
stars-template.wxml内容如下:
<template name='starsTemplate'>
<view class='stars-container'>
<view class='stars'>
<image src='/images/icon/star.png'></image>
<image src='/images/icon/star.png'></image>
<image src='/images/icon/star.png'></image>
<image src='/images/icon/star.png'></image>
<image src='/images/icon/star.png'></image>
</view>
<text class='star-score'>8.9</text>
</view>
</template>
stars-template.wxss内容如下:
.stars-container{
display: flex;
flex-direction: row;
}
.stars{
display: flex;
flex-direction: row;
height: 17rpx;
margin-right: 24rpx;
margin-top: 6rpx;
}
.stars image{
padding-left: 3rpx;
height: 17rpx;
width: 17rpx;
}
.star-score{
color: #1f3463
}
然后就是电影列表的template了,movie-template.wxml内容如下:
<import src='../stars/stars-template.wxml' />
<template name='movieTemplate'>
<view class='movie-container'>
<image class='movie-img' src='/images/yourname.jpg'></image>
<text class='movie-title'>你的名字.</text>
<template is='starsTemplate' />
</view>
</template>
movie-template.wxss内容如下:
@import "../stars/stars-template.wxss";
.movie-container{
display: flex;
flex-direction: column;
padding: 0 22rpx;
}
.movie-img{
width: 200rpx;
height: 270rpx;
padding-bottom: 20rpx;
}
.movie-title{
margin-bottom: 16rpx;
font-size: 24rpx;
}
接着就是完成movie-list的template,movie-list-template.wxml内容如下:
<import src='../movie/movie-template.wxml' />
<template name='movieListTemplate'>
<view class='movie-list-container'>
<view class='inner-container'>
<view class='movie-head'>
<text class='slogan'>正在热映</text>
<view class='more'>
<text class='more-text'>更多</text>
<image class='more-img' src='/images/icon/arrow-right.png'></image>
</view>
</view>
<view class='movies-container'>
<template is='movieTemplate' />
<template is='movieTemplate' />
<template is='movieTemplate' />
</view>
</view>
</view>
</template>
movie-list-template.wxss内容如下:
@import "../movie/movie-template.wxss";
.movie-list-container{
background-color: #fff;
display: flex;
flex-direction: column;
}
.inner-container{
margin: 0 auto 20rpx;
}
.movie-head{
padding: 30rpx 20rpx 22rpx;
/*
这种方式也能实现float: right;的效果
display: flex;
flex-direction: row;
justify-content: space-between;
*/
}
.slogan{
font-size: 24rpx;
}
.more{
float: right;
}
.more-text{
vertical-align: middle;
margin-right: 10rpx;
color: #1f4ba5;
}
.more-img{
width: 9rpx;
height: 16rpx;
vertical-align: middle;
}
.movies-container{
display: flex;
flex-direction: row;
}
运行效果:
RESTful是一种软件架构风格、设计风格,而不是标准,只是提供了一组设计原则和约束条件。它主要用于客户端和服务器交互类的软件。基于这个风格设计的软件可以更简洁,更有层次,更易于实现缓存等机制。
可重新表达的状态迁移(REST,英文:Representational State Transfer)是Roy Thomas Fielding博士于2000年在他的博士论文中提出来的一种万维网软件架构风格,目的是便于不同软件/程序在网络(例如互联网)中互相传递信息。
目前在三种主流的Web服务实现方案中,因为REST模式与复杂的SOAP和XML-RPC相比更加简洁,越来越多的web服务开始采用REST风格设计和实现。
需要注意的是,具象状态传输是设计风格而不是标准。REST通常基于使用HTTP,URI,和XML以及HTML这些现有的广泛流行的协议和标准。
所以RESTful API就像是一个URL,只不过返回的数据不一定是HTML而已,一般都是用于返回JSON数据。
这一节我们需要调用豆瓣API来填充我们小程序的页面,豆瓣API文档地址如下:
微信小程序关于网络请求的API文档地址:
https://mp.weixin.qq.com/debug/wxadoc/dev/api/api-network.html
但是要注意:由于不明原因,现在豆瓣的API已经屏蔽微信小程序的调用请求了,我这里都是使用自己的服务器代理来实现调用的。
因为我个人的服务器地址不便于透露,所以我这里的示例代码依旧是使用豆瓣的地址,毕竟说不定哪天就不屏蔽了呢233。
先把API地址存储到一个全局变量里,方便调用,之后就只需要加上url的后缀即可,编辑app.js内容如下:
App({
globalData:{
g_isPlayingMusic:false,
g_currentMusicPostId:"",
g_beforeMusicPostId: "",
doubanBase:'https://api.douban.com' # API地址
},
});
我们还需要完善一下页面的样式,让每个模板之间都有一个就间隔,编辑movies.wxml内容如下:
<import src="movie-list/movie-list-template.wxml" />
<view class='container'>
<view>
<template is="movieListTemplate" />
</view>
<view>
<template is="movieListTemplate" />
</view>
<view>
<template is="movieListTemplate" />
</view>
</view>
然后编辑movies.wxss内容如下:
@import "movie-list/movie-list-template.wxss";
.container{
background-color: #f2f2f2;
}
.container view{
margin-bottom: 30rpx;
}
最后编写获取数据的逻辑代码,将获取到的数据先在控制台输出,编辑movies.js内容如下:
var app = getApp();
Page({
onLoad: function (event) {
// start=0&count=3 表示只拿取三条数据
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);
this.getMovieListData(comingSoonUrl);
this.getMovieListData(top250Url);
},
// 请求API的数据
getMovieListData: function (url) {
// 通过reques来发送请求
wx.request({
url: url,
method: 'GET',
header: {
"Content-Type": "application/json"
},
success: function (res) {
console.log(res)
},
fail:function(){
console.log("API请求失败!请检查网络!")
}
});
}
})
控制台输出结果如下:
可以看到已经成功获取数据了,接下来就是把这些数据绑定到页面上即可。
编辑movies.js内容如下:
var app = getApp();
Page({
data: {
// 需要有一个初始值
inTheaters: {},
comingSoon: {},
top250: {}
},
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");
},
// 请求API的数据
getMovieListData: function (url, settedkey) {
var that = this;
// 通过reques来发送请求
wx.request({
url: url,
method: 'GET',
header: {
"Content-Type": "application/json"
},
success: function (res) {
that.processDoubanData(res.data, settedkey);
},
fail: function () {
console.log("API请求失败!请检查网络!")
}
});
},
// 处理API返回的数据
processDoubanData: function (moviesDouban, settedkey) {
// 存储处理完的数据
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 = {
title: title,
average: subject.rating.average,
coverageUrl: subject.images.large,
movieId: subject.id
};
movies.push(temp);
}
// 动态赋值
var readyData = {};
readyData[settedkey] = {
movies: movies
};
this.setData(readyData);
},
})
编辑movies.wxml内容如下:
<import src="movie-list/movie-list-template.wxml" />
<view class='container'>
<view>
<template is="movieListTemplate" data='{{...inTheaters}}' />
</view>
<view>
<template is="movieListTemplate" data='{{...comingSoon}}' />
</view>
<view>
<template is="movieListTemplate" data='{{...top250}}' />
</view>
</view>
然后就是将模板文件里的数据改为数据绑定形式的,movie-list-template.wxml:
<import src='../movie/movie-template.wxml' />
<template name='movieListTemplate'>
<view class='movie-list-container'>
<view class='inner-container'>
<view class='movie-head'>
<text class='slogan'>正在热映</text>
<view class='more'>
<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-template.wxml:
<import src='../stars/stars-template.wxml' />
<template name='movieTemplate'>
<view class='movie-container'>
<image class='movie-img' src='{{coverageUrl}}'></image>
<text class='movie-title'>{{title}}</text>
<template is='starsTemplate' data="{{average}}" />
</view>
</template>
stars-template.wxml:
<template name='starsTemplate'>
<view class='stars-container'>
<view class='stars'>
<image src='/images/icon/star.png'></image>
<image src='/images/icon/star.png'></image>
<image src='/images/icon/star.png'></image>
<image src='/images/icon/star.png'></image>
<image src='/images/icon/star.png'></image>
</view>
<text class='star-score'>{{average}}</text>
</view>
</template>
运行效果:
接着就是将星星评分的组件完成,我的思路是使用将表示星星数据处理成0和1来表示两种星星图片,而这个0和1存储在一个数组里,到时候就根据数组里的元素来决定显示哪一个星星图片。由于这个数据的处理是通用的,之后可能需要在别的地方调用它,所以我们先在根下新建一个目录,并在目录中创建一个.js文件,将代码写在这个文件里:
util.js内容如下:
// 生成一个用来表示星星数量的数组
function convertToStarsArray(stars) {
var num = stars.toString().substring(0, 1);
var array = [];
for (var i = 1; i <= 5; i++) {
if (i <= num) {
array.push(1);
} else {
array.push(0);
}
}
return array;
}
module.exports={
convertToStarsArray: convertToStarsArray
}
然后在movies.js里导入这个模块,并调用该方法:
var app = getApp();
// 导入模块
var util = require('../../utils/util.js');
Page({
data: {
// 需要有一个初始值
inTheaters: {},
comingSoon: {},
top250: {}
},
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");
},
// 请求API的数据
getMovieListData: function (url, settedkey) {
var that = this;
// 通过reques来发送请求
wx.request({
url: url,
method: 'GET',
header: {
"Content-Type": "application/json"
},
success: function (res) {
that.processDoubanData(res.data, settedkey);
},
fail: function () {
console.log("API请求失败!请检查网络!")
}
});
},
// 处理API返回的数据
processDoubanData: function (moviesDouban, settedkey) {
// 存储处理完的数据
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 readyData = {};
readyData[settedkey] = {
movies: movies
};
this.setData(readyData);
},
})
修改模板文件中的数据绑定语句,修改movie-template.wxml内容如下:
<import src='../stars/stars-template.wxml' />
<template name='movieTemplate'>
<view class='movie-container'>
<image class='movie-img' src='{{coverageUrl}}'></image>
<text class='movie-title'>{{title}}</text>
<!-- 这种数据绑定的方式是重新生成两个数据,相当于将它们重命名了,只有这样才能够传递两个参数 -->
<template is='starsTemplate' data="{{stars:stars, score: average}}" />
</view>
</template>
最后是stars-template.wxml:
<template name='starsTemplate'>
<view class='stars-container'>
<view class='stars'>
<!-- 遍历数组元素 -->
<block wx:for="{{stars}}" wx:for-item="i">
<!-- 元素不为0则显示亮着的星星图片 -->
<image wx:if="{{i}}" src='/images/icon/star.png'></image>
<!-- 元素为0则显示灰色的星星图片 -->
<image wx:else src='/images/icon/none-star.png'></image>
</block>
</view>
<text class='star-score'>{{score}}</text>
</view>
</template>
我们还有一个小细节没有完成,就是电影分类的标题还是硬编码的,所以需要改为数据绑定形式的,首先修改movies.js代码如下:
var app = getApp();
var util = require('../../utils/util.js');
Page({
data: {
// 需要有一个初始值
inTheaters: {},
comingSoon: {},
top250: {}
},
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");
},
// 请求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请求失败!请检查网络!")
}
});
},
// 处理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);
}
// 动态赋值
var readyData = {};
readyData[settedkey] = {
categoryTitle: categoryTitle,
movies: movies
};
this.setData(readyData);
},
})
然后修改movie-list-template.wxml代码如下:
<import src='../movie/movie-template.wxml' />
<template name='movieListTemplate'>
<view class='movie-list-container'>
<view class='inner-container'>
<view class='movie-head'>
<text class='slogan'>{{categoryTitle}}</text>
<view class='more'>
<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>
完成效果: