知识点
如何呈现动态数据
JavaScript首先从服务器拿到数据,然后通过数据绑定,如 setData
将数据给到View。
小程序最开始是没有双向数据绑定的,但是现在提供了简易的双向的数据绑定,双向数据绑定其实不是必需的。
关于数据绑定的微信小程序官方文档:数据绑定 | 微信开放文档 (qq.com)
理解DOM优先和数据优先的区别
关于JavaScript
生命周期函数由小程序调用,不需要开发者调用,在很多框架里生命周期函数被称为 hook function
。
我们在js文件下 Page({data:})
函数里定义的所有变量都可以直接在wxml里面使用,在wxml时加 {{}}
。
预先在 data
中定义绑定数据的初始值是值得推荐的做法,即先在 data
中定义后再在 onLoad
中 this.setData({})
。
setData
键和值相同可以简写。
条件渲染
条件渲染的表达式 wx:if=""
,当满足这个条件的时候,这个标签才会被显示。
if else也是可以实现的!
<view>
<text wx:if="{{flag}}">{{text}}</text>
<text wx:else>{{text}}</text>
</view>
列表渲染
用来展示一组js对象的数据。
// 拿到一个数组,用setData包装成js对象
onLoad(options): {
// 这里的content内的数据其实一般是服务端直接传来的
var content = [{
title: "text",
// ......
},{
title: "text",
// ......
}]
})
this.setData({
posts:content
})
}
<block wx:for="{{posts}}" wx:key="index" wx:for-item="item">
<view>
<text src="{{item.title}}"></text>
</view>
</block>
如果要取到序号的话用 {{index}}
即可。
示例:
onLoad(options) {
var content = [{
avater: "/images/avater/2.png",
title: "texttextexttext",
content: "texttextexttexttexttextexttexttexttextexttext",
reading: 102,
detail: "texttextexttexttexttextexttexttexttextexttext",
collection: 92,
headImg: "/images/banner/banner1.jpg",
author: "猫猫不是猫",
date: "Nov 13 2022",
}, {
avater: "/images/avater/2.png",
title: "texttextexttext",
content: "texttextexttexttexttextexttexttexttextexttext",
reading: 102,
detail: "texttextexttexttexttextexttexttexttextexttext",
collection: 92,
headImg: "/images/banner/banner1.jpg",
author: "猫猫不是猫",
date: "Nov 13 2022",
}]
this.setData({
posts: content
})
},
<block wx:for="{{posts}}">
<view class="post-container">
<view class="post-author-date">
<image class="post-author" src="{{item.avater}}"></image>
<text class="post-date">{{item.date}}</text>
</view>
<text class="post-title">{{item.title}}</text>
<image class="post-image" src="{{item.headImg}}"></image>
<text class="post-content">{{item.content}}</text>
<view class="post-like">
<l-icon class="post-like-image" color="#666" size="26" name="favor" />
<text class="post-like-font">{{item.collection}}</text>
<l-icon class="post-like-image" color="#666" size="32" name="eye" />
<text class="post-like-font">{{item.reading}}</text>
</view>
</view>
</block>
事件
首页跳转按钮示例:
- 捕捉事件
bindtap=""
- 在js文件中定义函数。
<view bind:tap="onTap" class="journey-container">
<text class="journey">开启小程序之旅</text>
</view>
Page({
onTap: function (params) {
wx.navigateTo({
url: '/pages/posts/posts',
})
}
})
最多只能有10个子页面。
wx.redirectTO
也是跳转,但是会卸载页面。
捕捉事件 catch
和 bind
的区别: catch
会阻止事件继续冒泡,bind
不会阻止事件冒泡。
js模块的导入导出
js模块的导出:
module.exports = {
postList:local_database
}
// 最新方式
export {
local_database
}
js模块的导入:
// 在Page({})之外
var postData = require("../../data/data")
// 更推荐的另一种导入方式,这种导入方式要和导出数据同名
import {local_database} from '../../data/data'
导入只能使用相对路径。
用View模拟出分割线
<view class="horizon"></view>
.horizon {
width: 660rpx;
height: 1px;
background-color: #e5e5e5;
}
如何设置元素浮动
align-items
设置子元素在交叉轴上的排布方式。
justify-content
设置子元素在主轴上的排布方式。
实现效果:
用flex方式实现:
<view class="tool">
<view class="circle">
<image src="/images/icon/collection.png"></image>
<image class="share-img" src="/images/icon/share.png"></image>
</view>
<view class="horizon"></view>
</view>
.circle {
display: flex;
/* 容器要有宽度后面的排布方式才生效 */
width: 660rpx;
flex-direction: row;
justify-content: flex-end;
}
.horizon {
width: 660rpx;
height: 1px;
background-color: #e5e5e5;
position: absolute;
/* 降低层级 */
z-index: -1;
}
.circle image {
width: 90rpx;
height: 90rpx;
}
.share-img {
margin-left: 30rpx;
}
自定义属性
<view data-<name>="">
,返回的键只有 <name>
。
如何通过自定义属性定位到相关页面(页面之间数据通信)
<!-- post.wxml -->
<view data-id="{{item.postId}}" bind:tap="onGoToDetail" class="post-container">
// posts.js
onGoToDetail(event) {
const pid = event.currentTarget.dataset.id
wx.navigateTo({
url: '/pages/post-detail/post-detail?pid=' + pid
})
}
// post-detail.js
onLoad(options) {
const postData = postList[options.pid]
console.log(postData)
this.setData({
postData
})
console.log(postData)
},
如何响应用户操作
关于同步和异步的区别:同步与异步的区别
app.js的一些作用
设置全局变量:
App({
onLaunch(){
console.log("小程序启动~")
}
})
缓存
// 设置缓存
wx.setStorageSync('flag', true)
wx.setStorageSync('flag2', true)
// 清除缓存
wx.removeStorageSync('flag')
// 清除所有缓存
wx.clearStorageSync()
// 获取同步缓存
wx.setStorageSync('flag', true)
// const flag = wx.getStorageSync('flag')
// 获取异步缓存
const flag = wx.getStorage({
key: 'flag',
// success(value){
// console.log(value.data)
// }
})
// 获取Promise的方法(传统)
flag.then((value)=>{
console.log(value)
})
// ES7获取异步缓存的方法:
// 在onLoad()前加上async
wx.setStorageSync('flag2', true)
const flag2 = await wx.getStorage({
key: 'flag2',
})
缓存就像是前端的数据库。
完善文章详情页收藏按钮
/**
* 页面的初始数据
*/
data: {
postData: {},
collected: false,
// 不做数据绑定的变量名开头加_
_pid: null,
_postsCollected: {},
},
/**
* 生命周期函数--监听页面加载
*/
onLoad(options) {
const postData = postList[options.pid]
// 获取pid
this.data._pid = options.pid
const postCollected = wx.getStorageSync('posts_collected')
this.data._postsCollected = postCollected
let collected = postCollected[this.data._pid]
if (collected == undefined) {
collected = false
}
this.setData({
postData,
collected
})
},
/**
* 收藏按钮
*/
onCollection(event) {
// 需要解决:
// 1.哪篇文章被收藏
// 2.多篇文章被收藏的情况
const postsCollected = this.data._postsCollected
postsCollected[this.data._pid] = !this.data.collected
this.setData({
collected: !this.data.collected
})
wx.setStorageSync('posts_collected', postsCollected)
},
<image wx:if="{{!collected}}" bind:tap="onCollection" src="/images/icon/collection-anti.png"></image>
交互组件
showToast组件:轻提示
wx.showToast({
title: this.data.collected ? '收藏成功' : '取消收藏',
// 停留时间
duration: 3000,
})
showModal组件:模态对话框
wx.showModal({
title: '这是一个提示框',
content: '',
complete: (res) => {
if (res.cancel) {
}
if (res.confirm) {
}
}
})
音乐组件
BackgroundAudioManager | 微信开放文档 (qq.com)
实现播放
<image bind:tap="onMusic" class="audio" src="/images/music/music-start.png"></image>
onMusic(event) {
const mgr = wx.getBackgroundAudioManager()
mgr.src = postList[this.data.pid].music.url
mgr.title = postList[this.data.pid].music.title
},
继续完善:状态切换
data: {
postData: {},
collected: false,
// 音乐播放标识(新增)
isPlaying: false,
// 不做数据绑定的变量名开头加_
_pid: null,
_postsCollected: {},
},
/**
* 音乐播放
* @param {onMusicStart} event
*/
onMusicStart(event) {
const mgr = wx.getBackgroundAudioManager()
mgr.src = postList[this.data._pid].music.url
mgr.title = postList[this.data._pid].music.title
// 设置音乐封面
mgr.coverImgUrl = postList[this.data._pid].music.coverImgUrl
this.setData({
isPlaying: true,
})
},
/**
* 音乐停止
* @param {onMusicStop} event
*/
onMusicStop(event) {
const mgr = wx.getBackgroundAudioManager()
mgr.stop()
this.setData({
isPlaying: false
})
},
<image wx:if="{{!isPlaying}}" bind:tap="onMusicStart" class="audio" src="/images/music/music-start.png"></image>
<image wx:else bind:tap="onMusicStop" class="audio" src="/images/music/music-stop.png"></image>
存在问题:音乐控制面板切换状态与页面没有同步(使用监听机制)
背景音频播放事件的监听函数:BackgroundAudioManager.onPlay(function listener) | 微信开放文档 (qq.com)
data: {
_mgr: null,
},
onLoad(options) {
const mgr = wx.getBackgroundAudioManager()
this.data._mgr = mgr
mgr.onPlay(this.onMusicStart)
mgr.onPause(this.onMusicPause)
},
onMusicStart(event) {
const mgr = this.data._mgr
},
onMusicPause(event) {
const mgr = this.data._mgr
mgr.pause()
this.setData({
isPlaying: false
})
},
存在问题:音乐后台播放时返回上一页后再回来状态为初始状态(用全局变量解决)
在app.js中加入控制音乐播放的全局变量
App({
onLaunch(){
gIsPlayingMusic: false
},
})
在post-detail.js中获取全局变量
const app = getApp()
在函数中尝试改变全局变量
onMusicStart(event) {
app.gIsPlayingMusic = true
},
初始化时给isPlaying赋全局变量gIsPlayingMusic的值
onLoad(options) {
this.setData({
isPlaying: app.gIsPlayingMusic
})
},
新问题:后台播放音乐时切换到其他文章仍然显示音乐正在播放
对全局变量做更改,用以标识ID,-1表示false
App({
onLaunch(){
// gIsPlayingMusic: false
gIsPlayingMusic: -1
},
})
currentMusicIsPlaying() {
if (app.gIsPlayingMusic != -1 && app.gIsPlayingMusic == this.data._pid) {
return true
}
return false
},
onLoad(options) {
this.setData({
postData,
collected,
isPlaying: this.currentMusicIsPlaying()
})
},
onMusicPause(event) {
app.gIsPlayingMusic = -1
},
onMusicStart(event) {
app.gIsPlayingMusic = this.data._pid
},
tabBar选项卡
app.json:
"tabBar": {
"selectedColor": "#333333",
"color": "#999999",
"list": [{
"pagePath": "pages/posts/posts",
"text": "阅读",
"iconPath": "images/tab/post.png",
"selectedIconPath": "images/tab/[email protected]"
},
{
"pagePath": "pages/movies/movies",
"text": "电影",
"iconPath": "images/tab/movie.png",
"selectedIconPath": "images/tab/[email protected]"
}
]
},
如果要跳转到带有tabBar选项卡的页面:
onTap: function (params) {
wx.switchTab({
url: '/pages/posts/posts',
})
}