微信小程序
微信小程序
前置知识
移动端适配
- 物理像素:屏幕的分辨率,设备能控制显示的最小单元,可以把物理像素看成对应的像素点
- 设备独立像素:也叫密度无关像素,可以认为是计算机坐标系统中的一个点,这个点代表一个可以由程序使用并控制的虚拟像素,比我css像素,只是在安卓机中的css像素就不叫css像素了,而是叫设备独立像素,然后由关系系统转为物理像素
- dpr:设备像素比,物理像素/设备独立像素,一般以iPhone6的dpr为准(dpr=2)
- ppi:一英尺显示屏上的像素点的个数
- dpi:最早指的是打印机在单位面积上打印的墨点数,墨点数越多越清晰
小程序适配
iPhone6:1rpx = 1物理像素 = 0.5px
微信官方提供的换算方式:
- 以iPhone6的物理像素个数为标准:750
- 1rpx = 目标设备宽度 / 750px
- 此时底层已经做了viewport适配处理,即实现了理想视口
视网膜屏幕:是分辨率超过人眼识别极限的高分辨率屏幕,由苹果公司在2010年发布iPhone4的发布会上首次推出的术语,dpr=2是人类肉眼分辨的极限
Hello 小程序
项目结构
- page 存放页面
- index 每个页面的名称,目录下包含该页面的配置
- index.js
- index.json
- index.wxml
- index.wxss
- ortherPage
...
- utils 存放工具代码
- util.js
...
app.js 小程序项目的入口文件
app.json 小程序项目的全局配置文件
app.wxss 小程序项目的全局样式文件
project.config.json 项目的配置文件
project.private.config.json
sitemap.json 用于配置小程序及其页面是否允许被微信索引,如果没有,默认为所有页面允许被索引
.eslintrc.js 代码检查工具
app.json
{
"pages":[ // 所有页面路径
"pages/index/index", // 第一个作为首页加载,tabBar必须在非tabBar前
"pages/logs/logs",
"pages/test/test"
],
"window":{ // 全局定义小程序所有页面的背景色、文字颜色等
"backgroundTextStyle":"light", // 下拉窗口loading样式,二选一:dark、light
"backgroundColor":"#fff", // 下拉窗口颜色
"navigationBarBackgroundColor": "#fff", // 导航栏背景颜色
"navigationBarTitleText": "Weixin", // 导航栏标题
"navigationBarTextStyle":"black", // 导航栏标题颜色,二选一:black、white
"enablePullDownRefresh":false, // 是否开启全局下拉刷新,一般在页面中单独开启
"onReachBottomDistance":50 // 上拉触底事件触发时距离页面底部的距离,一般用默认值
},
"tabBar":{ // 配置导航栏
"list":[{ // 2-5个导航栏
"pagePath":"pages/index/index", // 页面路径,必填
"text":"日志", // 导航标签名称,必填
"iconPath":"/images/tabs/index.png", // 导航标签图标
"selectedIconPath":"/images/tabs/index-active.png" // 选中的导航标签图标
},{
"pagePath":"pages/logs/logs",
"text":"首页",
"iconPath":"/images/tabs/logs.png",
"selectedIconPath":"/images/tabs/logs-active.png"
},{
"pagePath":"pages/test/test",
"text":"首页",
"iconPath":"/images/tabs/test.png",
"selectedIconPath":"/images/tabs/test-active.png"
}]
}
"style": "v2", // 全局定义小程序组件所使用的样式版本
"sitemapLocation": "sitemap.json" // 用来指明 sitemap.json 的位置
}
页面.json
{
"backgroundTextStyle":"light", // 下拉窗口loading样式,二选一:dark、light
"backgroundColor":"#fff", // 下拉窗口颜色
"navigationBarBackgroundColor": "#fff", // 导航栏背景颜色
"navigationBarTitleText": "Weixin", // 导航栏标题
"navigationBarTextStyle":"black", // 导航栏标题颜色,二选一:black、white
"enablePullDownRefresh":false, // 是否开启全局下拉刷新,一般在页面中单独开启
"onReachBottomDistance":50 // 上拉触底事件触发时距离页面底部的距离,一般用默认值
}
project.config.json
{
"description": "项目配置文件",
"packOptions": {
"ignore": [],
"include": []
},
"setting": { // 编译相关配置
"bundle": false,
"userConfirmedBundleSwitch": false,
"urlCheck": true,
"scopeDataCheck": false,
"coverView": true,
"es6": true,
"postcss": true,
"compileHotReLoad": false,
"lazyloadPlaceholderEnable": false,
"preloadBackgroundData": false,
"minified": true,
"autoAudits": false,
"newFeature": false,
"uglifyFileName": false,
"uploadWithSourceMap": true,
"useIsolateContext": true,
"nodeModules": false,
"enhance": true,
"useMultiFrameRuntime": true,
"useApiHook": true,
"useApiHostProcess": true,
"showShadowRootInWxmlPanel": true,
"packNpmManually": false,
"enableEngineNative": false,
"packNpmRelationList": [],
"minifyWXSS": true,
"showES6CompileOption": false,
"minifyWXML": true,
"babelSetting": {
"ignore": [],
"disablePlugins": [],
"outputPath": ""
},
"condition": false
},
"compileType": "miniprogram",
"libVersion": "2.19.4",
"appid": "wx8c8bf9a0912c75e9", // 自己的AppId
"projectname": "miniprogram-92", // 项目名称
"condition": {},
"editorSetting": {
"tabIndent": "insertSpaces",
"tabSize": 2
},
"checkSiteMap": false // sitemap 的索引提示是默认开启的,配置后关闭
}
修改首页
小程序app.json中pages配置项中,排在第一个的当做首页
只要在pages中配置的页面,会自动生成页面的骨架
WXML
和html相比
- 标签名不同
- html(div、span、img、a)
- wxml(view、text、image、navigator)
- 属性节点不同
<a href="#">超链接</a><navigator url="/pages/index/index"></navigator>
WXSS
和css相比
- 尺寸单位
- css需要手动进行像素换算,如rem
- wxss支持的新单位rpx可自适应屏幕大小,自动换算,通常以iPhone6为基准1 rpx = 0.5 px
- wxss有全局样式和局部样式
- wxss仅支持部分css选择器 --- 类选择器、id选择器、element、并集选择器、后代选择器、伪类选择器
- wxss支持样式导入
@import,后跟外联样式表的相对路径
运行机制
小程序启动过程
- 把小程序包下载到本地
- 解析app.json全局配置文件
- 执行app.js小程序入口文件,调用App()创建的小程序实例
- 渲染小程序首页
- 启动完成
页面渲染过程
- 加载解析页面的json文件
- 加载页面的wxml模板和wxss样式
- 执行页面js文件,调用Page()场景·创建页面实例
- 渲染完成
组件、API
九大组件
- 视图容器
- 基础内容
- 表单组件
- 导航组件
- 媒体组件
- map地图组件
- canvas画布组件
- 开发能力
- 无障碍访问
三大API
- 事件监听,以on开头,如
wx.onWindowResize(function callback)监听窗口尺寸变化的事件 - 同步API,以Sync结尾的,如
wx.setStorageSync('key', 'value')向本地存储中写入内容 - 异步API,如
wx.request()发起网络数据请求,通过 success 回调函数接收数据
视图容器
view:普通的视图区域,类似div,是一个块级元素,用来页面布局
scroll-view:可滚动的视图区域,常用来实现滚动列表
swiper 和 swiper-item:轮播图组件
<swiper class="s" indicator-dots indicator-color="#fff"> <swiper-item> <view>A</view> </swiper-item> <swiper-item> <view>B</view> </swiper-item> <swiper-item> <view>C</view> </swiper-item> </swiper>属性
- indicator-dots,是否显示指示点,默认false
- indicator-color,指示点颜色,默认rgba(0,0,0,.3)
- indicator-active-color,选中的指示点颜色,默认#000
- autoplay,自动切换,默认false
- interval,自动切换时间间隔,默认5000
- circular,是否采用衔接滑到,默认false
基础内容组件
- text:文本组件,类似span,行内元素
- selectable属性,支持长按选中
<text selectable>12345</text>
- selectable属性,支持长按选中
- rich-text:富文本组件,支持将html字符串渲染为wxml
- nodes属性,放html
<rich-text nodes="<h1> 标题1 </h1>"></rich-text>
- nodes属性,放html
其他常用组件
- button:按钮组件
- type:三选一,default默认灰底绿字,primary主色调按钮绿底白字,warn警告按钮灰底红字
- size:二选一,default,mini
- plain:镂空
- image:图片组件,默认宽度300px,高度240px
- mode:
- scaleToFill,默认值,变形填满,
- aspectFit,不变形,长边全显,
- aspectFill,不变形,短边全显
- widthFix,不变形,宽度不变
- heightFix,不变形,高度不变
- mode:
- navigator:导航组件
数据绑定
和vue一样,数据可以在初始化时存放在当前页面内存的data中
定义:在当前页面的js文件中进行配置
Page({
data: {
username:'lala',
password:'xxxxx',
imgUrl:'https://xxxxxxxxxxxxxx'
},
...
})
使用:在wxml中使用
<view>{{username}}</view>
和vue不同的是,差值语法不仅可以绑定文本,进行运算(算数运算、三元运算),还可以绑定属性
<image src="imgUrl"></image>
事件绑定
| 事件类型 | 绑定方式 | 说明 |
|---|---|---|
| tap | bindtap 或 bind:tap | 手指触摸后马上离开,类似于 HTML 中的 click 事件 |
| input | bindinput 或 bind:input | 文本框的输入事件 |
| change | bindchange 或 bind:change | 状态改变时触发 |
事件对象的属性:当事件回调触发的时候,会收到一个事件对象 event,它的详细属性如下表所示
| 属性 | 类型 | 说明 |
|---|---|---|
| type | String | 事件类型 |
| timeStamp | Integer | 页面打开到触发的时间 |
| target | Object | 触发事件的组件(冒泡的源头)的属性值集合 |
| currentTarget | Object | 当前组件(绑定事件的组件)的属性值的集合 |
| detail | Object | 额外的信息 |
| touches | Array | 触摸事件,当前停留在屏幕的触摸点信息的数组 |
| changedTouches | Array | 触摸事件,当前变化的触摸点信息的数组 |
事件传参 --- 通过data-kkk=“vvv”传参,通过e.target.dataset.xxx获取
- bindtap
<button type="primary" bindtap="test" data-info="{{2}}">按钮</button>
Page({
data:{
count:0
},
test(e){
console.log(e)
console.log(e.target.dataset.info)
this.setData({
count: ++this.data.count
})
}
})
- bindinput
<input bindinput='inputTest'></input>
Page({
inputTest(e){
console.log(e.detail.value) // 变化后最新的值
}
})
文本框的数据绑定
<input value="{{msg}}" bindinput='inputTest'></input>
Page({
data:{
msg:'你好呀'
},
inputTest(e){
this.setData({
msg:e.detail.value
})
}
})
条件渲染
<input value="{{sex}}" bindinput='inputTest'></input>
<view wx:if="{{sex == 1}}">男的</view>
<view wx:elif="{{sex == 2}}">女的</view>
<view wx:else>不知道</view>
Page({
data:{
sex:1
},
inputTest(e){
console.log(1111111111)
this.setData({
sex:e.detail.value
})
}
})
一次性控制多组件的显示隐藏,需要加<block>包裹,<block> 并不是一个组件,它只是一个包裹性质的容器,不会在页面中做任何渲染
<block wx:if="{{true}}">
<view> A </view>
<view> B </view>
<view> C </view>
</block>
hidden 相当于vue中的v-show,控制样式来实现的隐藏
<view hidden="{{true}}">展示</view>
频繁切换时用hidden,控制条件复杂时用wx:if
列表渲染
<view wx:for="{{array}}">
索引是:{{index}},值为:{{item}}
</view>
默认索引为index,变量名为item,可以手动指定
<view wx:for="{{array}}" wx:for-index="idx" wx-for-item="good">
索引是:{{idx}},值为:{{good}}
</view>
wx:key类似vue中的:key,指定唯一键
<view wx:for="{{userList}}" wx:key="id">
{{item.name}}
</view>
Page({
data:{
userList:[
{id:111,name:'小红'},
{id:222,name:'小黄'},
{id:333,name:'小白'}
]
}
})
网络请求
- 配置request合法域名(小程序只能发https请求),将接口的域名添加到信任列表
- 登录微信小程序管理后台 -> 开发 -> 开发设置 -> 服务器域名 -> 修改 request 合法域名
- 只能是备案的域名,不能使用ip和localhost
- 本地测试跳过合法域名校验:详情 -> 本地设置 -> 不校验....
- 微信小程序没有跨域,也没有ajax
get请求
wx.request({
url:'https://xxxxxxxxxxx',
method:'GET',
data:{
name:'xx',
age:11
},
success:(resp)=>{
console.log(resp)
}
})
post请求
wx.request({
url:'https://xxxxxxxxx',
method:'POST',
data:{
name:'vv',
age:22
},
success:(resp)=>{
console.log(resp)
}
})
生命周期
应用的生命周期
- onLaunch(options){}:小程序初始化完成,全局只触发一次
- onShow(options){}:小程序启动时,或从后天进入前提时触发
- onHide(){}:小程序从前台进入后台时触发
页面的生命周期
- onLoad(options){}:监听页面的加载,一个页面仅调用一次
- onShow(){}:监听页面显示
- onReady(){}:监听页面初次渲染完成,一个页面仅调用一次
- onHide(){}:监听页面隐藏
- onUnload(){}:监听页面卸载,一个页面仅调用一次
组件的生命周期
| 生命周期函数 | 参数 | 描述说明 |
|---|---|---|
| created | 无 | 在组件实例刚刚被创建时执行 |
| attached | 无 | 在组件实例进入页面节点树时执行 |
| ready | 无 | 在组件在视图层布局完成后执行 |
| moved | 无 | 在组件实例被移动到节点树另一个位置时执行 |
| detached | 无 | 在组件实例被从页面节点树移除时执行 |
| error | Object Error | 每当组件方法抛出错误时执行 |
// 生命周期函数--监听页面加载
onLoad(options){
this.getGoodList()
},
getGoodList(){}
页面导航
html中使用<a>或location.href,类似的,小程序也是有两种方式
声明式导航
- 导航到tabBar页面
- url:页面地址,必须以/开头
- open-type:六选一,
- switchTab:导航到tabBar页面
- navigate:导航到普通页面,可省略
- navigateBack:后退 和 delta 属性搭配使用,值为1时可省略
- exit:
- redirect:重定向
- reLaunch:
<navigator url="/pages/logs/logs" open-type="switchTab">导航到日志tabBar</navigator>
<navigator url="/pages/info/info" open-type="navigate">导航到信息</navigator>
<navigator url="/pages/info/info" open-type="navigateBack" delta="1">导航到信息</navigator>
编程式导航
<button bindtap="gotoXxx">跳转tabBar</button>
<button bindtap="gotoInfo">跳转非tabBar</button>
<button bindtap="gotoBack">回退</button>
Page({
gotoXxx(){
wx.switchTab({
url:"xxxxxxxx", // tabBar路径
successs:()=>{}, // 成功的回调
fail:()=>{}, // 失败的回调
complete:()=>{} // 必定执行的回调
})
},
gotoInfo(){
wx.navigateTo({
url:"xxxxxxxx", // 非tabBar路径
successs:()=>{}, // 成功的回调
fail:()=>{}, // 失败的回调
complete:()=>{} // 必定执行的回调
})
},
gotoBack(){
wx.navigateBack({ // 没有对象。默认回退一步
delta:1, // 回退步数
successs:()=>{}, // 成功的回调
fail:()=>{}, // 失败的回调
complete:()=>{} // 必定执行的回调
})
}
})
导航传参
传参:url拼接参数
<navigator url="/pages/logs/logs?user=aaa&age=20" open-type="switchTab">导航到日志tabBar</navigator>
gotoXxx(){
wx.switchTab({
url:"/pages/logs/logs?user=aaa&age=20", // tabBar路径
successs:()=>{}, // 成功的回调
fail:()=>{}, // 失败的回调
complete:()=>{} // 必定执行的回调
})
}
接收:在onLoad中接收
onLoad(options){
console.log(options)
}
页面事件
下拉刷新
通过onPullDownRefresh监听
<view> count = {{count}}</view>
<button bind:tap="addCount">
count+1
</button>
Page({
data:{
count:0
},
andCount(){
this.setData({
count:++this.data.count
})
},
onPullDownRefresh(){
this.setData({
count:0
})
wx.stopPullDownRefresh()
}
})
停止下拉刷新
当处理完下拉刷新后,下拉刷新的 loading 效果会一直显示,不会主动消失,所以需要手动隐藏下拉刷新的 loading 效果。此时,调用 wx.stopPullDownRefresh() 可以停止当前页面的下拉刷新
上拉触底
通过onReachBottom监听
无尽的颜色小案例
Page({
data:{
colorList:[],
isloading:false // 节流阀
},
getColor(){
this.setData({
isloading:true
})
// 开启loading
wx.showLoading({
title: '数据加载中'
})
setTimeout(()=>{
const arr = [1,2,3,4,5,6,7,8,9,0,'a','b','c','d','e','f']
const colorList = this.data.colorList
// const i = Math.random()*16
for(let j = 0 ; j < 30 ;j++){
let color = "#"
for(let i = 0 ; i < 6 ; i++){
const n = Math.floor(Math.random() * 16)
color = color + arr[n]
console.log(color)
}
colorList.push(color)
}
this.setData({
colorList
})
console.log(this.data.colorList)
wx.hideLoading() // 关闭loading
},3000)
this.setData({
isloading:false
})
},
// 页面加载
onLoad(options) {
this.getColor()
},
// 下拉刷新
onPullDownRefresh() {
if(isloading) return
this.setData({
colorList:[]
})
this.getColor()
wx.stopPullDownRefresh()
},
// 上拉触底
onReachBottom() {
if(isloading) return
this.getColor()
}
})
wxs脚本
虽然 wxs 的语法类似于 JavaScript,但是 wxs 和 JavaScript 是完全不同的两种语言:
①wxs 有自己的数据类型
number 数值类型、string 字符串类型、boolean 布尔类型、object 对象类型、
function 函数类型、array 数组类型、 date 日期类型、 regexp 正则
②wxs 不支持类似于 ES6 及以上的语法形式
不支持:let、const、解构赋值、展开运算符、箭头函数、对象属性简写、etc...
支持:var 定义变量、普通 function 函数等类似于 ES5 的语法
③wxs 遵循 CommonJS 规范
module 对象
require() 函数
module.exports 对象
内嵌
wxml 文件中的每个 <wxs></wxs> 标签,必须提供 module 属性,用来指定当前 wxs 的模块名称,方便在 wxml 中访问模块中的成员:
<view>{{m1.toUpper(name)}}</view>
<wxs module='m1'>
module.exports.toUpper = function(str){
return str.toUpperCase()
}
</wxs>
外联
编写在以 .wxs 为后缀名的文件内
module 用来指定模块的名称
src 用来指定要引入的脚本的路径,且必须是相对路径
在 wxs 中定义的函数不能作为组件的事件回调函数
wxs 不能调用 js 中定义的函数
wxs 不能调用小程序提供的 API
<view>{{m2.toLower(country)}}</view>
<wxs src="../xxxxxxx" module="m2"></wxs>
function toLower(str){
return str.toLowerCase()
}
module.exports = {
toLower:toLower
}
自定义组件
组件与页面的区别
- 组件的 .json 文件中需要声明 "component": true 属性
- 组件的 .js 文件中调用的是 Component() 函数
- 组件的事件处理函数需要定义到 methods 节点中
创建
①在项目的根目录中,鼠标右键,创建 components -> test 文件夹
②在新建的 components -> test 文件夹上,鼠标右键,点击“新建 Component”
③键入组件的名称之后回车,会自动生成组件对应的 4 个文件,后缀名分别为 .js,.json, .wxml 和 .wxss
注意:为了保证目录结构的清晰,建议把不同的组件,存放到单独目录中
引用
局部引用
在页面的json文件中,引入组件
{
"usingComponents":{
"my-test":"/components/test/test"
}
}
页面的wxml中使用
<my-test></my-test>
全局引用
{
"page":[],
"window":{},
"usingComponents":{
"my-test":"/components/test/test"
}
}
样式隔离
默认情况下,组件样式与页面样式互不影响
默认情况下的隔离性只对类选择器有效,id选择器,属性选择器,标签选择器依然会影响
修改隔离:在组件的js文件中添加如下配置 或 在json文件中添加配置
- isolated:启用样式隔离
- apply-shared:页面影响组件,组件不影响页面
- shared:相互影响
Component({ options:{ styleIsolation:'isolated' } }){ "styleIsolation":"isolated" }
js文件
Component({
data:{
good:{
name:'',
picUrl:''
}
},
properties:{ // 对外属性,用来接收外界传递到组件中的数据,相当于vue中的props
max:{ // 完整定义,定义类型和默认值
type:Number,
value:10
},
min:Number // 简单定义,只定义类型
},
methods:{},
observers:{ // 数据监听,类型vue中的watch
'max,min':function(maxNew,minNew){},
'good.name,good.picUrl':function(a,b){} // 监听属性或整个对象,当对象变化或指定属性变化时就会触发
'good.**':function(obj){} // 通配符监听对象及所有属性变化
}
})
<my-test max="10"></my-test>
- data用于存储组件的私有数据
- properties用于对外访问的数据
- 修改时也是使用this.setData
纯数据字段
不用于页面渲染的字段,提升渲染速度,可配置,如下
Component({
options:{
pureDataPattern:/^_/ // 配置_开头的字段为纯数据字段
},
data:{
a:'sss', // 普通字段
_b:true // 纯数据字段
}
})
组件的生命周期
常用的
created:组件实例刚被创建好的时候,created 生命周期函数会被触发
此时还不能调用 setData
通常在这个生命周期函数中,只应该用于给组件的 this 添加一些自定义的属性字段
attached:在组件完全初始化完毕、进入页面节点树后, attached 生命周期函数会被触发
此时, this.data 已被初始化完毕
这个生命周期很有用,绝大多数初始化的工作可以在这个时机进行(例如发请求获取初始数据)
detached:在组件离开页面节点树后, detached 生命周期函数会被触发
退出一个页面时,会触发页面内每个自定义组件的 detached 生命周期函数
此时适合做一些清理性质的工作
使用
可以直接在Component构造器中使用
推荐在Component构造器的lifetimes属性中使用
Component({ lifetimes:{ attached(){}, detached(){} } })
组件所在页面的生命周期
| 生命周期函数 | 参数 | 描述 |
|---|---|---|
| show | 无 | 组件所在的页面被展示时执行 |
| hide | 无 | 组件所在的页面被隐藏时执行 |
| resize | Object Size | 组件所在的页面尺寸变化时执行 |
使用
Component({
pageLifetimes:{
show(){},
hide(){},
resize(size){}
}
})
插槽
组件
<view>
<view>已知的组件的内部节点</view>
<!-- 不确定的内容,放一个插槽,使用时填充上 -->
<slot></slot>
</view>
使用
<my-test>
<view>插槽的内容</view>
</my-test>
启用多个插槽
Component({
options:{
multipleSlots:true
}
})
<view>
<view>已知的组件的内部节点</view>
<slot name="slot1"></slot>
<view>一些固定的内容</view>
<slot name="slot2"></slot>
</view>
<my-test>
<view slot="slot1">插槽内容</view>
<view slot="slot2">插槽内容</view>
</my-test>
组件通信
方式一:属性绑定:用于实现父向子传值,而且只能传递普通类型的数据,无法将方法传递给子组件
父
Component({
data:{
count:0
}
})
<my-test count="{{count}}"></my-test>
<view>------------------</view>
<view>父组件中,count={{count}}</view>
子
Component({
properties:{
count:Number
}
})
<text> 子组件中,count={{count}}</text>
方式二:自定义事件绑定:用于实现子向父传值,可以传递任何类型的数据
父
syncCount(e){
this.setData({
count:e.detail.value
})
}
<my-test count="{{count}}" bind:sysc="syscCount"></my-test>
子
Component({
properties:{
count:Number
}
methods:{
addCount(){
this.setData({
count:++this.properties.count
})
this.triggerEvent('sync',{value:this.properties.count}) // 事件名称,参数对象
}
}
})
<text>子组件中的count = {{count}}</text>
<button type="primary" bind:tap="addCount"> count + 1 </button>
方式三:获取组件实例
在父组件中调用this.selectComponent(“id或类选择器”)
<my-test count="{{count}}" bind:sysc="syscCount" class="customA"></my-test>
<button bind:tap="getChild">获取子组件实例对象</button>
getChild(){
const child = this.selectComponent('.costomA')
child.setData({
count:child.properties.count+1
})
child.addCount()
}
组件共享
behaviors类似vue中的mixins
创建
module.exports = Behaviors({
properties:{},
data:{},
methods:{},
behaviors:[],
created:function(){},
attached:function(){},
ready:function(){},
moved:function(){},
detached:function(){}
...
})
导入
const myBehavior = require("../../behaviors/my-behavior")
Component({
behaviors:[myBehavior]
})
第三方库
API Promise化
在小程序中,实现 API Promise 化主要依赖于 miniprogram-api-promise 这个第三方的 npm 包
npm i --save miniprogram-api-promise
app.js只需调用一次promisifyAll()即可实现异步api的Promise化
import {promisifyAll} from 'miniprogram-api-promise'
const wxp = wx.p = {}
promisifyAll(wx,wxp)
调用
<van-button type="danger" bindtap="getInfo">vant按钮</van-button>
async getInfo(){
const {data:res} = await wx.p.request({
method:'get',
url:'https://jpt-yf.jd.com/api/v1/adPerformance/list',
header:{
},
data:{
name:'zs',
age:20
}
})
console.log(res)
}
全局数据共享
Mobx类似vuex
引入两个包
mobx-miniprogram:用于创建Store对象
mobx-miniprogram-bindings:用来把 Store 中的共享数据或方法,绑定到组件或页面中使用
npm i --save mobx-miniprogram mobx-miniprogram-bindings
在store文件夹下新建一个js文件,创建Store实例
import {observable,action} from 'mobx-miniprogram'
export const store=observable({
numA:1,
numB:2,
get sum(){
return this.numA + this.numB
},
updateNumA:action(function(step){
this.numA += step
}),
updateNumB:action(function(step){
this.numB += step
})
})
使用:绑定到页面
import {createStoreBindings} from 'mobx-miniprogram-bindings'
import {store} from '../../store/store'
Page({
onLoad(options) {
this.storeBindings = createStoreBindings(this,{
store,
fields:['numA','numB','sum'],
actions:['updateNumA','updateNumB']
})
},
onUnload() {
this.storeBindings.destroyStoreBindings()
},
andNumA(e){
console.log(e.target.dataset.step)
this.updateNumA(e.target.dataset.step)
},
andNumB(e){
console.log(e.target.dataset.step)
this.updateNumB(e.target.dataset.step)
},
})
<view>{{numA}} + {{numB}} = {{sum}}</view>
<van-button type="primary" bindtap="andNumA" data-step="{{1}}">按钮</van-button>
<van-button type="default" bindtap="andNumB" data-step="{{-1}}">默认按钮</van-button>
绑定到成员
import {createStoreBindings} from 'mobx-miniprogram-bindings'
import {store} from '../../store/store'
Component({
behaviors:[storeBindingBehavior],
storeBindings:{
store,
fields:{
numA:()=>store.numA, // 绑定字段方式一
numB:(store)=>store.numB, // 绑定字段方式二
sum:'sum' // 绑定字段方式三
},
actions:{
updateNumA:'updateNumA',
updateNumB:'updateNumB'
}
},
methods:{
andNumA(e){
console.log(e.target.dataset.step)
this.updateNumA(e.target.dataset.step)
},
andNumB(e){
console.log(e.target.dataset.step)
this.updateNumB(e.target.dataset.step)
},
}
})
分包
对小程序进行分包的好处主要有以下两点:
可以优化小程序首次启动的下载时间
在多团队共同开发时可以更好的解耦协作
主包:一般只包含项目的启动页面或 TabBar 页面、以及所有分包都需要用到的一些公共资源
分包:只包含和当前分包有关的页面和私有资源
加载规则
在小程序启动时,默认会下载主包并启动主包内页面,tabBar 页面需要放到主包中
当用户进入分包内某个页面时,客户端会把对应分包下载下来,下载完成后再进行展示,非 tabBar 页面可以按照功能的不同,划分为不同的分包之后,进行按需下载
项目结构
- page 存放页面
- utils 存放工具代码
- packageA 分包A
- pages 分包下的页面
- page1
- page2
- packageB 分包B
- pages 分包下的页面
- page3
- page4
app.js 小程序项目的入口文件
app.json 小程序项目的全局配置文件
app.wxss 小程序项目的全局样式文件
project.config.json 项目的配置文件
project.private.config.json
sitemap.json 用于配置小程序及其页面是否允许被微信索引,如果没有,默认为所有页面允许被索引
.eslintrc.js 代码检查工具
配置
{
"page":[],
'subpackages':[{
"root":"packageA",
"pages":[{
"pages/page1",
"pages/page2"
}]
},{
"root":"packageB",
"name":"pack2",
"pages":[{
"pages/page3",
"pages/page4"
}]
}]
}
打包原则
- 小程序会按 subpackages 的配置进行分包,subpackages 之外的目录将被打包到主包中
- 主包也可以有自己的 pages(即最外层的 pages 字段)
- tabBar 页面必须在主包内
- 分包之间不能互相嵌套
独立分包
可以独立于主包和其他分包而单独运行,只需在普通的分包配置中,给独立分包加independent为true的字段
独立分包中不能引用主包内的公共资源
配置
{
"page":[],
'subpackages':[{
"root":"packageA",
"pages":[{
"pages/page1",
"pages/page2"
}]
},{
"root":"packageB",
"name":"pack2",
"pages":[{
"pages/page3",
"pages/page4"
}],
"independent":true // 独立分包
}]
}
分包预下载
{
"preloadRule":{
"page/test/test":{ // 进入页面后预下载
"network":"all", // 默认为wifi
"packages":["pack2"] // 预下载的分包,文件名root和别名name都可
}
}
}
uni-app
vue create -p dcloudio/uni-preset-vue my-project
