小程序开发实战_腾讯云大学小程序_电影周周看_笔记

368 阅读20分钟

一、页面设置、wxml、wxss和flex布局、rpx

项目包含知识

image-20210516142131633

重要知识:模板,自定义组件,自行学习

app.json的页面中只能是相对路径

配置顶部文字,背景

//about.json
{
    "navigationBarBackgroundColor": "#fff",
    "navigationBarTitleText": "豆瓣电影",
    "navigationBarTextStyle":"black",
    "backgroundTextStyle":"light"
}

【问题】动态获取页面标题

wmxl组件的属性

<text class="info" 
      id="abc" 
      style="color:red" 
      hidden="" 
      data-user-name="user">liujie</text>
//通过data-设置的属性会在事件触发时封装在事件对象中传递

多个元素放置在一个放置到一个容器中,以便对多个元素进行样式控制

wxss样式

页面布局三大目标

从上到下

相对均匀分布

水平居中

传统实现方式,以及其问题

/* pages/about/about.wxss */
.mycontainer{
  background-color: green;
  height:100vh;
  /* 2水平居中 */
  text-align: center;/*控制其容器内子元素水平居中*/
}

/*1水平放置*/
text{
  display: block;
}

/* 3竖直方向等间距 */
image,text{
  margin-bottom:60px;
}

问题:样式有的定义在父级元素上,有的定义子元素上;且严重依赖页面具体像素大小;

行级元素变为块级元素
text{
  display: inline/block;
}
基于flexbox layout的实现(弹性盒子)

首先找到弹性盒子的容器元素,首先要将其变成一个弹性盒子

display:flex;

.mycontainer{
  background-color: green;
  height:100vh;
 
  display:flex;
  /* 1主轴方向从上往下*/
  flex-direction: column;
  /* 2从上往下等间隔 */
  justify-content:space-around;
  /* 3水平居中 */
  align-items: center;
}

实现的是一个整体布局,可拓展性较高

【易错】margin多个元素并列写不需要逗号

margin:0 20rpx;//正确
margin0,20rpx//错误

响应式长度单位rpx

让元素的大小适应不同的设备

UI效果图,视觉设计稿通常使用iphone6来做,iphone实际宽度为375px,相对于小程序750rpx,换算比例为1:2;

让图片宽高保持为屏幕一半大小

.about-banner{
  width: 375rpx;
  height: 375rpx;
  border-radius:50%;//图片设置为圆角
}

单个元素样式,可采用直接在元素中设置

<text style="font-weight:bold;font-size:60rpx">电影周周看</text>

二、app.wxss公共样式表、navigator、tabBar、顶部导航栏样式

image-20210516152201031

weekly页面,每一个用户可访问页面都需要在app.json中注册

app.wxss全局样式表

//app.wxss

.mycontainer{
  background-color: green;
  height:100vh;
 
  display:flex;
  /* 1主轴方向从上往下*/
  flex-direction: column;
  /* 2从上往下等间隔 */
  justify-content:space-around;
  /* 3水平居中 */
  align-items: center;
}

配置weekly页面标题,weekly.json

navagator组件

image-20210516153418465

组件中包含的元素只能是纯文本,其他非文本的内容都会被忽略掉。

image-20210516153847206

<view class='mycontainer'>
  <image class="about-banner" src="/images/1.jpg"></image>
  <text style="font-weight:bold;font-size:60rpx">电影周周看</text>
  <view>
    <text>我</text>
    <navigator style="display:inline" url="/pages/weekly/weekly">每周推荐</navigator>
    <text>一部好片</text>
  </view>
  <text>我的微博:weibo.com/liujie</text>
</view>

由于mycontainer样式的设计,最外层view的子元素会分行,需要将navigator及其两个元素放在一行,需要再用一个view进行封装。

navigator默认是块级元素,需设置为inline元素

open-type属性
open-type="navigate"//默认可返回
open-type="redirect"//不可返回
hover-class属性——点击态样式效果
.nav-default{
  color:blue;
}
.nav-hover{
  color:red;
}

<navigator style="display:inline" url="/pages/weekly/weekly" open-type="navigate" class="nav-default" hover-class="nav-hover">每周推荐</navigator>

//样式谁在后面定义,谁胜出,navigate通过inline设置颜色,点击态颜色无效。

tabBar底部标签栏

tabBar本质是对若干一级入口的链接

tabBar代码
  "tabBar": {
    "list": [
      {
        "text": "每周推荐",
        "pagePath": "pages/weekly/weekly",
        "iconPath": "images/icons/weekly.png",
        "selectedIconPath": "images/icons/weekly-selected.png"
      },
      {
        "text": "关于",
        "pagePath": "pages/about/about",
        "iconPath": "images/icons/about.png",
        "selectedIconPath": "images/icons/about-selected.png"
      }
    ],
    "color": "#000",
    "selectedColor": "#00f"
  },
原来navigator链接无效处理

在app.json中配置了weekly对应的tabBar,

当在about中点击navigator链接,希望:跳转到链接页面+同时Tabbar也要切换。

此时open-type取值应该是“switchTab”

<navigator style="display:inline" url="/pages/weekly/weekly" open-type="switchTab" class="nav-default" hover-class="nav-hover">每周推荐</navigator>

全局顶部导航栏样式

//app.json 一次全局配置所有页面颜色,但是各个页面可自行配置,覆盖全局配置

  "window": {
    "navigationBarBackgroundColor": "#fff",
    "navigationBarTitleText": "小程序名称", //每个页面默认标题
    "navigationBarTextStyle": "black",
    "backgroundTextStyle": "light"
  },

三、数据绑定、条件渲染、列表渲染、swiper轮播图

数据绑定

image-20210516160525500

about页面视图中的数据可以硬编码,weekly页面的数据信息需要根据服务器返回数据渲染更新

传统方法:在页面加载过程中,通过一个ajax调用来请求server返回本周推荐电影的详细信息,然后收到一个javascript对象,改变html相应位置

image-20210516161758300

更新视图的代码与视图关系耦合太严重。

理想方式:让视图中的每一个部分与数据做一个映射,然后开发者就只需要关注如何获取数据以及对数据进行更新。

框架需要自动的根据更新的数据对视图进行渲染更新

小程序中使用page中的data属性存储数据(页面数据)

页面内部状态变量thisWeekMovie
  /**
   * 页面的初始数据
   */
  data: {
    thisWeekMovie:{
      name:"教父",
      comment:"最精彩的剧本,最真实的黑帮电影",
      imagePath:"/images/10.jpg"
    },
    count:123
  },
数据绑定到视图输出显示

对内部状态数据变量直接进行数据绑定

<view class='mycontainer'>
  <text>本周推荐</text>
  <image class="about-banner" src="{{thisWeekMovie.imagePath}}"></image>  
  <text>{{thisWeekMovie.name}}</text>
  <text>{{thisWeekMovie.comment}}</text>
</view>

内部状态变量,运算组合,数据绑定

  <text>{{count+score}}</text> //表达式
  <text>{{score>=60? "及格":"不及格"}}</text> //条件表达式

通过开发者工具调试器的APPdata这个type,我们可以实时的调试每个页面的所有内部状态变量的取值

小程序的运行环境和基本架构

运行环境:每个小程序都是运行在它所在的微信客户端上的,通过微信客户端给它提供的运行环境,小程序可以直接获取微信客户端的原生体验和原生能力。

比如访问本机照片,视频,相机,地理位置。

基本架构:视图层和逻辑层

视图层:wxml和wxss,每个页面在Webview中进行渲染

逻辑层:js和配置json,JsCore中

两层运行在各自独立的进程中,about页和weekly页,都内置了一个vebviewId的内部状态变量,来记录他们各自是在几号webview进程中进行渲染的。

视图层和逻辑层基于数据绑定和事件机制进行通信,

基于数据绑定,在逻辑层对应的逻辑代码对相应的数据进行更新之后,逻辑层会将数据更新的部分传递给视图层,视图层会找的需要更新的部分进行更新。

基于事件机制,视图层会接受到用户的交互反馈的行为,将反馈的行为传递给逻辑层对应的时间处理函数进行处理。

条件渲染wx:if

类似于编程if语句,只有条件成立时,视图组件才会生成

条件渲染与使用hidden的区别

//使用wx:if,只有条件成立时,视图组件dom节点才生成
<text wx:if="{{thisWeekMovie.isHighlyRecommended}}">强烈推荐</text>
//使用hidden,视图组件dom节点一定会生成,hidden属性只是控制了其可见性而已
<text hidden="{{thisWeekMovie.isHighlyRecommended}}">强烈推荐</text>

hidden属性首次加载时开销较大

对于元素可见性不会频繁切换时,使用wx:if较好

列表渲染:重复生成组件wx:for

将weekly中全页面展示改为紧凑的块状展示结果,

假如requires请求从server端返回的是一个对象数组

  data: {
    weeklyMovieList:[
      {
        name:"教父",
        comment:"点评:最精彩的剧本,最真实的黑帮电影",
        imagePath:"/images/10.jpg",
        isHighlyRecommended:true
      },
      {
        name:"泰坦尼克号",
        comment:"点评:失去的才是永恒的",
        imagePath:"/images/11.jpg",
        isHighlyRecommended:false
      },
      {
        name:"这个杀手不太冷",
        comment:"点评:小萝莉与怪蜀黍纯真灿烂的爱情故事",
        imagePath:"/images/12.jpg",
        isHighlyRecommended:true
      }
    ],
  },

数据列表渲染

//wxss
.movie{
  display:flex;
}

.movie-details{
  display:flex;
  flex-direction:column;
  width:550rpx;
}

.movie-image{
  width:200rpx;
  height:200rpx;
}

//wxml视图层提供循环的控制结构
<view class=''>
  <view class="movie" wx:for="{{weeklyMovieList}}">
      <image class="movie-image" src="{{item.imagePath}}"></image>  
      <view class="movie-details">
        <text></text>
        <text>第{{index+1}}周:{{item.name}}</text>
        <text>"{{item.comment}}"</text>
        <text style="color:red" wx:if="{{item.isHighlyRecommended}}">强烈推荐</text>
      </view>
  </view>  
</view>

<view class="movie" wx:for="{{weeklyMovieList}}">

采用item为遍历变量

wx:for内置下标变量{{index}}

【问题】此时如果列表右边文字没有设置外层view的大小可能会挤压左边图片的大小,所以需要设置大小

image-20210516171852931

swiper组件:幻灯片轮播展示

幻灯片轮播展示

swiper组件表示一个滑动容器,常用来表示幻灯片或者轮播图表示

每一个幻灯片使用子元素swiper-item表示

<swiper style="background:#f86;height:500px">//【易错】
    <swiper-item>
      <text>123</text>
      <image src="/images/10.jpg"></image>
    </swiper-item>
    <swiper-item>
      <text>456</text>
      <image src="/images/11.jpg"></image>
    </swiper-item>
    <swiper-item>
      <text>789</text>
      <image src="/images/12.jpg"></image>
    </swiper-item>
  </swiper>

【问题】swiper元素默认高度为150px高,但是我们设置了image元素高度为240px;——我们需要设置swiper的高度,让每个元素都能显示出来

swiper的每个swiper-item元素,的宽度和高度和swiper的宽高时相同的,所以设置swiper的宽高时一般在swiper上统一设置。

列表展示换为幻灯片轮播方式展示

//wxss
.movie{
  display:flex;
}

.movie-details{
  display:flex;
  flex-direction:column;
  width:550rpx;
}

.movie-image{
  width:200rpx;
  height:200rpx;
}

.movie-swiper{
  height:90vh;/*面板比例*/
}
//wxml
<swiper class="movie-swiper" indicator-dots="{{true}}">
    <swiper-item class="movie" wx:for="{{weeklyMovieList}}">
        <image class="movie-image" src="{{item.imagePath}}"></image>  
        <view class="movie-details">
          <text></text>
          <text>第{{index+1}}周:{{item.name}}</text>
          <text>"{{item.comment}}"</text>
          <text style="color:red" wx:if="{{item.isHighlyRecommended}}">强烈推荐</text>
        </view>
    </swiper-item> 
  </swiper> 

image-20210516174236493

indicator-dots="{{true}}"轮播图面板指示

需要放大展示

在每一个item内层加一个,采用全局样式布局

全局mycontainer中,元素高度会超过swiper高度,需要对view高度做一个重新设置;

.movie-card{
  height:100%;/*此时高度会恢复成父元素一样高*/
  width:100%;
}

image-20210516174941516

注意两层class样式的组合定义

幻灯片每一页前一页和后一页都露出一部分便于用户触摸交互

设置swiper的属性

previous-margin="50rpx" next-margin="50rpx"

image-20210516201216930

相邻的swiper-item是紧紧挨着放置的,内容也会紧紧挨着放置

为内容添加一定的边距,为里面的view元素设置外边距

样式优化

.movie{
  display:flex;
}

.movie-details{
  display:flex;
  flex-direction:column;
  width:550rpx;
}

.movie-image{
  width:200rpx;
  height:200rpx;
}

.movie-swiper{
  height:90vh;/*面板比例*/
}

.movie-card{
  height:100%;/*此时高度会恢复成父元素一样高*/
  width:100%;
  background-color: aqua;
  margin:0,20rpx;
}
<!--pages/weekly/weekly.wxml-->
<view>
    <swiper class="movie-swiper" style="height:1000rpx;background-color:red" indicator-dots="{{true}}" previous-margin="50rpx" next-margin="50rpx">
      <swiper-item class="movie" wx:for="{{weeklyMovieList}}">
          <view class="mycontainer movie-card">
            <image class="movie-image" src="{{item.imagePath}}"></image>  
            <text>第{{index+1}}周:{{item.name}}</text>
            <text>"{{item.comment}}"</text>
            <text style="color:red" wx:if="{{item.isHighlyRecommended}}">强烈推荐</text>
          </view>
      </swiper-item> 
    </swiper> 


</view>

四、生命周期函数onload()函数、this.setData、事件机制

image-20210516202038730

swiper默认会切换到列表渲染的第一个幻灯片页

可以使用swiper组件的current属性来制定默认展示页面

默认current=‘0’,我们想设置为最后一个对象的序号

current="{{weeklyMovieList.length-1}}"

返回本周按钮,相对定位+绝对定位

.movie-card{
  height:100%;/*此时高度会恢复成父元素一样高*/
  width:100%;
  background-color: rgb(241, 240, 240);
  margin:0 20rpx;
  padding:0 30rpx;/*易错,中间不用逗号隔开*/

  position:relative;
}

.return-button{
  position:absolute;
  right:40rpx;
  top:40px;

  font-size:26rpx;
  font-style:italic;
  border: 1px solid blue;
  border-radius: 10%;
}

<text class="return-button">返回本周</text>

父级元素采用相对定位,子级元素采用绝对定位

最后一张也生成了返回本周,条件渲染

<text wx:if='{{index<(weeklyMovieList.length-1)}}' class="return-button">返回本周</text>

绑定事件,返回本周

将current属性改为最后一个页面,

将current绑定到一个内部状态变量上

让其初始值为数组长度-1,在事件处理过程中,更新current,

问题:不能直接定义currentIndex=weeklyMovieList.length-1,

需要在onload函数中,页面初始化时setData

data:{
	    currentIndex:0
}

  /**
   * 生命周期函数--监听页面加载
   */
  onLoad: function (options) {
    this.setData({
      currentIndex:this.data.weeklyMovieList.length-1
    })
  },

【易错】在js中使用data数据时,需要使用this.data前缀

onload()

onShow()每一次页面从隐藏状态变为显式可见都要调用一次

onReady()页面已经初始化完成,可以进行页面交互时调用

onHide()每一次被隐藏

onUnload()页面被关闭,如redirect重定向

每一个页面加载,调用onLoad,onShow,onReady三个函数

逻辑层对数据进行更新必须采用this.setData方法调用

this.setData({})

image-20210516204907080

小程序没有提供逻辑层API对视图直接更新,

只能通过视图层建立数据绑定,逻辑层js对视图层绑定的内部状态数据进行更新,从而间接通过框架对视图层进行更新

对内部状态变量直接赋值写入,不能使得视图一起更新,且很容易引起数据不一致的问题

image-20210516205430876

要在小程序中更新内部状态变量,只能使用this.setData方法

image-20210516205608271

告诉框架,对数据更新,并且对视图层进行更新

this.setData功能

更新已有的内部状态变量的值,

也可动态新增变量(可以不先定义currentIndex内部状态变量)

还可实现对一小部分的数据进行更新,如weeklyMovieList数组的最后一个元素电影的name进行更新,“对指定路径的属性尽心更新”

image-20210516210000271

视图层的更新,不会引起内部状态变量的更新(切换weekly页面的swiper-item,其属性current是会变化,但currentIndex并不会发生变化)

小程序中视图层对内部状态变量的绑定是一个单向绑定

事件机制

image-20210516210454783

事件绑定

button元素绑定了一个事件处理函数f0,

f0是在button元素所在的页面,所对应的页面对象中定义的;

当button元素被用户点击,会触发一个tap事件,

框架会将事件发生时的信息封装到一个事件对象中,然后将事件对象传递给绑定的时间处理函数f0进行处理

冒泡事件和非冒泡事件

冒泡事件:点击子元素,会触发子元素事件;子元素会将事件传递给父元素,如果父元素也定义了事件,也会触发;bindTap

非冒泡事件:不会将时间传递给父元素;catchTap

事件对象(事件触发时,从视图层传递给逻辑层的事件对象包含的信息)

image-20210516211755738

image-20210516211739761

点击”返回本周“

<text bindtap="f0" wx:if='{{index<(weeklyMovieList.length-1)}}' class="return-button">返回本周</text>


  f0:function(){
    this.setData({
      currentIndex:this.data.weeklyMovieList.length-1
    })
  }

五、视图层组件的自定义属性+动态跳转id、逻辑层动态跳转后id的获取和视图渲染

视图层组件的自定义属性+动态跳转id(weekly页)

image-20210516212313801

给每一个电影卡片定义绑定一个事件处理函数,跳转到对应的电影详情页中

页面跳转,但此时都是跳转到同一个detail页面中

<swiper-item class="movie" wx:for="{{weeklyMovieList}}">
    <view bindtap="f1" class="mycontainer movie-card">
        
        
f1:function(event){
    wx.navigateTo({
      url: '/pages/detail/detail',
    })
  }

想要跳转到每一个电影对应的详情信息,对detail页做一个参数处理,如id

  f1:function(event){
    wx.navigateTo({
      url: '/pages/detail/detail?id=77',
    })
  }

每一次点击一个电影卡片对应的id取值是不一样的,如何从视图层将id传递到事件处理函数中。

为每个电影新增一个id值,接下来每一个view元素被点击后将id传递给时间处理函数处理

通过事件对象信息event.currentTarget找到当前卡片的子元素,在小程序中不支持;

打印event.currentTarget,dataSet属性是元素自定义属性image-20210516221112377

为组件定义一个“data-”自定义测试属性,转换为事件对象中是一个“驼峰表示法”

image-20210516222607775

image-20210516222621381

当一个组件元素触发一个事件的时候,在其封装的事件对象中,记录了一些关键性的数据,这些关键性数据实际上是抽取的以“data-”这样形式声明的自定义用户数据。

在事件处理函数中,属性的提取

  f1:function(event){
    //【关键】  
    var movieId=event.currentTarget.dataset.movieId;
      
    console.log(movieId);
    wx.navigateTo({
      url: '/pages/detail/detail?id='+movieId,
    })
  }

动态跳转后id获取和视图渲染(detail页)

image-20210516230855034

“返回本周”采用catchtap绑定事件,是非冒泡事件;bindtap是冒泡事件

只希望当前元素做事件相应处理

希望detail页自身能够知道在对应的完整url中被指定的id参数是多少

页面初始化获取query参数:onLoad(option)

程序框架在每次以完成的url跳转打开detail页时,会首先调用这个detail页面注册的onLoad生命周期函数,来对detail进行初始化;

【关键】在调用onLoad方法时,会将url中问号后面的queystring中的每个参数值解析出来,组成一个javascript参数对象,然后将这个对象的实参值传递给onLoad方法

weekly.js

image-20210516231952593

details.js/onLoad()

image-20210516232039652

options对象

image-20210516232105728

处理流程:

weekly页面第99号电影卡片被点击,会调用99号卡片所绑定的tap事件处理函数f1,

通过事件处理对象event获取到99号卡片元素“自定义的数据属性movieId的取值,

小程序框架再以附带id为99完整的URL来打开detail页;

首先会将url中包含的id=99的querystring解析成为一个options参数对象,

detail页面调用onLoad(options)生命周期函数,并且给onLoad生命周期函数传入options对象,

致辞detail页面中,能够获取到weekly页面中本次被打开电影卡片id,

后面可以将获取的电影id保存到detail页面状态数据中,然后再据其进行detail页面视图渲染

此时只是在detail页面中打印出id值

  onLoad: function (options) {
    this.setData({
      movieId:options.id
    })
  },
      
 <text>movieId={{movieId}}</text>

在detail页面上渲染更多的详情信息——发起request请求,获取数据,渲染视图

六、发起request请求+调用server端API,完成detail详情页面数据+视图渲染

发起请求requestAPI

image-20210517002104084

request请求

    wx.request({
      //传递参数
      url: 'url',
      method:"GET",
      data:{
        id:1,
        name:"liujie"
      },
      header:{

      },
      //回调函数,小程序接收到返回的response后的处理
      //小程序在接受http返回的response之后,会对response进行解析,将其中关键数据抽取出来封装成为一个js对象,然后传递给js回调函数的res参数
      success:function(res){
		console.log(res);
      },
      //调用失败,例如网络超时
      fail:function(){

      },
      //无论成功还是失败,都会调用
      complete:function(){

      }   
    })

合法域名检验

小程序对每一个网络请求指定的url对应的域名,都要求在小程序的后台中登记配置,每一个配置的域名必须是经过ICP备案的。

request方法调用,不同于jQuery的Ajax调用,在运行时接收到response之后,无论状态码是“200ok”还是对应错误的状态码(如403或404),都视为请求成功,然后进行下一步处理

success接收到的res回调函数包含信息

403返回

有一个data属性,抽取了response.body中的文本,然后转华为了一个String

header中返回的content-Type:“text/html”

image-20210517003856622

如果返回header中content-Type为一个application json格式,返回的response的body中就是一个json文本,小程序运行环境就会对json文本作进一步处理,将其解析为一个对应js对象

response的三个属性

data属性

header属性

statusCode属性,返回状态码,如statusCode:403

request是一个异步调用,调用request方法之后,不会阻塞,会立马返回,自己返回之后就会执行后面对应的语句或逻辑;

只是小程序运行环境在后台监听什么时候能够收到response,然后调用对应的回调函数进行处理。

调用server的API,渲染detail详情页

调用serverAPI
var that = this

wx.request({
    url: "http://101.200.78.125:8081/getMovie?id=" + options.id,   
    header: {
        "content-type": "json"
    },
	//method默认为GET,data属性也不需要
    
    success: function (res) {
        console.log(res)
        //判断response有效
        if(res.statusCode==200){
            //设置数据,用于渲染视图
            that.setData({
                movie: res.data
            })
        }

    }

})

豆瓣API将小程序请求禁止了,每一个小程序请求有一个固定的referer header,且固定不可设置

image-20210517010016576

收到返回的response之后,通过this.setData将数据保存到一个页面状态变量中

【错误】在success回调函数中进行处理的时候,此时的this指针指向success回调函数所在的==参数对象==(即wx.request函数的参数对象),不再指向页面注册的页面对象,此时的this就没有setData方法

image-20210517010816861

对象的方法中this的指向,指向其所属的对象

解决办法:在调用wx.request之前,先对页面对象做一个保存

var that=this;

将接受到的电影详情数据,渲染到视图中展示

通过新增的内部状态变量movie,来对detail页面相关属性进行数据绑定;

//detail.wxml

<!--pages/detail/detail.wxml-->
  <view class="mycontainer">
    <image src="{{movie.images.small}}"></image>
    <text style="font-weight:bold;font-size:50rpx">{{movie.title}}</text>
    <text>想看:{{movie.wish_count}}</text>
    <text>收藏:{{movie.collect_count}}</text>
    <text>评分:{{movie.rating_average}}</text>
    <text>简介:{{movie.summary}}</text>
  </view>
根据statusCode判断返回的response是否时成功的还是失败的

if(res.statusCode==200){

七、动态设置顶部导航栏的标题、设置和隐藏页面加载时顶部导航栏的加载动画、常见页面事件处理函数+自定义页面转发

image-20210517012406296

onLoad: function (options) {
    //console.log(options.id)
    this.setData({
      mid: options.id
    })

    var that = this
    wx.request({
      url: "http://101.200.78.125:8081/getMovie?id=" + options.id,   
      header: {
        "content-type": "json"
      },

      success: function (res) {
        console.log(res)
        //判断response有效
        if(res.statusCode==200){
          //设置数据
          that.setData({
            movie: res.data
          })
          //【3】动态设置顶部导航栏标题
          wx.setNavigationBarTitle({
            title: res.data.rating_average + "分: " + res.data.title,
          })
          //【2】响应到达后,隐藏顶部导航栏加载特效
          wx.hideNavigationBarLoading()
        }

      }

    })
    //【1】响应到达前加载顶部导航栏加载特效
    wx.showNavigationBarLoading()
  },

  //【4】自定义页面转发
  onShareAppMessage: function () {
    return {
      title: "向你推荐:" + this.data.movie.title
    }
  }
设置和隐藏页面加载时顶部导航栏的加载动画

detail页面打开时,在开始很短时间内,页面相关数据显示的都是空白;

wx.request是异步的,请求发出以后,就立马返回了,此时页面的初始化就完成了;

就开始进入wxml视图的渲染,视图渲染的时候回去找内部状态变量movie,但此时request请求还未返回响应,此时的还没有内部状态变量movie;此时wxml将所有数据绑定的表达式渲染的结果都置为空白;

只有当经过很短的时间之后,当请求返回成功之后,才会进入回调函数,

通过setData设置内部状态变量movie,并且让小程序框架自动更新视图重新渲染数据,获取到的数据才会真正加载到视图。

可以在请求的响应还未返回时,在页面顶部导航栏设置一个页面加载动画,等响应返回以后数据加载完毕再动态将页面顶部导航栏loading动画隐藏

加载动画 wx.showNavigationBarLoading()

隐藏动画 wx.hideNavigationBarLoading()

根据返回的电影详情数据中的字段,动态设置页面顶部导航栏标题
//动态设置顶部导航栏标题
wx.setNavigationBarTitle({
    title: res.data.rating_average+"分"+res.data.title,
})
常见页面事件处理函数+自定义页面转发

image-20210517014356539

自定义页面转发

image-20210517014426002

/**
   * 用户点击右上角分享
   */
  onShareAppMessage: function () {
    return{
      title:"向你推荐"+this.data.movie.title
    }
  }

八、server端JSON文件、站点定义

json文件

//douban.json

{
    "id1291841":{
        "title":"教父",
        "wish_count":500,
        "collect_count":1000,
        "rating_average":9.7,
        "summary":"做精彩的剧本,也是做真实的黑帮电影,从一个男生真正成为一个男人的电影",
        "images":{
            "large":"http://101.200.78.125:8081/public/images/1.jpg",
            "middle":"http://101.200.78.125:8081/public/images/1.jpg",
            "small":"http://101.200.78.125:8081/public/images/1.jpg"
        }

    },
    "id1292722":{
        "title":"这个杀手不太冷",
        "wish_count":500,
        "collect_count":1000,
        "rating_average":9.7,
        "summary":"做精彩的剧本,也是做真实的黑帮电影,从一个男生真正成为一个男人的电影",
        "images":{
            "large":"http://101.200.78.125:8081/public/images/1.jpg",
            "middle":"http://101.200.78.125:8081/public/images/1.jpg",
            "small":"http://101.200.78.125:8081/public/images/1.jpg"
        }

    },
    "id1295644":{
        "title":"心灵奇旅",
        "wish_count":500,
        "collect_count":1000,
        "rating_average":9.7,
        "summary":"做精彩的剧本,也是做真实的黑帮电影,从一个男生真正成为一个男人的电影",

        "images":{
            "large":"http://101.200.78.125:8081/public/images/1.jpg",
            "middle":"http://101.200.78.125:8081/public/images/1.jpg",
            "small":"http://101.200.78.125:8081/public/images/1.jpg"
        }

    }
}

nodejs服务器站点定义

//nodejs服务器
var express = require('express');
var app = express();
var fs = require("fs");

//获取静态资源
app.use('/public', express.static('public'));

//提供访问接口API
app.get('/getMovie', function (req, res) {
   // 读取已存在的数据
   fs.readFile( __dirname + "/" + "douban.json", 'utf8', function (err, data) {
      data = JSON.parse( data );
      console.log( data );
      var key="id"+req.query.id;
      var resdata = data[key] 
      console.log( resdata );
      res.header("Content-Type", "application/json; charset=utf-8")//【易错】不可遗忘,定义格式;
       
      res.end( JSON.stringify(resdata));
   });
})

var server = app.listen(8081, function () {

  var host = server.address().address
  var port = server.address().port
  console.log("应用实例,访问地址为 http://%s:%s", host, port)

})