# 小程序项目搭建
# 一、项目构建
# 1、创建准备
查看文档,注册小程序账号和下载开发者工具。
创建小程序需要先注册账号 小程序注册 (opens new window) ,注册后你就可以在你的账号上发布一个小程序,一个账号只能发布一个小程序。
参考链接:小程序文档 (opens new window)、开发者工具 (opens new window)
# 2、创建项目
打开开发者工具,项目-新建项目,到你注册的账号中去获取 微信公众平台 (opens new window) 找到设置-基础设置复制AppID 创建项目。
# 3、项目结构设计
项目创建好后,我们要配置项目结构中常见的模块目录,如assets、utils、componentsd等,和vue项目目录差不多。
├── api # Api ajax 等
├── assets # 本地静态资源
│ │ ├── images # 项目图片
│ │ ├── css # reset、common样式
│ │ ├── font # 字体库
│ │ ├── iconfont # iconfont库
│ │ └── less/sass # 公共less/sass文件
├── components # 业务公共组件
├── utils # 工具库
├── pages # 页面目录
│ ├── index # index页面
│ │ ├── index.js # 页面逻辑处理
│ │ ├── index.json # 页面配置
│ │ ├── index.wxml # html
│ │ ├── index.wxss # css
│ │ └── index.less # less/sass
├── .eslintrc.js # eslint配置文件
├── .gitignore # git忽略
├── package.json # 包管理
├── app.js # App 实例
├── app.wxss # 公共样式表
├── app.json # 全局配置
├── README.md
├── project.config.json # 项目配置文件
├── project.private.config.json # 和project.config相同,项目私有配置文件
└── sitemap.json # 配置小程序及其页面是否允许被微信索引
# 二、项目配置
# 1、基础配置
如果要配置项目页面文件的路径、窗口表现、设置网络超时时间、设置多 tab、公共组件引入 等,可以通过app.json 文件进行配置。全局配置 (opens new window)
{
"pages": [
"pages/index/index",
"pages/logs/index"
],
"entryPagePath": "pages/index/index",
"window": {
"navigationBarTitleText": "Demo"
},
"tabBar": {
"list": [{
"pagePath": "pages/index/index",
"text": "首页"
}, {
"pagePath": "pages/logs/index",
"text": "日志"
}]
},
"networkTimeout": {
"request": 10000,
"downloadFile": 10000
},
"sitemapLocation": "sitemap.json",
// 全局使用公共组件
"usingComponents": {
"van-button": "@vant/weapp/button/index"
}
}
如果要对某个页面单独配置如设置标题,标题颜色,引入的插件等,只需要在对应页面的 .json 文件中设置即可。页面配置 (opens new window)
{
"navigationBarBackgroundColor": "#ffffff",
"navigationBarTextStyle": "black",
"navigationBarTitleText": "微信接口功能演示",
"backgroundColor": "#eeeeee",
"backgroundTextStyle": "light",
"usingComponents": {
"van-dropdown-menu": "@vant/weapp/dropdown-menu/index",
}
}
项目配置,针对整个项目或程序的配置
项目根目录中的 project.config.json 和 project.private.config.json 文件可以对项目进行配置,project.private.config.json 中的相同设置优先级高于 project.config.json。project.private.config.json是配置个人的配置。项目配置文件 (opens new window)
这里配置比如一些小程序基础信息,插件构建路径。
{
"description": "项目配置文件,详见文档:https://developers.weixin.qq.com/miniprogram/dev/devtools/projectconfig.html",
"setting": {
"packNpmManually": true,
"packNpmRelationList": [
{
"packageJsonPath": "./package.json",
"miniprogramNpmDistDir": "./"
}
],
},
"compileType": "miniprogram",
"libVersion": "2.16.0",
"appid": "wx618158e394f27d94",
"projectname": "sanshiopsmanage",
},
"editorSetting": {
"tabIndent": "insertSpaces",
"tabSize": 2
}
}
# 2、CSS设置
通用样式我们在 app.wxss 全局样式文件中设置,相当于reset.css,每个页面都会自动引入。也可以在app.wxss中引入其他公共样式,比如引入插件需要的样式,自定义的样式都可以。
每个页面里的样式在.wxss中写,但是纯css写很麻烦,我们可以借助扩展插件使用less或sass来解决。
# 3、引入依赖包
小程序也可以像vue一样使用npm插件,创建好项目,打开终端,就可以直接安装插件了。
在根目录创建 package.json 文件,执行命令直接回车。只需初始化时执行一次,后续只要npm i 就可以了。
npm init
然后在小程序 package.json 所在的目录中执行命令安装 npm 包。
npm install xxx
安装好插件依赖后,还需要构建npm。
点击开发者工具中的菜单栏:工具 --> 构建 npm。
低版本的还需要勾选 npm 模块 选项。打开右上详情-本地设置。
为什么小程序要 构建npm,因为node_modules不会参与小程序的构建,需要使用构建npm来生成小程序能识别的包文件,构建会在包同级目录生成miniprogram_npm文件,里面目录结构和node_modules一一对应,我们引入也是引入此文件中的包。
生成的miniprogram_npm文件位置是根据 project.config.json 中 miniprogramRoot 设置的位置生成的,没有 miniprogramRoot 则和 project.config.json同级。
之前的旧版本构建位置默认在 miniprogram 文件中,没有和package.json同级,使用会有问题,需要在project.config.json文件中配置构建的目录,让构建的目录和package.json同级。
"packNpmManually": true,
"packNpmRelationList": [
{
"packageJsonPath": "./package.json",
"miniprogramNpmDistDir": "./"
}
]
目前最新版本的开发者工具默认构建在和package.json同级的,不需要再配置构建目录,为了保险起见我们都在project.config.json中为所有插件配置好。此配置只需配置一次。
# 4、引入Vant Weapp组件
文档:Vant Weapp (opens new window)
安装配置:
1、npm安装
npm i @vant/weapp -S --production
2、将 app.json 中的 "style": "v2" 去除。 3、修改构建目录,在project.config.json中统一设置,此配置只需配置一次。
"packNpmManually": true,
"packNpmRelationList": [
{
"packageJsonPath": "./package.json",
"miniprogramNpmDistDir": "./"
}
]
4、安装好后执行构建npm。然后在miniprogram_npm可以看到@vant 文件了 使用
1、在页面中使用
在页面中使用直接在页面的.json文件引入组件,和自定义组件一样,注意的是如果你的页面目录不对,组件引用地址可能会出问题,找不到此组件,可以尝试使用相对路径找到miniprogram_npm下对应的组件就可以了。
"usingComponents": {
"van-button": "@vant/weapp/button/index"
}
2、全局使用 全局使用直接在app.son中设置usingComponents,这样所有组件就都可以使用了。
"usingComponents": {
"van-button": "@vant/weapp/button/index"
}
<!--index.wxml-->
<view class="container">
<van-button type="default">默认按钮</van-button>
<van-button type="primary">主要按钮</van-button>
<van-button type="info">信息按钮</van-button>
<van-button type="warning">警告按钮</van-button>
<van-button type="danger">危险按钮</van-button>
</view>
使用内置样式
在 app.wxss 中引入内置样式,这样就可以使用vant自带的一些样式类了。
@import '@vant/weapp/common/index.wxss';
# 5、接口封装
小程序调用接口是使用自带的请求方法wx.request(),不需要再使用其他请求插件。但是这样每次调用都很麻烦,也没有做请求拦截,所以要封装一下,统一处理。
1、在utils下创建request.js文件,对接口请求统一处理。
// utils/request.js
/**
* @description 请求接口封装
* @author changz
* */
const BASE_URL = 'https://api.itops.yunsee.cn';
let hasInvalid = false; // 判断是否有token失效,不同地方多次调用此变量也可以被访问
/**
* @description 请求方法封装
* @desc 错误统一拦截
* @desc token过期统一处理
* @desc then里会返回所有的业务状态码,所以不是200的要返回提示
* @desc catch里只拦截接口请求错误,如404、401、500和fail里的错误
* 把这些错误统一成一种格式返回提示
* @param {String} [url] - 请求地址
* @param {String} [method] - 请求方法
* @param {Object} [params] - 请求参数 {}
* @param {String} [loadText] - 加载动画提示,默认无
* @example request({})
* @author changz
* */
function request({url, method, params, loadText}) {
return new Promise((resolve, reject) => {
if (loadText) {
wx.showLoading({
title: loadText,
})
}
let header = {
'content-type': 'application/json'
}
if (wx.getStorageSync('token')) {
header['Authorization'] = wx.getStorageSync('token');
}
wx.request({
url: `${BASE_URL}${url}`,
method,
data: params,
header,
success(res) {
wx.hideLoading();
const { statusCode, data } = res;
if (statusCode == 200) {
resolve(data)
} else if (statusCode == 401) {
if (hasInvalid) return // 已经有失效跳转到登录
wx.showToast({
title: '登录过期',
icon: 'none',
duration: 1500
})
hasInvalid = true
// 跳转到登录页
setTimeout(() => {
wx.reLaunch({
url: '/pages/empower/index',
complete: function() {
hasInvalid = false
}
})
}, 1500)
} else {
reject({
errMsg: `请求失败:${statusCode}`,
data: res
})
}
},
fail(err) {
wx.hideLoading();
reject({
errMsg: err.errMsg,
data: err
})
}
})
})
}
export default request
2、在api下创建接口地址统一处理文件
// api/login.js
import request from '../utils/request'
const api = {
miniLogin: '/api/common/miniLogin'
}
// 登录
export function miniLoginApi(parameter, loadText) {
return request({
url: api.miniLogin,
method: 'POST',
params: parameter,
loadText
})
}
3、在组件调用
import { miniLoginApi } from '../../api/login'
// 登录
userLogin() {
const that = this
const { code } = this.data
const params = {
code
}
miniLoginApi(params, '加装中...')
.then((res) => {
if (res.code !== 200) {
wx.showToast({
title: res.msg,
icon: 'none',
duration: 2000
})
return
}
console.log(res)
const { data, token } = res
wx.setStorageSync('token', token)
wx.setStorageSync('userInfo', data)
// 登录成功跳转到首页
wx.navigateTo({
url: '/pages/index/index'
})
}).catch((err) => {
console.log(err)
wx.showToast({
title: err.errMsg,
icon: 'none',
duration: 2000
})
})
}
# 6、登录权限判断
小程序登录情形大概分为两种,一种是小程序进来就需要登录,我们可以让小程序每次进入时就默认打开登录页,执行一遍登录操作后再进入;另一种不论登不登录都可以进来,当需要登录时再跳转到登录页或者直接调登录接口登录,然后再根据用户信息判断。
两种情形的权限判断都类似,只是第二种多了一步判断是否登录。
- 判断缓存是否有token,或者其他登录凭证。
- 没有token跳转到登录页,或者直接调用登录接口,登录后缓存token。
- 如果有token则直接进入页面调用接口。
- 如果调用接口后token过期失效,则重新跳到登录页登录。 这其中涉及到在哪进行判断是否登录,在哪里判断token是否过期,多次请求同时过期如何解决。
1、在哪里进行判断是否登录
因为很多页面都可能需要判断,所以我们在utils下创建一个permission.js文件单独用来做判断,然后引入到所需的页面去调用和判断。当然,可以在这个文件里根据项目需求进行相应的逻辑处理。
// utils/permission.js
/**
* 权限判断
* 在需要做权限判断的页面引入
* 如果返回true则已登录,则进行已登录的操作,没有登录跳转都登录页
* 当然也可以进行页面拦截,没有登录直接返回上一页
* 判断登录页也可以使用接口判断,因为是异步所以要使用async await 等待获取
* */
// 检查是否登录
function checkLogin() {
let isLogin = false
const token = wx.getStorageSync('token');
if (token) {
isLogin = true;
} else {
wx.clearStorageSync();
}
return isLogin
}
module.exports = {
checkLogin
}
在页面中进行获取,这里根据项目需求情况来判断。
<!--index.wxml-->
<view class="index">
<van-button type="default" bindtap="showToast">{{initData ? '已登录' : '请登录'}}</van-button>
<van-button type="primary" wx:if="{{!userIsLogin}}" bindtap="getLoginInfo">登录</van-button>
</view>
// index.js
import { menusApi } from '../../api/index'
import permission from '../../utils/permission'
Page({
data: {
userIsLogin: false,
initData: null
},
onShow: function () {
const isLogin = permission.checkLogin()
this.setData({
userIsLogin: isLogin
})
if (this.data.userIsLogin) {
this.getInitData()
}
},
getInitData() {
const that = this
menusApi({}, '加装中...')
.then((res) => {
if (res.code !== 200) {
wx.showToast({
title: res.msg,
icon: 'none',
duration: 2000
})
return
}
console.log(res)
const data = res.data
that.setData({
initData: data
})
}).catch((err) => {
console.log(err)
wx.showToast({
title: err.errMsg,
icon: 'none',
duration: 2000
})
})
},
// 去登录
getLoginInfo() {
if (this.data.userIsLogin) return
wx.navigateTo({
url: '/pages/empower/index'
})
}
})
2、判断token过期
我们在接口封装request.js中统一对错误请求进行了拦截,只需判断请求状态码为401就可以直接跳转到登录就行了。
3、多次请求同时过期如何解决
当一个页面同时请求几个接口,这时token失效了,判断401时会多次跳转到登录页,为了减少这种不必要的跳转,我们需要进行判断,只跳转一次登录页就行了。
我们可以在request.js中定义一个变量,这个变量相当于全局变量,不论在哪里引入都能访问这个变量,所以只需在request.js中对这个变量判断就行。
# 7、编码规范配置
1、格式化代码
格式化代码和vue项目一样,我们使用Prettier进行配置,在扩展中下载prettier插件,然后在项目根目录创建.prettierrc.js文件,进行配置我们需要的格式。
module.exports = {
// 一行最多 100 字符
printWidth: 180,
// 使用 2 个空格缩进
tabWidth: 2,
// 不使用缩进符,而使用空格
useTabs: false,
// 行尾需要有分号
semi: false,
// 使用单引号
singleQuote: true,
// 对象的 key 仅在必要时用引号
quoteProps: 'as-needed',
// 末尾不需要逗号
trailingComma: 'none',
// 大括号内的首尾需要空格
bracketSpacing: true,
// 箭头函数,只有一个参数的时候,也需要括号
arrowParens: 'always',
// 每个文件格式化的范围是文件的全部内容
rangeStart: 0,
rangeEnd: Infinity,
// 不需要写文件开头的 @prettier
requirePragma: false,
// 不需要自动在文件开头插入 @prettier
insertPragma: false,
// 使用默认的折行标准
proseWrap: 'preserve',
// 根据显示样式决定 html 要不要折行
htmlWhitespaceSensitivity: 'css'
}
然后在文件中右击->格式化文档,方法->配置默认格式化->Prettier。配置好后以后只需右击选择格式化文档就行了。
2、代码检查
暂时以vue项目的格式进行编写。