小程序
移动端相关
-
物理像素
- 屏幕的分辨率
- 设备能控制显示的最小单元,可以把物理像素看成是对应的像素点
-
设备独立像素 & css像素
-
设备独立像素(也叫密度无关像素),可以认为是计算机坐标系统中的一个点,这个点代
表一个可以由程序使用并控制的虚拟像素(比如:CSS 像素,只是在 android 机中 CSS 像素就
不叫”CSS 像素”了而是叫”设备独立像素”),然后由相关系统转换为物理像素。
-
-
dpr 比 & DPI & PPI
- dpr:设备像素比,物理像素/设备独立像素 = dpr,一般以iPhone6的dpr为准 dpr = 2,比如:iPhone6的设备像素是375*667,则反推iPhone6的物理像素是750**1334
- PPI:一英寸显示屏上的像素点个数
- DPI:最早指的是打印机在单位面积上打印的墨点数,墨点越多越清晰
移动端适配方案
-
viewport适配
-
为什么要做viewport适配
- 手机产商在生产时大部分的手机默认页面的宽度为980px
- 手机实际视口宽度都要小于980px,如iphon6为375px
- 开发需求:就是需要将980px的页面完全显示在手机屏幕上且没有滚动条
-
实现
<meta name="viewport" content="width=device-width,initial-scale=1.0">
-
-
rem适配
-
为什么做rem适配
-
机型太多,不同的机型屏幕大小不一样
-
需求: 一套设计稿的内容在不同的机型上呈现的效果一致,根据屏幕大小不
同的变化,页面中的内容也相应变化
-
-
实现
function remRefresh() { let clientWidth = document.documentElement.clientWidth; // 将屏幕等分 10 份 let rem = clientWidth / 10; document.documentElement.style.fontSize = rem + 'px'; document.body.style.fontSize = '12px'; } window.addEventListener('pageshow', () => { remRefresh() }) // 函数防抖 let timeoutId; window.addEventListener('resize', () => { timeoutId && clearTimeout(timeoutId); timeoutId = setTimeout(() =>{ remRefresh() }, 300) })
-
第三方实现库
lib-flexible + px2rem-loader
-
小程序特点
-
没有DOM
-
组件化开发:具备特定功能效果的代码集合
-
体积小,单个压缩包体积不能大于2M,否则无法上线
-
小程序的4个重要的文件
- js
- wxml --> view结构 --> html
- wxss --> view样式 --> css
- json --> view数据 --> json配置文件
-
小程序的适配方案:rpx (responsive pixel 响应式像素单位)
-
小程序适配方案:rpx
-
规定任何屏幕下宽度为750px
-
小程序会根据屏幕的宽度不同自动计算rpx值的大小
-
iphone6下:1rpx = 1 物理像素 = 0.5px
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pqVtRGl1-1634014846186)(E:\笔记\image\rpx.png)]
-
小程序配置
sitemap配置
微信现已开放小程序内搜索,开发者可以通过 sitemap.json
配置,或者管理后台页面收录开关来配置其小程序页面是否允许微信索引。当开发者允许微信索引时,微信会通过爬虫的形式,为小程序的页面内容建立索引。当用户的搜索词条触发该索引时,小程序的页面将可能展示在搜索结果中。 爬虫访问小程序内页面时,会携带特定的 user-agent:mpcrawler
及场景值:1129
。需要注意的是,若小程序爬虫发现的页面数据和真实用户的呈现不一致,那么该页面将不会进入索引中。
具体配置说明:
- 页面收录设置:可对整个小程序的索引进行关闭,小程序管理后台-功能-页面内容接入-页面收录开关;
- sitemap 配置:可对特定页面的索引进行关闭
小程序根目录下的 sitemap.json
文件用来配置小程序及其页面是否允许被微信索引。
具体规则见:
App() 必须在 app.js
中调用,必须调用且只能调用一次。不然会出现无法预期的后果
全局配置
小程序根目录下的 app.json
文件用来对微信小程序进行全局配置。文件内容为一个 JSON 对象
pages:页面路径列表
window:全局默认的窗口表现
- navigationBarBackgroundColor:导航栏背景颜色,只能使用十六进制
- navigationBarTitleText:导航栏标题文字内容
- navigationBarTextStyle:导航栏标题颜色,仅支持black/white
- sitemapLocation:指明sitemap.json 的位置
tabBar
客户端窗口的底部或顶部有 tab 栏可以切换页面
在全局配置中配置tabBar即可
页面配置
页面配置和全局配置差不多,只是一个是全局的一个是局部的
index页静态搭建
WXML语法
条件渲染wx:if
条件渲染和vue中的v-if,v-else-if,v-else效果等同
- wx:if=“条件”
- wx:elif=“条件”
- wx:else
wx:if vs hidden
因为 wx:if
之中的模板也可能包含数据绑定,所以当 wx:if
的条件值切换时,框架有一个局部渲染的过程,因为它会确保条件块在切换时销毁或重新渲染。
同时 wx:if
也是惰性的,如果在初始渲染条件为 false
,框架什么也不做,在条件第一次变成真的时候才开始局部渲染。
相比之下,hidden
就简单的多,组件始终会被渲染,只是简单的控制显示与隐藏。
一般来说,wx:if
有更高的切换消耗而 hidden
有更高的初始渲染消耗。因此,如果需要频繁切换的情景下,用 hidden
更好,如果在运行时条件不大可能改变则 wx:if
较好。
列表渲染wx:for
wx:for
在组件上使用 wx:for
控制属性绑定一个数组,即可使用数组中各项的数据重复渲染该组件。
默认数组的当前项的下标变量名默认为 index
,数组当前项的变量名默认为 item
<view wx:for="{{array}}">
{{index}}: {{item.message}}
</view>
Page({
data: {
array: [{
message: 'foo',
}, {
message: 'bar'
}]
}
})
使用 wx:for-item
可以指定数组当前元素的变量名,
使用 wx:for-index
可以指定数组当前下标的变量名:
wx:key
如果列表中项目的位置会动态改变或者有新的项目添加到列表中,并且希望列表中的项目保持自己的特征和状态(如 input 中的输入内容,switch 的选中状态),需要使用 wx:key
来指定列表中项目的唯一的标识符。
wx:key
的值以两种形式提供
- 字符串,代表在 for 循环的 array 中 item 的某个 property,该 property 的值需要是列表中唯一的字符串或数字,且不能动态改变。
- 保留关键字
*this
代表在 for 循环中的 item 本身,这种表示需要 item 本身是一个唯一的字符串或者数字。
当数据改变触发渲染层重新渲染的时候,会校正带有 key 的组件,框架会确保他们被重新排序,而不是重新创建,以确保使组件保持自身的状态,并且提高列表渲染时的效率。
如不提供 wx:key
,会报一个 warning
, 如果明确知道该列表是静态,或者不必关注其顺序,可以选择忽略
模板template
WXML提供模板(template),可以在模板中定义代码片段,然后在不同的地方调用
定义模板
使用name属性,作为模板的名字。然后在<template/>
内定义代码片段,如:
<--
index: int
msg: string
time: string
-->
<template>
<view>
<text>{{index}}: {{msg}}</text>
<text>Time: {{time}}</text>
</view>
</template>
使用摸板
使用is属性,声明需要使用的摸板,然后将摸板所需要的data传入,如:
<template is="msgItem" data="{{...item}}"></template>
page({
data: {
item: {
index: 0,
msg: 'this is a template',
time: '2019-09-15'
}
}
})
is属性可以使用Mustache语法,来动态决定具体需要渲染那个模块
<template name="odd">
<view> odd </view>
</template>
<template name="even">
<view> even </view>
</template>
<block wx:for="{{[1, 2, 3, 4, 5]}}">
<template is="{{item % 2 == 0 ? 'even' : 'odd'}}"/>
</block>
模板的作用域
模板拥有自己的作用域,只能使用data传入的数据以及模板定义文件中定义的 <wxs />
模块
数据绑定
在页面中的index.js文件中的,即可实现数据绑定
# index.js中的代码
data: {
msg: '初始化数据'
},
# wxml代码
<text class="userName">{{msg}}</text>
修改msg的状态数据, 语法:this.setData
onLoad: function (options) {
console.log('onLoad');
// 修改msg的状态数据, 语法:this.setData
console.log(this.data.msg); //this代表当前页面的实例对象
this.setData({
msg: '修改之后的数据'
})
console.log(this.data.msg);
},
数据绑定小程序与vue的区别
-
小程序
- data中初始化数据
- 修改数据:this.setData
- 修改的数据始终是同步的
- 数据流:单项:Model --> View 为实现双向数据绑定
-
vue
- data中初始化数据
- 修改数据:this.key = value
- 数据流:
- vue是单项数据流:Model —> View
- vue中实现了双向数据绑定:v-model
数据劫持代理
vue数据劫持代理
//模拟数据劫持代理
let data = {
username: 'jery',
age: 33
}
//模拟组件实例
let _this = {
}
//利用Object.defineProperty()
for(let item in data) {
Object.defineProperty(_this, item, {
//get: 用来获取扩展属性值的,当获取该属性值时调用get方法
get() {
console.log('get()')
return data[item]
}
//set:监视扩展属性的,只要以修改就调用
set(newValue) {
console.log('set()', newValue)
//_this.username = newValue; 千万不要在set方法中修改当前扩展属性的值,会出现死循环
data[item] = newValue
}
})
}
console.log(_this);
//通过Object.defineProperty的get方法添加的扩展属性不能直接对象.属性修改
_this.username = 'wade'
console.log(_this.username)
事件绑定
事件分为冒泡事件和非冒泡事件:
- 冒泡事件:当一个组件上的事件被触发后,该事件会向父节点传递。
- 非冒泡事件:当一个组件上的事件被触发后,该事件不会向父节点传递。
绑定事件
-
bind绑定:事件绑定不会阻止冒泡事件向上冒泡
<view bindtap="handTap" class="start_container"> <text class="start">开启小程序之旅</text> </view>
-
catch绑定:事件绑定可以阻止冒泡事件向上冒泡
<view catchtap="handTap" class="start_container"> <text class="start">开启小程序之旅</text> </view>
-
事件传参
语法:data-key=value
获取:event.target.dataset.key || event.currentTarget.dataset.key
事件流
事件流的三个阶段
- 捕获:从外向内
- 执行目标阶段
- 冒泡:从内向外
路由跳转相当于vue-router
-
wx.navigateTo(Object object)
保留当前页面,跳转到应用内的某个页面。但是不能跳到 tabbar 页面。使用 wx.navigateBack 可以返回到原页面。小程序中页面栈最多十层。
-
wx.redirectTo():关闭当前页面,跳转到应用内的某个页面。但是不允许跳转到 tabbar 页面
-
wx.reLaunch: 关闭所有页面,打开到应用内的某个页面
-
wx.switchTab:跳转到 tabBar 页面,并关闭其他所有非 tabBar 页面
-
可在局部配置"navigationBarTitleText": “日志”,局部配置高于优先级
-
更多见官方文档API中的路由
生命周期
五个钩子函数
onLoad() 监听页面加载
onShow() 监听页面显示
onReady() 监听页面初次渲染完成
onHide() 监听页面隐藏
onUnload() 监听页面卸载
是页面隐藏还是卸载取决于路由的跳转方式:
当路由的跳转方式为:调用 API:wx.reLaunch 等时 生命周期执行顺序为:
onLoad() --> onShow() --> onReady() --> onUnload()
当返回上一级页面时会执行,onLoad(), onShow(), onReady()重新进行页面的加载与渲染
当路由的跳转方式为:调用 调用 API :wx.navigateTo 生命周期执行顺序为:
onLoad() --> onShow() --> onReady() --> onHide()
当返回上一级页面时会执行:onShow()
获取用户基本信息
-
用户未授权即首次登陆
<button open-type='getUserInfo' bind>获取用户信息</button>
-
用户已经授权再次登录
//wx.getUserInfo wx.getUserInfo({ success: (res) => { console.log(res); this.setData({ userInfo: res.userInfo }) }, fail: (err) => { console.log(err); } })
版本跟新后,getUserInfo无法使用的话,可以使用新的API接口:getUserProfile
轮播图
swiper
swiper是一个滑块视图容器。其中只可放置swiper-item组件,否则会导致未定义的行为
swiper的多种属性
- indicator-dots:是否显示面板指示点
- indicator-color:指点颜色
- indicator-active-color:当前选中的指示点颜色
- autoplay:是否自动切换
如何使用IDE工具开发小程序
用vscode开发时,为了高亮,下载插件wxml,wxss,或者直接安装minapp即可
iconfont
iconfont字体图标的使用
-
先在阿里矢量库,下载想要的图标
-
将最新在线链接复制到浏览器url处打开,然后将其全部复制到iconfont.wxss文件中
-
创建一个文件夹iconfont,然后再文件下创建iconfont.wxss文件
-
在全局映入iconfont文件:@import “/static/iconfont/iconfont.wxss”;
-
在wxml中使用
<text class="iconfont icon-meirituijian"></text>
视图容器
- swiper:轮播图
- scroll-view:可滚动视图区域,可纵向滚动也可横向滚动
前后端数据交互
先进行服务器的测试,可以使用postman,也可以直接在服务器地址cmd打开,然后npm start如果不能启动成功,则需下载npm install -g nodemon,安装成功后得到http://localhost:3000,然后再浏览器中url直接测试,只能测试get请求,最好使用postman
网络请求API
使用语法wx.request发动网络请求获取数据
onLoad: function (options) {
wx.request({
url: 'http://localhost:3000/banner',
data: {
type: 2
},
success: (res) => {
console.log('请求成功',res);
},
fail: (err) => {
console.log('请求失败',err);
}
})
},
当是在会以下报错
http://localhost:3000 不在以下 request 合法域名列表中,请参考文档:https://developers.weixin.qq.com/miniprogram/dev/framework/ability/network.html(env: Windows,mp,1.05.2108130; lib: 2.19.2)
解决方法:
1. 打开小程序 > 开发管理 > 开发设置 > 配置服务器信息
2. 无法配置https时,详情本地设置中打开不校验合法域名
注意点:
- 协议必须是https协议
- 一个接口最多配置20个域名
- 并发限制上限是10个
封装请求功能函数
为了优化,减少http请求的次数,封装一个请求功能函数
//新建utils文件夹,下面由两个文件分别为:request.js, config.js
//request.js部分代码
import config from "./config";
export default (url, data={}, method='Get') => {
return new Promise((resolve, reject) => {
// new Promise初始化Promise实例的状态为pending
wx.request({
url: config.host + url,
data,
method,
success: (res) => {
console.log('请求成功',res);
resolve(res.data); //resolve修改promise状态为成功状态resolved
},
fail: (err) => {
console.log('请求失败',err);
reject(err) //reject修改promise状态为成功状态为rejectd
}
})
})
}
//cofig部分代码
// 配置服务器相关信息
export default {
host: 'http://localhost:3000',
}
// onLoad部分代码
onLoad: async function (options) {
// 获取banner处数据
let result = await request('/banner', {type: 2})
console.log('结果数据', result);
},
自定义组件
将相同的代码抽取出来成为一个组件,可以复用
Component(Object object)
-
创建一个components文件夹,在创建一个组件文件夹,将抽出的代码放进对应的地方
-
js文件中书写对应的数据
-
在想要复用的页面的json文件中配置路径
{ "usingComponents": { "NavHeader": "/components/navheader/NavHeader" } }
-
使用自定义组件时,和vue中的用法基本一致
内网穿透
真机调试时,因为电脑开的是电脑本地服务器,所以在手机上动态获取的数据无法显示,这时就需要内网穿透
事件委托
什么是事件委托
事件委托就是将子元素的事件委托(绑定)给父元素
事件委托的好处
- 减少绑定的次数
- 后期新添加的元素也可以享用之前委托的事件
事件委托的原理
冒泡
触发事件的是谁
子元素
如何找到触发事件的对象
event.target
currentTarget VS target
- currentTarget要求绑定事件的元素一定是触发事件的元素
- target绑定事件的元素不一定是触发事件的元素,因为事件委托
事件
什么是事件?
- 事件是视图层到逻辑层的通讯方式。
- 事件可以将用户的行为反馈到逻辑层进行处理。
- 事件可以绑定在组件上,当达到触发事件,就会执行逻辑层中对应的事件处理函数。
- 事件对象可以携带额外信息,如 id, dataset, touches。
事件的使用方式
-
在组件中绑定一个事件处理函数
- 如
bindtap
,当用户点击该组件的时候会在该页面对应的Page中找到相应的事件处理函数。
<view id="tapTest" data-hi="Weixin" bindtap="tapName"> Click me! </view>
id和data-hi都可以传值,hi是变量
当向event对象传一个唯一的标识,就用id
当向event对象里面传多个数据时,使用 “ data- ” 的形式
- 在相应的Page定义中写上相应的事件处理函数,参数是event。
Page({ tapName: function(event) { console.log(event) } })
- 可以看到console.log(even)出来的信息大致如下:
{ "type":"tap", "timeStamp":895, "target": { "id": "tapTest", "dataset": { "hi":"Weixin" } }, "currentTarget": { "id": "tapTest", "dataset": { "hi":"Weixin" } }, "detail": { "x":53, "y":14 }, "touches":[{ "identifier":0, "pageX":53, "pageY":14, "clientX":53, "clientY":14 }], "changedTouches":[{ "identifier":0, "pageX":53, "pageY":14, "clientX":53, "clientY":14 }] }
- 如
在对象里操作属性时,如果是个变量就需要中括号
数据缓存
又叫本地存储用于在用户登录时,存储用户的基本信息
语法:wx.setStorage(), wx.setStorageSync(), wx.getStorage, wx.getStorageSync()
注意点:
- 建议存储的数据为json格式,即将数据存储在本地缓存中指定的 key 中,JSON.stringify()
- 从本地缓存中异步获取指定 key 的内容,需要将json格式转为string格式,JSON.parse()
- 将数据存储在本地缓存中指定的 key 中。会覆盖掉原来该 key 对应的内容。除非用户主动删除或因存储空间原因被系统清理,否则数据都一直可用。单个 key 允许存储的最大数据长度为 1MB,所有数据存储上限为 10MB
- 属于永久存储,和h5的localStorage一样
上拉刷新
的下拉刷新和上拉刷星需要在组件里设置对应的属性,如下拉刷新:bindrefresherrefresh
上拉加载:bindscrolltolower
页面的下拉刷新,页面在配置中开启enablePullDownRefresh
,可以在局部json文件中开启,也可以在全局json文件中开启
点击分享
onShareAppMessage(Object object)
监听用户点击页面内转发按钮(button 组件 open-type="share"
)或右上角菜单“转发”按钮的行为,并自定义转发内容
媒体播放
音乐的播放主要看官网的API > 媒体音频 > 背景音频
getApp()可以解决页面销毁音乐播放状态问题:即播放时销毁页面,重新进入页面后播放的状态会不明确产生冲突
getApp(Object object)获取到小程序全局唯一的 App
实例
// other.js
var appInstance = getApp()
console.log(appInstance.msg.globalData) // I am global data
// app.js
globalData: {
msg: 'I am global data'
},
解决思路:在音乐详情界面销毁的时候把页面状态存到全局,重新进入到详情页面的时候再将页面状态读出来,就避免问题
音乐详情界面创建全局的appInstance,在app.js页面创建对应的globalData对象;
在音乐详情界面的生命周期监听页面加载的函数onLoad()中判断音乐是否在播放如果为true,将当前页面的音乐播放状态改为true;
通过创建控制音乐播放的实例来监听全局音乐的播放、暂停、停止中修改全局音乐播放的状态
部分代码
const appInstance = getApp()
onLoad: function (options) {
// options: 用于接收路由跳转的query参数
// 原生小程序中路由传参,对参数的长度有限至,如果参数长度过长会被自动截取掉
// console.log(JSON.parse(options.song));
let musicId = options.musicId
this.setData({
musicId
})
// 调用获取音乐数据详情的功能函数
this.getMusicInfo(musicId)
/**
* 问题:如果用户操作系统的控制音乐播放/暂停的按钮,页面不知道,
* 导致页面显示是否播放的状态和真实的播放状态不一致
* 结局方案:通过控制音频的实例backgroundAudioManager 去监视音乐的播放和暂停
*/
// 判断当前页面是否在播放
if(appInstance.globalData.isMusicPlay && appInstance.globalData.musicId === musicId){
// 修改当前页面的音乐播放状态为true
this.setData({
isPlay: true
})
}
// 创建控制音乐播放的实例
this.backgroundAudioManager = wx.getBackgroundAudioManager()
// 监视音乐的播放和暂停
this.backgroundAudioManager.onPlay(() => {
// 修改音乐是否播放的状态
this.changPlayState(true)
// 修改全局音乐播放的状态
appInstance.globalData.musicId = musicId
})
this.backgroundAudioManager.onPause(() => {
// 修改音乐是否播放的状态
this.changPlayState(false)
})
// 监听音乐的停止, 这里是为了防止手机上,点击叉号时音乐会停止
this.backgroundAudioManager.onStop(() => {
// 修改音乐播放的状态
this.changPlayState(false)
})
},
// 修改播放状态的功能函数
changPlayState(isPlay) {
// 修改音乐是否播放的状态
this.setData({
isPlay
})
// 修改全局音乐播放的状态
appInstance.globalData.isMusicPlay = true
},
音乐播放性能优化
当音乐播放时会发送一次网络请求,暂停后重新播放又会播放一次网络请求,这时其实我们只需要发送一次网络请求就行了
音乐播放进度条
BackgroundAudioManager.onTimeUpdate(function callback):监听背景音频播放进度更新事件,只有小程序在前台时会回调
BackgroundAudioManager.onEnded(function callback):监听背景音频自然播放结束事件
页面通信
路由传参
当点击页面跳转另一页面,比如在音乐界面点击某首音乐跳转至对应的界面,需要将这首歌曲的数据传至对应的歌曲详情界面,通过data-song=“{{item}}”,来将想要传的数据传入event事件中,然后从event.currentTarget.dataset.song自取
路由跳转传参: query参数,代码:
//toSongDetail为bindtap自定义的函数
toSongDetail(event) {
let song = event.currentTarget.dataset.song
wx.navigateTo({
// url地址有js的对象或者数组,如果有会自定调用toString方法转换为字符串
// 注意:不能直接间song作为参数直接传递,长度过长会被自动截取
// 错误写法:url: '/pages/songDetail/songDetail?song=' + JSON.stringify(song)
url: '/pages/songDetail/songDetail?musicId=' + song.id
})
},
详情页接收:在生命周期监听页面加载onLoad(options)中接收
onLoad: function (options) {
// options: 用于接收路由跳转的query参数
// 原生小程序中路由传参,对参数的长度有限至,如果参数长度过长会被自动截取掉
// console.log(JSON.parse(options.song));
let musicId = options.musicId
console.log(options);
console.log(musicId);
}
动态设置当前页面的标题;
wx.setNavigationBarTitle({
title:
})
定义事件相关
-
分类
- 标准的DOM事件
- 自定义事件
-
标准DOM事件
- 举例:click,input,…
- 事件名固定的,事件由浏览器触发
-
自定义事件
- 绑定事件
- 事件名
- 事件的回调
- 订阅方:绑定回调:PubSub.subscribe(事件名,事件的回调)
- 订阅方接受数据的一方
- 触发事件
- 事件名
- 提供事件参数对象,等同于原生事件的event对象
- 发布方:提供数据:PubSub.publish(事件名,提供的数据)
- 发布方提供数据的一方
先订阅后发布即先绑定事件后出发事件
- 绑定事件
消息订阅发布
- 使用第三方库:pubsub.js
- 安装:npm install pubsub-js
- 使用:
- 引入:import PubSub from ‘pubsub-js’
- 订阅消息:PubSub.subscribe(‘eventName’,callback)
- 发布消息:PubSub.publish(‘eventName’, data)
- 取消消息:PubSub.publishSync(‘eventName’)
EventChannel
页面间事件通信通道
使用方法
EventChannel.emit(string eventName, any args)
触发一个事件
EventChannel.on(string eventName, EventCallback fn)
持续监听一个事件
EventChannel.once(string eventName, EventCallback fn)
监听一个事件一次,触发后失效
EventChannel.off(string eventName, EventCallback fn)
取消监听一个事件。给出第二个参数时,只取消给出的监听函数,否则取消所有监听函数
使用npm包
-
初始化package.json
ynpm init一路enter或者npm init -y
-
勾选允许使用npm
小程序开发者工具 --> 详情 --> 勾选npm
构建npm
- 开发工具 —> 工具 —> 构建npm
- 会将node_modules中的包打包到miniprogram_npm中
Moment.js
Moment.js是一个JavaScript 日期处理类库
npm安装:npm install moment --save
显示时间有很多种,具体看相关文旦,分秒显示如下:
// 分秒显示
moment(songData.songs[0].dt).format('mm:ss') // 04:12
用户登录凭证code
wx.login()
服务器端用到的三方库:jsonwebtoken(加密token),flyio
分包加载
官网–> 指南 --> 基础能力 --> 分包加载
某些情况下,开发者需要将小程序划分成不同的子包,在构建时打包成不同的分包,用户在使用时按需进行加载。
在构建小程序分包项目时,构建会输出一个或多个分包。每个使用分包小程序必定含有一个主包。所谓的主包,即放置默认启动页面/TabBar 页面,以及一些所有分包都需用到公共资源/JS 脚本;而分包则是根据开发者的配置进行划分。
在小程序启动时,默认会下载主包并启动主包内页面,当用户进入分包内某个页面时,客户端会把对应分包下载下来,下载完成后再进行展示。
目前小程序分包大小有以下限制:
- 整个小程序所有分包大小不超过 20M
- 单个分包/主包大小不能超过 2M
对小程序进行分包,可以优化小程序首次启动的下载时间,以及在多团队共同开发时可以更好的解耦协作
常规分包
配置方法
假设支持分包的小程序目录如下
├── app.js
├── app.json
├── app.wxss
├── packageA
│ └── pages
│ ├── cat
│ └── dog
├── packageB
│ └── pages
│ ├── apple
│ └── banana
├── pages
│ ├── index
│ └── logs
└── utils
开发者通过在 app.json subpackages
字段声明项目分包结构:
写成 subPackages 也支持。
// app.json页面
{
"pages":[
"pages/index",
"pages/logs"
],
"subpackages": [
{
"root": "packageA",
"pages": [
"pages/cat",
"pages/dog"
]
}, {
"root": "packageB",
"name": "pack2",
"pages": [
"pages/apple",
"pages/banana"
]
}
]
}
subpackages
中,每个分包的配置有以下几项:
字段 | 类型 | 说明 |
---|---|---|
root | String | 分包根目录 |
name | String | 分包别名,分包预下载时可以使用 |
pages | StringArray | 分包页面路径,相对与分包根目录 |
independent | Boolean | 分包是否是独立分包 |
特点
- 加载小程序的时候先加载主包,当需要访问分包的页面时候才加载分包内容
- 分包的页面可以访问主包的文件,数据,图片等资源
- 主包:
- 主包来源:除了分包以外的内容都会被打包到主包中
- 通常放置启动页/tabBar页面
独立分包
开发者通过在app.json的subpackages字段中对应的分包设置项中定义independent
字段声明对应分包为独立分包。
设置 independent为true
特点:
- 独立分包可以单独访问分包的内容,不需要下载主包
- 独立分包不能依赖主包或者其他包的内容
使用场景:
- 通常某些页面和当前小程序的其他页面关联不大的时候可进行独立分包
- 如:临时加的广告页面 或者 活动页面 双十一活动
{
"pages": [
"pages/index",
"pages/logs"
],
"subpackages": [
{
"root": "moduleA",
"pages": [
"pages/rabbit",
"pages/squirrel"
]
}, {
"root": "moduleB",
"pages": [
"pages/pear",
"pages/pineapple"
],
"independent": true //独立分包设置
}
]
}
分包预下载
开发者可以通过配置,在进入小程序某个页面时,由框架自动预下载可能需要的分包,提升进入后续分包页面时的启动速度。对于独立分包,也可以预下载主包。
分包预下载目前只支持通过配置方式使用,暂不支持通过调用API完成。
vConsole 里有
preloadSubpackages
开头的日志信息,可以用来验证预下载的情况。
配置方法
预下载分包行为在进入某个页面时触发,通过在 app.json
增加 preloadRule
配置来控制。
{
"pages": ["pages/index"],
"subpackages": [
{
"root": "important",
"pages": ["index"],
},
{
"root": "sub1",
"pages": ["index"],
},
{
"name": "hello",
"root": "path/to",
"pages": ["index"]
},
{
"root": "sub3",
"pages": ["index"]
},
{
"root": "indep",
"pages": ["index"],
"independent": true
}
],
// 分包预下载设置
"preloadRule": {
"pages/index": {
"network": "all",
"packages": ["important"] //可以是subpackages中的root也可以是name
},
"sub1/index": {
"packages": ["hello", "sub3"]
},
"sub3/index": {
"packages": ["path/to"]
},
"indep/index": {
"packages": ["__APP__"] //预加载主包
}
}
}
preloadRule
中,key
是页面路径,value
是进入此页面的预下载配置,每个配置有以下几项:
字段 | 类型 | 必填 | 默认值 | 说明 |
---|---|---|---|---|
packages | StringArray | 是 | 无 | 进入页面后预下载分包的 root 或 name 。__APP__ 表示主包。 |
network | String | 否 | wifi | 在指定网络下预下载,可选值为: all : 不限网络 wifi : 仅wifi下预下载 |
独立分包时才会预加载主包
"pages": ["index"],
},
{
"root": "sub1",
"pages": ["index"],
},
{
"name": "hello",
"root": "path/to",
"pages": ["index"]
},
{
"root": "sub3",
"pages": ["index"]
},
{
"root": "indep",
"pages": ["index"],
"independent": true
}
],
// 分包预下载设置
“preloadRule”: {
“pages/index”: {
“network”: “all”,
“packages”: [“important”] //可以是subpackages中的root也可以是name
},
“sub1/index”: {
“packages”: [“hello”, “sub3”]
},
“sub3/index”: {
“packages”: [“path/to”]
},
“indep/index”: {
“packages”: [“APP”] //预加载主包
}
}
}
`preloadRule` 中,`key` 是页面路径,`value` 是进入此页面的预下载配置,每个配置有以下几项:
| 字段 | 类型 | 必填 | 默认值 | 说明 |
| :------- | :---------- | :--- | :----- | :----------------------------------------------------------- |
| packages | StringArray | 是 | 无 | 进入页面后预下载分包的 `root` 或 `name`。`__APP__` 表示主包。 |
| network | String | 否 | wifi | 在指定网络下预下载,可选值为: `all`: 不限网络 `wifi`: 仅wifi下预下载 |
独立分包时才会预加载主包