微信小程序


一、相关概念

1 基础知识

微信的前端语言类似于网站开发的前端语言:

  • HTML(wxml)
  • CSS(wxss)
  • JavaScript(js)

微信小程序开发IDE:微信小程序开发者工具。

本地开发环境:

  • 开发者工具
  • 后端API

线上部署环境:

  • 开发者工具,提交至微信(进行体验、发布)
  • API同时也需要部署到线上环境

2 工作流程

  1. 下载开发者工具:official::概览 | 微信开放文档 (qq.com)
  2. 注册小程序(ID):official::小程序 (qq.com)
    • 个人版小程序:主要是没有支付功能
    • 企业版小程序:可以结合自己的商户平台,管理支付数据。
  3. 登录账号:official::微信公众平台 (qq.com)
  4. 开发前端
  5. 开发后端

二、基本知识

1 初始界面

新建项目:绑定ID,然后后台服务不要选择云开发,云开发废钱。然后可以选择语言模版,一开始选JavaScript模板。

查看ID:Web上进行登录,登录后在开发——开发管理处查看。

初始配置:

  • 微信小程序默认是https模式。在本地测试时,需要将其修改成http模式,防止数据包无法发送到后端。修改方式:界面右上角——详细——本地设置——不校验合法域名、web-view…….HTTPS证书。

修改页面入口:最上方——普通编译——修改编译模式——修改掉启动页面

2 文件相关

文件结构:

  • pages:存放页面文件:

    • index:首页

      • index.js:当前页面js文件
      • index.json:当前页面配置文件
      • index.wxml:当前页面微信html文件
      • index.wxss:当前页面微信css文件
    • xxx:其他页面同理

  • utils:组件:

    • xxx.js:js组件,导出并进行调用
  • .eslintrc.js:eslint,语法检查

  • app.js:全局js文件

  • app.json:全局页面配置文件

    • pages:页面路径,在最前面的最先被访问
  • app.wxss:全局css

  • project.config.json:全局默认配置文件

  • project.private.config.json:全局配置文件(优先级更高)

  • sitemap.json:被微信索引的配置,一般不修改,official::配置小程序 / sitemap 配置 (qq.com)

文件夹新增:

  • 可以在根目录下新增一个images文件夹存放图片

文件操作:

  • 新建page:在pages中——右键新建文件夹——在新文件夹中——右键新建page(名字要一样)

3 wxml

组件:official::视图容器 | 微信开放文档 (qq.com)

<icon></icon>:系统自带的图标。

<!-- 相当于是html文件,但是标签有一些有区别的地方 -->
<text></text> == <span></span>
<view></view> == <div></div>
<image></image> == <img></img>
<navigator></navigator> == <a></a>
<!-- 普通跳转(非tabbar,也就是非菜单栏) -->
<navigator url='/pages/mine/mine'></navigator>
<!-- tabbar跳转 -->
<navigator url='/pages/mine/mine' open-type='switchTab'></navigator>


<!-- 属性基本也是类似,有一些不同的地方 -->
<!-- 点击事件 -->
<text bindtap="func"></text>

<!-- 传递数据,数据要以data-开头 -->
<text bindtap="func" data-nid='999' data-name='Bob'></text>

4 wxss

几乎和css一样,不同地方如下:

  • 微信小程序宽度最大是750rpx。rpx不同于px,rpx会自动根据手机分辨率进行缩放。

其他建议:

/* 和css一样,有的属性不同 */
.img{
/* rpx:不同于px,rpx会自动根据手机分辨率进行缩放 */
width: 200rpx;
}

5 js

API:official::基础 | 微信开放文档 (qq.com)

Page({
/* 初始数据 */
data: {

},

/* 自定义函数 */
func(e){
// 接收数据
console.log(e.target.dataset.nid);
console.log(e.target.dataset.name);
}


/* 其他生命周期函数 */
onLoad(options){},
})
/* 常用API */
// 跳转到非菜单栏页面
wx.naviagteTo({
url: '/pages/xxx/xxx'
})

// 跳转到菜单栏页面
wx.naviagteTab({
url: '/pages/xxx/xxx'
})

6 获取数据

可以用js中动态获取数据,不用在wxml写死。语法类似vue。

wx:key:通过key来确定唯一。official::WXML 语法参考 / 列表渲染 (qq.com)

<block></block>:相当于是<template></template>。在渲染时,该标签不会被实际渲染出来。

<tag hidden="true">:hidden,是否隐藏。当hidden为true时,标签就会被隐藏,否则会显示。注意,这个和if是由区别的。当if不成立时,标签根本不会被渲染到页面中。而当hidden为true时,标签一样会渲染到页面上,只是相当于加了一个display: none;。类似于vue中的v-ifv-show的区别。在开发中,如果有些数据有时候要展示有时候又不展示,建议使用hidden,效率更高。

<!-- info.wxml -->
<!-- 展示数据 -->
<view>
<text>{{city}}</text>
</view>

<!-- 循环 -->
<view>
<view>{{nameList[0]}}</view>
<view>{{nameList}}</view>
<!-- wx自带的循环(默认名字索引是index,内容是item)-->
<view wx:for="{{nameList}}" wx:key="index">{{index}} -- {{item}}</view>
<!-- 修改循环后的参数名称 -->
<view wx:for="{{nameList}}" wx:for-index='idx'
wx:for-item='ele' wx:key='idx'>{{idx}} -- {{ele}}</view>
</view>

<!-- 条件 -->
<view>
<text wx:if="{{city=='Beijing'}}">北京</text>
<text wx:elif="{{city=='Shanghai'}}">北京</text>
<text wx:else>其他</text>
</view>

<!-- hidden -->
<view>
<text hidden="{{ifHidden}}">发现我了</text>
</view>
// info.js
Page({
/* 初始数据 */
data: {
city: "Beijing",
nameList: ["mugi", "mio", "uyi"],
ifHidden: false
},
})
<!-- block案例 -->

<!-- Beijing所在的text会成为三级标签:view-view-text -->
<view>
<view wx:if="{{city=='Beijing'}}">
<text>China</text>
<text>Beijing</text>
</view>
</view>
<!-- Beijing所在的text会成为二级标签:view-text -->
<view>
<block wx:if="{{city=='Beijing'}}">
<text>China</text>
<text>Beijing</text>
</block>
</view>

7 修改数据

可以通过js相关API对数据进行修改。

在此处,数据并不是双向绑定的。也就是说当用户在input输入框中输入值后,js中的值并不会立刻同步发生改变,需要执行一次this.setData({})才会发生改变。

如果要实现双向绑定,可以给input绑定上bindinput事件,然后事件每次更新数据,这样就可以手动实现双向绑定。

当然现在微信也新增了双向绑定,只需要model:value="{{name}}"即可实现双向绑定。(老版本微信可能使用后会报警告,需要再加上一个bindinput="func"警告才会消除。绑定的函数可以没有任何内容,但是必须绑定一个函数)

input的数据和之前的data-绑定的数据获取方式有些不同。用data-的数据会存在e.target.dataset中,然后通过e.target.dataset.xxx获取。而input的数据是存在e.detail.value中,通过e.detail.value进行获取。如果是一个form,里面的input就需要定义名称,然后通过e.detail.value.xxx进行获取

<!-- info.wxml -->
<!-- 展示数据 -->
<view>
<text>显示:{{name}}</text>
<button bindtap="setName">点击后修改名字为Tom</button>
</view>

<!-- 单向绑定(input内容改变显示内容不会立刻改变) -->
<view>
<form bindsubmit='setOneWayName'>
<text>显示:{{oneWayName}}</text>
<input type="text" name="inputValue" value="{{oneWayName}}" placeholder="单向绑定案例"/>
<button formType="submit">点击后修改名字</button>
</form>
</view>

<!-- 双向绑定(input内容改变显示内容立刻改变) -->
<view>
<text>显示:{{twoWayName}}</text>
<input type="text" value="{{twoWayName}}" placeholder="双向绑定案例" bindinput="setTwoWayName"/>
</view>

<!-- 微信新增的双向绑定 -->
<view>
<text>显示:{{modelName}}</text>
<input type="text" model:value="{{modelName}}" />

<!--
老版本需要绑定一个空函数来消除警告
<input type="text" model:value="{{modelName}}" bindinput="emptyFunc" />
-->
</view>

<!-- 向后新增数据 -->
<view>
<text>显示:{{addList}}</text>
<button bindtap="addOne">加一个</button>
</view>
// info.js
Page({
/* 初始数据 */
data: {
name: 'Bob',
oneWayName: 'One',
twoWayName: 'Two',
modelName: 'Model',
addList: ['我']
},

setName() {
this.setData({
name: 'Tom'
})
},

setOneWayName(e) {
this.setData({
oneWayName: e.detail.value.inputValue
})
},

setTwoWayName(e) {
// input的数据存在于e.detail.value中
this.setData({
twoWayName: e.detail.value
})
},

emptyFunc() {},

// 因为使用的API是setData,所以在新增数据时,需要修改原数组,然后重新赋值
addOne() {
let arr = this.data.addList
arr = arr.concat('我')
this.setData({
addList: arr
})
}
})

8 tabBar

文档:official::小程序配置 / 全局配置 (qq.com)

tabBar需要在全局配置中进行配置。只能配置最少 2 个、最多 5 个 tab。

// app.json(使用案例时将注释去除)
{
"pages": [],
// 新增tabBar
"tabBar":{
// 导航栏位置
"position": "bottom",
// 被选中时图标颜色
"selectedColor": "#b4282d",
"list": [
// 字典顺序就是图标从左向右显示的顺序
{
// 页面路径
"pagePath": "pages/index/index",
// 文字
"text": "首页",
// 图标路径
"iconPath": "images/index.png",
// 被选中后图标路径(尽量不和未选中的图标一样)
"iconPath": "images/index_select.png",
},
{
"pagePath": "pages/my/my",
"text": "我的"
}
]
},
}

9 json常见配置

{
"usingComponents": {},
// 导航栏背景颜色
"navigationBarBackgroundColor": "#01ccb6",
// 顶端文字
"navigationBarTitleText": "",
// 是否支持下拉刷新(下拉刷新操作在js中写在onPullDownRefresh()中)
"enablePullDownRefresh": true,
// 左上角返回箭头或返回首页的颜色
"navigationBarTextStyle": "white",
// 背景颜色
"backgroundColor": "#01ccb6"
}

10 导入图标

本导入图标的方式为阿里巴巴矢量库。

还有别的不同的方式:

阿里巴巴导入:

  1. 找到图标,加入到库。
  2. 在右边找到购物车,将图标加入到项目,没有就随便新建一个。
  3. 在顶端栏找到资源管理——我的项目——我发起的项目。
  4. 点击项目,点击Font class,点击查看在线链接,点击生成代码。
  5. 点击css链接,然后复制代码,在微信小程序的根目录下新建一个styles,然后新建一个iconfont.wxss,然后把代码放进去。
  6. 使用时,可以选择全局引入,也可以选择局部引入。
/* iconfont.wxss */
/* 基础文件 */
@font-face {
font-family: "iconfont"; /* Project id 4582307 */
src: url('//at.alicdn.com/t/c/font_4582307_x7qu0xxxh4g.woff2?t=1718165133495') format('woff2'),
url('//at.alicdn.com/t/c/font_4582307_x7qu0xxxh4g.woff?t=1718165133495') format('woff'),
url('//at.alicdn.com/t/c/font_4582307_x7qu0xxxh4g.ttf?t=1718165133495') format('truetype');
}

/* 图标配置 */
.iconfont {
font-family: "iconfont" !important;
font-size: 16px;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}

/* 图标 */

.icon-renlianshibie_o:before {
content: "\eb67";
}

.icon-xuanfeng:before {
content: "\e607";
}
/* app.wxss */
/* 全局导入图标文件 */
@import"./styles/iconfont.wxss";

/* 如果需要修改图标大小可以如下修改
.iconfont{
font-size: 32px;
}
*/

三、常用API

1 界面API

相关API:official::界面 / 交互 / wx.showToast (qq.com)

wx.showToast:中间的弹窗。

wx.showLoading:加载中。

wx.showModel:可确认和取消的弹窗。

wx.showActionSheet:多选弹窗。

<!-- info.wxml -->
<view bindtap="myAlert">点我微信到账</view>
<view bindtap="myModal">点我确认微信到账</view>
<view bindtap="myActionSheet">点我选择微信到账金额</view>
// info.js
Page({
data: {
moneyList: ['1000', '2000', '3000']
},

myAlert() {
// 显示加载消息
wx.showLoading({
title: '等待到账'
})

setTimeout(() => {
// 隐藏加载消息
wx.hideLoading()

successInfo()
}, 2000)
},

myModal() {
// 显示模态框(选择框)
wx.showModal({
title: '打钱',
content: '要我给你打钱吗',
success: (res) => {
if (res.confirm) {
successInfo()
} else if (res.cancel) {
errorInfo()
}
}
})
},

myActionSheet() {
// 显示操作框
wx.showActionSheet({
itemList: this.data.moneyList,
success: (res) => {
// 通过res.tapIndex获取索引
successInfo(this.data.moneyList[res.tapIndex])
},
fail: () => {
errorInfo()
}
})
}
})

function successInfo(money = 2000) {
// 显示成功消息
wx.showToast({
title: `微信到账${money}元`,
icon: 'success',
duration: 2000
})
}

function errorInfo() {
// 显示失败消息
wx.showToast({
title: '微信没有到账',
icon: 'error',
duration: 2000
})
}

2 网络API

通讯规则:official::基础能力 / 网络 / 使用说明 (qq.com)

相关API:official::网络 / 发起请求 / wx.request (qq.com)

wx.request:向后端发送请求

wx.chooseImage:选择图片(已放弃维护,新版本要用wx.chooseMedia

wx.chooseMedia:选择媒体资源

wx.uploadFile:上传图片

<!-- info.wxml -->
<view bindtap="submitData">点我发送网络包</view>
<view bindtap="uploadFile">点我上传图片</view>
// info.js
Page({
data: {},

submitData() {
wx.request({
// 默认get
method: 'POST',
// 后端网址
url: 'http://127.0.0.1:8000/v1/info',
// 数据
data: {
name: ['张三', '李四'],
age: 18
},
// 请求头
header: {
// 不写默认是json
'content-type': 'application/json'
},
// 成功后获得后端返回的数据
success: (res) => {
console.log(res)
},
// 失败后获得后端返回的数据
fail: (err) => {
console.log(err)
}
})
},

uploadFile() {
// 选择图片
wx.chooseMedia({
count: 1,
mediaType: ['image'],
sourceType: ['album', 'camera'],
success(res) {
// 获得图片路径
const tempFilePaths = res.tempFilePaths
// 上传图片
wx.uploadFile({
// 后端网址
url: 'http://127.0.0.1:8000/v1/upload',
// 文件路径
filePath: tempFilePaths[0],
// 后端接收的参数名
name: 'file',
// 额外数据
formData: {
// 后端接收的参数名
user: '张三'
},
success: (res) => {
console.log(res)
},
fail: (err) => {
console.log(err)
}
})
}
})
}
})