一、基本概念
微信小程序:它是一种不需要下载安装即可使用的应用程序,它基于微信平台开发,能够在微信内直接运行的小型化的应用程序。相较于传统的原生应用程序,小程序具有轻量化、便捷性的特点,无需在设备上进行繁琐的下载和安装过程,用户可以直接在微信中查找和使用。它的主要用途涉及生活服务、购物消费、社会娱乐等方面
WXML:全称是 WeiXin Markup Language,即微信标记语言。专门为微信小程序设计的一种描述页面结构的标记语言, 用于定义小程序页面的布局和内容结构。WXML的核心功能可以概括为以下几点:
1、定义页面结构:在 WXML 中,开发者可以通过特定的标签来显示文本、图片、视频、按钮等页面元素,以及将数据绑定到页面中
2、数据绑定:在 WXML 中,双大括号{
{}}
用于数据绑定,允许开发者将 JavaScript 代码中的数据动态地绑定到页面上,例如 <text>{
{userName}}</text>。
3、UI 组件:WXML 还定义了小程序的 UI 组件。微信小程序提供了丰富的内置组件,如 view
、button
、image
、swiper
(轮播图)等。开发者可以使用这些组件来构建页面,类似于 HTML 中的 div
、button
、img
等元素,例如 <button bindtap="onTap">点击我</button>。
4、WXSS:WXML 主要用于定义页面的结构,而 WXSS(微信样式表)则用于定义页面的样式。WXSS 与 CSS 类似,但在某些方面有所不同,如支持小程序的尺寸单位(如 rpx
,响应式单位),例如 <view class="container">{
{text}}</view>。
5、组件化和模板支持:WXML 支持组件化开发,开发者可以在 WXML 中嵌套自定义组件,类似于 Web 开发中的 Web Components 或 Vue、React 等框架的组件化机制。组件可以包含自己的模板、样式和逻辑,形成独立的功能模块,例如 <custom-component></custom-component>。
(WXML 用来描述微信小程序页面的结构和内容,类似于 HTML,但专门针对微信小程序的需求进行了优化)
WXSS:全称是Weixin Style Sheets,即微信样式表。是微信小程序特有的样式表语言。WXSS 主要与 WXML结合使用,WXML 是微信小程序的结构层,负责页面元素的布局和结构,而 WXSS则负责定义页面元素的样式。WXSS 的语法与标准的 CSS 基本相同,支持选择器、属性和值来设置元素的样式,但是WXSS 采用 rpx(响应式像素)作为布局单位,而不是传统的 px 或 em。rpx
是微信小程序特有的单位,能够根据设备屏幕的宽度自适应调整,具有更好的跨设备适配能力。例如:
.button {
background-color: #4CAF50;
color: white;
padding: 15rpx 32rpx;
}
(通过使用 WXSS,开发者能够对小程序的界面和用户体验进行精确控制,同时确保跨设备的一致性,并使得开发过程更加高效)
JS/TS:JavaScript(简称JS)是一种脚本语言,用于网页的客户端编程。其设计目标是使网页更加互动和动态,支持浏览器端的脚本执行。而TypeScript 是 JavaScript 的超集,它在 JavaScript 的基础上引入了静态类型,即允许开发者在编写代码时显式地指定变量的类型。
(在微信小程序的开发中,JavaScript 和 TypeScript 都可以用于编写前端逻辑代码)
WXS:全称是Weixin Script,即微信脚本。它与 JavaScript (JS) 相似,但专为小程序前端开发设计,存在有一些不同的特点和用途。与 JS 不同的是,WXS 主要运行在微信小程序的渲染引擎中,不能直接访问小程序的 API,因此它的功能和用途较为有限。它是微信为小程序定制的一种轻量级脚本语言,用于在小程序页面中处理数据,做一些计算、过滤、格式化等任务,通常用于模板中或页面逻辑中需要频繁计算的部分。常见的应用场景包括
1、数据格式化:可以用 WXS 来格式化日期、数字等常见的数据类型,减少 JS 代码的复杂度。例如,格式化时间戳为用户友好的时间字符串。
2、列表过滤和排序:在模板渲染时,可以使用 WXS 进行数据的过滤、排序、查找等操作,尤其是在数据量较大时,WXS 的执行效率较高。
3、简单计算和逻辑处理:例如,计算折扣、价格、库存等常见的数字处理。
例如:
pages/cart/cart.wxs:
module.exports = {
formatPrice: function (price) {
return "¥" + price.toFixed(2); // 保留两位小数并加上“¥”符号
}
}
pages/cart/cart.wxml:
<view>
<view wx:for="{
{items}}" wx:key="index">
<text>{
{wxs.formatPrice(item.price)}}</text>
</view>
</view>
(WXS 专注于前端渲染时的计算任务,可以提高页面渲染效率,WXS 可以与 JavaScript 配合使用,从而在保证页面性能的同时,处理数据展示和逻辑操作,提升小程序的用户体验)
组件化开发:它是一种将系统或应用分解为多个独立、可重用的组件的开发方法。核心理念是将复杂的系统拆分成多个小而独立的模块,这些模块(或组件)可以单独开发、测试、更新和维护,并且能够在多个地方重复使用。具有模块化、重用性、可维护性、易于扩展等特点。
(微信小程序本身就支持组件化开发,可以通过自定义组件的方式来进行开发,因此微信小程序的组件可以分为两类,一是原生组件:微信提供的一些基础组件,如 <view>
、<button>
、<text>
等,都是由微信小程序官方提供的原生组件,开发者可以直接使用,可参考视图容器 | 微信开放文档。二是自定义组件:开发者可以根据自己的需求自定义组件,通过 component
配置来封装功能,并在其他页面或组件中进行引用。例如要开发一个常用的卡片组件,先在项目中创建一个名为 card的组件目录,然后编写组件代码
card.wxml:
<view class="card">
<image class="card-image" src="{
{imgSrc}}" />
<text class="card-title">{
{title}}</text>
<text class="card-price">{
{price}}</text>
</view>
card.wxss:
.card {
padding: 10px;
border-radius: 10px;
background-color: #fff;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
}
.card-image {
width: 100%;
height: auto;
border-radius: 5px;
}
.card-title {
font-size: 16px;
font-weight: bold;
}
.card-price {
color: red;
font-size: 14px;
}
card.js:
Component({
properties: {
title: String,
price: String,
imgSrc: String
}
});
在其他页面引用组件:
<import src="../../components/card/card.wxml" />
<template is="card" data="{
{title: '商品A', price: '¥100', imgSrc: 'path/to/image'}}" />
)
API接口:是 Application Programming Interface(应用程序编程接口)的缩写,API接口是指一组规范或协议,允许不同的软件系统、组件或模块之间进行交互与通信。API定义了两个软件系统之间如何通过调用某些预定的接口(函数、方法、URL等)来交换数据或请求服务。
(在微信小程序开发中,API接口扮演着至关重要的角色,小程序通常需要从服务器获取数据(例如用户信息、商品列表、天气信息等),这些数据通过调用微信小程序提供的 wx.request()
方法发起HTTP请求,调用后端提供的API接口来获取,或者在小程序中进行的某些操作(如支付、订单创建、评论提交等)通过API接口与后端交互,完成相应的业务逻辑处理,例如
wx.request({
url: 'https://example.com/api/getData',
method: 'GET',
success(res) {
console.log(res.data);
},
fail: (error) => {
console.error("调用失败", error);
}
});
另外微信小程序不仅能够调用外部API,还提供了大量的内置API,供开发者进行用户身份验证、设备信息获取、支付、分享等操作,例如
// 获取用户的基本信息(如昵称、头像等):
wx.getUserInfo({
success: res => {
console.log(res.userInfo);
},
fail: (error) => {
console.error("调用失败", error);
}
});
// 跳转到某个页面,保持当前页面:
wx.navigateTo({ url: '/pages/details/details?id=123' });
// 显示模态对话框:
wx.showModal({
title: '提示',
content: '是否确认删除该项目?',
success (res) {
if (res.confirm) {
console.log('用户点击确定');
} else if (res.cancel) {
console.log('用户点击取消');
}
},
fail: (error) => {
console.error("调用失败", error);
}
});
对于内置API,前端调用微信内置 API(如 wx.getUserProfile
、wx.login
等)时,不需要 access_token
,这些 API 是通过微信小程序的运行环境直接调用的,由微信平台负责验证开发者的身份。后端调用微信的服务端接口(如 code2Session
、模板消息发送
、支付接口
)时,通常需要使用 access_token
或其他签名/加密机制来确保请求的合法性,而是否需要签名/加密,视具体API接口而定,可见概述 | 微信开放文档。更多内置API可参考基础 | 微信开放文档。)
配置文件:配置文件在微信小程序开发中扮演着非常重要的角色,它们定义了小程序的全局(app.json)和页面级别(xxx.json)的设置.。app.json
它用于描述整个小程序的全局配置信息,位于项目的根目录下。
app.json的主要配置为:
1、
页面路径列表:定义了小程序所有页面的路径(即pages字段),这是小程序启动时用来构建页面栈的基础。第一个页面通常是小程序启动时默认打开的页面(index.wxml)。当新配置一个页面路径时,开发工具会自动生成页面的.wxml .wxss .json .ts文件
2、窗口表现:可以设置小程序所有页面的一些公共样式属性,如导航栏颜色、标题文字等(即 "window"字段)。
3、TabBar配置:如果小程序有底部或顶部的TabBar,可以在app.json
中定义其图标、文字以及对应的页面路径(即 "tabBar"字段)。
4、网络超时时间:可以设定网络请求的超时时间(即 "networkTimeout"字段)。
5、调试模式:可以通过设置debug
字段来开启或关闭调试模式(即 "debug"字段)。
6、其他配置:包括但不限于是否启用分包加载、性能监控等功能。
上述配置如下:
{
"pages": [
"pages/index/index",
"pages/logs/logs",
"pages/user/user"
],
"window": {
"backgroundTextStyle": "light",
"navigationBarBackgroundColor": "#fff",
"navigationBarTitleText": "WeChat",
"navigationBarTextStyle": "black"
},
"tabBar": {
"color": "#000",
"selectedColor": "#1aad19",
"borderStyle": "black",
"list": [
{
"pagePath": "pages/index/index",
"text": "首页",
"iconPath": "images/home.png",
"selectedIconPath": "images/home-active.png"
},
{
"pagePath": "pages/logs/logs",
"text": "日志",
"iconPath": "images/logs.png",
"selectedIconPath": "images/logs-active.png"
}
]
},
"networkTimeout": {
"request": 10000,
"downloadFile": 10000
},
"debug": true
}
xxx.json的主要配置为
页面特定配置:允许为每个页面单独设置窗口表现,例如背景颜色、导航栏样式等,这些设置会覆盖app.json
中的相同配置。
(app.json
和 page.json
文件通过提供结构化的配置选项,帮助开发者对小程序的外观和行为进行精确控制。)
调试工具:指微信开发者工具,它是微信官方提供的一款集成开发环境(IDE),专门用于开发、调试和测试微信小程序、小游戏以及小程序插件的工具,并且提供了从代码编辑、调试到上传发布的全方位支持。
二、操作步骤
1、注册小程序账号
首先需要提供相关信息注册小程序账号,包括邮箱验证、个人身份信息、小程序名称等。
注册地址:微信小程序
(用于后续在开发工具中进行登录,以便将开发的小程序与账号相关联)
2、完成小程序备案
在小程序首页进行小程序信息、类目及其他信息(比如后端服务器)的补充,并发起备案申请。
首页地址:小程序
(根据微信官方要求,小程序备案是一个必要的步骤,确保开发的小程序符合微信的相关法律和内容规定)
3、下载微信开发者工具
微信提供了官方的小程序开发工具,用于编写和调试小程序,安装完成后,使用注册的小程序账号进行登录,并填入账户信息中的AppID(小程序ID)
下载地址:微信开发者工具下载地址与更新日志 | 微信开放文档
( 微信开发者工具使用小程序调试,可以完成小程序的前端页面和API的开发调试、代码查看和编辑、小程序预览和发布等功能)
4、配置git账户及仓库
为了更好地管理小程序项目代码,可以使用Git进行版本控制。在本地小程序代码对应的文件夹下进行git相关的配置。
Git全局设置:
git config --global user.name "xxx"
git config --global user.email "xxx@xxx"
初始化git仓库
git init
git remote add origin xxxx
git add .
git commit
git push -u origin master
代码管理地址:登录 - 微信开发者代码管理
(在小程序开发中,使用 Git 可以方便地记录代码的开发历史,便于多人协作开发,并且能够轻松地回滚到之前的版本,以解决代码出现的问题)
5、小程序代码开发
前端代码开发:
使用WXML(微信标记语言)和WXSS(微信样式表)来构建页面和样式
使用JavaScript或TS来处理业务逻辑、事件绑定、页面生命周期等
可通过微信小程序API来实现用户授权、获取数据、支付等功能
后端调用:
小程序可以通过wx.request向服务器发起HTTP请求,获取后端数据
后端服务通常使用Python、Java、PHP等开发语言,处理小程序的业务逻辑和数据存储
数据的传输可以采用JSON格式,确保小程序与后端的通信高效、准确
小程序开发文档地址:微信开放文档
(代码开发时小程序开发的核心步骤,它直接影响到上传、审核、上线后的稳定性以及用户体验效果,基本步骤可参考 额外补充 -》前后端交互的主要步骤)
6、上传代码,提交审核
完成开发后,在开发者工具的“工具”菜单栏中选择“上传”按钮,将本地开发版本上传到微信服务器。上传后,可以在微信公众平台小程序首页的版本管理中填写小程序的版本号、描述等信息并提交审核,审核通过后就可以选择将小程序发布上线。
7、正式上线验证
程序上线后,即可进行正式的验证,确保小程序在正式环境中的正常运行。
总结
微信小程序的开发流程的本质就是注册和备案小程序后,用专门的开发工具以及特别的写法开发界面并调用后端,然后提交审核上线。关键点在于对开发文档中包括特殊标签、样式、API及脚本的写法的理解与使用
三、额外补充
1、如何打断点调试
1.1、在开发者工具中调试
打开 模拟器 及 调试器,在调试器的弹窗中点击wxml tab标签可看到页面结构,进行样式调整,点击调试器弹窗右上角的三个点,可见 Search,点击Search后搜索对应代码,然后即可在Surces中显示出对应文件,然后在对应代码行打上断点,在模拟器中操作即可进行调试
1.2、真机调试
可在开发者工具中 真机调试-》自动真机调试-》编译并自动调试(选择自己移动设备对应的系统),编译启动后,在微信界面会自动打开要调试的小程序,同时开发者工具也会自动弹出一个调试弹窗(类似浏览器的控制台)
然后在弹窗中点击wxml tab标签可看到页面结构,进行样式调整,点击Sources->user可看到自己小程序的所有js/ts文件,点击打开文件在对应代码行打上断点,操作移动设备即可进行调试
2、前后端交互的主要步骤
2.1、前端获取code
初始加载时,前端在app.ts中wx.login获取code,
并将code
保存发送到后端
App<IAppOption>({
globalData: {
loginCode: "",
token: ""
},
onLaunch() {
// 前端代码
wx.login({
success: (res) => {
if (res.code) {
console.log("登录成功,code:", res.code);
this.globalData.loginCode = res.code; // 保存到全局变量
} else {
console.error("登录失败", res.errMsg);
}
},
});
},
})
在其他页面中假设存在confirm函数
confirm(){
const app = getApp<IAppOption>(); // 获取全局 App 实例
const loginCode = app.globalData.loginCode; // 获取保存的 code
// 调用 wx.getUserProfile 获取用户信息
wx.getUserProfile({
desc: "用于完善用户信息",
success: (profileRes) => {
const { nickName, avatarUrl } = profileRes.userInfo; // 用户昵称和头像
// 发送到后端
wx.request({
url: "https://xxx.xxx/program/saveUser", // 替换为后端接口地址
method: "POST",
data: {
code: loginCode,
nickName: nickName,
avatarUrl: avatarUrl,
},
success: (result) => {
app.globalData.token = result.data.toString();
console.log("用户信息保存成功", app.globalData.token);
},
fail: (error) => {
console.error("保存用户信息失败", error);
},
});
},
fail: (error) => {
console.error("用户拒绝授权", error); // 检查这里是否输出错误信息
}
});
}
2.2、后端保存用户信息
后端根据code以及appid\appSecrete调用jscode2session可获得标识唯一用户的openid,保存用户数据并生成token返回前端(mapper类及sql自行补充)
@Value("${wx.appid}")
private String appid;
@Value("${wx.secret}")
private String secret;
@PostMapping("/saveUser")
public String saveUser(@RequestBody UserSaveDTO userSaveDTO) {
String code = userSaveDTO.getCode();
String nickName = userSaveDTO.getNickName();
String avatarUrl = userSaveDTO.getAvatarUrl();
// 使用HTTPS GET请求微信API根据code换取openid和session_key
String apiUrl = "https://api.weixin.qq.com/sns/jscode2session?appid=" + appid + "&secret=" + secret + "&js_code=" + code + "&grant_type=authorization_code";
try {
// 创建 URL 对象
URL url = new URL(apiUrl);
// 打开连接
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
// 设置请求方法为 GET
connection.setRequestMethod("GET");
// 获取响应码
int responseCode = connection.getResponseCode();
if (responseCode == HttpURLConnection.HTTP_OK) {
// 读取响应内容
BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
String line;
StringBuilder response = new StringBuilder();
while ((line = reader.readLine()) != null) {
response.append(line);
}
reader.close();
// 打印响应结果
Gson gson = new Gson();
// 将 JSON 字符串转换为 Map
Map<String, Object> map = gson.fromJson(response.toString(), Map.class);
String openid = (String) map.get("openid");
programMapper.insertUser(nickName, avatarUrl, openid);
return JwtTokenUtil.generateToken(openid);
} else {
System.out.println("请求失败,响应码: " + responseCode);
return "error";
}
} catch (Exception e) {
throw new RuntimeException("保存用户信息接口失败", e);
}
}
JWT工具类
package com.example.demo.miniprogram.utils;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.SignatureException;
import java.util.Date;
public class JwtTokenUtil {
// 自定义密钥(实际使用时请妥善保管,建议配置到配置文件中)
private static final String SECRET_KEY = "my_mini_program";
// 30 分钟有效期(单位:毫秒)
private static final long EXPIRATION_TIME = 30 * 60 * 1000;
/**
* 根据传入的 openid 生成 token,token 有效期为 30 分钟
* @param openid 微信用户的 openid
* @return JWT Token 字符串
*/
public static String generateToken(String openid) {
Date now = new Date();
Date expiryDate = new Date(now.getTime() + EXPIRATION_TIME);
return Jwts.builder()
// 这里使用 subject 存放 openid,也可在 payload 中增加其他信息
.setSubject(openid)
// 也可以使用 claim 存放更多信息
.claim("openid", openid)
.setIssuedAt(now)
.setExpiration(expiryDate)
// 使用 HS512 对称加密算法签名
.signWith(SignatureAlgorithm.HS512, SECRET_KEY)
.compact();
}
/**
* 验证 token 的有效性,包含签名和是否过期的检查
* @param token 待验证的 JWT Token
* @return true 表示 token 有效;false 表示 token 无效或已过期
*/
public static boolean validateToken(String token) {
try {
// 解析 token,如果解析成功则 token 合法
Jwts.parser().setSigningKey(SECRET_KEY).parseClaimsJws(token);
return true;
} catch (ExpiredJwtException e) {
// token 已经过期
System.out.println("Token 已过期:" + e.getMessage());
} catch (SignatureException e) {
// token 签名不正确
System.out.println("Token 签名错误:" + e.getMessage());
} catch (Exception e) {
// 其他异常,例如 token 格式不正确
System.out.println("Token 无效:" + e.getMessage());
}
return false;
}
/**
* 刷新 token
* 如果 token 合法(即使过期了也可以获取到 claims),则根据 token 中的 openid 生成新的 token。
* 如果 token 无法解析,则返回 null。
*
* @param token 需要刷新的旧 token
* @return 新的 JWT Token 字符串,或 null 表示 token 无法刷新
*/
public static String refreshToken(String token) {
try {
// 尝试解析 token,获取 claims(如果 token 已过期,ExpiredJwtException 中也包含 claims)
Claims claims = Jwts.parser()
.setSigningKey(SECRET_KEY)
.parseClaimsJws(token)
.getBody();
String openid = claims.get("openid", String.class);
return generateToken(openid);
} catch (ExpiredJwtException e) {
// 如果 token 已经过期,通过异常获取 claims
Claims claims = e.getClaims();
String openid = claims.get("openid", String.class);
return generateToken(openid);
} catch (Exception e) {
// 如果 token 解析失败,无法刷新,返回 null 或者抛出自定义异常
System.out.println("刷新 token 失败:" + e.getMessage());
return null;
}
}
}
2.3、后端token验证
前端后续调用后端接口附带token,后端验证token后处理业务逻辑
假如我后续某个页面要搜索已经保存信息的用户名称
searchUserName: function (e) {
const app = getApp();
wx.request({
url: 'https://xxx.xxx/program/selectUserByName?name='+e.detail.value,
method: 'GET',
header: {
'Authorization': app.globalData.token, // 添加Authorization请求头
'content-type': 'application/json' // 默认值,根据实际情况可能需要调整
},
success(res) {
console.log(res.data);
}
});
}
全局拦截器验证token
package com.example.demo.miniprogram.filter;
import com.example.demo.miniprogram.utils.JwtTokenUtil;
import org.springframework.stereotype.Component;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@Component
public class JwtAuthenticationFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
// 初始化配置,如果需要可以在这里加载配置参数
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
// 强制转换为 HttpServletRequest 和 HttpServletResponse
HttpServletRequest httpRequest = (HttpServletRequest) request;
HttpServletResponse httpResponse = (HttpServletResponse) response;
// 获取请求 URI
String uri = httpRequest.getRequestURI();
// 如果请求路径为 /saveUser,则直接放行,不进行 token 验证
if (uri.contains("/saveUser")) {
chain.doFilter(request, response);
return;
}
// 从请求头中获取 token,假设 token 存储在 "Authorization" 字段中
String token = httpRequest.getHeader("Authorization");
// 如果 token 为空或验证不通过,则返回 401 状态码
if (token == null || !JwtTokenUtil.validateToken(token)) {
httpResponse.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
// 可根据需要返回错误信息
httpResponse.getWriter().write("Unauthorized: Invalid or missing token.");
return;
}
// token 验证通过,继续执行后续 Filter 或目标资源
chain.doFilter(request, response);
}
@Override
public void destroy() {
// 资源释放操作,如无需要可留空
}
}
2.4、后端调用微信API
后端调用微信内置API时,通过getAccessToken获取acess_token调用(某些场景的特殊API接口需要签名或加密解密处理(如支付接口、用户信息解密))
// 获取 access_token 的 URL(注意:此接口适用于公众号和部分小程序场景,不同场景接口可能不同)
private static final String ACCESS_TOKEN_URL =
"https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s";
/**
* 通过调用微信接口获取 access_token
* @return 微信接口返回的 access_token 字符串
* @throws Exception 当获取 token 失败时抛出异常
*/
public String getAccessToken() {
try {
String url = String.format(ACCESS_TOKEN_URL, appid, secret);
ResponseEntity<String> response = restTemplate.getForEntity(url, String.class);
String body = response.getBody();
// 将返回的 JSON 字符串转换为 Map
Map<String, Object> result = objectMapper.readValue(body, Map.class);
return (String) result.get("access_token");
}catch (Exception e){
throw new RuntimeException("获取微信token接口失败", e);
}
}
// TODO 使用accessToken调用小程序后端服务端的其他API
3、开发者工具缓存问题
修改或重新上传资源文件(比如图片)后,需要在开发工具 清缓存-》清除编译缓存 后重新编译,否则资源会刷新不过来
另外在调试时也会存在各种意料之外的问题,比如断点不进入,页面不刷新等,可以选择清缓存-》全部清除,后重新尝试,基本解决大部分问题
4、开发者工具拉取/推送代码失败
在微信小程序开发者工具中,拉取远程分支时提示 Pull failed Error: invalid authentication scheme
,通常与认证方式或凭据问题有关。可尝试在 版本管理-》设置-》网络和认证 的认证方式中,将认证方式修改为使用用户名和密码,然后重新尝试