边作边学入门微信小程序之仿豆瓣评分

微信小程序因为适用性强、逻辑简要、开发迅速的特性,叠加具备海量活跃用户的腾讯公司背景,逐渐成为了轻量级单一功能应用场景的较佳承载方式,诸如电影购票、外卖点餐、移动商城、生活服务等场景服务提供商迅速切入了。css

为了贴合实际的应用状况,本篇以豆瓣评分小程序为参考样例,边作边学小程序的入门开发知识。git

目录程序员

效果图
Demo源码
开发环境
了解官方样例
开发者工具
样例源码结构
开发实战
底部Tab卡页
分析开发需求
评分条模板
rpx长度单位
数据绑定
条件渲染
列表渲染
电影海报模板
模板的使用
区块模板
主页
网络请求
逻辑实现
setData
点击事件
详情页
更多页
扩展知识
思考题

效果图

先看一下对比效果图,共三个页面,分别为首页、更多页和详情页,左侧为豆瓣评分官方小程序,右侧为仿做。因API数据问题,没有作搜索功能。github

主页json

 

imgimg小程序

 

更多页微信小程序

 

imgimg数组

 

详情页ruby

 

imgimgbash

 

Demo源码

本篇完整源码已提交在: https://github.com/cnwen/wechatapp_movie

开发环境

调试基础库:1.9.91(2018.03.07)

微信开发者工具:Windows版v1.02.1802270

了解官方样例

打开微信开发者工具,新建一个小程序项目。

1.选择项目代码存放的目录;

2.填入你的小程序AppID(若无AppID请点击“注册”获取,也可选择“体验小程序”,如需真机预览须有AppID);

3.勾选“创建普通快速启动模板”。

点击“肯定”按钮后,开发者工具将为咱们创建一个简单的小程序模板,咱们能够经过这个样例来创建对开发者工具和小程序的初步认识。

imgimg

 

开发者工具

咱们观察开发者工具,发现由三个主要区域构成,分别是模拟器、编辑器和调试器。

 

imgimg

 

模拟器:顶端含有三个下拉列表,能够配置模拟的机型和所处的网络环境。

编辑器:分为源码目录区域和代码区域。

调试器:顶端含有控制台、网络、存储等选项卡页。

样例源码结构

根目录含有pages、utils文件夹和三个名称为app的文件。顾名思义,pages正是存放小程序各个页面的文件夹,一些公共的工具类建议放在utils文件夹,app文件是小程序的全局文件。

点击查看app.json文件的源码,能够看到含有pages和window两个键值对。

 

imgimg

 

pages负责配置小程序的页面,里面有2条路径,分别对应index和logs页面。

Tips:1.第一条路径固定为小程序的首页,若是把logs路径放到首位,那么logs页面是首页;2.同一个页面的js/wxml/wxss文件的名称必须相同,由于路径是以文件名称来识别的,路径是“pages/index/index”,注意后面不带js/wxml/wxss等后缀,系统会在该路径寻找须要格式文件;3.须要显示的独立页面都须要在此处配置,template模板文件则不须要。

window负责全局的窗口配置,如导航栏背景色、导航栏文字等。你能够修改它们的值,保存后在模拟器上看到效果。

试试将navigationBarBackgroundColor的值改成#ffae00,将navigationBarTitleText的值改成“电影排行榜”,按Ctrl+S键保存看看模拟器中的效果吧。

Tips:1.backgroundTextStyle的值目前只有两种:light和dark;2.navigationBarTextStyle的值目前只有两种:black和white。

回到源码目录,对比index和logs页面的构成,发现index页面并无.json文件,可见这个文件并不是是必须的。可是,若是有这个文件,那么必然不能为空,不然控制台会报错,可在里面写入一个大括号{}保存便可。

开发实战

官方样例先认识到这里,咱们对开发者工具和小程序源码构成有了一个初步的印象后,开始边作边学。

底部Tab卡页

咱们使用鼠标右键将源码目录pages下的index/logs两个文件夹删除,并打开app.json,在pages的值中配置下图中的两条路径。

 

imgimg

 

按Ctrl+S键保存,开发者工具将自动在指定路径为咱们建立两个页面,以下图所示。

imgimg

 

此时,模拟器中的首页已经变成了movies目录下的index页面,由于咱们刚才把这个页面的路径配置在app.json文件中pages值的首位了。

imgimg

 

若是咱们要查看mine页面怎么办呢?除了使用后文将提到的页面跳转功能,这里用Tab卡页的切换功能来试试。在app.json文件中添加tabBar内容,以下所示。

{
"pages":[
"pages/movies/index",
"pages/mine/mine"
],
"window":{
"backgroundTextStyle":"light",
"navigationBarBackgroundColor": "#ffae00",
"navigationBarTitleText": "电影排行榜",
"navigationBarTextStyle":"white"
},
"tabBar": {
"list": [
{
"pagePath": "pages/movies/index",
"text": "电影"
},
{
"pagePath": "pages/mine/mine",
"text": "个人"
}
],
"borderStyle": "black",
"selectedColor": "#ffae00"
}
}

模拟器预览效果以下图:

imgimg

 

在list的值中,咱们配置了2个卡页,text是卡页的文字,pathPath表明了页面路径,当点击卡页时,将跳转到指定路径的页面。注意卡页数必须为2-5个才合规,不然控制台会报错。而且,这里的路径必须被包含在顶端的pages值中,由于全部可抵达页面都必须在pages中配置路径。

红色箭头指向处有一条水平灰色线,这是卡页和内容页的分界线,由borderStyle属性控制,其值默认为black,目前暂时只有black和white值可选。

selectedColor表示卡页选中时,其文字的颜色,用十六进制表示。另外卡页背景色也可配置。

选项卡能够含有图标,配置方法以下:

{
"pagePath": "pages/movies/index",
"text": "电影",
"iconPath": "images/tabbar/movie.png",
"selectedIconPath": "images/tabbar/movieSelected.png"
}

 

imgimgimgimg

 

一个为默认图标,一个是选中时显示的图标。(请看图标路径,我在左侧目录树的根目录新建了images/tabbar目录,并放入了4张图标,图标资源在Github源码中有)

这样,首页Tab便完成了。接下来咱们来分析页面结构,并实现一些公用的template模板文件。

分析开发需求

做为编码者,在开始编码以前,咱们要养成先从总体层面上分析总体需求的好习惯,有利于后续的代码编写及维护。

 

imgimg

 

观察首页、更多页和电影详情页,能够很容易地概括出一些能够共用的页面元素:1.首页由三大块组成,正在热映、即将上映和排行榜区块除了数据不一样,页面结构是相同的(即红色框,后文我用block区块模板代指这块);2.每一个block模板中含有若干个海报模板,由电影海报、电影名称和评分条、评分数组成(蓝色框,后文称poster海报模板);3.每一个评分条是由5颗星星组成的(粉红框,后文称ratingbar评分条模板)。

评分条模板

模板页面(template)是官方提供的一种实现页面元素复用、减小重复工做的良好实现形式。

从上面的分析中,咱们发现这里提到的三个模板是层层嵌套的,所以,做为入门学习者,咱们先从最内层的模板开始实现,即先实现评分条ratingbar模板文件。

 

imgimg

 

评分星星有三种状态,咱们在images目录中新建ratingbar目录,并将这三个星星图标放入。(Github源码中含有本文所需的全部素材)

 

imgimg

 

在movies目录右键鼠标,依次新建名为ratingbar的目录和Page。打开app.json文件,咱们发现开发者工具自动在pages值为咱们配置了ratingbar页面的路径。

 

imgimg

 

做为模板文件,是在其它页面中导入使用的,它不会单独被使用,所以其实它不须要在app.json的pages值中配置路径,而且该页面只需wxml和wxss便可,js和json文件都是用不上的,它所含的页面元素的数据和行为都是由引用它的页面来操纵的,后文会对此有所涉及。

但在此时,咱们须要在模拟器中调试、查看其效果,因此要将它看成单独页面来使用一次,调试完后可将js/json文件删除,并删除在app.json中pages值中的路径,此是后话,暂且略过。

咱们在app.json中将ratingbar页面路径移到pages值的首位(见上图),保存后发现模拟器的首页变成了ratingbar页面。

 

imgimg

 

页面上惟一的一条内容是由开发者工具在新建页面时自动生成的。咱们打开ratingbar.wxml页面,将自动生成的标签内容删除,并输入如下内容,按Shift+Alt+F键格式化代码:

<!--pages/movies/ratingbar/ratingbar.wxml-->
<view class='ratingbar-stars'>
<!--全黄星星-->
<image src='/images/ratingbar/star_fill_whole.png'/>
<image src='/images/ratingbar/star_fill_whole.png'/>
<image src='../../../images/ratingbar/star_fill_whole.png'/>
<!--半黄半灰星星-->
<image src='/images/ratingbar/star_fill_half.png'/>
<!--全灰星星-->
<image src='../../../images/ratingbar/star_fill_none.png'/>
</view>

能够视为官方提供的一种容器,须要成对出现的,在这里它内部含有5个image组件。class表示其样式,它将会去同页面的wxss文件中查找并渲染值为.ratingbar-stars的样式(见下文)。image是图像组件,有一个属性src,表示要显示的图片的地址。像这类内容不须要再包含其它控件的控件,你也能够写成单闭合标签的形式。

这里src的路径出现了2种写法,绝对路径和相对路径,若是不了解的可另外拓展一下,这里的路径是同样的。

再点开ratingbar.wxss文件,并输入如下内容:

/* pages/movies/ratingbar/ratingbar.wxss */
/* class="ratingbar-stars"的控件的样式 */
.ratingbar-stars {
display: flex;
flex-direction: row;
padding-right: 4rpx;
}
/* class="ratingbar-stars"的控件下所包含的image控件的样式 */
.ratingbar-stars image {
height: 17rpx;
width: 17rpx;
padding-top: 5rpx;
padding-right: 4rpx;
}

这里的首个.ratingbar-stars样式(请注意样式名前面有个小点号“.”),与的class相呼应,将会用于渲染该控件。

这里采用了CSS中著名的flex弹性盒子模型,flex-direction:row;意味着其内部控件将采用水平横向的方式排列,要表示竖直排列可将值改成column。

第二个.ratingbar-stars image样式(请注意中间有空格,且image前面没有点号),表示渲染class='ratingbar-stars'的控件内部包含的image控件,这里表示了高height、宽width、距离顶部的内边距padding-top、距离右侧的内边距padding-right。CSS的更多属性知识欢迎另行拓展,这是一个多记多练才能生巧的知识。

rpx长度单位

rpx是微信小程序推出的单位,能够根据不一样手机不一样的屏幕宽度进行内容自适应,使页面元素在不一样屏幕宽度的手机上看起来具备一致性。

不管手机屏幕实际宽度是多少,小程序都会在底层将屏幕宽度换算成750份,若是设计师以iphone6的750*1334(物理像素)为标准出设计稿的话,1rpx=0.5px=1物理像素,你能够直接使用设计师标注的参数加上rpx便可。

上面的width:17rpx表示不管在什么样的移动设备上,其大小都为750份中的17份,宽屏则显示大一些,窄屏则显示小一些,视觉效果一致。

按Ctrl+S键保存现有代码,模拟器即时显示出了目前的页面效果:3颗黄星、1颗半星、1颗灰星。

 

imgimg

 

在wxml文件中,咱们在内写了5个静态的image图像控件。然而在实际场景中,这个不多是写死的,而应该是根据电影的不一样评分进行相应的显示。

动态数据涉及到一些数据绑定等相关的知识,这里先简要介绍一下。

数据绑定

{{}}

WXML 中的动态数据均来自对应 Page 的 data,数据绑定使用 Mustache 语法(双大括号)将变量包起来,如:

<view wx:for="{{count}}">
<text>{{stars}}</text>
</view>

页面渲染时,系统将去对应页面的js文件的data属性中寻找count和stars变量。

条件渲染

wx:if

在框架中,使用 wx:if="{{条件语句}}" 来判断是否须要渲染该代码块:

<image wx:if="{{stars>30}}" src='/images/ratingbar/star_fill_whole.png' />

上条语句表示当知足stars>30的条件时,渲染image控件。

除了if条件外,还有wx:elif 和 wx:else语句:

<image wx:if="{{stars>30}}" src='/images/ratingbar/star_fill_whole.png' />
<image wx:elif="{{stars>20}}" src='/images/ratingbar/star_fill_half.png' />
<image wx:else src='/images/ratingbar/star_fill_none.png' />

wx:if 有且只有一个;

wx:elif 是else if的意思,能够有多个;

wx:else 最多只有一个。

系统按顺序判断各个条件,遇到成立的条件时则渲染该控件,其他控件则不会渲染。

注意:内部的条件语句的结果为{{false}}才表示条件不成立,不带{{}}的值将会被视为文本从而断定为条件成立。

<view wx:if="{{false}}"/> <!--条件不成立-->
<view wx:if="false"/> <!--条件成立-->
<view wx:if="3"/> <!--条件成立-->
列表渲染

wx:for

在组件上使用 wx:for 控制属性绑定一个数组,便可使用数组中各项的数据重复渲染该组件。数组长度为多少,就会重复渲染多少次。

<block wx:for="{{count}}">
<text>{{index}}:{{item}}</text>
</block>

在循环时,当前项的变量名默认为 item,其下标变量名默认为 index。

<block wx:for="{{count1}}">
<block wx:for="{{count2}}">
<text>{{index}}:{{item}}</text>
</block>
</block>

若是遇到这种多重循环呢,如何在内部表示不一样数组的当前项和下标呢?

能够用wx:for-item和wx:for-index分别指定当前项的变量名和下标的变量名:

<block wx:for="{{count1}}" wx:for-item="outer" wx:for-index="i">
<block wx:for="{{count2}}" wx:for-item="inner" wx:for-index="j">
<text>{{i}}:{{outer}}</text>
<text>{{j}}:{{inner}}</text>
</block>
</block>

数据绑定相关的知识大体了解了,咱们打开ratingbar.js,并在data内定义两个变量:

// pages/movies/ratingbar/ratingbar.js
Page({
data: {
count:[3,5,6,8,9],
stars:16
}
})

而后将ratingbar.wxml文件内容修改成:

<!--pages/movies/ratingbar/ratingbar.wxml-->
<view class='ratingbar-stars'>
<!--count数组长度为5,共5次循环显示5颗星星-->
<block wx:for="{{count}}">
<!--全黄星星-->
<image wx:if="{{stars/10>=index+1}}" src='/images/ratingbar/star_fill_whole.png' />
<!--半黄半灰星星-->
<image wx:elif="{{stars/10>=index && stars%10!=0}}" src='/images/ratingbar/star_fill_half.png' />
<!--全灰星星-->
<image wx:else src='/images/ratingbar/star_fill_none.png' />
</block>
</view>

按Ctrl+S保存看看模拟器的效果,把stars的值改成其它数(0-50之间)试试看星星的显示效果吧。Tips:这里的条件语句是研究豆瓣电影API里电影评分的规律得来的。它的stars取值为0/5/10……40/45/50。

据咱们以前对豆瓣评分小程序的分析,评分条通常做为一个元素在相关页面中显示,不会独立做为页面来显示。小程序官方提供了机制来解决这种复用性的问题,代码片断一处编写,多处使用,极大地精简了代码的臃肿,也令程序员有更多精力专一于必要的地方。其结构以下:

<template name="模板名称">
<!--这里是要复用的代码片断-->
</template>

咱们将刚才编写的ratingbar.wxml代码最外层加上模板标识:

<!--pages/movies/ratingbar/ratingbar.wxml-->
<template name="template-ratingbar-stars">
<view class='ratingbar-stars'>
<!--数组长度为5,共5次循环显示5颗星星-->
<block wx:for="{{[3,5,6,8,9]}}">
<!--全黄星星-->
<image wx:if="{{stars/10>=index+1}}" src='/images/ratingbar/star_fill_whole.png' />
<!--半黄半灰星星-->
<image wx:elif="{{stars/10>=index && stars%10!=0}}" src='/images/ratingbar/star_fill_half.png' />
<!--全灰星星-->
<image wx:else src='/images/ratingbar/star_fill_none.png' />
</block>
</view>
</template>

模板名称是template-ratingbar-stars,在其它页面引入本模板后,根据该名称便可找到此模板。由于评分条有且只有5颗星星,因此这里将count的值直接写在此处wx:for="{{[3,5,6,8,9]}}",而后咱们把ratingbar.js中的相关值注释掉:

Page({
data: {
// count:[3,5,6,8,9],
// stars:16
}
})

由于做为模板,将在多处调用,其所使用的值(如这里的stars)将由调用的地方传入,也正由于这样,才有复用性可言。其实,模板文件只有wxml和wxss有用,js和json文件删除亦可。

电影海报模板

接下来,咱们来编写电影海报,就是蓝框这个:

imgimg有多处使用了这样的结构,显然,也应当是一个模板文件。

 

咱们能够参照编写评分条模板的步骤,先将其看成为一个页面,配置在小程序的首页,在js中模拟数据,调试成功后,再改为模板页面。

首先,在movies目录下新建poster目录和poster页面,在app.json的pages属性中,将poster页面路径放在首位(ratingbar路径能够删除),以便在模拟器中查看效果和调试。

{
"pages": [
"pages/movies/poster/poster",
"pages/movies/ratingbar/ratingbar",
"pages/movies/index",
"pages/mine/mine"
],
……
}

在poster.js中写入一些模拟数据:

// pages/movies/poster/poster.js
Page({
data: {
title: "奇迹男孩 Wonder",
images: {
large: "https://img1.doubanio.com/view/photo/s_ratio_poster/public/p2507709428.jpg"
},
rating: {
average: 8.6,
max: 10,
min: 0,
stars: "45"
}
}
})

咱们将在页面中经过绑定数据来获取这些数据,如电影名称{{title}}、海报图片{{images.large}}、电影评分{{rating.average}}等。

在poster.wxss中写入:

/* 导入评分条模板wxss文件,注意是@import */
@import "../ratingbar/ratingbar.wxss";
.movie {
display: flex;
flex-direction: column;
padding-right: 12rpx;
}
.poster {
width: 200rpx;
height: 270rpx;
padding-bottom: 10rpx;
}
.movie-name {
color: #333333;
font-size: 24rpx;
line-height: 24rpx;
margin: 10rpx 0 5rpx 0;
}
.ratingbar {
display: flex;
flex-direction: row;
}
.ratingbar-score{
color: #999999;
font-size: 20rpx;
}
模板的使用

这里用到了评分条模板,所以在开头导入了评分条模板的wxss样式。每一个.样式都对应着下文相关控件的class。

在poster.wxml中写入:

<!--导入评分条模板wxml文件,注意别少了后面的 / 符号-->
<import src="../ratingbar/ratingbar.wxml" />
<view class='movie' catchtap='catchTapMovie' data-movieid='{{id}}'>
<!--海报图-->
<image class="poster" src='{{images.large}}'></image>
<!--电影名称-->
<text class='movie-name'>{{title}}</text>
<!--评分星星和数字-->
<view class='ratingbar'>
<!--评分条-->
<template is="template-ratingbar-stars" data="{{...rating}}" />
<!--评分分数-->
<text class='ratingbar-score'>{{rating.average}}</text>
</view>
</view>

同理,开头也导入了评分条模板的wxml文件,并经过如下方式使用。

<!--评分条-->
<template is="template-ratingbar-stars" data="{{...rating}}" />

is属性值正是评分条模板的name名称,data值将相关数据传入评分条模板。

poster.js的data属性中含有rating数据,其格式见下文。上文中的…rating便是将rating数据散开,将其内容传入评分条模板,评分条模板里能够直接使用{{stars}},而不须要经过{{rating.stars}}的方式。

rating: {
average: 8.6,
max: 10,
min: 0,
stars: "45"
}

这里还出现了诸以下文的属性名,咱们将留到后面讲解。

<view class='movie' catchtap='catchTapMovie' data-movieid='{{id}}'>

如今,将poster.js的data属性中的模拟数据注释或删除掉,并将poster.wxml封装成模版,以下文所示。

<!--导入评分条模板wxml文件,注意别少了后面的 / 符号-->
<import src="../ratingbar/ratingbar.wxml" />
<!--封装成名称为template-poster的模板-->
<template name="template-poster">
<view class='movie' catchtap='catchTapMovie' data-movieid='{{id}}'>
<!--海报图-->
<image class="poster" src='{{images.large}}'></image>
<!--电影名称-->
<text class='movie-name'>{{title}}</text>
<!--评分星星和数字-->
<view class='ratingbar'>
<!--评分条-->
<template is="template-ratingbar-stars" data="{{...rating}}" />
<!--评分分数-->
<text class='ratingbar-score'>{{rating.average}}</text>
</view>
</view>
</template>

区块模板

有了电影海报模板后,接下来咱们进行下一步。观察到首页是由三个结构如出一辙的红色区块组成,显然,这也能够是一个模板,暂且称之为block吧。

 

imgimg

 

步骤和先前个模板同样,为节省篇幅,这里会更简略地以贴代码为主。首页在movies目录下新建block目录和页面,并在app.json文件的pages中将block页面的路径移到首位,以便观察模拟器效果。

在images目录新建block目录,放入下面这张名为arrow-right.png的右箭头图片。

imgimg

 

在block.js文件的data属性中写入模拟的数据(以下),有两个键值对,一为blockTitle区块标题,一为blockMovies为区块电影数据(与豆瓣API返回的格式一致,有删减字段,但结构不变)。

// pages/movies/block/block.js
Page({
data: {
blockTitle:"正在热映",
blockMovies: {
"count": 4,
"start": 0,
"subjects": [{
"casts": [{
"avatars": {
"large": "https://img1.doubanio.com/view/celebrity/s_ratio_celebrity/public/p1509423054.09.jpg"
},
"name": "阿德瓦·香登"
},
{
"avatars": {
"large": "https://img1.doubanio.com/view/celebrity/s_ratio_celebrity/public/p13628.jpg"
},
"name": "阿米尔·汗"
},
{
"avatars": {
"large": "https://img3.doubanio.com/view/celebrity/s_ratio_celebrity/public/p1494080264.12.jpg"
},
"name": "塞伊拉·沃西"
}
],
"comments_count": 5951,
"countries": [
"印度"
],
"directors": [{
"avatars": {
"large": null
},
"name": "阿德瓦·香登"
}],
"genres": [
"剧情",
"音乐"
],
"id": 259,
"images": {
"large": "https://img3.doubanio.com/view/photo/s_ratio_poster/public/p2508925590.jpg"
},
"original_title": "神秘巨星 Secret Superstar",
"rating": {
"average": 8.2,
"max": 10,
"min": 0,
"stars": "40"
},
"reviews_count": 292,
"summary": "14岁的印度少女尹希娅(塞伊拉·沃西 饰)热爱唱歌,因父亲阻挠,她只能蒙面拍摄并上传自弹自唱原创歌曲的视频,孰料凭借天籁歌喉在网上一炮而红,备受争议的音乐人夏克提·库马尔(阿米尔·汗 饰)也向她抛出橄榄枝,尹希娅的生活发生了翻天覆地的变化……",
"title": "神秘巨星 Secret Superstar",
"warning": "数据来源于网络整理,仅供学习,禁止他用。若有侵权请联系公众号:小楼昨夜又秋风。我将及时删除。",
"wish_count": 22447,
"year": 2017
},
{
"casts": [{
"avatars": {
"large": "https://img3.doubanio.com/view/celebrity/s_ratio_celebrity/public/p19485.jpg"
},
"name": "李芳芳"
},
{
"avatars": {
"large": "https://img3.doubanio.com/view/celebrity/s_ratio_celebrity/public/p1359895311.0.jpg"
},
"name": "章子怡"
},
{
"avatars": {
"large": "https://img3.doubanio.com/view/celebrity/s_ratio_celebrity/public/p1472787652.32.jpg"
},
"name": "黄晓明"
}
],
"comments_count": 58027,
"countries": [
"中国大陆"
],
"directors": [{
"avatars": {
"large": null
},
"name": "李芳芳"
}],
"genres": [
"剧情",
"爱情",
"战争"
],
"id": 265,
"images": {
"large": "https://img3.doubanio.com/view/photo/s_ratio_poster/public/p2507572275.jpg"
},
"original_title": "无问西东",
"rating": {
"average": 7.5,
"max": 10,
"min": 0,
"stars": "40"
},
"reviews_count": 4354,
"summary": "若是提早了解了你所要面对的人生,你是否还会有勇气前来?吴岭澜、沈光耀、王敏佳、陈鹏、张果果,几个年轻人满怀诸多渴望,在四个非同凡响的时空中一路前行。\\n吴岭澜(陈楚生 饰),出发时意气风发,却很快在途中迷失了方向。沈光耀(王力宏 饰),自愿参与了最残酷的战争,他一直在努力去作那些令他惧怕,但重要的事。王敏佳(章子怡 饰)最初的错误,只是为了虚荣撒了一个小谎;最初的烦恼,只是在两个优秀的男人中选择一个。但命运,却把她拖入被众人唾骂的深渊。陈鹏(黄晓明 饰)把爱情摆在了理想前面,但爱情却没有把他摆在前面。他说,“我有人要照顾”,纵然这意味着与全部人做对,意味着要和她一块儿被放逐千里。张果果(张震 饰),身处尔虞我诈的职场,“赢”是他的习惯。为了赢,他老是见招拆招,先发制人。而有一天,他却面临了一个比“赢”更重要的选择。这几个年轻人,在最好的年纪迎来了最残酷的...",
"title": "无问西东",
"warning": "数据来源于网络整理,仅供学习,禁止他用。若有侵权请联系公众号:小楼昨夜又秋风。我将及时删除。",
"wish_count": 32890,
"year": 2018
},
{
"casts": [{
"avatars": {
"large": "https://img3.doubanio.com/view/celebrity/s_ratio_celebrity/public/p57551.jpg"
},
"name": "斯蒂芬·卓博斯基"
},
{
"avatars": {
"large": "https://img1.doubanio.com/view/celebrity/s_ratio_celebrity/public/p1456737567.18.jpg"
},
"name": "雅各布·特伦布莱"
},
{
"avatars": {
"large": "https://img1.doubanio.com/view/celebrity/s_ratio_celebrity/public/p8889.jpg"
},
"name": "朱莉娅·罗伯茨"
}
],
"comments_count": 4854,
"countries": [
"美国"
],
"directors": [{
"avatars": {
"large": null
},
"name": "斯蒂芬·卓博斯基"
}],
"genres": [
"剧情",
"家庭",
"儿童"
],
"id": 269,
"images": {
"large": "https://img1.doubanio.com/view/photo/s_ratio_poster/public/p2507709428.jpg"
},
"original_title": "奇迹男孩 Wonder",
"rating": {
"average": 8.6,
"max": 10,
"min": 0,
"stars": "45"
},
"reviews_count": 162,
"summary": "电影《奇迹男孩》改编自全球畅销小说《奇迹》,讲述了一个温暖千万家庭的成长故事。10 岁的奥吉(雅各布·特伦布莱 Jacob Tremblay 饰)天生脸部畸形,此前一直在家中和妈妈(朱莉娅·罗伯茨 Julia Roberts 饰)自学。当他小学五年级时,奥吉进入父母为他精心挑选的学校上学。在这里,奥吉将与校长、老师以及性格迥异的同窗相处,他不寻常的外表让他成为同窗们讨论的焦点,并终日受到嘲笑和排斥,就连好不容易交到的新朋友也彷佛不太值得信任。幸运的是,在成长过程当中,奥吉的父母、姐姐一直是他最坚强的后盾,在他们的支持与关爱下,奥吉凭借自身的勇气、善良、聪敏影响激励了许多身边的人,并收获了友谊、尊重与爱,最终成长为你们心目中的难以想象的“奇迹”。",
"title": "奇迹男孩 Wonder",
"warning": "数据来源于网络整理,仅供学习,禁止他用。若有侵权请联系公众号:小楼昨夜又秋风。我将及时删除。",
"wish_count": 29417,
"year": 2017
},
{
"casts": [{
"avatars": {
"large": "https://img3.doubanio.com/view/celebrity/s_ratio_celebrity/public/p20143.jpg"
},
"name": "丁晟"
},
{
"avatars": {
"large": "https://img1.doubanio.com/view/celebrity/s_ratio_celebrity/public/p1509429399.29.jpg"
},
"name": "王凯"
},
{
"avatars": {
"large": "https://img3.doubanio.com/view/celebrity/s_ratio_celebrity/public/p1422629943.25.jpg"
},
"name": "马天宇"
}
],
"comments_count": 6927,
"countries": [
"中国大陆",
"香港"
],
"directors": [{
"avatars": {
"large": null
},
"name": "丁晟"
}],
"genres": [
"剧情",
"动做"
],
"id": 260,
"images": {
"large": "https://img3.doubanio.com/view/photo/s_ratio_poster/public/p2508615612.jpg"
},
"original_title": "英雄本色2018",
"rating": {
"average": 5.2,
"max": 10,
"min": 0,
"stars": "25"
},
"reviews_count": 711,
"summary": "周凯(王凯 饰)参与走私,被身为缉毒警察的弟弟周超(马天宇 饰)逮捕入狱。三年后,周凯出狱,改过自新。曾经的手下阿仓(余皑磊 饰)已为毒贩头目,为获取周凯的海外客户资料,设计加害周凯。江湖中的好兄弟马柯(王大陆 饰)为了替周凯报仇,失去一条腿。本身的亲弟弟周超不相信哥哥周凯已金盆洗手,不断搜集证据,欲亲手逮捕周凯。最终,周凯与警方合做,逮捕了阿仓,两兄弟重归于好。",
"title": "英雄本色2018",
"warning": "数据来源于网络整理,仅供学习,禁止他用。若有侵权请联系公众号:小楼昨夜又秋风。我将及时删除。",
"wish_count": 4552,
"year": 2018
}
]
}
}
})

在block.wxss文件中写入如下数据:

/* pages/movies/block/block.wxss */
/* 导入电影海报模板的WXSS */
@import "../poster/poster.wxss";
.block-title-bar {
display: flex;
flex-direction: row;
justify-content: space-between;
padding: 30rpx 20rpx 0rpx 20rpx;
}
.block-title {
color: #333333;
font-size: 30rpx;
}
.block-more {
display: flex;
flex-direction: row;
align-items: center;
}
.block-more-text {
color: #ffae00;
font-size: 24rpx;
}
.block-more-icon {
width: 12rpx;
height: 20rpx;
padding-left: 6rpx;
}
.block-scroll-view {
display: flex;
flex-direction: row;
}
.block-movie-row{
display: flex;
flex-direction: row;
padding: 20rpx 0 20rpx 20rpx;
}
.block-movie-card {
display: flex;
flex-direction: row;
margin-right: 10rpx;
}

在block.wxml中写入:

<!--pages/movies/block/block.wxml-->
<!--导入电影海报模板-->
<import src="../poster/poster.wxml" />
<view>
<!--区块顶栏-->
<view class='block-title-bar'>
<!--类别标题,如正在热映-->
<text class='block-title'>{{blockTitle}}</text>
<view class='block-more' catchtap='catchMore' data-title='{{blockTitle}}'>
<!--更多-->
<text class='block-more-text'>更多</text>
<!--右箭头-->
<image class='block-more-icon' src='/images/block/arrow-right.png'></image>
</view>
</view>
<!--电影海报展现条-->
<scroll-view scroll-x="{{true}}" class='block-scroll-view'>
<view class='block-movie-row'>
<block wx:for="{{blockMovies.subjects}}" wx:for-item="poster">
<!--单个电影海报-->
<view class='block-movie-card'>
<template is="template-poster" data="{{...poster}}" />
</view>
</block>
</view>
</scroll-view>
</view>

按Ctrl+S保存后,模拟器效果以下。第一个出现了电影名称过长的情形,咱们后续会写一个stringUtil.js的工具类来截断。

 

imgimg

 

咱们在block页面导入了poster模板的wxml和wxss文件,并经过下文代码使用了。

<!--导入电影海报模板-->
<import src="../poster/poster.wxml" />
……
<!--电影海报展现条-->
<scroll-view scroll-x="{{true}}" class='block-scroll-view'>
<view class='block-movie-row'>
<block wx:for="{{blockMovies.subjects}}" wx:for-item="poster">
<!--单个电影海报-->
<view class='block-movie-card'>
<template is="template-poster" data="{{...poster}}" />
</view>
</block>
</view>
</scroll-view>
……

这里使用了一个新的控件滑动条,有scroll-x和scroll-y属性,用以设定滑动的方向是水平仍是竖直。

在滑动条内部,经过wx:for循环取出blockMovies.subjects的值,用poster表示当前项。

电影海报经过海报模板导入,经过{{…poster}}的形式散开poster的值传入海报模板中,为海报模板中的同名变量提供对应的值。

<!--类别标题,如正在热映-->
<text class='block-title'>{{blockTitle}}</text>
<view class='block-more' catchtap='catchMore' data-title='{{blockTitle}}'>

在上文中又出现了catchtap和data-形式的属性名,这是界面上“更多”按钮的点击事件和自定义属性,后文详细讲解。

最后将block.js中data里的相关数据注释或删除,并在block.wxml里封装模板。

<!--导入电影海报模板-->
<import src="../poster/poster.wxml" />
<!--封装成区块模板-->
<template name="template-block">
<view>
……
</view>
</template>

别忘了在app.json文件的data属性中将主页的路径“pages/movies/index”提到首位,咱们即将要编写主页了。

到目前为止,咱们所须要的三个模板已经所有封装完了。

block模板里导入了poster模板,后者又嵌入了ratingbar模板,极大的精简了相关的代码,增强了代码的易维护性。不信?看主页,咱们只需寥寥数行代码便可。

下篇:https://mp.weixin.qq.com/s/Isfk9s2cgtyXdh5Olap9QA

相关文章
相关标签/搜索