为了账号安全,请及时绑定邮箱和手机立即绑定

微信小程序版豆瓣电影

2017.02.28 11:24 20074浏览

最近,工作没有那么忙,终于有时间学习微信小程序的开发了。学习的过程还是比较顺利的,入门相对简单,即便没有多少前端开发经验的人也能很快上手。

现在微信小程序的资料还比较少,查看官方文档是很好的方式。微信小程序的官方文档还是很容易阅读的,并没有什么阅读障碍。在一个悠闲的午后,泡一杯清茶,开始了我的小程序之旅。花了一下午的时间把官方文档刷了一遍。接着,下载官方提供的 Demo,在微信开发者工具运行,查看每个组件的效果,使用方式,调试着看界面布局,学习API接口,顺便将弹性盒子模式复习了下。

在项目中学习才是最有效的学习方式。于是,我开始思考要做些什么项目。小程序适合开发低频使用,用完即走,业务不能太复杂的应用。工具类的应用首先被考虑,其次希望能把关注点放在微信小程序的开发,最好能有现成的后台接口。确认了方向之后,最终决定仿豆瓣电影的功能,开发一款微信小程序版的豆瓣电影。

准备工作:

数据来源:豆瓣电影API:https://developers.douban.com/wiki/?title=movie_v2

开发工具:微信开发者工具 0.14.140900

功能:

  • 电影榜单列表
  • 电影搜索
  • 电影条目信息
  • 影人条目信息

预览:
电影首页

电影首页:显示“影院热映”,“即将上映”以及“精选榜单”,测试之后发现精选榜单只有Top250的 API 接口能正常使用,于是,豆瓣Top250、口碑榜、新片榜、票房榜使用同一个 API 接口,只是请求的数据参数不一样。由于微信小程序的 request 的最大并发数是 5,所以用户进入程序时只加载“影院热映”、“即将上映”的数据,界面滑动之后再加载榜单数据。

  /** 滑动屏幕 */
  handleTouchMove: function (event) {
    var offsetTop = event.target.offsetTop;
    console.log("handleTouchMove offsetTop: " + offsetTop);
    if (offsetTop > 10 && !this.data.acquiredSelected) {
      this.getSelectedListData();
    }
  },

“更多”右侧的箭头这里并没有使用图标,而是使用样式来实现的。微信小程序对 app 的体积有限制,超过1M就不能上传。其实,不只是微信小程序,网页也一样。能用样式实现的就不用字体图标;能用字体图标实现的就不用 sprite 图;能用 sprite 图实现的就不用单一图标。样式 > 字体图标 > sprite 图 > 单一图标,不能说是绝对,但基本原则是这样。这样做的目的也是为了减少 app 的体积,减少 HTTP 的请求次数,减轻服务器的压力。

显示更多组件

<text class="session-header-more" bindtap="bindMore" data-type-id="intheaters">更多</text>

显示更多样式

.session-header-more {
  font-size: 28rpx;
  color: #32cd32;
  font-weight: 500;
  position: relative;
  padding-right: 20rpx;
}

.session-header-more::after {
  content: " ";
  display: inline-block;
  position: absolute;
  top: 50%;
  width: 12rpx;
  height: 12rpx;
  transform: matrix(0.71, 0.71, -0.71, 0.71, 0, 0);
  margin-top: -8rpx;
  border-width: 2rpx 2rpx 0px 0px;
  border-color: #32cd32;
  border-style: solid;
}

微信小程序提供了模板功能,可以在模板中定义代码片段,在不同的地方调用。模板可以减少重复性代码,使代码结构更加清晰,增强代码的可读性,也方便以后维护代码。模板粒度的划分可以根据页面的复杂度跟组件被重用的频率。模板可以组合嵌套使用,大的功能组件可以利用模板划分成更小的功能组件。在电影首页中,“影院热映”,“即将上映”展示的是电影信息列表,可以将电影海报,电影名字,评分,想看人数作为一个大的“组件”抽象出来形成电影信息块模板组件。评分在首页电影,更多列表中多次被使用,可以抽象出评分模板组件。

评分模板

<!--pages/movie/movie-rating/movie-rating-template.wxml-->
<template name="rating-template">
  <view class="rating">
    <view class="rating-star allstar{{rating.average | 0}}"></view>
    <text class="rating-average">{{rating.average}}</text>
  </view>
</template>

电影信息块模板

<!--pages/movie/movie-grid/movie-grid-template.wxml-->
<import class="lazyload" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC" data-original="/pages/movie/movie-rating/movie-rating-template.wxml" />
<template name="movie-grid-template">
  <view class="movie-wrapper" bindtap="bindMovieDetail" data-id="{{id}}">
    <view class="movie-content">
      <image class="poster" class="lazyload" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC" data-original="{{images.medium}}"></image>
      <text class="name">{{title}}</text>
      <template is="rating-template" data="{{rating}}" />
      <text class="wish-count">{{collect_count}}人想看</text>
    </view>
  </view>
</template>

评分用星星表示不同的分数,10分用5星表示,1分显示半星。这里使用 sprite 图,可以减少图片的数量。在组件样式中指定图片位置的偏移量,用于显示不同的图标。
评分星星

评分样式

.rating {
  display: flex;
  flex-direction: row;
  position: relative;
  margin-top: 10rpx;
  margin-bottom: 10rpx;
}

.rating-star {
  content: "";
  display: inline-block;
  width: 55px;
  height: 11px;
  position: absolute;
  background-repeat: no-repeat;
  background-image: url(/images/icon/ic_rating_s.png);
}

.allstar10 {
  background-position: 0px 0px;
}

.allstar9 {
  background-position: 0px -11px;
}

.allstar8 {
  background-position: 0px -22rpx;
}

.allstar7 {
  background-position: 0px -33px;
}

.allstar6 {
  background-position: 0px -44px;
}

.allstar5 {
  background-position: 0px -55px;
}

.allstar4 {
  background-position: 0px -66px;
}

.allstar3 {
  background-position: 0px -77px;
}

.allstar2 {
  background-position: 0px -88px;
}

.allstar1 {
  background-position: 0px -99px;
}

.allstar0 {
  background-position: 0px -110px;
}

.rating-average {
  margin-left: 120rpx;
  font-size: 20rpx;
  line-height: 22rpx;
  color: #878787;
  height: 22rpx;
}

更多

电影列表:显示更多电影列表。这里使用标签页切换“正在热映”、“即将上映”。使用 wx:if 控制组件的显示与隐藏,电影列表可以抽象出电影信息模板。

<!--pages/movie/movie-list/movie-list.wxml-->
<import class="lazyload" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC" data-original="/pages/movie/movie-rating/movie-rating-template.wxml" />
<template name="movie-list-template">
  <view class="movie-wrapper" bindtap="bindMovieDetail" data-id="{{id}}">
    <view class="movie-content">
      <image class="poster" class="lazyload" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC" data-original="{{images.medium}}"></image>
      <view class="movie-summary">
        <text class="name">{{title}}</text>
        <text class="directors">导演:{{directors}}</text>
        <text class="casts">主演:{{casts}}</text>
        <text class="genres">类型:{{genres}}</text>
        <template is="rating-template" data="{{rating}}" />
        <text class="wish-count" style="color:#9bdff9;">{{collectCount}}人想看</text>
      </view>
      <block wx:if="{{typeId == 'comingsoon'}}">
        <text class="wish-btn" style="color:#de9703;border-color:#de9703" catchtap="handleWishtap">想看</text>
      </block>
      <block wx:if="{{typeId == 'intheaters'}}">
        <text class="ticket-btn" style="color:#9bdff9;border-color:#9bdff9" catchtap="handleTickettap">购票</text>
      </block>
    </view>
  </view>
</template>

精选榜单

精选榜单:显示电影榜单列表。这里要说的是列表序号。列表序号左右两边有横线,这里也是使用样式实现。前三个序号显示的颜色不一样。

列表序号组件

<text class="selected-index">{{index + 1}}</text>

列表序号样式

.selected-index::before {
  content: "";
  width: 80rpx;
  border-bottom: 2rpx solid #e9e9e9;
  box-sizing: border-box;
  display: inline-block;
  margin-right: 15rpx;
  margin-bottom: 10rpx;
}

.selected-index::after {
  content: "";
  width: 80rpx;
  border-bottom: 2rpx solid #e9e9e9;
  box-sizing: border-box;
  display: inline-block;
  margin-left: 15rpx;
  margin-bottom: 10rpx;
}

.selected-wrapper:first-child .selected-index {
  color: #e14c63;
}

.selected-wrapper:nth-child(2) .selected-index {
  color: #fca167;
}

.selected-wrapper:nth-child(3) .selected-index {
  color: #f5c564;
}

电影搜索

电影搜索:电影搜索没有太多要讲的。点击搜索区块跳到搜索界面,获取 input 的输入值,后台请求电影信息。当输入框有值时,显示 x,点击 x 之后可以清空输入框内容。

<icon class="search-icon" type="search" size="16"></icon>
<input class="search-content" placeholder-class="search-placeholder" bindinput="bindSearchInput" placeholder="搜索电影" value="{{searchValue}}" />
<block wx:if="{{showDelete}}">
  <text class="search-delete" bindtap="bindSearchDelete">x</text>
</block>
<text class="search-cancel" bindtap="bindSearchCancel">取消</text>

使用bindinput获取输入框的值

/** 搜索影视 */
bindSearchInput: function (event) {
  var value = event.detail.value;
  var readyData = { showDelete: false };
  if (value.length > 0) {
    readyData = { showDelete: true };
    this.handleSearchData(value);
  }
  this.setData(readyData);
},
/**清空输入框 */
bindSearchDelete: function (event) {
  var readyData = { searchValue: "", showDelete: false, result: {} };
  this.setData(readyData);
},

影片详情

影片详情:可以查看影片信息,影人信息,给电影评分,但是评分 API 接口不支持,评分数据不能上传到服务器。影人信息的描述信息无法获取。这里要说一下评分,刚开始的想法是通过 sprite 图,手指在星星上滑动时可以显示不同的评分,但是,微信小程序是基于数据驱动的模式,没有 window、document 对象,不能使用 JavaScript 操作 DOM,无法获取组件的坐标值,这样就无法确定手指的坐标是在哪个星星上。于是,只好显示五个星星图标,通过获取 tap 事件来实现评分功能。评分描述则通过样式控制透明度实现显示与隐藏。

事件处理

  bindMark: function (event) {
    var id = event.target.dataset.id;
    this.setData({ "mark": id });
  },
<view class="rating">
  <view class="rating-desc">
    <text class="desc-text {{mark == 1 ? 'desc-text-show' : ''}}">很差</text>
    <text class="desc-text {{mark == 2 ? 'desc-text-show' : ''}}">较差</text>
    <text class="desc-text {{mark == 3 ? 'desc-text-show' : ''}}">还行</text>
    <text class="desc-text {{mark == 4 ? 'desc-text-show' : ''}}">推荐</text>
    <text class="desc-text {{mark == 5 ? 'desc-text-show' : ''}}">力荐</text>
  </view>
  <view class="rating-stars-wrapper" bindtap="bindMark">
    <block wx:for="{{[1,2,3,4,5]}}" wx:for-item="id">
      <image class="{{mark >= id ? 'star-HL' : 'star'}}" class="lazyload" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC" data-original="#" data-id="{{id}}"></image>
    </block>
  </view>
  <!-- Don't use sprite, can't give a mark -->

  <!--<image class="rating-star" bindtap="handleRating" class="lazyload" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC" data-original="#"></image>-->
</view>

评分组件样式

.desc-text {
  width: 32px;
  height: 22px;
  font-size: 15px;
  line-height: 22px;
  text-align: center;
  color: #9e9e9e;
  opacity: 0;
}

.desc-text-show {
  opacity: 1;
}

.star {
  width: 32px;
  height: 32px;
  background: url("/images/icon/ic_rating_star.png") no-repeat;
}

.star-HL {
  width: 32px;
  height: 32px;
  background: url("/images/icon/ic_rating_star_HL.png") no-repeat;
}

这个项目还是比较简单的,前后花了5天的时间就完成了。所使用的接口是豆瓣电影的公开接口,限定40次请求/分钟。对于学习来说已经足够了。如果运行时出现400的错误,是请求过于频繁,稍等一会就好了。

最后,附上项目的Github地址:https://github.com/bruintong/wechat-webapp-douban-movie

点击查看更多内容
110人点赞

若觉得本文不错,就分享一下吧!

评论

相关文章推荐

正在加载中
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消