进入 微信公众平台 进行注册。
选择小程序:
注意这里的邮箱,必须是之前没有和微信有过联系的邮箱:
邮箱激活就是打开邮箱点击新连接,跳转至信息登记页面:
注意这里的主体类型,选择不同的类型,需要填写和上传不同的资质。
注意:如果主体类型选择的是企业,则后面的步骤需要使用企业银行账户向腾讯指定账号打款,以此进行企业验证,打的款后面验证步骤完成后会退回,而在后面一些小程序资质认证相关步骤,主体类型为企业的,仍需要支付300元,来使用第三方服务来辅助,必须的步骤了。
开发前端时,我们使用浏览器来预览项目,开发小程序,同样需要一个用来预览的工具,这个工具能模拟微信的小程序环境。
它不仅是个小程序浏览器,也可以进行开发编辑等等,但可能用的少,使用不习惯,所以可以使用其他代码编辑器开发,使用开发者工具来预览和调试,真的把它当成一个「浏览器」来使用。
下载微信官方的 微信开发者工具。
开发者工具下载完成,打开后使用微信扫一扫登录后,界面如下:
可以选择用来开发或引入不同类型的项目。
点击导入或新建小程序,导入小程序会让你选择一个目录,新建小程序的界面如下:
最后点击新建,会自动创建目录,生成一个无实际内容的项目结构。
小程序的语法,和 vue 是极度类似的。
每个页面,有 wxml、wxss、js 和 json 四个文件,json 作为页面的配置文件,暂时忽略。
wxml 就是起着 html 的作用,内部结构类似于 vue 的 template 中的内容,内部标签做过封装的 html。
wxss 的样式上,默认情况,只有全局的 app.wxss 内样式会全局生效,单个页面或组件的样式文件,只影响本身的样式,不会影响全局、子组件、其他组件等,但如果有需要求,需要样式穿透,需要修改该页面或组件的 js 中的 options.styleIsolation 字段,详见 组件样式隔离。
/pages/
:页面文件们
index/
:一个页面,里面的文件名和此文件夹名一致,只是格式不同
index.js
:js 文件,此页面的逻辑开发文件index.json
:json 文件,配置文件,可在此页面,覆盖配置全局 /app.json 文件中的某些配置index.wxml
:wxml 文件,页面结构,类似于 html 文件index.wxss
:wxss 文件,页面中的样式,类似于 css 文件logs/
:另一个页面
logs.js
logs.json
logs.wxml
logs.wxss
/utils/
:给用户预留的用来写工具的文件夹,可删/app.js
:项目总入口js,项目初始化、全局钩子函数等等/app.json
:项目全局配置文件,路由配置、顶部栏和顶部栏的功能和样式配置等等/app.wxss
:项目全局样式文件/project.config.json
:项目信息等,类似于 npm 的 package.json 文件/sitemap.json
:微信索引配置文件身为入口文件,需要初始化 app,同时可以绑定一些 app 级的钩子函数、全局方法、全局变量等。
可以写一些其他方法,用此文件可以用 this 可以访问,其他页面需要用 getApp() 方法,拿到 App 实例对象后访问。
App({
onLaunch() {}, // 钩子函数,App 刚被打开
onHide() {}, // 钩子函数,App 被隐藏,进入后台
onShow() {}, // 钩子函数,App 从后台打开至前台
onError(error) {}, // 事件监听,发生错误
onPageNotFound() {}, // 事件监听,第一次打开时,默认页面没找到(一般是由于路径写错了)
onThemeChange() {}, // 事件监听,监听到系统主题变化
// 其他对象,比如下面这个惯例用来存放全局数据
globalData: {},
})
该文件为项目的整体配置文件,包括页面路由、插件、网络超时时间等均在此文件配置,页面内容可配置内容如下:
{
pages: [], // 必填 页面路径列表,无论是页面(使用 Page 生成)还是组件(使用 Component 生成),都可以作为页面使用
entryPagePath: '', // 小程序默认启动首页
window: {}, // 全局的默认窗口表现
tabBar: {}, // 底部 tab 栏的表现
networkTimeout: {}, // 网络超时时间
debug: boolean, // 是否开启 debug 模式,默认关闭
functionalPages: boolean, // 是否启用插件功能页,默认关闭
subpackages: {}, // [] 分包结构配置
workers: '', // Worker 代码放置的目录
requiredBackgroundModes: [], // 需要在后台使用的能力,如「音乐播放」
plugins: {}, // 使用到的插件
preloadRule: {}, // 分包预下载规则
resizable: boolean, // PC 小程序是否支持用户任意改变窗口大小(包括最大化窗口);iPad 小程序是否支持屏幕旋转。默认关闭
usingComponents: {}, // 全局自定义组件配置 开发者工具
permission: {}, // 小程序接口权限相关设置
sitemapLocation: '', // 指明 sitemap.json 的位置
style: '', // 指定使用升级后的weui样式
useExtendedLib: {}, // 指定需要引用的扩展库
entranceDeclare: {}, // 微信消息用小程序打开
darkmode: boolean, // 小程序支持 DarkMode
themeLocation: '', // 指明 theme.json 的位置,darkmode为true为必填 开发者工具 1.03.200427
lazyCodeLoading: '', // 配置自定义组件代码按需注入
singlePage: {}, // 单页模式相关配置
}
对于路由的触发方式以及页面生命周期函数如下:
路由方式 | 触发时机 | 路由前页面 | 路由后页面 |
---|---|---|---|
初始化 | 小程序打开的第一个页面 | onLoad, onShow | |
打开新页面 | 调用 API wx.navigateTo 使用组件 <navigator open-type="navigateTo"/> |
onHide | onLoad, onShow |
页面重定向 | 调用 API wx.redirectTo 使用组件 <navigator open-type="redirectTo"/> |
onUnload | onLoad, onShow |
页面返回 | 调用 API wx.navigateBack 使用组件 <navigator open-type="navigateBack"> 用户按左上角返回按钮 |
onUnload | onShow |
Tab 切换 | 调用 API wx.switchTab 使用组件 <navigator open-type="switchTab"/> 用户切换 Tab |
各种情况请异步官方文档 | |
重启动 | 调用 API wx.reLaunch 使用组件 <navigator open-type="reLaunch"/> |
onUnload | onLoad, onShow |
是小程序中,使用 js 能实现的功能,主要是通过 wx[方法名] 的方式使用,也有其他方式的调用,其功能包括并不限于基础、系统、更新、小程序、调试、定时器、环境变量、路由、界面、交互、键盘、发起请求、下载、上传...等功能,具体参考官方文档吧,功能太多了。
使用 Page 方法初始化页面,传入一个对象,这个对象可以用来编写逻辑
Page({
data: {}, // 页面的初始数据
options: {}, // 页面的组件选项,同 Component 构造器 中的 options ,需要基础库版本 2.10.1
onLoad() {}, // 生命周期—监听页面加载
onShow() {}, // 生命周期—监听页面显示
onReady() {}, // 生命周期—监听页面初次渲染完成
onHide() {}, // 生命周期—监听页面隐藏
onUnload() {}, // 生命周期—监听页面卸载(一般跳转页面,不会卸载)
onPullDownRefresh() {}, // 监听用户下拉动作
onReachBottom() {}, // 页面上拉触底事件的处理函数
onShareAppMessage() {}, // 用户点击右上角转发
onShareTimeline() {}, // 用户点击右上角转发到朋友圈
onAddToFavorites() {}, // 用户点击右上角收藏
onPageScroll() {}, // 页面滚动触发事件的处理函数
onResize() {}, // 页面尺寸改变时触发,详见 响应显示区域变化
onTabItemTap() {}, // 当前是 tab 页时,点击 tab 时触发
// 其他 any 开发者可以添加任意的函数或数据到 Object 参数中,在页面的函数中用 this 可以访问
})
定义变量:
// pages/index/index.js
Page({
/**
* 页面的初始数据
*/
data: {
name: '我的名字',
people: {
name: 'people 的名字',
age: 18,
},
},
}
修改变量:
// 没错,用法和 react 的 this.setState 很相似,和 react 不同的是,this.setData 是一个同步函数
console.log(this.data.name) // 我的名字
this.setData({
name: '新的名字',
'people.age': 19, // 只修改 people 的 age 字段,等效于下面注释的内容
// people: {
// ...this.data.people,
// age: 19,
// }
})
console.log(this.data.name) // 新的名字
类似于 html 中的事件,小程序也支持很多事件,比如点击事件 tap、手指触摸动作开始 touchstart 等等,
这些事件有多个绑定方式,把绑定方式拼接在事件前即可:
注意: 不能在事件中传值,只能写一个方法名,想传数据,需要设置为标签的自定义属性,再在事件对象中获取。
使用时,需要添加前缀 bind: 比如:
<view bindtap="clickName" data-age="{{people.age}}">{{people.name}}</view>
事件方法
Page({
clickName(e) {
console.log(e)
// 将打印事件对象,包含点击位置、点击对象、点击对象的位置信息、绑定的自定义属性等
}
})
常用事件:
onLoad(options):生命周期函数--监听页面加载
onReady():生命周期函数--监听页面初次渲染完成
onShow():生命周期函数--监听页面显示
onHide():生命周期函数--监听页面隐藏
onUnload():生命周期函数--监听页面卸载
onPullDownRefresh():页面相关事件处理函数--监听用户下拉动作
onReachBottom():页面上拉触底事件的处理函数
onShareAppMessage():用户点击右上角分
类似于前端开发的 localStorage,小程序也有:storage。
以下是操纵 storage 的方法的同步版本,把 Sync 去掉就是异步版本,但用法会有所不同,需要添加成功失败的回调函数等等,详情异步官方教程。
wx.setStorageSync(key, value) // 设置
wx.getStorageSync(key) // 获取
wx.removeStorageSync(key) // 移除
wx.getStorageInfoSync() // 获取 storage 存储信息
wx.clearStorageSync() // 清空 storage
wxml 和 html 变化比较大的是下面两个:
所以小程序的代码中,看不到 div 和 span,但可能会看到大量的 view 和 text 标签。
有以下特性:
等输入,需要添加 decode 属性支持 JPG、PNG、SVG、WEBP、GIF 等格式。
页面链接,类似 a 标签,但 navigator 是块级元素。
样式相关属性:
一个关键属性 open-type,取值如下:
小程序提供的一些iconfont,没几个,通过 type、size、color 来控制展示。
变量需要使用双花括号引入,直接写 js 中 data 对象中定义好的字段即可。
如果是标签的自定义属性,需要添加 data- 前缀,否则无法显示。
<view>{{name}}</view>
<view data-age="{{people.age}}">{{people.name}}</view>
在 js 中绑定数组 list
Page({
data: {
list: [
{
thisId: 1,
name: '名字1'
},
{
thisId: 2,
name: '名字2'
},
{
thisId: 3,
name: '名字3'
},
],
},
}
在 wxml 中使用
<view
wx:for="{{list}}"
wx:key="thisId"
wx:for-index="index"
wx:for-item="item"
>
<view>索引值:{{index}}</view>
<view>名字:{{item.name}}</view>
</view>
wx:for 也可以遍历对象,遍历对象时 wx:for-index 为当前字段的 key,wx:for-item 为当前字段的值。
<view wx:if="{{false}}">不渲染</view>
<view wx:elif="{{false}}">不渲染</view>
<view wx:else="{{false}}">渲染</view>
<view wx:hidden="{{true}}">不显示</view>
在 WXML 中,普通的属性的绑定是单向的,但有时这个会比较麻烦,尤其输入框的值,比如:
<!-- 当 value 值改变时,input 显示的值也会变化,但当用户修改 input 时,this.data.value 却不会变 -->
<input value="{{value}}" />
如果想实现类似 vue 的 v-model 功能,则可以是用「简易双向绑定机制」
可以在对应项目之前加入 model: 前缀:
<input model:value="{{value}}" />
当用户修改 input 的值时,this.data.value 的值,也会相当于执行了 this.setData() 一样,同时被修改。
还可以在使用自定义组件时,使用简易双向绑定功能
<!-- 父组件的 wxml -->
<!-- 把 this.data.pageValue 传递给子组件的 myValue -->
<MyComponent model:my-value="{{pageValue}}"></MyComponent>
// 子组件的js
Component({
properties: {
myValue: String, // 接收值
},
ready() {
// 直接更新 myValue,此时父组件的 this.data.pageValue 也会被同步修改
this.setData({
myValue: 'leaf'
})
}
})
WXML 提供两种文件引用方式:import 和 include 两个标签。
import 可以在该文件中使用目标文件定义的 template。
使用 <import src="wxml 文件路径">
引入其他 wxml 文件,然后就可以使用此文件定义的模板 template 了。
<import src="item.wxml"/>
<template is="item" data="{{text: 'forbar'}}"/>
include 标签可以将目标文件除了 <template/>
<wxs/>
外的整个代码引入,相当于是拷贝到 include 位置
比如:
<include src="header.wxml"/>
<view> body </view>
wxs 脚本,类似于 html 中的 script 标签,可以写脚本。
但 wxs 脚本的语法基于 js,但和 js 有一些不同。
最好还是不要使用。
规定页面宽度固定是 750rpx(类似于 css 的 vw、vh 的概念),使用 rpx 可以保证无论多大尺寸的屏幕上,元素的大小比例都是一样的。
在某个 wxss 文件中引入其他的 wxss 文件,需要使用 @import,只支持相对路径引入,比如:
@import "../index/index.wxss";
一般会再根目录下,创建一个 /components 文件夹,放置所有的组件,比如:
/components/
:组件文件们
Tabs/
:一个组件,里面的文件名和此文件夹名一致,只是格式不同
Tabs.js
:js 文件,此组件的逻辑开发文件Tabs.json
:json 文件,配置文件,可在此组件,覆盖配置全局 /app.json 文件中的某些配置Tabs.wxml
:wxml 文件,组件结构,类似于 html 文件Tabs.wxss
:wxss 文件,组件中的样式,类似于 css 文件/pages/
:页面文件们/utils/
:给用户预留的用来写工具的文件夹,可删/app.js
:项目总入口js,项目初始化、全局钩子函数等等/app.json
:项目全局配置文件,路由配置、顶部栏和顶部栏的功能和样式配置等等/app.wxss
:项目全局样式文件/project.config.json
:项目信息等,类似于 npm 的 package.json 文件/sitemap.json
:微信索引配置文件其中 json 文件默认内容如下:
{
"component": true,
"usingComponents": {}
}
js 文件默认内容如下(去除了无用的换行和空格):
// components/Tabs/Tabs.js
Component({
properties: {}, // 组件的属性列表
data: {}, // 组件的初始数据
methods: {}, // 组件的方法列表
created() {}, // 生命周期函数-在组件实例刚刚被创建时执行,注意此时不能调用 setData
attached() {}, // 生命周期函数-在组件实例进入页面节点树时执行
ready() {}, // 生命周期函数-在组件布局完成后执行
moved() {}, // 生命周期函数-在组件实例被移动到节点树另一个位置时执行
detached() {}, // 生命周期函数-在组件实例被从页面节点树移除时执行
error(error) {}, // 每当组件方法抛出错误时执行
// 和页面相关的生命周期函数
show() {}, // 页面被展示
hide() {}, // 页面被隐藏
resize(size) {}, // 页面尺寸变化
observers: {}, // 组件数据字段监听器,用于监听 properties 和 data 的变化,参见 数据监听器
behaviors: [], // 类似于mixins和traits的组件间代码复用机制,参见 behaviors
relations: {}, // 组件间关系定义,参见 组件间关系
externalClasses: [], // 组件接受的外部样式类,参见 外部样式类
})
已经写完一个组件,比如写了 /components/Tabs/Tabs 组件,那么这个组件就是「被使用组件」,需要使用该组件的页面或组件,称为「使用者」。
打开使用者的 json 文件,在 usingComponents 字段中添加被使用组件,可以使用相对路径或绝对路径:
"usingComponents": {
"Tabs": "../../components/Tabs/Tabs"
// "Tabs": "/components/Tabs/Tabs"
}
然后打开使用者的 wxml 文件,直接使用标签即可。
<!-- 使用者的 wxml -->
<Tabs><Tabs>
假设父组件为 /pages/index/index,子组件为 /components/Tabs/Tabs。
<!-- /pages/index/index.wxml 中 -->
<Tabs name="小明" age="{{18}}"></Tabs>
在子组件的 properties 属性中进行接收,即可把传来的字段,认为是注册在 data 中一样使用了。
// /components/Tabs/Tabs.js 中
Component({
/**
* 组件的属性列表
*/
properties: {
name: {
type: String, // 将会把传来的值,隐形转换为 type 指定的类型
value: '没有传 name', // 如果父组件没有传这个值时的缺省值
},
age: Number, // 可以直接指定 type 即可,不设置缺省值
},
ready() {
console.log(this.data.name) // 小明
console.log(this.properties.name) // 小明
},
// ...其他字段省略
})
子组件使用方法 this.triggerEvent() 方法,触发父组件监听的方法,并传递数据和配置。
父组件使用 bind{事件名} 来监听子组件事件,并绑定方法进行处理。
this.triggerEvent(name, detail, options)
假设父组件为 /pages/index/index,子组件为 /components/Tabs/Tabs。
子组件发射数据
// /components/Tabs/Tabs.js 中的某方法中
this.triggerEvent('tabsSend', 'from Tabs Data') // 触发 pageEventListener
父组件接受数据
<!-- 父组件 /pages/index/index.wxml -->
<!-- 绑定事件监听,使用 bind{事件名} -->
<Tabs bindtabsSend="tabsSend"></Tabs>
父组件处理接受到事件后的方法
// 父组件 /pages/index/index.js
Page({
// 添加方法 --- 如果为组件,需要把方法写在 methods 对象中。
tabsSend(e) {
// e.detail 即为传过来的数据
console.log(e.detail) // from Tabs Data
}
})
和 vue 的插槽类似。
默认可支持单个不具名插槽,如果需要多个插槽,也就是具名插槽,需要在该该组件的 js 文件的 options 配置对象中,添加 multipleSlots: true。
假设父组件为 /pages/index/index,子组件为 /components/Tabs/Tabs。
子组件开发时,做好预先处理,使用 留好位置:
<!-- /components/Tabs/Tabs -->
<view>子组件中</view>
<slot></slot>
<!-- /components/index/index -->
<Tabs>
<view>这是父组件传入的节点</view>
</Tabs>
behaviors 是用于组件间代码共享的特性,类似于一些编程语言中的 “mixins” 或 “traits”。
每个 behavior 可以包含一组属性、数据、生命周期函数和方法。组件引用它时,它的属性、数据和方法会被合并到组件中,生命周期函数也会在对应时机被调用。 每个组件可以引用多个 behavior ,behavior 也可以引用其它 behavior 。
只有组件才能使用 behaviors,且 behaviors 中可以再引入使用其他的 behaviors。
behaviors 中会有和组件相同的字段或方法的定义,其遵循:「同名字段的覆盖和组合规则」
其大致规则如下:
创造一个 behaviors:
// /components/behavior_1.js 中
module.exports = Behavior({
properties: {}, // 同组件的属性
data: {}, // 同组件的数据
methods: {}, // 同自定义组件的方法
behaviors: [], // 引入其它的 behavior
created() {}, // 生命周期函数
attached() {}, // 生命周期函数
ready() {}, // 生命周期函数
moved() {}, // 生命周期函数
detached() {}, // 生命周期函数
})
引入使用 behaviors:
// 某个组件中
// 先引入
const behaviors_1 = require('../behavior_1')
// 再使用
Component({
behaviors: [ behaviors_1 ],
// 其他字段...
})
内置 behaviors
小程序内置一些 behaviors,自定义组件可以通过引用内置的 behavior 来获得内置组件的一些行为:
Component({
behaviors: ['wx://form-field']
})
更多内置 behaviors 参考官方文档。
只有组件才有的数据监听功能 observers,其类似于 vue 的 watch。
observers 是 setData 方法执行时被触发时,监听的变量被赋值,哪怕赋值前后的值无变化,也会被触发。
Component({
data: {
numA: 1,
numB: 100,
numAll: 0,
people: {name: '小明'},
list: [0, 1, 2],
},
// 监听数据变化
observers: {
// 监听 numAll 被修改
numAll(numAll) {},
// 在 numA 或者 numB 被设置时,执行这个函数
'numA, numB'(numA, numB) {},
// 监听 people.name 被修改
'people.name'(name) {},
// 监听数组 list 第一项被修改
'list[0]'(list0) {},
// 监听 people 任何一项被修改
'people.**'(people) {},
// 每次 setData 时都触发
'**'(data) {},
},
})
data 中定义的字段,和 properties 接受的属性们,都可以使用再 wxml 中,但很多时候,我们的一些字段仅仅是记录在 js 中使用,而并不会参与页面展示。
这时可以把这个字段定义为「纯数据字段」,不用于 WXML 中的界面渲染,可以用于提升页面更新性能。
使用方式就是指定规则,然后 data 和 properties 属性中所有符合规则的数据,都被指定为纯数据字段。
使用方式一:在 js 中设置 ,在组件的 js 文件中,给 options 配置对象添加 pureDataPattern 字段,赋值正则表达式。
Component({
options: {
pureDataPattern: /^_/ // 指定所有 _ 开头的数据字段为纯数据字段
},
data: {
a: 1,
_a: 123, // 纯数据字段
},
properties: {
a: Boolean,
_b: { // 纯数据字段
type: Boolean,
observer() {}, // 不要这样做!这个 observer 永远不会被触发
},
}
})
使用方式二:在 json 中设置 ,在组件的 json 文件中,给 options 配置对象添加 pureDataPattern 字段,赋值正则表达式的字符串。
{
"pureDataPattern": "^_"
}