一、配置文件
app.json 是当前小程序的全局配置,包括了小程序的所有页面路径、界面表现、网络超时时间、底部 tab 等。
各配置项的含义:
1. pages:当前小程序所有页面路径
2. window:小程序所有页面的顶部背景颜色,文字颜色定义等
3. tabBar:底部 tab 栏的表现
4. subPackages:分包加载,在构建时打包成不同的分包,用户在使用时按需进行加载。默认会下载主包并启动主包内页面,当用户进入分包内某个页面时,客户端会把对应分包下载下来,下载完成后再进行展示
project.config.json是工具配置文件,在工具上做的任何配置都会写入到这个文件,当你重新安装工具或者换电脑工作时,你只要载入同一个项目的代码包,开发者工具就自动会帮你恢复到当时你开发项目时的个性化配置,其中会包括编辑器的颜色、代码上传时自动压缩等等一系列选项。
二、文件类型
1.JSON
配置文件,JSON文件都是被包裹在一个大括号中 {},通过key-value的方式来表达数据,JSON的Key必须包裹在一个双引号中,无法使用注释。
2.WXML
模板文件,类似HTML,由标签、属性等构成。
3.WXSS
样式文件,具有 CSS 大部分的特性。
1)新增尺寸单位rpx
2)提供了全局样式和局部样式,全局样式app.wxss会作用于小程序的所有页面,局部样式page.wxss 仅对当前页面生效
4.JS
页面交互逻辑,如响应用户的点击、获取用户的位置等。可以在 JS 中调用小程序提供的API,例如获取用户信息、本地存储、微信支付等。
微信原生 API有以下类型:
1)事件监听API
以 on 开头的 API 用来监听某个事件是否触发,如:wx.onCompassChange,它接受一个回调函数作为参数,当事件触发时会调用这个回调函数,并将数据以参数形式传入。
wx.onCompassChange(function (res) {
console.log(res.direction)
})
2)同步API
以 Sync 结尾的 API 都是同步 API,如 wx.setStorageSync,它的执行结果可以通过函数返回值直接获取,如果执行出错会抛出异常。
try {
wx.setStorageSync('key', 'value')
} catch (e) {
console.error(e)
}
3)异步API
大多数 API 都是异步 API,如 wx.request,wx.login 等。这类 API 接口通常都接受一个 Object 类型的参数。
wx.login({
success(res) {
console.log(res.code)
}
})
当接口参数 Object 对象中不包含 success/fail/complete 时将默认返回 promise,否则仍按回调方式执行,无返回值。
三、小程序的运行环境
小程序的运行环境分成渲染层和逻辑层,其中 WXML 模板和 WXSS 样式工作在渲染层,JS 脚本工作在逻辑层。
渲染层的界面使用了WebView 进行渲染;逻辑层采用JsCore线程运行JS脚本。一个小程序存在多个界面,所以渲染层存在多个WebView线程,这两个线程的通信会经由微信客户端Native做中转,逻辑层发送网络请求也经由Native转发。
打开小程序到显示第一个页面的过程:
1. 微信客户端在打开小程序之前,会把整个小程序的代码包下载到本地。
2. 小程序启动之后,在 app.js 中定义的 App 实例的 onLaunch 回调会被执行:
App({
onLaunch: function () {
// 小程序启动之后 触发
}
})
3. 通过 app.json 的 pages 字段就可以知道小程序的页面路径,pages 字段的第一个路径就是小程序的首页。
{
"pages":[
"pages/index/index",
"pages/logs/logs"
]
}
4. 微信客户端把首页的代码装载进来,pages/index/index 下包括4种文件,微信客户端会先根据 index.json 配置生成一个界面,顶部的颜色和文字都可以在这个 json 文件里定义好,紧接着客户端就会装载这个页面的 WXML 结构和 WXSS 样式。最后客户端会装载 index.js:
Page({
data: { // 参与页面渲染的数据
user:""
},
onLoad: function () {
// 页面渲染后 执行
}
})
Page 是一个页面构造器,在生成页面的时候,小程序框架会把 data 数据和 index.wxml 一起渲染出这个首页。
四、其他
1.globalData和storage的区别
globalData全局的临时变量,是内存中的数据,不能持久化,关闭小程序后 globaData就没了。
而storage是可以持久化的,是存储在本地的数据,小程序重启后,还是可以找到的。
2. 小程序在模板语法中使用js方法无效问题
在wxml页面中,只能在插值{{ }}中写简单的js表达式,而不能调用js方法,例如想取出一个字符串的最后一位,不能调用slice()方法。通常的解决办法是在page的data对象中先把这个字符串截取好赋给某个变量,在页面中使用这个变量,如果变量多了要定义很多次。
解决办法:WXS
WXS(WeiXin Script)是小程序的一套脚本语言,它是为了满足能在页面中使用js而存在的。
使用方法:
①写好wxs文件,导出要使用的方法或变量
②在待使用页面引入
③在插值{{}}中使用tools.方法名(参数)
示例如下:
// util.wxs文件
function indexOf(arr, value) {
if (arr.indexOf(value) < 0) {
return false;
}else {
return true;
}
}
module.exports.indexOf = indexOf;
// 引入
<wxs src="../../utils/util.wxs" module="tools" />
// 使用
<view>{{tools.indexOf([1, 2, 3], 1) ? '包含' : '不包含'}}</view>
3. 页面跳转,通过事件的发布订阅,实现数据传递
跳转到指定页面,通过wx.navigateTo()
wx.navigateTo({
url: '/page/entry/address/index',
success: function (res) {
//通过eventChannel向被打开页面传送数据
res.eventChannel.emit('acceptData', {
type
})
}
})
进入当前跳转页面,onload()
onLoad: function () {
const eventChannel = this.getOpenerEventChannel()
//监听acceptData事件,获取上一个页面通过eventChannel传送到当前页面的数据
eventChannel.on('acceptData', function(data) {
console.log(data)
})
}
4. onLoad与onShow的区别
onLoad: 页面加载时触发,从二级页面回来时不会触发,数据实时性要求不高可以onLoad里面触发对应的请求,可以通过options获取参数。
onShow:页面显示,切入前台触发,简单来说就是这个页面每出现一次(包括前进后退到这个页面)就调用一次,有内容修改时,把函数方法放在onShow可以使界面能及时更新。
5. 列表渲染(wx:for、wx:for-item、wx:key、wx:for-index的用法)
(1) wx:for
主要用于循环数组,进行列表渲染。在小程序中,数组当前项的下标变量名默认为 index,数组当前项的变量名默认为 item。
const cityList=[
{"id": "35", "city": "广州", "code": "152900" },
{ "id": "38", "city": "深圳", "code": "210300" }
]
页面代码:
<view wx:for="{{cityList}}" wx:key="{{item.id}}">{{item.city}} {{item.code}}</view>
(2) wx:for-item
如果数组是二维(多维)数组,需要多层嵌套wx:for,需要注意的是:在多层循环当中,内层循环会把外层循环的item覆盖掉,外层的item就取不到值。
为了弥补这个缺陷,定义了wx:for-item来指代数组当前项的别名。
(3) wx:key
如果列表中项目的位置会动态改变或者有新的项目添加到列表中,并且希望列表中的项目保持自己的特征和状态,需要使用 wx:key 来指定列表中项目的唯一的标识符。
当数据改变触发渲染层重新渲染的时候,会校正带有key的组件,框架会确保它们被重新排序,而不是重新创建,提高列表渲染时的效率。
(4) wx:for-index
使用wx:for-index来指代数组当前项下标的别名。
6.自定义组件
创建自定义组件的步骤:
(1) 新建自定义组件文件
在根目录的components文件夹,右键新建自定义组件目录
(2) 组件json文件配置
{
"component": true, //这一组文件设为自定义组件
"usingComponents": {}
}
(3) 组件wxss文件,因为全局样式不会自动导入组件内,若需要可导入
/* 自定义组件 */
@import "../../app.wxss";
在父组件中使用该自定义组件
(1) 在父组件json文件的usingComponents中导入组件
{
"usingComponents": {
"number-input":"../../../components/NumberInput"
}
}
(2) 在父组件wxml文件中以组件名作为标签使用组件
<number-input></number-input>
父子组件通信
(1) 父传子
在父组件中的子组件标签添加属性,给子组件传递数据
<number-input number="{{pcs}}"></number-input>
子组件在js中通过properties接收,可以指定接收数据类型
Component({
/**
* 组件的属性列表
*/
properties: {
number:Number, //子组件通过properties接收,可以指定接收数据类型
}
})
(2) 子传父
子组件用this.triggerEvent('自定义事件', '传递的参数'),发布自定义事件submit
this.triggerEvent("submit", this.properties.number)
在父组件中的子组件标签通过bind监听自定义事件
<number-input number="{{pcs}}" bind:submit="submitPcs"></number-input>
上一步执行后,自定义事件绑定的函数submitPcs就会执行,同时接收子组件传过来的数据。
submitPcs(e) {
this.setData({
pcs: e.detail
})
}
7. 页面跳转
wx.switchTab: 跳转到tabBar页面,并关闭其他非tabBar页面,跳转的url不能带参数。
wx.navigateTo: 保留当前页面,跳转到应用内的某个页面,url可以携带参数,但是不能跳转到tabBar页面,使用wx.navigateBack()可以返回原页面。
8.环境变量
const envVersion =__wxConfig.envVersion // envVersion类型为字符串
envVersion: 'develop', //开发版
envVersion: 'trial', //体验版
envVersion: 'release', //正式版
9.微信登录
登录流程如下
1)授权用户信息
wx.getUserProfile({
desc: '用于完善会员资料', // 声明获取用户个人信息后的用途,必须填写
success: (res) => {
this.login(res) // 具体的登录逻辑
},
fail: (res) => {
console.log(res)
}
})
2)调用wx.login()获取用户登录凭证code(有效期五分钟)
3)调用后台接口完成登录
async login(data) {
const params = {
iv: data.iv,
encryptedData: data.encryptedData,
code: this.data.code
}
const res = await userApi.fastLogin(params)
if (res && res.success) {
//调用登录接口成功后存储token
wx.setStorageSync('token', res.data)
}
}
10.微信支付
wx.requestPayment({
timeStamp: '', //时间戳
nonceStr: '',
package: '',
signType: 'MD5',
paySign: '',
success (res) { },
fail (res) { }
})
11.请求的封装
在微信小程序中使用wx.request()发送网络请求,为简化接口的调用做了一次封装,见utils/request.js。
const fetch = function(url, params, contentType,method='POST') {
const App = getApp()
return new Promise((resolve, reject) => {
wx.request({
url: BASE_URL + url,
method,
header: {
token: wx.getStorageSync('token'),
'content-type': contentType||'application/json'
},
data: params,
success(res) {
resolve(res.data)
},
fail(err) {
reject(err)
}
})
})
}