【20190506】电影周周看V3

本周继续完善电影周周看微信小程序,

1. 组件的自定义

  • 需求:从weekly 页面上的电影卡片跳转到电影详情页,因此,要新增 detail页面
  • 使用 wx.navigateTo()
  • 参数化的 page path
  • 组件的自定义数据属性:向逻辑层的业务数据传递

首先,新建details页面,这里给出 detail页的基本代码:
details.wxml

   <text>detail page</text>

detail.json

{
    "navigationBarTitleText": "电影详情页"
}

detail.js

   Page({})

然后,在weekly.wxml中,每一个电影,都对应了一个卡片,我们找到它所在的view,需要给它一个点击函数,然后我们在weekly.wxml新增代码:
【20190506】电影周周看V3
这样就绑定了tab事件处理函数,同进,在weekly.js里面添加事件处理函数:
【20190506】电影周周看V3
从代码中可以看到,在f1中,实现了页面的跳转,使用的是wx.navgigateTo 函数。这个函数的功能是保留当前页面,中转到应用内的某个页面,同时,使用 wx.navigateBack 函数可以返回原页面。

同时,微信还提供了其它几个方式,比如,wx.redirectTo 是关闭当前页面,跳转到应用中的某个页面(注意:使用的过程中,当前的页面是会关闭的)。类似的还有 wx.switchTab ,是跳转到 tabBar 页面,并关闭当前所有非 tabBar 页面。

现在可以看一下效果,当点击一个电影元素,就跳转一下面的 detail 页:
【20190506】电影周周看V3
同时,可以注意到,每次点击一个电影卡片,我们希望得到的详情是不一样的。那么如何实现这一功能呢?这样,我们给每一个电影的信息里,添加一个元素 id,如下所示:
【20190506】电影周周看V3
每个电影的 id 是不一样的,同进,在视图层 weekly.wxml 中添加代码,把电影的 id 显示出来,如下图所示:
【20190506】电影周周看V3
那么问题来了,如何把 view 元素中的取值,传递给逻辑层呢?
为详细说明这一操作,我们给 weekly.wxml 添加下面代码:
【20190506】电影周周看V3
然后,在逻辑层 weekly.js 添加下面的代码:
【20190506】电影周周看V3
接着,运行小程序,点击电影卡片,可以看到控制台有下面的输出:
1291841
blabla
这说明什么呢?当视图层的 view 触发一个事件的时候,它封装了一些数据,这些关键数据,实际上是抽取的,形式为 " data-" 开头,声明的自定义的一些用户数据。
比如说,data-user-name,到逻辑层就变为了:event.currentTarget.dataset.userName的格式
data-movie-id,到逻辑层就变成了:event.currentTarget.dataset.movieId 的格式。
这样,就要可以方便的把电影的 id 传递给 navigateTo 函数,如下所示:
【20190506】电影周周看V3

2. 实现电影详情页的基本框架

主要包括下面内容:

  • 页面初始化获取 query 参数:onLoad(options)
  • detail 页的初始代码和基本流程
  • 上一节遗留问题:恢复 weekly 页上每个“返回本周”按钮的点击行为(catchtap应用)

现在来看,每个页面上有一个 “返回本周” 的按钮,当你点击这个按钮,它也会跳转到 detail 页面。

这和我们期望的行为是不一样的,我们期望是当点击这个按钮时,只要切换到最后一张电影页就可以了。

这个原因是什么呢?这是因为 bindtap 是一个冒泡事件,点击的时候,会触发上一层的事件。首先,它会调用自己绑定的事件 f0 来处理,这是第一步。这个事件完成以后,它会向上冒泡,传递给自已的父元素,也就是这个卡片。这样,f1 事件就会处理,获取电影ID,然后跳转到 detail 页面。

解决的方法是什么呢?相信大家也都想到了,那就是把 bindtap 函数,修改为不会冒泡的 catchtap 函数。这样,就阻止了向上冒泡。点击按钮以后,会触发 f0 事件,而 f1 事件则不会被触发。

这就是一个 catchtap 的典型应用场景,当前元素自己对用户的交互做出响应处理,而不允许父元素做响应处理。

接下来,我们来实现 detail 页的页面元素。 detail 要完成一个解析,知道传入的电影ID是多少。传入时的代码如下:
【20190506】电影周周看V3
这里的机制是这样的,每次 detal 页面打开时,都会执行一个 onLoad 方法,会自行的解析“问号”后面的信息,来获取到 url 中传入的各种参数的取值。解析的代码如下:
【20190506】电影周周看V3
通过这样的操作,就能够解析传入的 电影 id,然后保存到页面自已的内部数据中。

那么问题来了,如何在页面中显示电影更多的详细信息呢?这个就需要发起网络请求,从服务器端获取。这也是我们接下来要讲的内容。

3. 发起网络请求API

wx.request 是小程序网络相关API,类似的还有:wx.uploadFile, wx.downloadFile, webSocket 相关的API。

wx.request 发起 HTTP request,调用 server 端一个 API来获取数据或者操作数据。在调用的时候,需要注意下面内容:

  • 基本参数:发起一个什么请求
  • 回调函数:收到 request 之后或者调用失败以后如何处理
  • 这个是一个 异步调用形式
  • 服务器域名的配置

一个典型的小程序请求如下,可以通过 url 来指定请求的服务器地址;可以通过 method 来指定这是一个 GET 请求;可以通过 data,来给服务器传递一些参数;还可以指定 header 字段。这些字段只是指定了小程序发的是一个什么请求。
【20190506】电影周周看V3
那么,小程序接收到 server 端的信息以后如何处理?是通过下面三个字段来实现的:
【20190506】电影周周看V3
具体三个有什么区别,大家可以自己搜索相关信息,这里不再多说。

4. 调用豆瓣API

这一节主要讲解,如何调用豆瓣API获取电影的详情并进行展示。
目前豆瓣开发者平台已经关闭了,但是相关的API还可以使用,我们在浏览器地址拦输入:
https://api.douban.com/v2/movie/subject/1291841
可以看到返回的《教父》这部电影的信息:
【20190506】电影周周看V3
需要指出的是 1291841 是《教父》这部电影在豆瓣中的 ID。
【20190506】电影周周看V3
我们通过 wx.request 发起请求,可以看到无法获取信息:
【20190506】电影周周看V3
这时我们其实给的地址是正确的,通过浏览器,就能够正确访问。但通过小程序就不能访问,这是因为来自于小程序的调用过多,豆瓣将来自于小程序的调用给禁止了。

那么我们想知道,豆瓣是如何知道调用是来自于微信小程序呢?小程序在发起请求时,会定义一个字段,说明这个请求是来自于小程序的。

请一个请求,都被设定了一个固定格式:https://servicewechat.com/{appid}/{version}/page-frame.html

其中 {appid} 为小程序的 appid,{version} 为小程序的版本号,版本号为 0 表示为开发版、体验版及审核版本。

豆瓣接收到以后,发现是小程序发起的请求,就会返回一个 403 forbidden ,禁止访问。

那么我们如何实现电影周周看这个程序呢?

知乎上肯一个提问:
【20190506】电影周周看V3
有热心的网友做一个转发代理:
【20190506】电影周周看V3
我们在发起请求的时候,可以先把请求发给转发代理,转发代理向 douban 发起请求,然后再返回,可以解决豆瓣屏蔽小程序请求问题

**备注:**豆瓣API文档已经关闭,有网友提前下载了一份,可以在线查看,地址为https://douban-api-docs.zce.me/

豆瓣API接口地址:https://douban.uieee.com (支持 HTTP / HTTPS)

接口限流:10000 次 / 1 小时,由于是豆瓣官方的限流,所以所有使用我搭建的这个反向代理服务的朋友都是共享这 10000 次请求的,我也没办法再去提高这个数字(普通个人用户是 100 次 / 1 小时),所以还是希望大家不要滥用。

wx.requrest 的代码如下:

wx.request({
      url: "https://douban.uieee.com/v2/movie/subject/" + options.id,
      header: {
        "Content-Type": "json"
      },
      success: function (res) {
        console.log(res)
        if(res.statusCode==200){
          that.setData({
            movie: res.data
          })
          wx.setNavigationBarTitle({
            title: res.data.rating.average + "分: " + res.data.title,
          })
          wx.hideNavigationBarLoading()
        }
      }
    })

这样,我们就可以看到电影详情了。

5. 动态调协导航栏

这一节介绍,如何动态的调协导航栏的标题,主要有三个操作:

  • wx.showNavigatorBarLoading(),可以在导航栏左方显示一个loading 的动画,提示用户,这个页面正在加载中;
  • wx.hideNavigatorBarLoading(),主要功能是隐藏掉这个加载的动画;
  • wx.setNavigationBarTitle(),直接动态的来设置这个页面的标题。

在前面的例子中,在 detail 页面打开时,相当长的时间内,显示的标题为空白。这是什么原因呢?

这是因为,一开始在渲染的时候,页面并没有收到服务器返回的信息。这样我们修改 sucess 部分:
【20190506】电影周周看V3
这样,当 detail 页打开时,我们可以看到标题被设置为了下面情况:
【20190506】电影周周看V3

6. 页面事件处理函数

常用的页面事件处理函数包括:

  • onPulldownRefresh,页面下拉刷新时调用
  • onReachBottom, 上滑触底时调用
  • onPageScroll,在页面上滑动的时候被调用
  • onShareAppMessage,用户点击分享时被调用

需求:

  • 给 weekly 页自定义转发 title:“向你推荐:”
  • 给 detail 页自定义转发 title: “向你推荐:{{当前电影名称}}”
    【20190506】电影周周看V3

主要实现方式为,给week.js 添加下面的代码:

  onShareAppMessage: function(){
    return {
      title: "每周推荐"
    }
  }

这样,就可以触发转发行为:
【20190506】电影周周看V3
需要指出的是,如果这个函数为空,也会出现转发行为,不过,默认的标题为小程序的名称。

类似的,给 detail.js 添加下面代码:

  onShareAppMessage: function () {
    return {
      title: "向你推荐:" + this.data.movie.title
    }
  }

即可以实现对电影详情的一个转发,图示如下:【20190506】电影周周看V3