您的位置:时时app平台注册网站 > 编程知识 > 其四个页面:营造新闻详细情形页面 【时

其四个页面:营造新闻详细情形页面 【时

2019-12-06 10:48

14.wx.showToast交互反馈

wx.showToast文档

post-detail.js添加个消息提示框

onCollectionTap: function(ev) {
    var postsCollected = wx.getStorageSync('posts_Collected')
    var postCollected = postsCollected[this.data.currentPostId]
    postCollected = !postCollected;
    postsCollected[this.data.currentPostId] = postCollected;
    // 更新文章是否收藏的缓存值
    wx.setStorageSync('posts_Collected', postsCollected)
    // 更新数据绑定变量,实现切换图片
    this.setData({
      collected: postCollected
    })

    wx.showToast({
      title: postCollected ? "收藏成功" : "取消成功",
      duration: 1000,
      icon: "success"
    })
  } 

效果

时时app平台注册网站 1


时时app平台注册网站 2


1、小程序的目录结构

小程序的目录结构如下所示。

时时app平台注册网站 3

其中项目级别的的文件包括 app.js、app.json、app.wxss 这三个。其中.js
后缀的是脚本文件,.json
后缀的文件是配置文件,.wxss
后缀的是样式表文件。
页面级别可以包含很多个页面,如index,detail等页面,每个页面都包含.js,.json,.wxml,.wxss这些文件,其中.wxml为页面视图文件,是自定义标签的HTML页面。
app.js是小程序的脚本代码。我们可以在这个文件中监听并处理小程序的生命周期函数、声明全局变量,可以调用框架提供的丰富的 API。
app.json 是对整个小程序的全局配置。我们可以在这个文件中配置小程序是由哪些页面组成,配置小程序的窗口�背景色,配置导航条样式,配置默认标题。
app.wxss 是整个小程序的公共样式表。我们可以在页面组件的 class 属性上直接使用 app.wxss 中声明的样式规则。
一个小程序主体部分由三个文件组成,必须放在项目的根目录。

时时app平台注册网站 4

微信小程序中的每一个页面的【路径 页面名】都需要写在 app.json 的 pages 中,且 pages 中的第一个页面是小程序的首页。
每一个小程序页面是由同路径下同名的四个不同后缀文件的组成,如:index.js、index.wxml、index.wxss、index.json。.js
后缀的文件是脚本文件,.json
后缀的文件是配置文件,.wxss
后缀的是样式表文件,.wxml
后缀的文件是页面结构文件。
index.json 是页面的配置文件:页面的配置文件是非必要的。当有页面的配置文件时,配置项在该页面会覆盖 app.json 的 window 中相同的配置项。如果没有指定的页面配置文件,则在该页面直接使用 app.json 中的默认配置。

时时app平台注册网站 5

逻辑层(App Service)
小程序开发框架的逻辑层是由JavaScript编写。
逻辑层将数据进行处理后发送给视图层,同时接受视图层的事件反馈。 在 JavaScript 的基础上,我们做了一些修改,以方便地开发小程序。
增加 App 和 Page 方法,进行程序和页面的注册。
增加 getApp 和 getCurrentPages 方法,分别用来获取 App 实例和当前页面栈。
提供丰富的 API,如微信用户数据,扫一扫,支付等微信特有能力。
每个页面有独立的作用域,并提供模块化能力。
由于框架并非运行在浏览器中,所以 JavaScript 在 web 中一些能力都无法使用,如 document,window 等。
开发者写的所有代码最终将会打包成一份 JavaScript,并在小程序启动的时候运行,直到小程序销毁。类似 ServiceWorker,所以逻辑层也称之为 App Service。

视图层
框架的视图层由 WXML 与 WXSS 编写,由组件来进行展示。
将逻辑层的数据反应成视图,同时将视图层的事件发送给逻辑层。
WXML(WeiXin Markup language)用于描述页面的结构。
WXSS(WeiXin Style Sheet)用于描述页面的样式。
组件(Component)是视图的基本组成单元。

基础组件
框架为开发者提供了一系列基础组件,开发者可以通过组合这些基础组件进行快速开发。
什么是组件:
组件是视图层的基本组成单元。
组件自带一些功能与微信风格的样式。
一个组件通常包括开始标签
和结束标签
,属性
用来修饰这个组件,内容
在两个标签之内。

<tagname property="value">
  Content goes here ...
</tagename>

注意:所有组件与属性都是小写,以连字符-连接

API

框架提供丰富的微信原生API,可以方便的调起微信提供的能力,如获取用户信息,本地存储,支付功能等。

说明:

wx.on 开头的 API 是监听某个事件发生的API接口,接受一个 CALLBACK 函数作为参数。当该事件触发时,会调用 CALLBACK 函数。
如未特殊约定,其他 API 接口都接受一个OBJECT作为参数。
OBJECT中可以指定success, fail, complete来接收接口调用结果。
参数名 类型 必填 说明
success Function 否 接口调用成功的回调函数
fail Function 否 接口调用失败的回调函数
complete Function 否 接口调用结束的回调函数(调用成功、失败都会执行)

2、小程序接口功能列表

框架提供丰富的微信原生API,可以方便的调起微信提供的能力,如获取用户信息,本地存储,支付功能等。

1)网络 API 列表:
wx.request 发起网络请求
wx.uploadFile 上传文件
wx.downloadFile 下载文件
wx.connectSocket 创建 WebSocket 连接
wx.onSocketOpen 监听 WebSocket 打开
wx.onSocketError 监听 WebSocket 错误
wx.sendSocketMessage 发送 WebSocket 消息
wx.onSocketMessage 接受 WebSocket 消息
wx.closeSocket 关闭 WebSocket 连接
wx.onSocketClose 监听 WebSocket 关闭

2)媒体 API 列表:
wx.chooseImage 从相册选择图片,或者拍照
wx.previewImage 预览图片
wx.startRecord 开始录音
wx.stopRecord 结束录音
wx.playVoice 播放语音
wx.pauseVoice 暂停播放语音
wx.stopVoice 结束播放语音
wx.getBackgroundAudioPlayerState 获取音乐播放状态
wx.playBackgroundAudio 播放音乐
wx.pauseBackgroundAudio 暂停播放音乐
wx.seekBackgroundAudio 控制音乐播放进度
wx.stopBackgroundAudio 停止播放音乐
wx.onBackgroundAudioPlay 监听音乐开始播放
wx.onBackgroundAudioPause 监听音乐暂停
wx.onBackgroundAudioStop 监听音乐结束
wx.chooseVideo 从相册选择视频,或者拍摄

3)文件 API 列表:
wx.saveFile 保存文件
wx.getSavedFileList 获取已保存的文件列表
wx.getSavedFileInfo 获取已保存的文件信息
wx.removeSavedFile 删除已保存的文件信息
wx.openDocument 打开文件

4)数据 API 列表:
wx.getStorage 获取本地数据缓存
wx.getStorageSync 获取本地数据缓存
wx.setStorage 设置本地数据缓存
wx.setStorageSync 设置本地数据缓存
wx.getStorageInfo 获取本地缓存的相关信息
wx.getStorageInfoSync 获取本地缓存的相关信息
wx.removeStorage 删除本地缓存内容
wx.removeStorageSync 删除本地缓存内容
wx.clearStorage 清理本地数据缓存
wx.clearStorageSync 清理本地数据缓存

5)位置 API 列表:
wx.getLocation 获取当前位置
wx.chooseLocation 打开地图选择位置
wx.openLocation 打开内置地图
wx.createMapContext 地图组件控制

6)设备 API 列表:
wx.getNetworkType 获取网络类型
wx.onNetworkStatusChange 监听网络状态变化
wx.getSystemInfo 获取系统信息
wx.getSystemInfoSync 获取系统信息
wx.onAccelerometerChange 监听加速度数据
wx.startAccelerometer 开始监听加速度数据
wx.stopAccelerometer 停止监听加速度数据
wx.onCompassChange 监听罗盘数据
wx.startCompass 开始监听罗盘数据
wx.stopCompass 停止监听罗盘数据
wx.setClipboardData 设置剪贴板内容
wx.getClipboardData 获取剪贴板内容
wx.makePhoneCall 拨打电话
wx.scanCode 扫码

7)界面 API 列表:
wx.showToast 显示提示框
wx.showLoading 显示加载提示框
wx.hideToast 隐藏提示框
wx.hideLoading 隐藏提示框
wx.showModal 显示模态弹窗
wx.showActionSheet 显示菜单列表
wx.setNavigationBarTitle 设置当前页面标题
wx.showNavigationBarLoading 显示导航条加载动画
wx.hideNavigationBarLoading 隐藏导航条加载动画
wx.navigateTo 新窗口打开页面
wx.redirectTo 原窗口打开页面
wx.switchTab 切换到 tabbar 页面
wx.navigateBack 退回上一个页面
wx.createAnimation 动画
wx.createContext 创建绘图上下文
wx.drawCanvas 绘图
wx.stopPullDownRefresh 停止下拉刷新动画

8)WXML节点信息 API 列表:
wx.createSelectorQuery 创建查询请求
selectorQuery.select 根据选择器选择单个节点
selectorQuery.selectAll 根据选择器选择全部节点
selectorQuery.selectViewport 选择显示区域
nodesRef.boundingClientRect 获取布局位置和尺寸
nodesRef.scrollOffset 获取滚动位置
nodesRef.fields 获取任意字段
selectorQuery.exec 执行查询请求

9)开放接口:
wx.login 登录
wx.getUserInfo 获取用户信息
wx.chooseAddress 获取用户收货地址
wx.requestPayment 发起微信支付
wx.addCard 添加卡券
wx.openCard 打开卡券

17.完善音乐播放功能

在文章详情页,点击播放音乐后,然后返回到文章列表页,再进到详情页,发现播放按钮是暂停状态,这是因为应用程序存在生命周期,下面就解决这个问题。

app.js绑定一个全局的变量(音乐播放状态)

App({
  globalData: {
    g_isPlayingMusic: false,
    g_currentMusicPostId: null,
  },
})

post-detail.js

var app = getApp();

Page({

  data: {
    isPlayingMusic: false
  },

  onLoad: function(options) {
    .
    .
    .

    if (app.globalData.g_isPlayingMusic && app.globalData.g_currentMusicPostId === postId) {
      this.setData({
        isPlayingMusic: true
      })
    }
    this.setMusicMonitor()
  },

  setMusicMonitor:function(){
    var that = this;
    wx.onBackgroundAudioPlay(function () {
      that.setData({
        isPlayingMusic: true
      })
      app.globalData.g_currentMusicPostId = that.data.currentPostId
      app.globalData.g_isPlayingMusic = true
    });
    wx.onBackgroundAudioPause(function () {
      that.setData({
        isPlayingMusic: false
      })
      app.globalData.g_currentMusicPostId = null
      app.globalData.g_isPlayingMusic = false
    });  
  },

切换文章图片

以上我们完成了简单的音乐播放和暂停以及音乐图标的切换,而且也说明了coverImg中引入的图片只有在真机上,进入音乐界面后才能够看到,但是我们也可以将coverImg引入的图片显示在文章详情页上,只需要做一个简单的图片切换即可:

<image src='{{isPlayingMusic ? postData.music.coverImg : postData.headImgSrc}}' class='head-iamge'></image>

运行效果:
播放:
时时app平台注册网站 6

暂停:
时时app平台注册网站 7


3、相关处理代码

1)注册程序处理代码

App({
  onLaunch: function(options) {
    // Do something initial when launch.
  },
  onShow: function(options) {
      // Do something when show.
  },
  onHide: function() {
      // Do something when hide.
  },
  onError: function(msg) {
    console.log(msg)
  },
  globalData: 'I am global data'
})

2)注册页面处理代码

//index.js
Page({
  data: {
    text: "This is page data."
  },
  onLoad: function(options) {
    // Do some initialize when page load.
  },
  onReady: function() {
    // Do something when page ready.
  },
  onShow: function() {
    // Do something when page show.
  },
  onHide: function() {
    // Do something when page hide.
  },
  onUnload: function() {
    // Do something when page close.
  },
  onPullDownRefresh: function() {
    // Do something when pull down.
  },
  onReachBottom: function() {
    // Do something when page reach bottom.
  },
  onShareAppMessage: function () {
   // return custom share data when user share.
  },
  onPageScroll: function() {
    // Do something when page scroll
  },
  // Event handler.
  viewTap: function() {
    this.setData({
      text: 'Set some data for updating view.'
    })
  },
  customData: {
    hi: 'MINA'
  }
})

3)JS函数模块化

// common.js
function sayHello(name) {
  console.log(`Hello ${name} !`)
}
function sayGoodbye(name) {
  console.log(`Goodbye ${name} !`)
}

module.exports.sayHello = sayHello
exports.sayGoodbye = sayGoodbye

在需要使用这些模块的文件中,使用 require(path) 将公共代码引入

var common = require('common.js')
Page({
  helloMINA: function() {
    common.sayHello('MINA')
  },
  goodbyeMINA: function() {
    common.sayGoodbye('MINA')
  }
})

4)网络数据请求处理代码

//点击搜索按钮调用的函数
  search:function(e){
    var that = this;

    //数据加载完成之前,显示加载中提示框
    wx.showToast({
      title: '加载中。。。',
      icon: 'loading',
      duration: 10000
    });

    //发起请求,注意 wx.request发起的是 HTTPS 请求
    wx.request({
      url: url   "?city="   that.data.inputValue   "&key="   apiKey,
      data: {},
      header: {
          'content-type': 'application/json'
      },
      success: function(res) {
        var data = res.data;
        //将数据从逻辑层发送到视图层,同时改变对应的 this.data 的值
        that.setData({
          restation: data.result,
          condition: false
        });
        //数据加载成功后隐藏加载中弹框
        wx.hideToast();
      }
    })

  }

15.音乐播放功能

音乐播放API文档

在posts-data.js里面给每篇文章添加一个music属性

 music: {
    url: "http://music.163.com/song/media/outer/url?id=108242.mp3",
    title: "她说-林俊杰",
    coverImg: "http://y.gtimg.cn/music/photo_new/T002R150x150M000001TEc6V0kjpVC.jpg?max_age=2592000"
  }

post-detail.wxml

  • 没播放音乐就显示文章图片,播放音乐就显示音乐歌手图片
  • 绑定事件,添加播放和暂停音乐以及图片切换功能
 <!-- <image class="head-image" src="{{postData.headImgSrc}}"></image> -->
  <image class='head-image' src="{{isPlayingMusic?postData.music.coverImg:postData.headImgSrc}}"></image>
  <image catchtap='onMusicTap' class='audio' src="{{isPlayingMusic? '/images/music/music-stop.png': '/images/music/music-start.png'}}"></image>

post-detail.js

// 播放音乐
  onMusicTap: function (ev) {
    var currentPostId = this.data.currentPostId;
    var postData = postsData.postlist[currentPostId];
    var isPlayingMusic = this.data.isPlayingMusic;
    if (isPlayingMusic) {
      wx.pauseBackgroundAudio();
      this.setData({
        isPlayingMusic: false
      })
    }
    else {
      wx.playBackgroundAudio({
        dataUrl: postData.music.url,
        title: postData.music.title,
        coverImgUrl: postData.music.coverImg,
      })
      this.setData({
        isPlayingMusic: true
      })
    }
  }

交互反馈wx.showActionSheet

​showActionSheet可以显示操作菜单,以下使用实际示例演示一下showActionSheet的使用:

1.在分享图标上加上一个点击事件:

<image catchtap='onShareTap' class='share-img' src='icon/share.png'></image>

2.事件代码如下:

onShareTap:function(event){
    var itemList = [
      "分享给微信好友",
      "分享到朋友圈",
      "分享到QQ",
      "分享到微博",
    ]
    wx.showActionSheet({
      itemList: itemList,  // 按钮的文字数组,数组长度最大为6个
      itemColor:"#405f80",  // 设置字体颜色
      success:function(res){
        //res.tapIndex  用户点击的按钮,从上到下的顺序,从0开始
        wx.showModal({
          title: itemList[res.tapIndex],
          content: '现在无法实现分享功能,什么时候能支持还未知',
        })
      }, 
    })
  },

运行效果:
时时app平台注册网站 8
时时app平台注册网站 9

注:到目前为止,微信小程序官方还尚未提供能够将小程序直接分享到朋友圈的相关api,不过有一些曲线救国的方案,可以参考以下两篇文章,或者使用百度、谷歌等搜索引擎搜索解决方案:



微信小程序在无论在功能、文档及相关支持方面,都是优于前面几种微信账号类型,它提供了很多原生程序才有的接口,使得我们的小程序在很多方面突破H5页面应用的限制,更加接近原生程序的功能,因此微信小程序具有很大的前景想象力。它提供了自己的视图层描述语言 WXML 和 WXSS,以及基于 JavaScript 的逻辑层框架,并在视图层与逻辑层间提供了数据传输和事件系统,可以让开发者可以方便的聚焦于数据与逻辑上。

18.轮播图跳转到文章详情

post.wxml

<swiper catchtap='onSwiperTap' indicator-dots='true' autoplay='true' interval='2000'>

post.js

onSwiperTap(event) {
    var postId = event.target.dataset.postid
    wx.navigateTo({
      url: 'post-detail/post-detail?id='   postId
    })
  },

使用数据填充新闻详情页面

首先是postId的获得,因为不同的postId需要输出不同的文章详情数据:
1.在post.js的navigateTo方法的url参数中,加上一个id参数:

onPostTap: function(event){
    // 从事件源中获取postId数据
    var postId = event.currentTarget.dataset.postid;
    //console.log("on post id is "   postId);
    wx.navigateTo({
      url: 'post-detail/post-detail?id='   postId,  // 通过url传递postId
    })
  },

2.然后在post-detail.js中,写一个onLoad函数把id获得到手:

Page({
  onLoad:function(option){
    var postId = option.id; // 这里的id对应的是url参数上的id
    console.log(postId);
  }
})

3.编译之后,点击不同的文章,看看控制台中是否有输出相应的postId,有输出的话就证明获得成功。

完成以上操作后,就可以把新闻详情页面的数据放进数据文件中,然后进行数据绑定:
post-data.js文件内容:

// 将数据整合成数组类型
var local_database = [
  {
    date: "Jan 06 2018",
    title: "正是虾肥蟹壮时",
    imgSrc: "post/crab.png",
    avatar: "vatar/1.png",
    content: "“山明水净夜来霜,数树深红出浅黄。试上高楼清入骨,岂如春色嗾人狂。”金秋时节,天高云淡,秋风送爽,气候宜人。秋风秋阳中,硕果坠挂枝头,玉米抚须含笑,高粱引颈高歌,豆荚饱满圆润。",
    reading: "112",
    collection: "96",
    headImgSrc: "post/crab.png",
    author: "zero",
    dataTime:"24小时前",
    detail: "“山明水净夜来霜,数树深红出浅黄。试上高楼清入骨,岂如春色嗾人狂。”金秋时节,天高云淡,秋风送爽,气候宜人。秋风秋阳中,硕果坠挂枝头,玉米抚须含笑,高粱引颈高歌,豆荚饱满圆润。棉桃鼓胀欲裂,水稻灌浆初熟,世间万物经过春的孕育,夏的生长,即将抵达收获的季节。在这瓜果飘香、稻黍起舞的召唤声中,又是一度蟹肥虾壮时。地处黄海之滨的小城,在秋风的抚慰、秋阳的光照下,瞬间也喧嚣起来。任意走进城中的每一个菜市场,在显眼的位置上,冲入耳际的是此起彼伏的吆喝声,映入眼帘的是那些小商小贩们抢占有利地势将一只只塑料箱一字排开的情景。浅箱中,健壮的对虾、竹节虾在水中跳跃,舒展着弯曲的身体;深箱中,一贯横行霸道的螃蟹拥挤在狭小的空间里,相互肆意践踏,有些不甘蜗居的螃蟹,顺着笔直的箱壁艰难地攀爬着,虽经百般努力,终以失败而告终。那些聚集在网兜里的螃蟹,更是不甘寂寞,身体被束缚着无法动弹,便利用可以自由呼吸的嘴巴,于窸窸窣窣中不停地吐着一串串泡沫,以示抗议,也以此证明自己是个活物。特别是那些个头较大的螃蟹,仿佛知道自己的身价不菲,为此,更是气宇轩昂,自以为是。也许,它们是得到垂青和恩宠的一类吧,受到了特别的眷顾,活动的空间相对较大,所以也更加肆无忌惮。只要有人试图靠近,便会举着那两只肥硕的大螯向你示威,仿佛在警告你:别碰我,否则休怪我无礼!",
    postId: 0,
  },
  {
    date: "Jan 03 2018",
    title: "比利·林恩的中场战事",
    imgSrc: "post/bl.png",
    avatar: "vatar/2.png",
    content: "伊拉克战争时期,来自美国德州的19岁技术兵比利·林恩(乔·阿尔文 Joe Alwyn 饰)因为一段偶然拍摄的视频而家喻户晓。那是一次规模不大却激烈非常的遭遇战,战斗中林恩所在的B班班长(范·迪塞尔 Vin Diesel 饰)遭到当地武装分子的伏击和劫持,而林恩为了营救班长不惜铤而走险冲锋陷阵。",
    reading: "92",
    collection: "65",
    headImgSrc: "post/bl.png",
    dataTime: "一天前",
    author: "妮可",
    detail: "伊拉克战争时期,来自美国德州的19岁技术兵比利·林恩(乔·阿尔文 Joe Alwyn 饰)因为一段偶然拍摄的视频而家喻户晓。那是一次规模不大却激烈非常的遭遇战,战斗中林恩所在的B班班长(范·迪塞尔 Vin Diesel 饰)遭到当地武装分子的伏击和劫持,而林恩为了营救班长不惜铤而走险冲锋陷阵。视频公布于世让他成为全美民众所崇拜的英雄,然而却鲜有人理解他和战友们所经历的一切。为了安葬班长,B班得到了短暂的休假,因此他们得以受邀参加一场在德州举行的橄榄球比赛。林恩的姐姐因某事件深感愧疚,她希望弟弟能借此机缘回归普通生活。而周围的经纪人、球迷、大老板、普通民众则对战争、卫国、士兵有着各种各样想当然的理解。球场上的庆典盛大开幕,林恩和战友们的心却愈加沉重与焦躁…… ",
    postId: 1,
  },
  {
    date: "Jan 05 2018",
    title: "肖申克的救赎",
    imgSrc: "post/xs.jpg",
    avatar: "vatar/3.png",
    content: "20世纪40年代末,小有成就的青年银行家安迪(蒂姆·罗宾斯 Tim Robbins 饰)因涉嫌杀害妻子及她的情人而锒铛入狱。在这座名为肖申克的监狱内,希望似乎虚无缥缈,终身监禁的惩罚无疑注定了安迪接下来灰暗绝望的人生。",
    reading: "92",
    collection: "65",
    headImgSrc: "post/xs.jpg",
    dataTime: "两天前",
    author: "John",
    detail: "20世纪40年代末,小有成就的青年银行家安迪(蒂姆·罗宾斯 Tim Robbins 饰)因涉嫌杀害妻子及她的情人而锒铛入狱。在这座名为肖申克的监狱内,希望似乎虚无缥缈,终身监禁的惩罚无疑注定了安迪接下来灰暗绝望的人生。未过多久,安迪尝试接近囚犯中颇有声望的瑞德(摩根·弗里曼 Morgan Freeman 饰),请求对方帮自己搞来小锤子。以此为契机,二人逐渐熟稔,安迪也仿佛在鱼龙混杂、罪恶横生、黑白混淆的牢狱中找到属于自己的求生之道。他利用自身的专业知识,帮助监狱管理层逃税、洗黑钱,同时凭借与瑞德的交往在×××中间也渐渐受到礼遇。表面看来,他已如瑞德那样对那堵高墙从憎恨转变为处之泰然,但是对自由的渴望仍促使他朝着心中的希望和目标前进。而关于其罪行的真相,似乎更使这一切朝前推进了一步…… ",
    postId: 2,
  },
  {
    date: "Jan 01 2018",
    title: "霸王别姬",
    imgSrc: "post/bj.jpg",
    avatar: "vatar/4.png",
    content: "段小楼(张丰毅)与程蝶衣(张国荣)是一对打小一起长大的师兄弟,两人一个演生,一个饰旦,一向配合天衣无缝,尤其一出《霸王别姬》,更是誉满京城,为此,两人约定合演一辈子《霸王别姬》。但两人对戏剧与人生关系的理解有本质不同,段小楼深知戏非人生,程蝶衣则是人戏不分。",
    reading: "92",
    collection: "65",
    headImgSrc: "post/bj.jpg",
    dataTime: "三天前",
    author: "Jack",
    detail: "段小楼(张丰毅)与程蝶衣(张国荣)是一对打小一起长大的师兄弟,两人一个演生,一个饰旦,一向配合天衣无缝,尤其一出《霸王别姬》,更是誉满京城,为此,两人约定合演一辈子《霸王别姬》。但两人对戏剧与人生关系的理解有本质不同,段小楼深知戏非人生,程蝶衣则是人戏不分。段小楼在认为该成家立业之时迎娶了名妓菊仙(巩俐),致使程蝶衣认定菊仙是可耻的第三者,使段小楼做了叛徒,自此,三人围绕一出《霸王别姬》生出的爱恨情仇战开始随着时代风云的变迁不断升级,终酿成悲剧。",
    postId: 3,
  },
  {
    date: "Jan 08 2018",
    title: "这个杀手不太冷",
    imgSrc: "post/ss.jpg",
    avatar: "vatar/5.png",
    content: "里昂(让·雷诺饰)是名孤独的×××,受人雇佣。一天,邻居家小姑娘马蒂尔达(纳塔丽·波特曼饰)敲开他的房门,要求在他那里暂避杀身之祸。原来邻居家的主人是警方缉毒组的眼线,只因贪污了一小包×××而遭恶警(加里·奥德曼饰)杀害全家的惩罚。",
    reading: "92",
    collection: "65",
    headImgSrc: "post/ss.jpg",
    dataTime: "四天前",
    author: "Bill",
    detail: "里昂(让·雷诺饰)是名孤独的×××,受人雇佣。一天,邻居家小姑娘马蒂尔达(纳塔丽·波特曼饰)敲开他的房门,要求在他那里暂避杀身之祸。原来邻居家的主人是警方缉毒组的眼线,只因贪污了一小包×××而遭恶警(加里·奥德曼饰)杀害全家的惩罚。马蒂尔达得到里昂的留救,幸免于难,并留在里昂那里。里昂教小女孩使枪,她教里昂法文,两人关系日趋亲密,相处融洽。女孩想着去×××,反倒被抓,里昂及时赶到,将女孩救回。混杂着哀怨情仇的正邪之战渐次升级,更大的冲突在所难免…… ",
    postId: 4,
  },
  {
    date: "Jan 04 2018",
    title: "阿甘正传",
    imgSrc: "post/ag.jpg",
    avatar: "vatar/1.png",
    content: "阿甘(汤姆·汉克斯 饰)于二战结束后不久出生在美国南方阿拉巴马州一个闭塞的小镇,他先天弱智,智商只有75,然而他的妈妈是一个性格坚强的女性,她常常鼓励阿甘“傻人有傻福”,要他自强不息。",
    reading: "92",
    collection: "65",
    headImgSrc: "post/ag.jpg",
    dataTime: "五天前",
    author: "Tony",
    detail: "阿甘(汤姆·汉克斯 饰)于二战结束后不久出生在美国南方阿拉巴马州一个闭塞的小镇,他先天弱智,智商只有75,然而他的妈妈是一个性格坚强的女性,她常常鼓励阿甘“傻人有傻福”,要他自强不息。阿甘像普通孩子一样上学,并且认识了一生的朋友和至爱珍妮(罗宾·莱特·潘 饰),在珍妮和妈妈的爱护下,阿甘凭着上帝赐予的“飞毛腿”开始了一生不停的奔跑。阿甘成为橄榄球巨星、越战英雄、乒乓球外交使者、亿万富翁,但是,他始终忘不了珍妮,几次匆匆的相聚和离别,更是加深了阿甘的思念。有一天,阿甘收到珍妮的信,他们终于又要见面了……",
    postId: 5,
  },
]

// 设置一个数据出口
module.exports = {
  // 输出的是一个Array对象
  postList: local_database,
}

post-detail.js文件内容:

var postsData = require('../../../data/posts-data.js')

Page({
  onLoad:function(option){
    var postId = option.id; // 这里的id对应的是url参数上的id
    var postData=postsData.postList[postId];
    this.setData({
        postData
    });
  }
})

post-detail.wxml文件内容:

<view class='container'>
  <image src='{{postData.headImgSrc}}' class='head-iamge'></image>
  <image class='audio' src='music/music-start.png'></image>
  <view class='author-date'>
    <image src='{{postData.avatar}}' class='avatar' ></image>
    <text class='author'>{{postData.author}}</text>
    <text class='const-text'>发表于</text>
    <text class='date'>{{postData.dataTime}}</text>
  </view>
  <text class='title'>{{postData.title}}</text>
  <view class='tool'>
    <view class='circle-img'>
      <image src='icon/collection.png'></image>
      <image class='share-img' src='icon/share.png'></image>
    </view>
    <view class='horizon'></view>
  </view>
  <text class='detail'>{{postData.detail}}</text>
</view>

运行效果:
时时app平台注册网站 10


16.监听音乐播放事件

监听音乐播放文档

post-detail.js的onLoad函数里面添加监听事件

var that = this;
    wx.onBackgroundAudioPlay(function(){
      that.setData({
        isPlayingMusic: true
      })
    });
    wx.onBackgroundAudioPause(function () {
      that.setData({
        isPlayingMusic: false
      })
    });
  },

绑定监听事件后,播放按钮的状态就可以同步切换了

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

实现这个功能我们需要使用到两个图标进行状态的轮换,由于小程序中没有document,我们需要使用if判断来实现这个功能。

post-detail.wxml代码如下:

<!-- 判断collected的值是否为真,是的话就显示src中指定的图片 -->
<image wx:if="{{collected}}" catchtap='onCollectionTap' src='icon/collection.png'></image>
<!-- 否则显示这张图片 -->
<image wx:else catchtap='onCollectionTap' src='icon/collection-anti.png'></image>

post-detail.js代码如下:

var postsData = require('../../../data/posts-data.js')

Page({
  data:{

  },
  onLoad: function (option) {
    var postId = option.id; // 这里的id对应的是url参数上的id
    // 把postId设置到数据集里,这样就能够全局获取
    this.data.currentPostId = postId;
    var postData = postsData.postList[postId];
    this.setData({
      postData
    });

    // 从缓存中获取数据,键值对形式的
    var postsCollected = wx.getStorageSync('posts_collected');
    // 判断数据是否不为空
    if (postsCollected) {
      // 不为空就拿出与postId对应的下标值
      var postsCollected = postsCollected[postId];
      // 并将值更新到数据绑定里
      this.setData({
        collected: postsCollected
      });
    } else {
      // 如果为空就赋值一个空对象
      var postsCollected = {}
      // 并把与postId对应的下标中的值设置为false
      postsCollected[postId] = false;
      // 更新到缓存里
      wx.setStorageSync('posts_collected', postsCollected);
    }
  },

  // 点击事件方法
  onCollectionTap: function (event) {
    // 获取缓存数据
    var postsCollected = wx.getStorageSync('posts_collected');
    // 从数据集中获取postId
    var postCollected = postsCollected[this.data.currentPostId];
    // 收藏变成未收藏,未收藏变成收藏
    postCollected = !postCollected;
    postsCollected[this.data.currentPostId] = postCollected;
    // 更新文章是否收藏的缓存值
    wx.setStorageSync('posts_collected', postsCollected);
    // 更新数据绑定变量,从而实现切换图片
    this.setData({
      collected: postCollected
    });
  },

})

运行效果:

未收藏状态:
时时app平台注册网站 11

收藏状态:
时时app平台注册网站 12


真机如何清除缓存与template的路径问题

在小程序中的缓存数据都是没有时效期的,不主动清除的话就会一直存在,在模拟器上我们可以点击工具提供的清除缓存按钮清除缓存数据:
时时app平台注册网站 13

但是如果在真机上,则需要自己手动编写一个清除缓存的按钮,需要使用到wx.clearStorageSync()或wx.clearStorage()方法,前者是同步通清理本地数据缓存,后者则是异步清理本地数据缓存。当点击这个按钮的时候就能触发一个点击事件去执行这个清除缓存的方法。

template的路径问题:

我们都知道template文件中的代码目的是为了给其他页面文件复用的,所以template代码中的所包含的文件路径不要写相对路径,写绝对路径比较好,因为如果文件A引用了template文件中的代码,但是文件A和template文件并不是同一级的,那么这时候如果使用相对路径就会有问题。

配置全局导航栏颜色

上面把基本的静态页面做完了,但是导航栏颜色还不太对,而且少了个标识文字,所以现在就来把这个位置的样式完善好。
app.json文件内容:

{
  "pages": [
    "pages/welcome/welcome",
    "pages/posts/post",
    "pages/posts/post-detail/post-detail"
  ],
  "window": {
    "navigationBarBackgroundColor": "#405f80"
  }
}

welcome.json文件内容:

{
  "navigationBarBackgroundColor": "#b3d4db"
}

post.json文件内容:

{
    "navigationBarTitleText": "文与字"
}

post-detail.json文件内容:

{
  "navigationBarTitleText": "阅读"
}

完成效果:
时时app平台注册网站 14


继续完善音乐播放

以上我们简单介绍了一下关于页面状态与全局变量以及应用程序生命周期,现在就可以使用全局变量来继续完善音乐播放的功能了:

app.js代码如下:

App({

  globalData:{
    g_isPlayingMusic:false
  },

});

post-detail.js代码如下:

var postsData = require('../../../data/posts-data.js')
// 获得全局的app对象
var app = getApp();

Page({
  data: {
    isPlayingMusic: false
  },

  onLoad: function (option) {

        ......以上代码省略......

    // 当全局变量的状态为播放时,也把页面的状态设置为teur 
    if (app.globalData.g_isPlayingMusic){
      this.setData({
        isPlayingMusic: true
      });
    }

    this.setMusicMonitor();
  },

  // 把监听音乐的事件代码提取出来
  setMusicMonitor:function(){
    var that = this;
    // 当音乐播放时将页面以及全局状态状态改为true
    wx.onBackgroundAudioPlay(function () {
      that.setData({
        isPlayingMusic: true
      });
      app.globalData.g_isPlayingMusic = true;
    });

    // 当音乐暂停时将页面以及全局状态都改为false
    wx.onBackgroundAudioPause(function () {
      that.setData({
        isPlayingMusic: false
      });
      app.globalData.g_isPlayingMusic = false;
    });
  },

              ......以下代码省略......

})

使用全局变量记录状态后,就不会出现之前的问题了,这时我们就可以在页面加载时根据全局变量来设置页面变量的状态。


音乐播放最终章

除了以上的问题之外,我还找到了三个问题,第一个问题是当我们点击音乐播放时,背景图片会切换,但是我们只需要切换当前页面的图片,别的页面不应该也跟着切换,而这个问题就是别的页面也会跟着切换图片,这个问题我们可以通过把页面id存储到全局变量里,根据id来决定是哪个页面才会切换图片,这样就可以解决这个问题。

第二个问题是当我们关闭音乐播放器时,图片不会切换,依旧停留在播放状态,这个问题我们可以通过wx.onBackgroundAudioStop来解决。

第三个问题就是当我们在文章A里播放了音乐,然后到文章B上点击音乐播放器的总控开关时,文章B的图片也会跟着切换,解决这个问题稍微有点麻烦,因为要考虑到点击图标开关和点击音乐播放器开关两种情况,以及回到原本的页面时还需切换图片,我的解决思路是使用一个全局变量记录上一个页面,也就是原始页面的id,通过这个id来决定切不切换图片。

app.js文件内容如下:

App({

  globalData:{
    g_isPlayingMusic:false,
    g_currentMusicPostId:"",
    g_beforeMusicPostId: ""
  },

});

以下是修改后的post-detail.js文件内容:

var postsData = require('../../../data/posts-data.js')
// 获得全局的app对象
var app = getApp();

Page({
  data: {
    isPlayingMusic: false
  },

  onLoad: function (option) {
    var postId = option.id; // 这里的id对应的是url参数上的id
    // 把postId设置到数据集里,这样就能够全局获取
    this.data.currentPostId = postId;
    var postData = postsData.postList[postId];
    this.setData({
      postData
    });

    // 从缓存中获取数据
    var postsCollected = wx.getStorageSync('posts_collected');
    // 判断数据是否不为空
    if (postsCollected) {
      // 不为空就拿出与postId对应的下标值
      var postsCollected = postsCollected[postId];
      // 并将值更新到数据绑定里
      this.setData({
        collected: postsCollected
      });
    } else {
      // 如果为空就赋值一个空对象
      var postsCollected = {}
      // 并把与postId对应的下标中的值设置为false
      postsCollected[postId] = false;
      // 更新到缓存里
      wx.setStorageSync('posts_collected', postsCollected);
    }

    // 音乐在播放时改变状态为true 
    if (app.globalData.g_isPlayingMusic && app.globalData.g_currentMusicPostId === postId){
      this.setData({
        isPlayingMusic: true
      });
    }

    this.setMusicMonitor();
  },

  // 把监听音乐的事件代码提取出来
  setMusicMonitor:function(){
    var that = this;

    // 监听音乐播放
    wx.onBackgroundAudioPlay(function () {
      // 在原始页面触发播放事件时,切换页面图片,并且记录当前文章的id
      if (app.globalData.g_beforeMusicPostId != "" && app.globalData.g_beforeMusicPostId === that.data.currentPostId){
        that.setData({
          isPlayingMusic: true
        });
        app.globalData.g_isPlayingMusic = true;
        app.globalData.g_currentMusicPostId = that.data.currentPostId;
        app.globalData.g_beforeMusicPostId = app.globalData.g_beforeMusicPostId;

      // 产生原始页面时,或者图标开关被点击时,切换页面图片,并且记录当前文章的id
      } else if (app.globalData.g_beforeMusicPostId == "" || that.data.isPlayingMusic){
        that.setData({
          isPlayingMusic: true
        });
        app.globalData.g_isPlayingMusic = true;
        app.globalData.g_currentMusicPostId = that.data.currentPostId;
        app.globalData.g_beforeMusicPostId = that.data.currentPostId;

      // 在非原始页面触发播放事件时,不切换该页面的图片
      } else{
        that.setData({
          isPlayingMusic: false
        });
        app.globalData.g_isPlayingMusic = true;
        app.globalData.g_currentMusicPostId = app.globalData.g_beforeMusicPostId;
      }
    });

    // 当音乐暂停时将页面以及全局状态都改为false,并且把当前文章的id清空
    wx.onBackgroundAudioPause(function () {
      that.setData({
        isPlayingMusic: false
      });
      app.globalData.g_isPlayingMusic = false;
      app.globalData.g_currentMusicPostId = "";
    });

    // 当音乐停止时将页面以及全局状态都改为false,并且把当前文章以及上一篇文章的id清空
    wx.onBackgroundAudioStop(function(){
      that.setData({
        isPlayingMusic: false
      });
      app.globalData.g_isPlayingMusic = false;
      app.globalData.g_currentMusicPostId = "";
      app.globalData.g_beforeMusicPostId = "";
    });
  },

  //点击事件方法
  onCollectionTap: function (event) {
    // 获取缓存数据
    var postsCollected = wx.getStorageSync('posts_collected');
    // 获取postId
    var postCollected = postsCollected[this.data.currentPostId];
    // 收藏变成未收藏,未收藏变成收藏
    postCollected = !postCollected;
    postsCollected[this.data.currentPostId] = postCollected;

    // 自定义函数也需要使用this来访问
    this.showModal(postsCollected, postCollected);
  },

  showModal: function (postsCollected, postCollected) {
    // 把this指代的Page对象先存储起来
    var that = this;
    wx.showModal({
      title: '收藏',
      content: postCollected ? '是否收藏该文章?' : '是否取消收藏该文章?',
      showCancel: 'true',
      cancelText: '取消',
      cancelColor: '#333',
      confirmText: '确认',
      confirmColor: '#405f80',
      success: function (res) {
        if (res.confirm) {
          // 更新文章是否收藏的缓存值
          wx.setStorageSync('posts_collected', postsCollected);
          // 更新数据绑定变量,从而实现切换图片
          that.setData({
            collected: postCollected
          });
          that.showToast(postsCollected, postCollected);
        }
      },
    });
  },

  showToast: function (postsCollected, postCollected) {
    wx.showToast({
      // 使用三元表达式来判断状态
      title: postCollected ? '收藏成功!' : '取消成功!',
      // 设置图标停留的时间,单位是毫秒
      duration: 1000,
      // icon可以设置图标,默认就是success
      icon: "success",
    });
  },

  onShareTap: function (event) {
    var itemList = [
      "分享给微信好友",
      "分享到朋友圈",
      "分享到QQ",
      "分享到微博",
    ]
    wx.showActionSheet({
      itemList: itemList,
      itemColor: "#405f80",
      success: function (res) {
        //res.cancel  用户是否点击了取消按钮
        //res.tapIndex  数组元素的索引
        wx.showModal({
          title: itemList[res.tapIndex],
          content: '现在无法实现分享功能,什么时候能支持还未知',
        })
      },
    })
  },

  onMusicTap: function (event) {
    var currentPostId = this.data.currentPostId;
    var postData = postsData.postList[currentPostId];

    // 使用变量来记录音乐的状态
    var isPlayingMusic = this.data.isPlayingMusic;
    if (isPlayingMusic) {
      // 暂停音乐
      wx.pauseBackgroundAudio();
      this.setData({
        isPlayingMusic : false
      });

    } else {
      wx.playBackgroundAudio({
        // 流媒体文件的URL,目前支持的格式有 m4a, aac, mp3, wav
        dataUrl: postData.music.url,
        // 音乐标题
        title: postData.music.title,
        // 音乐封面URL
        coverImgUrl: postData.music.coverImg,
      });
      this.setData({
        isPlayingMusic: true
      });
    }
  },
})

以上就算是完成了一个基本的音乐播放效果,这个文章详情页面也就是算是完成了,虽然我感觉可能还存在一些问题,毕竟没有完美的代码,如果后续出现问题后再进行修复。我个人觉得开发项目应该先开发出一个能够上线运行的原型,在运营的过程中再逐步去修复bug,迭代版本。


音乐播放基本实现

以上我们已经完成了文章详情页的大部分内容,现在还剩一个音乐播放功能还未实现,官方也提供了一个audio组件可以实现音乐播放。除了组件之外还有相关的API可以使用,在这里我们使用API来实现音乐播放功能,因为使用API的方式比较方便于自定义。

官方文档:

API:
组件:

我们需要使用到两个API,playBackgroundAudio以及pauseBackgroundAudio。前者是用于音乐的播放,后者是用于音乐的暂停。

先给音乐图标添加一个事件,并且使用三元运算符来判断图标是显示暂停图标还是启动图标:

<image catchtap='onMusicTap' class='audio' src='{{isPlayingMusic ? "music/music-stop.png" : "music/music-start.png"}}'></image>

事件方法实现代码如下:

data: {
    isPlayingMusic: false
},

onMusicTap: function (event) {
    // 获取数据文件中的数据
    var currentPostId = this.data.currentPostId;
    var postData = postsData.postList[currentPostId];

    // 使用变量来记录音乐的状态
    var isPlayingMusic = this.data.isPlayingMusic;
    if (isPlayingMusic) {
      // 暂停音乐
      wx.pauseBackgroundAudio();
      // 改变状态
      this.setData({
        isPlayingMusic : false
      });

    } else {
      wx.playBackgroundAudio({
        // 流媒体文件的URL,目前支持的格式有 m4a, aac, mp3, wav
        dataUrl: postData.music.url,
        // 音乐标题
        title: postData.music.title,
        // 音乐封面URL
        coverImgUrl: postData.music.coverImg,
      })
      // 改变状态
      this.setData({
        isPlayingMusic: true
      });
    }
  },

注:dataUrl只能够是引用流媒体文件,不能够使用本地的音乐文件,coverImgUrl也是如此,因为小程序的大小限制是1M,一个音乐文件都不止1M了,所以只能使用流媒体文件的URL形式引入音乐。coverImgUrl引入的图片只有在真机上才能看到得到。

数据文件内容如下,增加了音乐连接、音乐标题、音乐图片属性:

// 将数据整合成数组类型
var local_database = [
  {
    date: "Jan 06 2018",
    title: "正是虾肥蟹壮时",
    imgSrc: "post/crab.png",
    avatar: "vatar/1.png",
    content: "“山明水净夜来霜,数树深红出浅黄。试上高楼清入骨,岂如春色嗾人狂。”金秋时节,天高云淡,秋风送爽,气候宜人。秋风秋阳中,硕果坠挂枝头,玉米抚须含笑,高粱引颈高歌,豆荚饱满圆润。",
    reading: "112",
    collection: "96",
    headImgSrc: "post/crab.png",
    author: "zero",
    dataTime:"24小时前",
    detail: "“山明水净夜来霜,数树深红出浅黄。试上高楼清入骨,岂如春色嗾人狂。”金秋时节,天高云淡,秋风送爽,气候宜人。秋风秋阳中,硕果坠挂枝头,玉米抚须含笑,高粱引颈高歌,豆荚饱满圆润。棉桃鼓胀欲裂,水稻灌浆初熟,世间万物经过春的孕育,夏的生长,即将抵达收获的季节。在这瓜果飘香、稻黍起舞的召唤声中,又是一度蟹肥虾壮时。地处黄海之滨的小城,在秋风的抚慰、秋阳的光照下,瞬间也喧嚣起来。任意走进城中的每一个菜市场,在显眼的位置上,冲入耳际的是此起彼伏的吆喝声,映入眼帘的是那些小商小贩们抢占有利地势将一只只塑料箱一字排开的情景。浅箱中,健壮的对虾、竹节虾在水中跳跃,舒展着弯曲的身体;深箱中,一贯横行霸道的螃蟹拥挤在狭小的空间里,相互肆意践踏,有些不甘蜗居的螃蟹,顺着笔直的箱壁艰难地攀爬着,虽经百般努力,终以失败而告终。那些聚集在网兜里的螃蟹,更是不甘寂寞,身体被束缚着无法动弹,便利用可以自由呼吸的嘴巴,于窸窸窣窣中不停地吐着一串串泡沫,以示抗议,也以此证明自己是个活物。特别是那些个头较大的螃蟹,仿佛知道自己的身价不菲,为此,更是气宇轩昂,自以为是。也许,它们是得到垂青和恩宠的一类吧,受到了特别的眷顾,活动的空间相对较大,所以也更加肆无忌惮。只要有人试图靠近,便会举着那两只肥硕的大螯向你示威,仿佛在警告你:别碰我,否则休怪我无礼!",
    postId: 0,
    music: {
      url: "http://ws.stream.qqmusic.qq.com/C100003507bR0gDKBm.m4a?fromtag=38",
      title: "夜夜夜夜-齐秦",
      coverImg: "http://y.gtimg.cn/music/photo_new/T002R150x150M000001TEc6V0kjpVC.jpg?max_age=2592000"
    }
  },
  {
    date: "Jan 03 2018",
    title: "比利·林恩的中场战事",
    imgSrc: "post/bl.png",
    avatar: "vatar/2.png",
    content: "伊拉克战争时期,来自美国德州的19岁技术兵比利·林恩(乔·阿尔文 Joe Alwyn 饰)因为一段偶然拍摄的视频而家喻户晓。那是一次规模不大却激烈非常的遭遇战,战斗中林恩所在的B班班长(范·迪塞尔 Vin Diesel 饰)遭到当地武装分子的伏击和劫持,而林恩为了营救班长不惜铤而走险冲锋陷阵。",
    reading: "92",
    collection: "65",
    headImgSrc: "post/bl.png",
    dataTime: "一天前",
    author: "妮可",
    detail: "伊拉克战争时期,来自美国德州的19岁技术兵比利·林恩(乔·阿尔文 Joe Alwyn 饰)因为一段偶然拍摄的视频而家喻户晓。那是一次规模不大却激烈非常的遭遇战,战斗中林恩所在的B班班长(范·迪塞尔 Vin Diesel 饰)遭到当地武装分子的伏击和劫持,而林恩为了营救班长不惜铤而走险冲锋陷阵。视频公布于世让他成为全美民众所崇拜的英雄,然而却鲜有人理解他和战友们所经历的一切。为了安葬班长,B班得到了短暂的休假,因此他们得以受邀参加一场在德州举行的橄榄球比赛。林恩的姐姐因某事件深感愧疚,她希望弟弟能借此机缘回归普通生活。而周围的经纪人、球迷、大老板、普通民众则对战争、卫国、士兵有着各种各样想当然的理解。球场上的庆典盛大开幕,林恩和战友们的心却愈加沉重与焦躁…… ",
    postId: 1,
    music: {
      url: "http://ws.stream.qqmusic.qq.com/C100003GdCmG4NkEOR.m4a?fromtag=38",
      title: "鬼迷心窍-李宗盛",
      coverImg: "http://y.gtimg.cn/music/photo_new/T002R150x150M000002xOmp62kqSic.jpg?max_age=2592000"
    }
  },
  {
    date: "Jan 05 2018",
    title: "肖申克的救赎",
    imgSrc: "post/xs.jpg",
    avatar: "vatar/3.png",
    content: "20世纪40年代末,小有成就的青年银行家安迪(蒂姆·罗宾斯 Tim Robbins 饰)因涉嫌杀害妻子及她的情人而锒铛入狱。在这座名为肖申克的监狱内,希望似乎虚无缥缈,终身监禁的惩罚无疑注定了安迪接下来灰暗绝望的人生。",
    reading: "92",
    collection: "65",
    headImgSrc: "post/xs.jpg",
    dataTime: "两天前",
    author: "John",
    detail: "20世纪40年代末,小有成就的青年银行家安迪(蒂姆·罗宾斯 Tim Robbins 饰)因涉嫌杀害妻子及她的情人而锒铛入狱。在这座名为肖申克的监狱内,希望似乎虚无缥缈,终身监禁的惩罚无疑注定了安迪接下来灰暗绝望的人生。未过多久,安迪尝试接近囚犯中颇有声望的瑞德(摩根·弗里曼 Morgan Freeman 饰),请求对方帮自己搞来小锤子。以此为契机,二人逐渐熟稔,安迪也仿佛在鱼龙混杂、罪恶横生、黑白混淆的牢狱中找到属于自己的求生之道。他利用自身的专业知识,帮助监狱管理层逃税、洗黑钱,同时凭借与瑞德的交往在×××中间也渐渐受到礼遇。表面看来,他已如瑞德那样对那堵高墙从憎恨转变为处之泰然,但是对自由的渴望仍促使他朝着心中的希望和目标前进。而关于其罪行的真相,似乎更使这一切朝前推进了一步…… ",
    postId: 2,
    music: {
      url: "http://ws.stream.qqmusic.qq.com/C100004HLusI2lLjZy.m4a?fromtag=38",
      title: "女儿情-万晓利",
      coverImg: "http://y.gtimg.cn/music/photo_new/T002R150x150M000004Wv5BO30pPc0.jpg?max_age=2592000"
    }
  },
  {
    date: "Jan 01 2018",
    title: "霸王别姬",
    imgSrc: "post/bj.jpg",
    avatar: "vatar/4.png",
    content: "段小楼(张丰毅)与程蝶衣(张国荣)是一对打小一起长大的师兄弟,两人一个演生,一个饰旦,一向配合天衣无缝,尤其一出《霸王别姬》,更是誉满京城,为此,两人约定合演一辈子《霸王别姬》。但两人对戏剧与人生关系的理解有本质不同,段小楼深知戏非人生,程蝶衣则是人戏不分。",
    reading: "92",
    collection: "65",
    headImgSrc: "post/bj.jpg",
    dataTime: "三天前",
    author: "Jack",
    detail: "段小楼(张丰毅)与程蝶衣(张国荣)是一对打小一起长大的师兄弟,两人一个演生,一个饰旦,一向配合天衣无缝,尤其一出《霸王别姬》,更是誉满京城,为此,两人约定合演一辈子《霸王别姬》。但两人对戏剧与人生关系的理解有本质不同,段小楼深知戏非人生,程蝶衣则是人戏不分。段小楼在认为该成家立业之时迎娶了名妓菊仙(巩俐),致使程蝶衣认定菊仙是可耻的第三者,使段小楼做了叛徒,自此,三人围绕一出《霸王别姬》生出的爱恨情仇战开始随着时代风云的变迁不断升级,终酿成悲剧。",
    postId: 3,
    music: {
      url: "http://ws.stream.qqmusic.qq.com/C100002mWVx72p8Ugp.m4a?fromtag=38",
      title: "恋恋风尘-老狼",
      coverImg: "http://y.gtimg.cn/music/photo_new/T002R150x150M000001VaXQX1Z1Imq.jpg?max_age=2592000",
    }
  },
  {
    date: "Jan 08 2018",
    title: "这个杀手不太冷",
    imgSrc: "post/ss.jpg",
    avatar: "vatar/5.png",
    content: "里昂(让·雷诺饰)是名孤独的×××,受人雇佣。一天,邻居家小姑娘马蒂尔达(纳塔丽·波特曼饰)敲开他的房门,要求在他那里暂避杀身之祸。原来邻居家的主人是警方缉毒组的眼线,只因贪污了一小包×××而遭恶警(加里·奥德曼饰)杀害全家的惩罚。",
    reading: "92",
    collection: "65",
    headImgSrc: "post/ss.jpg",
    dataTime: "四天前",
    author: "Bill",
    detail: "里昂(让·雷诺饰)是名孤独的×××,受人雇佣。一天,邻居家小姑娘马蒂尔达(纳塔丽·波特曼饰)敲开他的房门,要求在他那里暂避杀身之祸。原来邻居家的主人是警方缉毒组的眼线,只因贪污了一小包×××而遭恶警(加里·奥德曼饰)杀害全家的惩罚。马蒂尔达得到里昂的留救,幸免于难,并留在里昂那里。里昂教小女孩使枪,她教里昂法文,两人关系日趋亲密,相处融洽。女孩想着去×××,反倒被抓,里昂及时赶到,将女孩救回。混杂着哀怨情仇的正邪之战渐次升级,更大的冲突在所难免…… ",
    postId: 4,
    music: {
      url: "http://ws.stream.qqmusic.qq.com/C100000Zn0vS4fKKo8.m4a?fromtag=38",
      title: "沉默是金-张国荣",
      coverImg: "http://y.gtimg.cn/music/photo_new/T002R150x150M000003at0mJ2YrR2H.jpg?max_age=2592000"
    }
  },
  {
    date: "Jan 04 2018",
    title: "阿甘正传",
    imgSrc: "post/ag.jpg",
    avatar: "vatar/1.png",
    content: "阿甘(汤姆·汉克斯 饰)于二战结束后不久出生在美国南方阿拉巴马州一个闭塞的小镇,他先天弱智,智商只有75,然而他的妈妈是一个性格坚强的女性,她常常鼓励阿甘“傻人有傻福”,要他自强不息。",
    reading: "92",
    collection: "65",
    headImgSrc: "post/ag.jpg",
    dataTime: "五天前",
    author: "Tony",
    detail: "阿甘(汤姆·汉克斯 饰)于二战结束后不久出生在美国南方阿拉巴马州一个闭塞的小镇,他先天弱智,智商只有75,然而他的妈妈是一个性格坚强的女性,她常常鼓励阿甘“傻人有傻福”,要他自强不息。阿甘像普通孩子一样上学,并且认识了一生的朋友和至爱珍妮(罗宾·莱特·潘 饰),在珍妮和妈妈的爱护下,阿甘凭着上帝赐予的“飞毛腿”开始了一生不停的奔跑。阿甘成为橄榄球巨星、越战英雄、乒乓球外交使者、亿万富翁,但是,他始终忘不了珍妮,几次匆匆的相聚和离别,更是加深了阿甘的思念。有一天,阿甘收到珍妮的信,他们终于又要见面了……",
    postId: 5,
    music: {
      url: "http://ws.stream.qqmusic.qq.com/C100002I8eGJ28BI17.m4a?fromtag=38",
      title: "朋友-谭咏麟",
      coverImg: "http://y.gtimg.cn/music/photo_new/T002R150x150M000004eGsCN3SUheO.jpg?max_age=2592000"
    }
  },
]

// 设置一个数据出口
module.exports = {
  // 输出的是一个Array对象
  postList: local_database,
}

运行效果:
播放:
时时app平台注册网站 15

暂停:
时时app平台注册网站 16


交互反馈 wx.showToast

以上我们实现了收藏和未收藏图标的一个轮换功能,但是还缺少了个提示功能,在用户点击收藏时要提示用户收藏成功,再次点击则需要提示用户取消成功。

小程序提供了几个实现交互反馈功能的API,详情参考以下官方文档:

我们需要使用到其中三个API,分别是wx.showToast、wx.showModal、wx.showActionSheet。

首先来应用wx.showToast这个API,在事件方法中,加入如下代码:

wx.showToast({
      // 使用三元表达式来判断状态
      title: postCollected ? '收藏成功!' :'取消成功!',
      // 设置图标停留的时间,单位是毫秒
      duration: 1000,
      // icon可以设置图标,默认就是success
      icon: "success",
});

运行效果:
时时app平台注册网站 17
时时app平台注册网站 18


操作反馈wx.showModal

wx.showModal可以显示模态弹窗,我们可以把wx.showModal与wx.showToast相结合使用。

修改代码如下:

var postsData = require('../../../data/posts-data.js')

Page({
  data: {

  },
  onLoad: function (option) {
    var postId = option.id; // 这里的id对应的是url参数上的id
    // 把postId设置到数据集里,这样就能够全局获取
    this.data.currentPostId = postId;
    var postData = postsData.postList[postId];
    this.setData({
      postData
    });

    // 从缓存中获取数据
    var postsCollected = wx.getStorageSync('posts_collected');
    // 判断数据是否不为空
    if (postsCollected) {
      // 不为空就拿出与postId对应的下标值
      var postsCollected = postsCollected[postId];
      // 并将值更新到数据绑定里
      this.setData({
        collected: postsCollected
      });
    } else {
      // 如果为空就赋值一个空对象
      var postsCollected = {}
      // 并把与postId对应的下标中的值设置为false
      postsCollected[postId] = false;
      // 更新到缓存里
      wx.setStorageSync('posts_collected', postsCollected);
    }
  },

  // 点击事件方法
  onCollectionTap: function (event) {
    // 获取缓存数据
    var postsCollected = wx.getStorageSync('posts_collected');
    // 获取postId
    var postCollected = postsCollected[this.data.currentPostId];
    // 收藏变成未收藏,未收藏变成收藏
    postCollected = !postCollected;
    postsCollected[this.data.currentPostId] = postCollected;

    // 自定义函数也需要使用this来访问
    this.showModal(postsCollected, postCollected);
  },

  showModal: function (postsCollected, postCollected){
    // 把this指代的Page对象先存储起来
    var that = this;
    wx.showModal({
      title: '收藏',
      content: postCollected ? '是否收藏该文章?' :'是否取消收藏该文章?',
      showCancel: 'true',
      cancelText: '取消',
      cancelColor: '#333',
      confirmText: '确认',
      confirmColor: '#405f80',
      success:function(res){
        if(res.confirm){
          // 更新文章是否收藏的缓存值
          wx.setStorageSync('posts_collected', postsCollected);
          // 更新数据绑定变量,从而实现切换图片
          that.setData({
            collected: postCollected
          });
          that.showToast(postsCollected, postCollected);
        }
      },
    });
  },

  showToast: function (postsCollected, postCollected){
    wx.showToast({
      // 使用三元表达式来判断状态
      title: postCollected ? '收藏成功!' : '取消成功!',
      // 设置图标停留的时间,单位是毫秒
      duration: 1000,
      // icon可以设置图标,默认就是success
      icon: "success",
    });
  },
})

运行效果:
收藏:
时时app平台注册网站 19
时时app平台注册网站 20

取消收藏:
时时app平台注册网站 21
时时app平台注册网站 22

注:在实际开发中这种成本低的操作是不需要把交互反馈做得这么麻烦的,一般只使用showToast即可。所谓成本指的是误操作带来的损失,如果成本低的操作交互反馈太麻烦的话,会感觉体验不好。


应用程序生命周期

文章详情页中的音乐播放功能看起来基本是没什么问题了,不过这也仅限于文章详情这一个页面内而已,如果我点击了播放音乐,然后返回到上一级页面,再点击进入文章详情页的话,页面的状态就会是初始化时的状态,这时音乐图片就不会自动切换到播放状态的图片。这是因为我们的状态代码写在js文件的Page对象里,会受到页面生命周期的影响,当我们返回上一级页面,再点击进入文章详情页时,Page对象会被加载,页面代码就会被重新执行一遍,所以音乐图标的状态就会是初始时的状态。

解决这个问题我们需要用到全局变量来保存状态,全局变量不会受页面生命周期的影响,而且在任何页面中都可以获取到全局变量的值。在小程序中全局变量需要写在app.js文件中,该文件中的代码需要写在App对象里,就像我们的页面代码需要写在Page中一样,Page代表的是一个页面,而App对象则是代表着整个应用程序,该对象的生命周期也就是应用程序的生命周期。以下是该对象的生命周期方法:

App({

  /**
   * 当小程序初始化完成时,会触发 onLaunch(全局只触发一次)
   */
  onLaunch: function () {

  },

  /**
   * 当小程序启动,或从后台进入前台显示,会触发 onShow
   */
  onShow: function (options) {

  },

  /**
   * 当小程序从前台进入后台,会触发 onHide
   */
  onHide: function () {

  },

  /**
   * 当小程序发生脚本错误,或者 api 调用失败时,会触发 onError 并带上错误信息
   */
  onError: function (msg) {

  }
})

从文章列表跳转到新闻详情页(组件自定义属性及获取属性)

在编写从文章列表跳转到新闻详情页的代码之前,先来修改一下之前的页面,之前我们编写了两个模板文件,但是还有两个细节没有完善好,一个是post.wxss中的.post-container样式没有移植到模板文件中,另一个是wxml模板文件中每句数据绑定代码都需要通过item这个子元素去调用属性,显得有点麻烦,我们可以使用一种语法去解决这个问题。

1.首先将post.wxss中的.post-container样式移植到模板文件中

2.解决item重复的问题,在post.wxml中将之前的 template 代码修改为以下内容:

<template is="postItem" data="{{...item}}" />

然后模板文件中的数据绑定代码就不需要重复使用item子元素进行属性的调用了:

<!-- 模板文件需要使用template标签包围 -->
<template name="postItem">
  <view class='post-container'>
      <view class='post-author-date'>
        <image src='{{avatar}}' class='post-author'></image>
        <text class="post-date">{{date}}</text>
      </view>
      <text class='post-title'>{{title}}</text>
      <image class='post-image' src='{{imgSrc}}'></image>
      <text class='post-content'>{{content}}</text>
      <view class='post-like'>
        <image src='../..icon/chat.png' class='post-like-img'></image>
        <text class='post-like-font'>{{reading}}</text>
        <image src='../..icon/view.png' class='post-like-img'></image>
        <text class='post-like-font'>{{collection}}</text>
      </view>
    </view>
</template>

完成以上的修改后,就可以开始编写新闻详情页的代码了:

1.构建目录文件结构:
时时app平台注册网站 23

2.由于我们需要实现点击一个文章列表中的文章就跳转到该文章的详情页面,所以我们还得给每一个文章做一个标识符,不然谁知道你点的是哪篇文章。这个标识符可以写在数据文件中,作为一个属性存在,所以需要在数据文件中为每一个文章数据都加上一个属性,我定义的属性名称是postId:

// 将数据整合成数组类型
var local_database = [
  {
    date: "Jan 06 2018",
    title: "正是虾肥蟹壮时",
    imgSrc: "post/crab.png",
    avatar: "vatar/1.png",
    content: "“山明水净夜来霜,数树深红出浅黄。试上高楼清入骨,岂如春色嗾人狂。”金秋时节,天高云淡,秋风送爽,气候宜人。秋风秋阳中,硕果坠挂枝头,玉米抚须含笑,高粱引颈高歌,豆荚饱满圆润。",
    reading: "112",
    collection: "96",
    postId:0,
  },
  {
    date: "Jan 03 2018",
    title: "比利·林恩的中场战事",
    imgSrc: "post/bl.png",
    avatar: "vatar/2.png",
    content: "伊拉克战争时期,来自美国德州的19岁技术兵比利·林恩(乔·阿尔文 Joe Alwyn 饰)因为一段偶然拍摄的视频而家喻户晓。那是一次规模不大却激烈非常的遭遇战,战斗中林恩所在的B班班长(范·迪塞尔 Vin Diesel 饰)遭到当地武装分子的伏击和劫持,而林恩为了营救班长不惜铤而走险冲锋陷阵。",
    reading: "92",
    collection: "65",
    postId: 1,
  },
  {
    date: "Jan 05 2018",
    title: "肖申克的救赎",
    imgSrc: "post/xs.jpg",
    avatar: "vatar/3.png",
    content: "20世纪40年代末,小有成就的青年银行家安迪(蒂姆·罗宾斯 Tim Robbins 饰)因涉嫌杀害妻子及她的情人而锒铛入狱。在这座名为肖申克的监狱内,希望似乎虚无缥缈,终身监禁的惩罚无疑注定了安迪接下来灰暗绝望的人生。",
    reading: "92",
    collection: "65",
    postId: 2,
  },
  {
    date: "Jan 01 2018",
    title: "霸王别姬",
    imgSrc: "post/bj.jpg",
    avatar: "vatar/4.png",
    content: "段小楼(张丰毅)与程蝶衣(张国荣)是一对打小一起长大的师兄弟,两人一个演生,一个饰旦,一向配合天衣无缝,尤其一出《霸王别姬》,更是誉满京城,为此,两人约定合演一辈子《霸王别姬》。但两人对戏剧与人生关系的理解有本质不同,段小楼深知戏非人生,程蝶衣则是人戏不分。",
    reading: "92",
    collection: "65",
    postId: 3,
  },
  {
    date: "Jan 08 2018",
    title: "这个杀手不太冷",
    imgSrc: "post/ss.jpg",
    avatar: "vatar/5.png",
    content: "里昂(让·雷诺饰)是名孤独的×××,受人雇佣。一天,邻居家小姑娘马蒂尔达(纳塔丽·波特曼饰)敲开他的房门,要求在他那里暂避杀身之祸。原来邻居家的主人是警方缉毒组的眼线,只因贪污了一小包×××而遭恶警(加里·奥德曼饰)杀害全家的惩罚。",
    reading: "92",
    collection: "65",
    postId: 4,
  },
  {
    date: "Jan 04 2018",
    title: "阿甘正传",
    imgSrc: "post/ag.jpg",
    avatar: "vatar/1.png",
    content: "阿甘(汤姆·汉克斯 饰)于二战结束后不久出生在美国南方阿拉巴马州一个闭塞的小镇,他先天弱智,智商只有75,然而他的妈妈是一个性格坚强的女性,她常常鼓励阿甘“傻人有傻福”,要他自强不息。",
    reading: "92",
    collection: "65",
    postId: 5,
  },
]

// 设置一个数据出口
module.exports = {
  // 输出的是一个Array对象
  postList: local_database,
}

3.在post.wxml文件中增加一个view标签,把template标签包围起来,因为template标签只是相当于一个占位符,编译之后这个标签是不存在的。然后给这个view标签注册一个tap事件,并且自定义一个属性进行postId的数据绑定:

<!-- 自定义属性必须以 data- 为前缀,后面连接的单词可以自定义 -->
<view catchtap="onPostTap" data-postId="{{item.postId}}">
      <template is="postItem" data="{{...item}}"/>
</view>

4.然后到post.js文件中增加一个事件函数:

onPostTap: function(event){
    // 从事件源中获取postId数据
    var postId = event.currentTarget.dataset.postid;
    console.log("on post id is "   postId);
 },

event是事件源对象,是默认会传入的参数,currentTarget是当前被触发事件的目标对象,dataset是数据集对象,数据要从数据集对象中获取。至于为什么是通过postid获取数据而不是通过data-postId或者postId获取,请参考下图:
时时app平台注册网站 24

如图,可以看到,自定义属性被编译之后的名称并不是原本的名称,所以我们通过dataset数据集对象获取自定义属性的数据时需要以编译后的名称为准。

5.接着就可以开始实现页面跳转了,先在post-detail.wxml中编写一段话:

<text>
  这是文章详情页面
</text>

然后再app.json中加上一段post-detail的信息配置,每当我们新增页面都需要如此进行配置:

"pages/posts/post-detail/post-detail"

回到post.js中,编写页面跳转代码:

  onPostTap: function(event){
    // 从事件源中获取postId数据
    var postId = event.currentTarget.dataset.postid;
    wx.navigateTo({
      url: 'post-detail/post-detail',
    })
  },

完成以上操作编译之后现在点击文章列表中的文章就可以跳转到文章详情页面了:
时时app平台注册网站 25


监听播放事件完善音乐播放

在音乐播放的时候,可以看到会弹出来一个音乐播放的总控开关,我们点击音乐图标的时候能够正常的切换图片,但是点击总控开关的时候不会切换图片,这是因为我们只监听了图标上的事件,没有监听音乐播放、暂停的事件。所以我们还需要完善这点小细节,让点击总控开关的时候也能切换图片,实现这一步需要使用到两个API,onBackgroundAudioPlay以及onBackgroundAudioPause,前者用于监听音乐播放,后者用于监听音乐暂停。

在onLoad生命周期方法中增加以下代码:

    var that = this;
    // 当音乐播放时将isPlayingMusic状态改为true
    wx.onBackgroundAudioPlay(function(){
      that.setData({
        isPlayingMusic: true
      });
    });

    // 当音乐暂停时将isPlayingMusic状态改为false
    wx.onBackgroundAudioPause(function(){
      that.setData({
        isPlayingMusic: false
      });
    })

加入以上代码后就可以实现点击总控开关也能切换图片,而且以上代码也体现出了数据绑定机制的好处,只需要修改数据集中相应数据的值即可,无需每次都去获得节点对象后才能操作相应的数据的值。


缓存Storage的基本用法

在文章详情页中我们需要实现一个文章收藏的功能,由于我们没有使用到服务器,所以使用本地缓存来记录这个文章是否被用户收藏的一个状态。

小程序中提供了一个setStorageSync方法来实现缓存,从方法名也可以看出这个方法是带有同步的。除此之外还有一个异步的缓存方法setStorage,这个方法可以用于异步缓存数据。

注:和缓存相关的方法,例如得到缓存数据、删除缓存数据等方法,都有同步和异步两个,方法名末尾有Sync的表示同步,否则是异步。

首先演示一下setStorageSync方法的使用方式:

// 第一个参数是键,第二个参数则是需要存储的数据
wx.setStorageSync('key', "Test");

我在post-detail.js文件中的onLoad方法里加入了以上这段代码,此时我点击进入文章详情页面,就会缓存这个数据,缓存数据在Storage界面查看:
时时app平台注册网站 26

在小程序中,如果用户不去主动清除缓存数据,那么数据就会一直存在,所以现在即便我关闭开发工具或者重新进行编译,这个数据都会存在,除非我主动删掉它。

通过键可以改变缓存数据:

wx.setStorageSync('key', {
      game:"eat chicken",
      developer:"LD",
});

运行结果:
时时app平台注册网站 27

获取缓存的数据:

<!-- 在收藏图标上加上一个事件 -->
<image catchtap='onCollectionTap' src='icon/collection.png'></image>

使用getStorageSync方法即可得到缓存数据:

onCollectionTap:function(event){
    var game=wx.getStorageSync('key');
    console.log(game);
}

运行结果:
时时app平台注册网站 28

删除缓存数据:

<!-- 在分享图标上加上一个事件 -->
<image catchtap='onShareTap' class='share-img' src='icon/share.png'></image>

使用removeStorageSync方法即可删除缓存数据:

onShareTap:function(event){
    wx.removeStorageSync('key');
},

运行结果,可以看到数据已经不存在了:
时时app平台注册网站 29

删除所有缓存数据的方法:

wx.clearStorageSync();

注:小程序规定缓存数据的大小上限是10MB


先静后动,先构建新闻详情页面样式

编写post-detail.wxml代码:

<view class='container'>
  <image src='post/sls.jpg' class='head-iamge'></image>
  <image class='audio' src='music/music-start.png'></image>
  <view class='author-date'>
    <image src='vatar/2.png' class='avatar' ></image>
    <text class='author'>zero</text>
    <text class='const-text'>发表于</text>
    <text class='date'>3天前</text>
  </view>
  <text class='title'>审美的进化机制</text>
  <view class='tool'>
    <view class='circle-img'>
      <image src='icon/collection.png'></image>
      <image class='share-img' src='icon/share.png'></image>
    </view>
    <view class='horizon'></view>
  </view>
  <text class='detail'>2017年读的书中,有一本书是《纽约时报》年度十佳(2017 Ten Best Books),即:《美的进化——达尔文被遗忘的择偶理论如何塑造动物世界乃至我们》(The Evolution of Beauty: How Darwin’s Forgotten Theory of Mate Choice Shapes the Animal World — and Us)。时报网站刊登了英文版评介的译文:如果一本科学书籍能做到有颠覆性,倡导女权主义,还能改变我们看待自己身体的方式,但同时主要还是关于鸟类的,那就是这本书了。普鲁姆是一位鸟类学家,他为达尔文的另一个基本上被忽略了的雌雄淘汰理论进行了辩护。</text>
</view>

post-detail.wxss代码:

.container {
  display: flex;
  flex-direction: column;
}

.head-iamge {
  width: 750rpx;
  height: 460rpx;
}

.author-date {
  flex-direction: row;
  margin-left: 30rpx;
  margin-top: 20rpx;
}

.avatar {
  height: 64rpx;
  width: 64rpx;
  vertical-align: middle;
}

.author {
  font-size: 30rpx;
  font-weight: 300;
  margin-left: 20rpx;
  vertical-align: middle;
  color: #666;
}

.const-text {
  font-size: 24rpx;
  color: #999;
  margin-left: 20rpx;
}

.date {
  font-size: 24rpx;
  margin-left: 30rpx;
  color: #999;
  vertical-align: middle;
}

.title {
  margin-left: 40rpx;
  font-size: 36rpx;
  font-weight: 700;
  margin-top: 30rpx;
  letter-spacing: 2px;
  color: #4b556c;
}

.tool {
  margin-top: 20rpx;
}

.circle-img {
  float: right;
  margin-right: 40rpx;
  vertical-align: middle;
}
.circle-img image{
  width: 90rpx;
  height: 90rpx;
}
.share-img {
  margin-left: 30rpx;
}

.horizon {
  width: 660rpx;
  height: 1px;
  background-color: #e5e5e5;
  vertical-align: middle;
  position: relative;
  top: 46rpx;
  margin: 0 auto;
  z-index: -99;
}

.detail{
  color: #666;
  margin-left: 30rpx;
  margin-top: 20rpx;
  margin-right: 30rpx;
  line-height: 44rpx;
  letter-spacing: 2px;
}

.audio{
  width: 102rpx;
  height: 110rpx;
  position: absolute;
  left: 50%;
  margin-left: -51rpx;
  top: 180rpx;
  opacity: 0.6;  // 设置透明度为0.6
}

app.wxss代码:

text{
  font-family: MicroSoft Yahei;
  font-size: 24rpx;
}

完成效果:
时时app平台注册网站 30


笔记内容:构建新闻详情页面
笔记日期:2018-01-09

同步异步方法对比

我们把之前的onCollectionTap方法中的同步获取缓存的方法改为异步获取缓存的方法,以此来演示同步与异步方法之间的区别,修改代码如下:

onCollectionTap: function (event) {
    // 把当前this指代的当前对象先存储起来
    var that = this;
    // 异步获取缓存数据
    var postsCollected = wx.getStorage({
      key: 'posts_collected',
      success: function (res) {
        var postsCollected = res.data;
        // 获取postId
        var postCollected = postsCollected[that.data.currentPostId];
        // 收藏变成未收藏,未收藏变成收藏
        postCollected = !postCollected;
        postsCollected[that.data.currentPostId] = postCollected;

        that.showModal(postsCollected, postCollected);
      },
    });
  },

以上就是异步方法的实现方式,与同步方法的主要区别在于,同步会等待wx.getStorageSync('posts_collected');方法执行完之后才会往下执行,所以如果当获取缓存得很慢的时候,操作界面就会卡在那。而异步则不会,异步获取缓存数据的时候,代码还会继续往下执行,异步获取完成之后再执行success里的方法。

注:通常情况下,在小程序中必须要使用异步方法的情况比较少,建议如果对异步方法不熟悉的话,最好不要使用异步方法,不然不仅会让你的代码变得难以阅读,而且很容易埋下一些隐藏bug,或者难以解决的错误。至于使用异步还是同步,需要根据业务来决定,当可以使用同步的情况下,优先使用同步。


本文由时时app平台注册网站发布于编程知识,转载请注明出处:其四个页面:营造新闻详细情形页面 【时

关键词: