微信小程序> 《微信小程序入门与实战》(已完结)

《微信小程序入门与实战》(已完结)

浏览量:2724 时间: 来源:sgzl111

知乎专栏:https://www.zhihu.com/people/qi_yue/activities
知乎专栏【小楼昨夜又秋风】:https://zhuanlan.zhihu.com/oldtimes
项目中的一些小问题:https://zhuanlan.zhihu.com/p/24554026

小程序

第1-2章 微信小程序与开发环境介绍

  1. 小程序特性:业务逻辑简单、使用频率低、性能要求低
  2. 基础:JS+ES6 Promise+CSS (小程序无DOM!)
  3. 微信Web开发者工具 下载地址

  1. 小程序4大特点:

    (1)无需下载安装APP (2)触手可及(二维码扫一扫) (3)用完即走 (4)无需卸载

第3章  编写第一个小程序页面 (启动页)

  1. 小程序目录结构
  2. View、Image、Text组件
  3. 移动端设备分辨率及小程序自适应单位RPX
  4. Flex弹性盒子模型
  5. 小程序app.json基本配置项

  1. 从性能上考虑,建议把静态样式放到wxss文件中,把动态样式放到wxml文件的style属性中;从规范性考虑,应该把样式都放在wxss文件中;

  2. 小程序的wxml页面最外围有page层,在页面中未显示,但在小程序开发工具-调试器-Wxml栏目中可见;可设置page高度(100%)和背景颜色,使整个页面完全填充,如果设置wxml页面可见的最外层标签高度为100%及背景颜色,则背景颜色只能局部填充页面。page{ height: 100%; background: #b3d4db; }

  3. 移动端设备分辨率及小程序自适应单位RPX

  • 屏幕尺寸(英寸):指的是屏幕对角线的距离

  • pt:逻辑分辨率,与实际移动设备的尺寸有关,简单理解为长度单位

  • px:物理分辨率,与实际移动设备的尺寸无关,简单理解为像素点

  • Reader(px/pt):每个pt包含了几个px,即每个单位长度可以包含几个像素点。同一个单位下,像素点越多,图像的显示更加清晰。

  • PPI/DPI:指每英寸包含多少个像素点

  • 为什么模拟器下ip6的分辨率是375而设计图一般给750?375是指pt,而设计图的750是px。但小程序中显示的是pt,根据iPhone6的2倍关系,将设计图的物理分辨率折算成逻辑分辨率。

  • 如何适配不同的机型?小程序使用自适应单位RPX ,会自动在不同分辨率下进行转换,而使用px为单位不会自动转换。

    转换公式:iPhone6下 1px = 1rpx = 0.5pt
  • 为什么要用iphone6的物理分辨率来做设计图?用iphone6的换算关系1px=1rpx,便于计算;若是其他模型,如iPhone6 plus, 换算关系为1px=0.6rpx,不便于计算。

  • 为什么plus版本并不会比相应普通版本更加清晰?视网膜屏,在单位像素密度下,它所承担的像素个数已经达到了人类眼睛所能分辨的极限,再增加像素个数也不会感觉更加清晰。

  • 微信小程序中不是所有的单位都适用rpx,因为有时候无需根据屏幕尺寸做自适应变化,比如主标题字体大小。
    小程序

  1. Flex弹性盒子模型。
    微信小程序中不建议使用float和position布局,取而代之的是Flex布局,主要作用域页面容器上。.container { display: flex; flex-direction: column; }。本项目中关于flex布局较麻烦的一块movie-list-template.wxml页面中“正在热映”与“更多”一栏使用flex布局实现对齐。

  2. 在app.json中可通过Window属性设置小程序导航栏样式,如navigationBarBackgroundColor属性设置导航栏背景颜色;

第4章   第二个页面:新闻阅读列表

  1. Swiper组件构建轮播图
  2. 关于导航栏、标题的全局配置与页面配置
  3. Page页面与应用程序的生命周期
  4. 数据绑定(核心)
  5. setData方法绑定数据
  6. 数据绑定的扩展用法
  7. 条件渲染与列表渲染
  8. 小程序的事件机制——catch与bind
  9. 冒泡事件

1.Swiper组件构建轮播图

  • indicator-dots :添加轮播图底部的小点;
  • autoplay='true’设置自动播放;
  • interval=‘5000’ 设置间隔为5s ;
  • vertical='true’设置纵向滚动,若要设置为false,写成{{false}}形式;
  • Swiper组件有默认高度,因此需要根据内容设定高度或者是采用自适应高度的方法;
 swiper indicator-dots='true' autoplay='true' interval='5000' vertical='{{false}}'    !-- swiper-item中宽高自动设置为100% --    swiper-item      image catchtap='onSwiperImageTap' src='/image/wx.png' data-postId="4"/image    /swiper-item    swiper-item      image catchtap='onSwiperImageTap' src='/image/iqiyi.png' data-postId="6"/image    /swiper-item    swiper-item      image catchtap='onSwiperImageTap' src='/image/vr.png' data-postId="5"/image    /swiper-item  /swiper

2.关于导航栏、标题的全局配置与页面配置

//app.json{ "window": {    "navigationBarBackgroundColor": "#405f80"  }}
//post.json{  "navigationBarBackgroundColor": "#405f80",  "navigationBarTitleText":"文与字",  "navigationBarTextStyle":"white",  "enablePullDownRefresh":true}

3.wx.navigateTo()与wx.redirectTo() 两者在生命周期上的区别

  • wx.navigateTo()从父页面跳到子页面,有返回字样(最多有5级),跳转到子页面后,父页面被隐藏了,执行onHide()函数;

  • wx.redirectTo()两个页面之间平行跳转,没有返回字样;跳转到其他页面后,该页面生命周期结束,执行onUnload()函数;

4.数据绑定

  • 在item前面加三个小点,那么在post-item-template.wxml文件中不需要再写item.title ,直接写变量名称title即可
  • template是占位符,不能把事件放在template中,可以在template外面放一对view标签,将事件放在view标签上
  • is=“postItem” 是template的名字,对应了哪个template
  • 当某个页面引入某template模板时,需要引入template模板的wxml和wxss文件,wxss文件引用:@import "post-item/post-item-template.wxss";
  import src="post-item/post-item-template.wxml" /  ...  block wx:for="{{post_key}}" wx:for-item="item"     view catchtap="onPostTap" data-postid="{{item.postId}}"      template is="postItem" data="{{...item}}" /    /view  /block
  • 以下是template模板,数据由前面的template is="postItem" data="{{...item}}" /传入。
//post-item-template.wxmltemplate name="postItem"  view class='post-container'    view class='post-author-date'      !-- 元素的显示与隐藏  wx:if="{{false}}" --      image wx:if="{{img_condition}}" src='{{img.avatar}}' class='post-author-img'/image      text class='post-date'{{date}}/text    /view    text class='post-title'{{title}}/text    image src='{{img.imgSrc}}' class='post-img'/image    text class='post-content'{{content}}/text    view class='post-like'      image src='/image/icon/chat.png' class='post-like-img'/image      text class='post-like-count'{{collection}}/text      image src='/image/icon/view.png' class='post-like-img'/image      text class='post-like-count'{{reading}}/text    /view  /view/template
  • Template模板使用的问题。我们在template模板页面中设置了图片的相对路径,若该emplate模板不仅仅用于post页面,而是用于很多页面,此时设置相对路径就会导致图片读取失败,所以最好是设置绝对路径。

5.setData方法绑定数据

  • Page()中的data为页面初始数据,我们可以在其中设置一些初始值,如果要动态改变这些值,就需要用到setData()函数来绑定数据。
onLoad: function () {    // 绑定数据    this.setData({      post_key: postData.postList    });    // this.data.post_key = postData.postList;  },
  • this.data是用于获取页面data对象的,而this.setData是用来更新界面的;
  • this.setData存储的是this.data的副本,而界面是从this.setData里面托管的this.data的副本取数据的,所以更改this.data并不会直接更新界面,this.setData需要将数据从逻辑层发送到视图层,同时改变对应的this.data值。

6.数据绑定的扩展用法

  • 在总目录下创建一个新的文件夹data,并在底下新建一个data.js文件,将数据都下入data.js文件,其他页面可通过require(url)获取data.js文件中的数据。
  • 使用require()时, 只能用相对路径,用绝对路径会出错
//data.jsvar local_database = [{...},{...},{...}]// 使数据通过出口exports输出到别的脚本中去module.exports = {  postList:local_database}
//post.js中var postData = require("../../data/post-data.js");

7.条件渲染与列表渲染

(1)条件渲染wx:if

view wx:if="{{length  5}}" 1 /viewview wx:elif="{{length  2}}" 2 /viewview wx:else 3 /view

(2)列表渲染wx:for

  • 在组件上使用wx:for绑定一个数组,使用数组中各项的数据重复渲染该组件。
  • 默认数组的当前项的下标默认为index,数组当前项默认为item
  block wx:for="{{post_key}}" wx:for-item="item" wx:for-index="idx"    view catchtap="onPostTap" data-postid="{{item.postId}}"      template is="postItem" data="{{...item}}" /    /view  /block

8.小程序的事件机制——catch与bind

  • 事件是视图层到逻辑层的通信方式,将用户的行为反馈到逻辑层处理;当用户触发事件,就会执行逻辑层中对应的事件处理函数。
  • tap事件相当于click点击事件;
  • bindtap=“onTap”,这种绑定不会阻止冒泡事件向上冒泡
  • catchtap = "onTap",这种绑定可以阻止冒泡事件向上冒泡
  • event对象中的target是事件产生的源头组件,而currentTarget则是当前捕获这个事件的组件。
  • 点击post页面的轮播图,实现页面跳转,有以下两种方式:第一,在swiper组件中绑定一个catchtap='onSwiperTap'事件,在js中通过event.target.dataset.postid获取Id号;第二,在swiper下的每个图片中都绑定一个 catchtap='onSwiperImageTap'事件,在js中通过event.currentTarget.dataset.postid获取Id号;
onSwiperTap: function (event) {    // target是事件产生的源头组件    var postId = event.target.dataset.postid;    wx.navigateTo({      url: "post-detail/post-detail?id=" + postId    })  }
// onSwiperImageTap放在三个Image中,currentTarget是当前捕获这个事件的组件。  onSwiperImageTap:function(event){    var postId = event.currentTarget.dataset.postid;    wx.navigateTo({      url:"post-detail/post-detail?id=" + postId    })  }

9.冒泡事件

view class='moto-container' bindtap='onTap'  text class='moto' bindtap='onTextTap'开启小程序之旅/text/view
Page({  onTap:function(){    console.log("我是父");  },  onTextTap:function(){    console.log("我是子");  } })

点击文本 ,输出:“我是子”   “我是父”
点击父元素,输出:“我是父”

阻止事件冒泡将bindtap 用 catchtap 来代替使用,可以阻止冒泡事件发生

view class='moto-container' catchtap='onTap'  text class='moto' catchtap='onTextTap'开启小程序之旅/text/view

第5章   小程序的模板化与模块化

优化代码,使用require构建模块儿化的JavaScript代码以及使用template构建模板化小程序。感受在小程序中使用template的优势。
这块内容在上一章都有提及了,不重复说明了。


  1. 将业务中的数据分离到单独的数据文件中
  2. 使用require方法加载js模块儿文件
  3. template模板的使用

第6章   第三个页面:构建新闻详情页面

新闻详情页面包括音乐播放、文章收藏等功能。本节将讲解音乐播放器的用法,重点学习缓存、条件渲染及Toast、ActionSheet接口的使用。


  1. 构建新闻详情页面样式
  2. 使用数据填充新闻详情页面
  3. 缓存Storage的基本用法
  4. 使用缓存实现文章收藏功能
  5. 交互反馈API wx.showToast
  6. 操作反馈API  wx.showModal   (显示模态弹窗)
  7. 交互反馈API wx.showActionSheet (显示操作菜单)
  8. 音乐播放实现
  9. 实现swiper组件内容跳转

1.如何把一个数据绑定到某个元素标签的属性中? data-postId = “{{item.postId}}”,data-postId为自定义属性。

2.小程序开发目前不能加载html网页,因为不支持webView,考虑到安全问题和可控性问题;因此在新闻详情页面中填充的仅是简单的文本内容,要想直接添加更加丰富的内容,比如文字加粗等样式或者是在内容中包含图片等,目前还是不可行。

3.缓存Storage的基本用法(设置缓存/获取缓存/删除缓存/清空缓存,四种用法都有同步和异步两种操作)。注意,缓存的上限最大不能超过10MB。

另外,在真机运行中,没有清空所有缓存的功能,只是在模拟器中加入了这个功能,这样会造成一些莫名其妙的问题,比如你在真机上设置了某些缓存,然后在模拟器中改变了这些缓存数据,再放到真机中运行,然而真机中新设置的缓存数据并没有代替原来的缓存数据(更新),而真机中又无法清空缓存数据(更新缓存数据首先要清空真机中的的缓存,再显示新的缓存数据)。如果程序在真机上出现了一些奇怪的问题而程序又使用了缓存,首先考虑是不是缓存导致了这些问题。

解决办法:清空真机上的缓存数据。在程序中放置一个按钮,点击按钮调用wx.clearStorage方法清除真机上的缓存;

4.使用缓存实现文章收藏功能。

用户未收藏则收藏按钮显示为灰色;点击收藏按钮则显示为蓝色。另外,不能像jQuery一样通过getElementById等选择符拿到DOM元素,用脚本动态控制DOM元素实现属性样式的变换,因为小程序中没有DOM,必须通过数据绑定或者小程序组件来实现动态切换小程序是数据优先的思想

//条件渲染 判断文章是否被收藏image wx:if="{{collected}}" src='/image/icon/collection.png' catchtap='onCollectionTap'/imageimage wx:else src='/image/icon/collection-anti.png' catchtap='onCollectionTap'/image
  onCollectionTap: function (event) {    this.getPostsCollectedSyc();//同步缓存  },  getPostsCollectedSyc:function(){    var pcs = wx.getStorageSync('posts_Collected');    var pc = pcs[this.data.curId - 1];    // 取反操作    pc = !pc;    // 更新缓存    pcs[this.data.curId - 1] = pc;    this.showModal(pcs, pc);  },

注意posts_Collected变量的初始化哦

   onLoad:function(option){    ...    // 初始化    var pcs = wx.getStorageSync('posts_Collected');    if (pcs)    {      var pc = pcs[postId-1];      if(typeof(pc) == "undefined"){        pc = false;      }      this.setData({        collected : pc      })    }    else{    // 若posts_Collected缓存为空      var pcs = {};      pcs[postId - 1] = false;      wx.setStorageSync('posts_Collected', pcs);      // 这里没必要再用setData更新数据绑定,因为最开始没有缓存,collected默认为false;    }

同步异步缓存方法对比

  • 同步缺点:若同步调用方法运行很慢,会阻塞整个程序的运行;
  • 异步优点:加速主线程的运行,避免同步运阻塞程序;但当程序比较复杂时,异步的回调函数会很长,且代码的可读性会变差,另外很容易产生问题,因此不建议优先使用异步缓存;
  • 异步的选择最好是以明确的业务作为指导思想,脱离了业务谈异步没有什么实际性意义。

5.交互反馈 : wx.showToast与wx.showModal

  • 区别:前者不需要用户确认自动消失,而后者必须经用户确认反馈。

6.音乐播放API

  • 前面关于收藏事件,定义了两个Image标签,在两张图片之间切换;在音乐播放事件中,定义了一个Image 标签,通过判断isPlayingMusic=true/false选择不同的图片;
image src="{{isPlayingMusic? '/image/music/music-stop.png':'/image/music/music-start.png'}}" class='audio' catchtap='onMusicTap'  /
  • onMusicTap事件控制音乐播放事件。当用户点击播放音乐,播放图片变为暂停图片,背景图片变换为封面图片;当用户点击暂停按钮,暂停图片变为播放图片,音乐的封面图片变为原始的背景图片。
data:{    isPlayingMusic:false  },onMusicTap:function(event){    var isPlayingMusic = this.data.isPlayingMusic;    var curMusic = postData.postList[this.data.curId - 1].music;    if(isPlayingMusic){      // 暂停播放      wx.pauseBackgroundAudio();      this.setData({        isPlayingMusic:false      })    }    else{      // 启动播放      wx.playBackgroundAudio({        dataUrl: curMusic.url,        title: curMusic.title,        // 在模型中可能无法显示封面图片,在真机上显示正常        coverImgUrl: curMusic.coverImg      })      this.setData({        isPlayingMusic:true      })    }  }
  • 问题1,点击底部的音乐播放控件如何使顶部的图片做相应的变换调整?监听播放事件完善音乐播放,在onLoad函数中监听。
// 监听音乐播放    var that  = this;    wx.onBackgroundAudioPlay(function(){      that.setData({        isPlayingMusic : true      })    })    // 监听音乐停止    wx.onBackgroundAudioPause(function(){      that.setData({        isPlayingMusic : false      })    })    //关于数据绑定的好处:    //1.小程序中的后台数据绑定简单方便优于jQuery方式;    //2. 同一个状态变量可以绑定多个标签,改变该状态变量使前端相关的数据绑定实现一次性的数据变换;    //3. 微信小程序中在做数据绑定时只是操作状态变量,并没有取操作UI,便于做单元测试;
  • 问题2,当点击音乐播放后返回到上个页面,再进入该页面发现音乐继续仍然播放,但顶部显示为播放按钮,按理说应该显示为暂停按钮?

    当退出该页面再进入该页面,页面重新加载,再次执行了onLoad函数。因此,这里需要一个和页面生命周期无关的状态来保持变量,使用缓存的缺点是即使整个程序关闭了,再次运行该程序还是为程序关闭前的状态,这不符合音乐播放功能要求。所以,我们要求的是当页面关闭时,这个状态依然保存着变量,而当应用程序全部关闭时,所有的状态变量都恢复为默认值。此问题可由全局变量解决,在app.js文件中定义全局变量。

var app = getApp();  
onLoad:function(option){...// 判断全局变量是否为真,若为真,则改变局部变量isPlayingMusic为真     if(app.globalData.g_isPlayingMusic){      this.setData({        isPlayingMusic:true      })    }    this.setAudioMonitor(); }
 setAudioMonitor:function(){    // 监听音乐播放    var that = this;    wx.onBackgroundAudioPlay(function () {      that.setData({        isPlayingMusic: true      })      app.globalData.g_isPlayingMusic = true;    })    // 监听音乐暂停    wx.onBackgroundAudioPause(function () {      that.setData({        isPlayingMusic: false      })      app.globalData.g_isPlayingMusic = false;    })  }
  • 问题3,继问题2后,我们在某页面中播放音乐,然后返回进入另一个页面发现另一个页面顶部显示暂停图片,但播放的是原先页面的歌而当前页面并未点击播放啊?

    原因:更换页面后,重新读取全局变量 app.globalData.g_isPlayingMusic=true(因为退出前一个页面状态时并未停止音乐播放),导致进入另一个页面时根据该全局变量设置为播放状态;

    解决方法:再定义一个全局变量来记录当前播放页面的postId。

  • 问题4,音乐播放完成后图标状态没有复位。

    解决办法:添加一个事件来监听音乐停止,方法基本同监听音乐暂停事件

    // 监听音乐停止    wx.onBackgroundAudioStop(function () {      that.setData({        isPlayingMusic: false      })      app.globalData.g_isPlayingMusic = false;      app.globalData.g_curMusicPostId = null;    })

第7章   第四个页面:制作电影资讯页面

调用服务器数据,编写电影资讯首页。包括正在热映、即将上映、top250三类电影数据的加载,进一步的深入使用template、学习使用wx.request加载服务器数据。


  1. 给项目加入 tab 栏,切换页面
  2. 3个嵌套template标签构建电影资讯页面
  3. 从服务器加载数据:RESTful API简介及调用豆瓣API,获取正在热映、即将上映和Top250的数据
  4. 电影页面数据绑定
  5. 星星评分组件的实现
  6. 更换电影分类标题

1.在`post.wxml`页面中加入tab栏,实现方式:在`app.json`中设置`tabBar`,注意图片路径最前面不要加"/",会报错。
"tabBar": {    "borderStyle":"white",      "position":"bottom",    "list": [      {        "pagePath": "pages/post/post",        "iconPath": "image/tab/yuedu.png",        "selectedIconPath": "image/tab/yuedu_hl.png",        "text": "阅读"      },      {        "pagePath": "pages/movies/movies",        "text": "电影",        "iconPath": "image/tab/dianying.png",        "selectedIconPath": "image/tab/dianying_hl.png"      }    ]  },

1.RESTful API 用于 Web 数据接口

(1)五种操作

  • GET : 获取资源
  • HEAD:只获取某个资源的头部信息
  • POST:新建资源
  • PUT  :  更新资源的所有属性
  • PATCH:更新资源的部分属性
  • DELETE:删除资源

(2)URI && URL

  • URI  统一资源标识符,表示请求服务器的路径或者资源的名字
  • URL 统一资源定位符,同时说明要如何访问这个资源(http://)
  • URL是URI的子集,所以URL一定是URI,而URI不一定是URL
  • 我们常把网址成为URL,因为它提供了资源的位置信息

(3)状态码

  • 1xx:相关信息
  • 2xx:操作成功
  • 3xx:重定向
  • 4xx:客户端错误
  • 5xx:服务器错误

(4)服务器回应

  • API 返回的是一个 JSON 对象(结构化数据),将服务器回应的 HTTP 头的Content-Type属性要设为”application/json“。
    2.以下代码向服务器分别获取了”正在热映“、”即将上映“、”TOP250“的资源,在返回的结果中我们看到返回的数据并不是按调用顺序显示,这是因为从服务器加载数据是异步操作,无法确定先后顺序。
var app = getApp();Page({  onLoad:function(event){    var inTheatersUrl = app.globalData.doubanBase + '/v2/movie/in_theaters';    var comingSoonUrl = app.globalData.doubanBase + '/v2/movie/coming_soon';    var top250Url = app.globalData.doubanBase + '/v2/movie/top250';    this.getMovieListData(inTheatersUrl);    this.getMovieListData(comingSoonUrl);    this.getMovieListData(top250Url);  },  getMovieListData:function(url){    // 发起一个网络请求,这里主要是查询数据,用GET方式,POST是向服务器提交数据    wx.request({      url: url,      method: 'GET',       header: {        "Content-Type": "application/xml" //不能设置为 ”application/json“      },      success: function (res) {        console.log(res);      },      fail: function (error) {        console.log(error);      }    })  }})

3.刚开始设置URL为“https://api.douban.com/v2/movie/…”,但是出现403错误,于是参考博客将URL前半部分改为“https://douban.uieee.com”,成功获取服务器数据,然。。。吃了顿饭回来再次刷新报错112:rate_limit_exceeded2 IP访问速度限制,于是再次换了一个代理地址“http://t.yushu.im”,又成功获取数据啦。

4.星星评分组件的实现。在util.js文件中单独写了一个convertToStarsArray()函数,将服务器中获取的评分数据如3.5,转换成[1,1,1,0,0]形式,在前端显示星星图像时,循环数组判断是否为1,若为1显示为黄色星星;若为0显示为灰色星星;这里只考虑了整数情况,因为没有半颗黄色星星的图标。若是考虑小数,则可以将评分数据转换成[1,1,2,2,0]形式。具体实现如下:

//util.jsfunction convertToStarsArray(stars){  var num = stars.toString().substring(0,1); //获取第一个数字,如3.5就取3  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 util = require("../../utils/util.js");   ...   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 tmp = {         stars:util.convertToStarsArray(subject.rating.stars), //形式为:[1,1,1,0,0]         title:title,         average:subject.rating.average,         coverageUrl: subject.images.large,         movieId:subject.id       }       movies.push(tmp);    }    // 动态属性解决    var readyData = {};    readyData[settedkey] = {      movies:movies      };    this.setData(readyData);  }
//在movie-template.wxml页面中,注意“data="{{stars:stars,score:average}}" ”写法import src="../stars/stars-template.wxml" /template name="movieTemplate"  view class='movie-container'    image src='{{coverageUrl}}'/image    text{{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"        image wx:if="{{i}}" src='/image/icon/star.png'/image        image wx:else src='/image/icon/none-star.png'/image        !-- 方式二  考虑半颗星星的情况--        !-- image wx:if="{{i==1}}" src='/image/icon/star.png'/image         image wx:elif="{{i==2}}" src='/image/icon/none-star.png'/image         image wx:else="{{i==0}}" src='/image/icon/none-star.png'/image --      /block    /view    text{{score}}/text  /view/template

5.更换电影分类标题。一种是读取服务器数据中的title然后绑定到前端相应位置;这里考虑到只有“正在热映”,“即将上映”,“豆瓣TOP250”三类,直接在this.getMovieListData()函数传入具体的title,如 this.getMovieListData(inTheatersUrl,“inTheaters”,“正在热映”);

第8章   第五个页面:更多电影及电影搜索页面的实现

完成更多电影页面及电影资讯检索页面,template模板将在本章被大量使用,可以充分体现模板化编程思想的重要性。


  1. 电影类型获取
  2. 动态设置导航栏标题
  3. 更多电影页面加载数据
  4. 实现movie-grid template
  5. 实现上滑加载更多数据 scroll-view组件【可滚动视图区域】
  6. 设置loading状态
  7. 实现下拉刷新数据
  8. backgroundColor 到底设置的是哪里的颜色
  9. 电影搜索页面构建

1.电影类型获取。在movie-list-template.wxml页面中给“更多”一项绑定事件,当点击“更多”时,跳转到“更多电影”页面,在movies.js中添加onMoreTap事件,跳转到more-movie.wxml页面,然后在more-movie.js中获取传过来的category值。

  //movies.js  onMoreTap:function(event){    var category = event.currentTarget.dataset.category;    wx.navigateTo({      url: 'more-movie/more-movie?category='+category    })  }
//more-movie.jsPage({  data: {  },  onLoad: function (options) {    var category = options.category;  }})

2.动态设置导航栏标题。

wx.setNavigationBarTitle 为什么要在onready之后的生命周期函数中设置!!!否则不显示  

将上面第一步中传过来的category值保存在data中,需要时再取出使用。

Page({  data: {    navigateTitle:""  },  onLoad: function (options) {    var category = options.category;    this.data.navigateTitle = category;  },  // 当页面准备完毕了才执行页面函数  onReady:function(event){    wx.setNavigationBarTitle({      title: this.data.navigateTitle,      success: function (res) {      }    })  }})

3.更多电影页面【more-movie】加载数据
这里情况类似于上一个“电影资讯页面”,加载数据的方法雷同,首先根据more-movie.js中获取到的电影资讯类别category获取对应的URL,再通过getMovieListData()和processDoubanData()来获取URL地址的数据以及对数据进行筛选处理。

var app = getApp();var util = require("../../../utils/util.js");Page({  data: {    navigateTitle: "",    movies:{}  },  onLoad: function(options) {    var category = options.category;    this.data.navigateTitle = category;    var dataUrl = "";    switch (category) {      case "正在热映":        //默认返回20条信息         dataUrl = app.globalData.doubanBase + "/v2/movie/in_theaters";        break;      case "即将上映":        dataUrl = app.globalData.doubanBase + "/v2/movie/coming_soon";        break;      case "豆瓣TOP250":        dataUrl = app.globalData.doubanBase + "/v2/movie/top250";        break;    }    console.log(dataUrl);    util.http(dataUrl, this.processDoubanData);  },  processDoubanData: function (moviesDouban) {    // 获取相关数据    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 tmp = {        stars: util.convertToStarsArray(subject.rating.stars), //形式为:[1,1,1,0,0]        title: title,        average: subject.rating.average,        coverageUrl: subject.images.large,        movieId: subject.id      }      movies.push(tmp);    }    this.setData({      movies: movies    });  },  // 当页面准备完毕了才执行页面函数  onReady: function(event) {    wx.setNavigationBarTitle({      title: this.data.navigateTitle,      success: function(res) {}    })  }})

4.实现movie-grid template
经上一步筛选得到数据后,接下来就是把数据绑定到前台页面,首先实现一个movie-grid-template ,其中嵌套了movie-template,再将movie-grid-template添入more-movie页面,添加more-movie页面样式,页面效果如下,每个电影模块相当于一个movie-template,整个电影版块相当于一个movie-grid-template
小程序

//more-movie.wxmlimport src="../movie-grid/movie-grid-template.wxml" /template is="movieGridTemplate" data="{{movies}}"/template
//movie-grid-template.wxml页面import src="../movie/movie-template.wxml" /template name="movieGridTemplate"  view class='grid-container'    block wx:for="{{movies}}" wx:for-item="movie"      view class='single-view-container'        template is="movieTemplate" data="{{...movie}}"/template      /view    /block  /view/template

5.实现上滑加载更多数据【敲重点!!!

(1)scroll-view组件代替view组件实现可视区域上下滚动,且scroll-view组件需要给当前元素指定一个高度,否则无法确定什么时候算开始滚动。bindscrolltolower指定页面滚动到底部时需要触发的事件“onScrollLower”

 scroll-view scroll-y="true" scroll-x="false" bindscrolltolower="onScrollLower" class='grid-container' ... /scroll-view

(2)操作事件函数,

onScrollLower:function(){    var nextUrl = this.data.requestUrl + "?start=" + this.data.totalCount + "&count=20";    util.http(nextUrl, this.processDoubanData);}

第一,requestUrl就是onLoad函数中的dataUrl,但现在需要将dataUrl从一个函数传给另一个函数,需要将dataUrl保存到this.data中,即this.data.requestUrl = dataUrl;,再在onScrollLower函数中取出requestUrl,记得在data:{}中给requestUrl 一个初始化data: { navigateTitle: "", movies:{}, requestUrl:"", totalCount:0, isEmpty:true }

第二,用变量totalCount来记录当前获取的电影条目的总数量,接下来应该从totalCount开始继续往后取20(默认每次从服务器取20条)条数据,形成新的nextUrl地址,继续做数据绑定util.http(nextUrl, this.processDoubanData);。但刷新页面后发现,上滑页面只显示了新的20条电影数据,而原始的数据消失了。这里需要把新加载的20条数据与原先的数据整合在一起。每次增加数据,实际需要把全部数据都重新显示一遍。

 processDoubanData: function (moviesDouban) {    // 获取相关数据    ...    var totalMovies = {};    //若isEmpty为true,则数据为空 ,直接将movies赋给totalMovies;否则将新获取的movies数据与原先的数据合并,然后再赋给totalMovies    if (!this.data.isEmpty){      totalMovies = this.data.movies.concat(movies);    }    else{      totalMovies = movies;      this.data.isEmpty = false;    }    this.setData({      movies: totalMovies      totalCount: this.data.totalCount +20    });  }

6.设置loading状态。当用户发起上滑页面时出现loading,当setData新数据时结束loading。启动loading状态:wx.showNavigationBarLoading();。结束loading状态:wx.hideNavigationBarLoading();

7.实现下拉刷新数据。
more-movie.json中添加状态"enablePullDownRefresh": "true",以实现下拉刷新,如果在全局app.json中定义此状态,则会导致每个页面都会下拉刷新;
130400版本更新后,如果页面包含有scroll-view组件,则无法实现下拉刷新,解决方案更新在知乎上。

最坑最无语的一点,按照知乎上的方案更改后,下拉刷新还是失败,onPullDownRefresh依然无法触发,最后才意识到mac上下拉刷新需要用一只手指按住(一定要按下去啊)触摸板往下拉才会触发onPullDownRefresh???~ 我败了 ~

具体效果可以下拉刷新然后查看Network的状态。

还有一个问题,下拉刷新后数据依然不止20条,每次下拉刷新数据都重复出现,下拉刷新要记得清除原先的记录哦 !!!

onPullDownRefresh:function(event){    console.log("下拉");    var refreshUrl = this.data.requestUrl + "?start=0&count=20";     // 下拉刷新要记得清除原先的记录哦     this.data.movies = {};    this.data.isEmpty = true;    this.data.totalCount = 0;    util.http(refreshUrl, this.processDoubanData);    wx.showNavigationBarLoading(); //启动loading状态  }

8.backgroundColor 到底设置的是哪里的颜色
more-movie.json中设置"backgroundColor":"red",发现下拉刷新时顶部空出来的一部分变成了红色。

9.电影搜索页面构建。在movies.wxml顶部添加一个input搜索框,给input绑定bindfocus="onBindFocus"事件,同时在movies.wxml添加view显示电影搜索结果/view,通过事件与两个布尔型变量来切换电影搜索页面的显示与隐藏。

onBindFocus:function(event){    console.log("show search");    this.setData({      containerShow:false,      searchPanelShow:true    })  }

第二步,在input后添加一个关闭的图像,绑定bindtap='onCancelImgTap'事件,当点击关闭图标后,切换“电影资讯页面”与“电影搜索页面”的显示与隐藏状态,同时要清空电影搜索页面内容;另外,对关闭图标也要做一个相应的显示与隐藏操作,其状态是与“电影搜索页面”状态同步的。

onCancelImgTap:function(event){    console.log("cancel search");    this.setData({      containerShow: true,      searchPanelShow: false,      searchResult:{}    })  }

第三步,电影搜索页面数据绑定。首先给input绑定bindblur='onBindChange'事件,当用户点击input外面或是按回车键时,触发资源搜索,由searchResult对象保存搜索结果,最后将搜索结果显示到页面。

onBindChange:function(event){    // detail属性自定义事件所携带的数据,如表单的提交事件会携带用户的输入    var text = event.detail.value;    console.log(text);    var searchUrl = app.globalData.doubanBase + "/v2/movie/search?q=" + text;    this.getMovieListData(searchUrl,"searchResult","")  }
!-- 搜索页面 --view class='search-pannel' wx:if="{{searchPanelShow}}"  template is="movieGridTemplate" data="{{...searchResult}}" //view

第9章   第六个页面:构建电影详情页面

  1. 电影详情页面数据绑定
  2. 电影详情页面中图片的缩放与裁剪
  3. 电影详情页面样式

1.点击某个电影时,跳转到电影详情页面,并传递相应的电影ID号,然后根据ID从豆瓣获取资源再反馈到页面上。
//movie-template.wxml页面import src="../stars/stars-template.wxml" /template name="movieTemplate"  view class='movie-container' catchtap='onMovieTap' data-movieId = "{{movieId}}"     image src='{{coverageUrl}}'/image    text{{title}}/text    template is="starsTemplate" data="{{stars:stars,score:average}}" /  /view/template
  //movies.js  onMovieTap:function(event){    // dataset后面都是小写    var movieId = event.currentTarget.dataset.movieid;    wx.navigateTo({      url: 'movie-detail/movie-detail?id=' + movieId    })  }
  //在movie-detail.js中获取传过来的Id值  onLoad: function (options) {    var movieId = options.id;    var url = app.globalData.doubanBase + "/v2/movie/subject/" + movieId;    util.http(url,this.processDoubanData);  },  processDoubanData:function(data){    console.log(data);    ...  }  

2.电影详情页面中图片的缩放与裁剪
Image组件默认宽为300px,高为225px,其model有12种模式,包含4种缩放模式和9种裁剪模式。
当然,使用缩放模式前,需要给图片设置宽高。

image class='head-img' src="{{movie.movieImg}}" mode='aspectFill'/image

小程序
3.在设计页面样式中:

  • 模糊图片,设置图片属性-webkit-filter: blur(20px);
  • 给图片添加“点击查看”功能,绑定catchtap='viewMoviePostImg'事件
// 图片预览  viewMoviePostImg:function(event){    var src = event.currentTarget.dataset.src;    wx.previewImage({      current:src,  //当前显示的图片      urls:[src] //需要预览的图片列表,可以放入多张图片    })  }
  • @import引入template样式要注意页面样式是否被template样式覆盖

铛铛铛~到此为止,整个程序终于结束了,这是慕课网两年前的课程啦,现在的微信小程序开发工具又做了一些改进,所以学习过程中总是碰到一些奇怪的问题,但所幸都成功解决啦,再接再厉,探索永无止境。

版权声明

即速应用倡导尊重与保护知识产权。如发现本站文章存在版权问题,烦请提供版权疑问、身份证明、版权证明、联系方式等发邮件至197452366@qq.com ,我们将及时处理。本站文章仅作分享交流用途,作者观点不等同于即速应用观点。用户与作者的任何交易与本站无关,请知悉。

产品经理

手机 : 13312967497

擅长 : 小程序流量变现

扫码领取礼包

最新资讯

热门模板

  • 头条
  • 搜狐
  • 微博
  • 百家
  • 一点资讯
  • 知乎