微信小程序项目实战
目录
[TOC]
小程序前后端交互
语法说明
- 每个微信小程序需要事先设置通讯域名,小程序 只可以跟指定的域名进行网络通信
- 服务器域名请在 「小程序后台-开发-开发设置-服务器域名」 中进行配置
- 默认超时时间和最大超时时间都是 60s
- 超时时间可以在app.json中通过networktimeout配置
- 小程序为了安全起见只支持Https 请求 wx.request最大并发限制10个
- 开发中可以在微信开发工具中不校验合法域名
export default (url,data={},method='GET')=>{
return new Promise((resolve,reject)=>{
wx.request({
url:'http://localhost:3000'+url,
data,
success:(res)=>{
resolve(res.data)
},
fail:(err)=>{
reject(err)
}
})
})
}
自定义组件的使用
语法说明
新建component组件 不会生路径
在使用的父页面 json中 usingComponents注册组件
父传值通过属性 title="排行榜" 子组件 properties 接收
properties 定义
api 框架----》自定义组件
定义段 | 类型 | 是否必填 | 描述 | 最低版本 |
---|---|---|---|---|
type | 是 | 属性的类型 | ||
optionalTypes | Array | 否 | 属性的类型(可以指定多个) | 2.6.5 |
value | 否 | 属性的初始值 | ||
observer | Function | 否 | 属性值变化时的回调函数 |
案例
子组件
<view class="header">
<text class="title">{{title}}</text>
<view>
<text>{{nav}}</text>
<text class="more"> 查看更多</text>
</view>
</view>
// pages/index/commponents/NavHeader/NavHeader.js
Component({
/**
* 组件的属性列表
*/
properties: {
title:{
type:String,
value:'默认值'
},
nav:{
type:String,
value:'默认值'
}
},
})
父组件
{
"usingComponents": {
"NavHeader":"../index/commponents/NavHeader/NavHeader"
}
}
<NavHeader title="推荐歌曲" nav='为你精心推荐'></NavHeader>
微信小程序的事件对象
e.target和e.currentTarget
在小程序的事件回调触发时,会接收一个事件对象,事件对象的参数中包含一个target和currentTarget属性,接下来说说这二者的区别。
<view id='tar-father' bindtap='click'>
父组件
<view id='tar-children'>子组件</view>
</view>

event.target 为其子组件,也就是触发该事件的源头组件, event.target 为父组件,因为触发的源头也就是父组件本身
event.currentTarget 为事件所绑定的组件 event.currentTarget 始终为事件所绑定的组件
总结:target对应的是触发事件的源头组件,这个组件有可能是子组件,有可能是父组件,主要是看执行动作的区域。而currentTarget始终对应事件所绑定的组件。
微信小程序的事件传参
- 什么是事件委托
将子元素的事件委托(绑定)给父元素- 事件委托的好处(ul 下面的100li需要添加事件,可以直接绑定再父元素上)
- 减少绑定的次数
- 后期新添加的元素也可以享用之前委托的事件
- 事件委托的原理
- 冒泡
- 触发事件的是谁
- 子元素
- 如何找到触发事件的对象
- event.target
- currentTarget VS target
- currentTarget要求绑定事件的元素一定是触发事件的元素
- target绑定事件的元素不一定是触发事件的元素
传参方式一: data-key='value'
ps:key 可以自定义 传递多个
<input class="" data-key="phone" placeholder="请输入用户名" bindinput="change"> </input>
<input class="" data-key="password" placeholder="请输入用户名" bindinput="change" > </input>
#js
change(evet) {
console.log(evet);
let value = evet.detail.value
let type = evet.currentTarget.dataset.key
this.setData({
[type]: value
})
},
传参方式二: id='value'
唯一值
<input class="" id="phone" placeholder="请输入用户名" bindinput="change"> </input>
<input class="" id="password" placeholder="请输入用户名" bindinput="change" > </input>
#js
change(evet) {
console.log(evet);
let value = evet.detail.value
let type = evet.currentTarget.id
this.setData({
[type]: value
})
},
scroll-view 使用
tips y轴滚动时要计算滚动高度
scroll-view 中使用flex布局
enable-flex
启用 flexbox 布局。开启后,当前节点声明了 display: flex
就会成为 flex container,并作用于其孩子节点。
scroll-view 开启display:flex 设置 enable-flex 必须设置大小否则 scroll-view报错纵向布局高度
<scroll-view class="scroll" enable-flex scroll-x>
<view class="scrollItem" wx:for='{{recommendList}}' wx:key='id'>
<image src="{{item.picUrl}}"></image>
<text>{{item.name}}</text>
</view>
</scroll-view>
.scroll{
display: flex;
height: 300rpx;
}
scroll-into-view
值应为某子元素id(id不能以数字开头)。设置哪个方向可滚动,则在哪个方向滚动到该元素
scroll-into-view 是 scroll-view 的一个属性,主要作用是用于滚动到指定元素的位置,其对应值是元素的id,使用方法如下:
<scroll-view
class="navScroll"
scroll-x
enable-flex
scroll-into-view="{{'scroll' + navid}}"
>
<view class="navItem" id="{{'scroll' + item.id}}"wx:for='{{GroupList}}' wx:key='id'>
<view class="navContent {{navid==item.id?'active':''}}" bindtap='navChange' id="{{item.id}}">
{{item.name}}
</view>
</view>
</scroll-view>
data: {
GroupList: [],
navid: '',
VideoList: [],
isTriggered: false //下拉刷新
},
//tags切换
navChange(event) {
// 保存点击id ,视频列表赋值为空
this.setData({
navid: event.currentTarget.id,
VideoList: []
})
//开启加载提示,发送请求
wx.showLoading({
title: '正在加载',
})
this.getVideoList(event.currentTarget.id)
},
下拉刷新 上拉加载
下拉刷新
refresher-enabled:开启自动义下拉刷新
定义下拉刷新时触发回调 bindrefresherrefresh
refresher-triggered 设置当前下拉刷新状态,true 表示下拉刷新已经被触发,false 表示下拉刷新未被触发 控制刷新状态
上拉触底
bindscrolltolower定义 上拉触底 时触发回调
- //为了实现下拉加载数据 1.后端分页 2.前端分页
- // 1.后端分页 一般触发请求 告诉后端第几页 和条目数
- // 2.前端分页 直接返回100条 第一次1-9 触底之后10-19
//下拉刷新
handleRefresher() {
console.log('下拉刷新');
this.getVideoList(this.data.navid)
},
// 上拉触底
handleToLower() {
console.log('上拉触底');
let list=this.data.VideoList
list.push(...list)
this.setData({
VideoList:list
})
}
data: {
GroupList: [],
navid: '',
VideoList: [],
isTriggered: false //下拉刷新
},
<scroll-view
class="view-scroll"
scroll-y
refresher-enabled
bindrefresherrefresh="handleRefresher"
bindscrolltolower="handleToLower"
refresher-triggered="{{isTriggered}}"
>
<view class="vieoItem" wx:for='{{VideoList}}' wx:key='index'>
<video src="{{item.data.previewUrl}}"> </video>
</scroll-view>
微信小程序分享功能的实现方法有两种:
第一种
在page.js中实现onShareAppMessage,便可在小程序右上角选择分享该页面
监听用户点击页面内转发按钮( button 组件 open-type="share"
)或右上角菜单“转发”按钮的行为,并自定义转发内容。
参数 | 类型 | 说明 | 最低版本 |
---|---|---|---|
from | String | 转发事件来源。 | |
button :页面内转发按钮; | |||
menu :右上角转发菜单 | 1.2.4 | ||
target | Object | 如果 from 值是 button ,则 target 是触发这次转发事件的 button ,否则为 undefined | 1.2.4 |
webViewUrl | String | 页面中包含 web-view 组件时,返回当前 web-view 的url | 1.6.4 |
onShareAppMessage: function () {
return {
title: '弹出分享时显示的分享标题',
desc: '分享页面的内容',
path: '/page/user?id=123' // 路径,传递参数到指定页面。
}
}
判读用户点击的是那个
onShareAppMessage: function ({from}) {
console.log(from);
if(from === 'button'){
return {
title: '来自button的转发',
page: '/pages/video/video',
imageUrl: '/static/images/nvsheng.jpg'
}
}else {
return {
title: '来自menu的转发',
page: '/pages/video/video',
imageUrl: '/static/images/nvsheng.jpg'
}
}
}
第二种
自定义按钮实现分享,在page中添加一个带有open-type='share'的button标签
点击该按钮后,即会自动触发已经在page.js中定义好的onShareAppMessage方法,实现分享功能。
()。
如上例,path属性指向的是user页面,并附带id=123的参数。我们只需在user.js的onLoad函数中,通过options查看传递过来的参数:
// user.js
Page({
onLoad: function(options) {
console.log(options);
}
})
微信音乐播放器
页面 布局
<!-- 进度条控制区域 -->
<view class=".progerss">
<text>{{currentTime}}</text>
<!-- 总进度 -->
<cview class="bar">
<!-- 实时进度 -->
<view class="audio-bar" style="width: {{width + 'rpx'}}">
<!-- 小圆球 -->
<view class="audio-circle" ></view>
</view>
</cview>
<text>{{endTime}}</text>
</view>
<!-- 底部控制播放区域 -->
<view class="musicControl">
<text class="iconfont icon-iconsMusicyemianbofangmoshiShuffle"></text>
<text class="iconfont icon-shangyishou" id="pre" bindtap='handleSwitch'></text>
<text class="iconfont {{isPlay?'icon-zanting': 'icon-bofang'}} big" bindtap="handleMusicPlay"></text>
<text class="iconfont icon-next" id="next" bindtap='handleSwitch'></text>
<text class="iconfont icon-iconsMusicyemianbofangmoshiPlayList"></text>
</view>
</view>
.musicControl {
position: absolute;
width: 100%;
bottom: 40rpx;
left: 0;
display: flex;
border-top: 1px solid #ffffff;
}
.musicControl text {
width: 20%;
height: 120rpx;
line-height: 120rpx;
text-align: center;
color: #ffffff;
font-size: 50rpx;
}
.musicControl text .big {
font-size: 80rpx;
}
/* 进度条 */
.progerss {
width: 640rpx;
height: 80rpx;
line-height: 80rpx;
display: flex;
position: absolute;
bottom: 200rpx;
}
.progerss .bar {
position: relative;
width: 450rpx;
height: 8rpx;
background: rgba(0, 0, 0, .4);
margin: auto;
}
.bar .audio-bar {
position: absolute;
top: 0;
left: 0;
height: 8rpx;
background-color: red;
z-index: 99;
}
.audio-circle {
position: absolute;
right: -18rpx;
top: -6rpx;
width: 18rpx;
height: 18rpx;
border-radius: 50%;
background-color: #fff;
}
组件共享PubSubJS
1.使用第三方库: pubsub-js
2.安装: npm install pubsub-js
3.使用:
- a) Import PubSub from ‘pubsub-js’
- b)订阅消息: PubSub.subscribe(‘eventName’, callback)
- c)发布消息: PubSub.publish(‘eventName’, data)
- d)取消订阅: PubSub.unsubscribe(‘eventName’)
小程序使用 npm 包
- 初始化 package.json npm init
- 勾选允许使用 npm
- 下载 npm包
- 构建 npm 1. 开发工具 --->工具--->构建npm 2. 会将node_modules中的包打包到miniprogram_npm 中
背景音频api使用说明
- BackgroundAudioManager 获取实例
- BackgroundAudioManager.onPlay(function callback) 监听背景音频播放事件
- BackgroundAudioManager.onPause(function callback) 监听背景音频暂停事件
- BackgroundAudioManager.onStop(function callback) 监听背景音频停止事件
- BackgroundAudioManager.onTimeUpdate(function callback) 监听背景音频播放进度更新事件,只有小程序在前台时会回调
- BackgroundAudioManager.onEnded(function callback) 监听背景音频自然播放结束事件
- BackgroundAudioManager.stop() 停止音乐
- BackgroundAudioManager.pause() 暂停音乐
string src
音频的数据源( 2.2.3 开始支持云文件ID)。默认为空字符串, 当设置了新的 src 时,会自动开始播放 ,目前支持的格式有 m4a, aac, mp3, wav。
number startTime
音频开始播放的位置(单位:s)。
string title
音频标题,用于原生音频播放器音频标题(必填)。原生音频播放器中的分享功能,分享出去的卡片标题,也将使用该值。
number currentTime
当前音频的播放位置(单位:s),只有在有合法 src 时返回。(只读)
代码示例
//获取全局app应用实例
const app = getApp()
import PubSub from 'pubsub-js'
import request from '../../utils/request'
import moment from 'moment'
Page({
data: {
isPlay: false,
song: {},
id: '',
linkUrl: '',
currentTime: '00:00',
endTime: '00:00',
width: 0
},
onLoad: function (options) {
this.setData({
id: options.id
})
this.getMusicInfo(options.id)
//判断当前音乐是否在播放
console.log(app.globalData.musicId, app.globalData.isMUsicPlay + '全局de', options.id + '点击');
if (app.globalData.isMUsicPlay && app.globalData.musicId == options.id) {
this.setData({
isPlay: true
})
}
//创建音乐播放的实例对象
this.getBackgroundAudioManager = wx.getBackgroundAudioManager()
// 监听用户点击操作系统的播放暂停
this.getBackgroundAudioManager.onPlay(() => {
this.changePlayStatus(true)
app.globalData.musicId = options.id
})
this.getBackgroundAudioManager.onPause(() => {
this.changePlayStatus(false)
})
this.getBackgroundAudioManager.onStop(() => {
this.changePlayStatus(false)
})
// 监听音乐实时播放进度
this.getBackgroundAudioManager.onTimeUpdate(() => {
// 实时时长
let time = this.getBackgroundAudioManager.currentTime
// 总时长
let totalTime = this.getBackgroundAudioManager.duration
let currentTime = moment(time * 1000).format('mm:ss')
let width = time / totalTime * 450
this.setData({
currentTime,
width
})
})
//监听音乐播放自然结束
this.getBackgroundAudioManager.onEnded(() => {
//自动换至下一首音乐,并自动播放
PubSub.publish('SwitchType', 'next');
//将进度条长度恢复为0
this.setData({
width: 0,
endTime: '00:00'
})
})
},
//获取音乐详情
async getMusicInfo(ids) {
let {
songs
} = await request('/song/detail', {
ids
})
//转换总实长
let endTime = moment(songs[0].dt).format('mm:ss')
this.setData({
song: songs[0],
endTime
})
wx.setNavigationBarTitle({
title: this.data.song.name,
})
},
//修改状态功能函数
changePlayStatus(isPlay) {
this.setData({
isPlay
})
//修改应用全局状态
app.globalData.isMUsicPlay = isPlay
},
// 点击开始暂停按钮
handleMusicPlay() {
let isPlay = !this.data.isPlay
this.setData({
isPlay
})
let {
id,
linkUrl
} = this.data
this.musicControl(isPlay, id, linkUrl)
},
// 播放 暂停 功能回调
async musicControl(isPlay, id, linkUrl) {
//性能优化: 没有url时再去请求 有的时候就拿全局变量
if (!linkUrl) {
let {
data
} = await request('/song/url', {
id
})
linkUrl = data[0].url
this.setData({
linkUrl
})
}
if (isPlay) { //播放
// 必须给实例添加url 和title
this.getBackgroundAudioManager.src = linkUrl
this.getBackgroundAudioManager.title = this.data.song.name
} else { //暂停
this.getBackgroundAudioManager.pause()
}
},
// 点击切歌的回调
handleSwitch(e) {
let type = e.currentTarget.id
//关闭当前音乐
this.getBackgroundAudioManager.stop()
//发布消息
PubSub.publish('SwitchType', type);
//订阅消息拿到回传id
PubSub.subscribe('musiceId', (msg, id) => {
console.log(msg, id);
//获取音乐信息
this.getMusicInfo(id)
//自动播放
this.musicControl(true, id)
//接收到之后取消订阅
PubSub.unsubscribe('musiceId');
})
}
})
小程序分包流程
为什么要分包
-
- 小程序要求压缩包体积不能大于 2M,否则无法发布
-
- 实际开发中小程序体积如果大于 2M 就需要使用分包机制进行发布上传
-
- 分包后可解决 2M 限制,并且能分包加载内容,提高性能
-
- 分包后单个包的体积不能大于 2M
-
- 分包后所有包的体积不能大于 16M
分包形式
-
- 常规分包
-
- 独立分包
-
- 分包预下载
常规分包

-
开发者通过在 app.json subpackages 字段声明项目分包结构
-
特点:
a) 加载小程序的时候先加载主包,当需要访问分包的页面时候才加载分包内容
b) 分包的页面可以访问主包的文件,数据,图片等资源
c) 主包:
主包来源: 除了分包以外的内容都会被打包到主包中 通常放置启动页/tabBar 页面
"subPackages":[
{
"root": "songPackge",
"pages": [
"pages/recommendSong/recommendSong",
"pages/songDetail/songDetail"
]
}
],
独立分包
1.设置independent为true 2.特点: a)独立分包可单独访问分包的内容,不需要下载主包 b)独立分包不能依赖主包或者其他包的内容 3.使用场景 a)通常某些页面和当前小程序的其他页面关联不大的时候可进行独立分包 b)如:临时加的广告页||活动页
分包预下载
配置 a) app.json中设置preloadRule选项 b) key(页面路径): {packages: [预下载的包名||预下载的包的根路径])} 2.特点: a)在加载当前包的时候可以设置预下载其他的包 b)缩短用户等待时间,提高用户体验
支付流程详细说明
- 1.用户在小程序客服端下单(包含用户及商品信息)
- 2.小程序客户端发送下单支付请求给商家服务器
- 3.商家服务器同微信服务器对接获取唯一标识openID
- 4.商家服务器根据openId生成商户订单(包含商户信息)
- 5.商家服务器发送请求调用统一下单API获取预支付订单信息
- a)接口地址:api.mch.weixin.qq.com/pay/unified…
- 6.商家对预支付信息签名加密后返回给小程序客户端
- a)签名方式:MD5 b)签名字段:小程序ID,时间戳, 随机串,数据包,签名方式 c)参考地址 : pay.weixin.qq.com/wiki/doc/ap… 7.用户确认支付(鉴权调起支付) a) API: wx.requestPayment() 8.微信服务器返回支付结果给小程序客户端 9.微信服务器推送支付结果给商家服务器端

小程序获取用户唯一标识(openId)
1. wx.login()
- 2.发送code给服务器端
- 3.服务器端发送请求携带参数(code, appSecret, appId)给微信服务器获取openId
- a)接口地址:
- 4. appSecret,appId在小程序首页获取
- 5.服务器获取openId后进行加密返回给前端
