慕尚花坊 --- 项目初始化
1. 项目概述
[慕尚花坊] 是一款 同城鲜花订购 的小程序, 专业提供各地鲜花速递、鲜花预定、网上订花、包月鲜花等服务。最快3小时送花上门, 保证花材新鲜和鲜花质量, 可先送花后付款, 专业花艺师傅精美包扎, 品质保证, 至诚服务。
2. 项目技术栈
[慕尚花坊] 使用原生小程序进行搭建开发
- 页面搭建: 采用小程序内置组件 + Vant 组件库实现页面结构的搭建
- 项目中使用了 css 拓展语言 Scss 绘制页面结构
- 小程序内置 API : 交互、支付、文件上传、地图定位、网络请求、预览图片、本地存储等
- 小程序分包加载: 降低小程序的启动时间、包的体积, 提高用户体验度
- 小程序的组件开发: 将页面内的功能模块抽象成自定义组件, 实现代码的复用
- 网络请求封装: request 方法封装、快捷方式封装、响应拦截器、请求拦截器
- 骨架屏 组件: 利用开发者工具提供了自动生成骨架屏代码的能力, 提高了整体使用体验和用户满意度
- UI 组件库: 使用 Vant 组件库实现小程序结构的绘制
- LBS : 使用腾讯地图服务进行 LBS 逆地址解析, 实现选择收货地址功能
- miniprogram-licia: 使用 licia 进行函数的防抖节流
- async-validator: 使用 async-validator 实现表单验证
- miniprogram-computed: 使用 miniprogram-computed 进行计算属性功能
- mobx-miniprogram: 使用 mobx-miniprogram 进行项目状态的管理
3. 接口文档
4. 申请开发权限
在开发一个小程序项目之前,需要先申请开发权限, 需要将自己的微信号发送给对应小程序账号的管理员, 在小程序微信公众后台添加自己为开发者。
管理员登录微信公众后台,进行开发成员的添加
在管理员将自己设置为项目成员以后, 开发者自己也可以登录当前小程序后台, 获取 ApppId
在获取到小程序 AppId后,就可以使用 AppId 新建小程序项目 或者 切换小程序项目的 AppId
5. 项目初始化
1. 创建项目
-
在微信开发者工具左侧菜单栏中选择 [小程序]
-
点击 + 号开始新建项目
-
输入小程序项目相关信息, 点击确定即可
2. 清空无用文件内容
删除 app.json
文件中的下面三行
{
"renderer": "skyline",
"rendererOptions": {
"skyline": {
"defaultDisplayBlock": true,
"disableABTest": true,
"sdkVersionBegin": "3.0.0",
"sdkVersionEnd": "15.255.255"
}
},
"componentFramework": "glass-easel",
}
删除app.json
文件中配置了的自定义导航栏选项
{
"window": {
"navigationBarTextStyle": "black",
"navigationStyle": "custom" // 删除这一行
}
}
删除 app.wxss
文件中的全部内容
删除 components
文件夹中的所有文件
删除 pages/index
文件夹中的所有内容
3. 调整目录结构
随着项目的功能越来越多、项目越来越复杂, 文件目录也变得很繁琐, 为了方便开发,会对目录结构进行调整,将项目所有源码放在 miniprogram
目录下
1. 首先在项目根目录下创建 miniprogram
文件夹
2. 将 conponents文件夹
、pages文件夹
、app.js文件
、app.json文件
、app.wxss文件
、sitemap.json文件
移动到 miniprogram
文件夹中
3. 在 project.config.json
配置 miniprogramRoot
,指定小程序源码目录
{
"miniprogramRoot": "miniprogram/",
"srcMiniprogramRoot": "miniprogram/"
}
4. 在 project.config.json
配置 setting.packNpmManually 为 true
开启自定义 node_modules 和 miniprogram_npm 位置的构建 npm 方式
{
"setting": {
"packNpmManually": true,
}
}
5. 在终端执行 Npm 初始化命令
npm init -y
**6. 在 project.config.json
配置 setting.packNpmRelationList
指定 packageJsonPath
和 miniprogramNpmDistDir
的位置, 其中 packageJsonPath
表示 node_modules 源 对应的 package.json
、 miniprogramNpmDistDir
表示 node_modules 的构建结果目标位置 **
{
"setting": {
"packNpmManually": true,
// 注意这个配置项在文件下面有定义,需要先删除下面的同名配置项
"packNpmRelationList": [
{
"packageJsonPath": "./package.json",
"miniprogramNpmDistDir": "./miniprogram"
}
]
}
}
4. 包下载、构建NPM
1. 下载 Vant 组件库
npm i @vant/weapp
2. 工具 => 构建Npm
3. 如遇到错误, 项目 => 重新打开此项目
5. 集成 Sass
1. 在 project.config.json
配置 setting.usecCompilerPlugins
{
"setting": {
"useCompilerPlugins": ["sass"],
}
}
2. 将所有 .wxss
为后缀的 CSS 文件, 改为 .scss
后缀
3. 清除缓存 => 编译
6. 路径别名
在 app.json
文件中新增 resolveAlias
配置项
- key: 必须以
/*
结尾 - value: 如果在
projet.config.json
中配置了miniprogramRoot
配置项, 则/*
表示 这个配置项的目录, 如果没有配置, 则是整个项目的根路径
app.json
{
"resolveAlias": {
"@/*":"/*"
}
}
7. 配置分包和预加载
在分包后, 通过查看代码依赖检查是否分包完成: 详情 => 基本信息 => 代码依赖分析
1. 创建 miniprogram/modules
文件夹, 用来存放所有分包
1. 这里以系统设置分包为例, 配置完成后会自动在 modules/settingModule
目录中生成 pages/...
对应目录结构
app.json
{
"subPackages": [{
"root": "modules/settingModule",
"name": "settingModule",
"pages": [
"pages/setup/personal-data/personal-data",
"pages/setup/receive-address/add/add",
"pages/setup/receive-address/list/list"
]
}],
"preloadRule": { // 预下载配置项
"pages/my/my": { // 在访问 index 页面时开始预下载
"network": "all", // 网络模式, all(不限制网络预下载), wifi(只有链接wifi时才会预下载)
"packages": ["settingModule"] // 指定预下载分包的别名或目录 modules/goodModule
}
}
}
6. 导航栏
app.json
{
"window": {
"navigationBarBackgroundColor": "#f3514f",
"navigationBarTitleText":"慕尚花坊",
"enablePullDownRefresh": true,
"backgroundColor": "#efefef",
"backgroundTextStyle":"dark"
},
}
7. tabBar
app.json
{
"tabBar": {
"borderStyle":"black",
"backgroundColor": "#efefef",
"selectedColor": "#f3514f",
"color": "#000",
"list": [{
"pagePath": "pages/index/index",
"text": "首页",
"iconPath": "./assets/tabBars/tabbar-1.png",
"selectedIconPath": "./assets/tabBars/tabbar-1-selected.png"
},
{
"pagePath": "pages/cate/cate",
"text": "分类",
"iconPath": "./assets/tabBars/tabbar-2.png",
"selectedIconPath": "./assets/tabBars/tabbar-2-selected.png"
},
{
"pagePath": "pages/cart/cart",
"text": "购物车",
"iconPath": "./assets/tabBars/tabbar-3.png",
"selectedIconPath": "./assets/tabBars/tabbar-3-selected.png"
},
{
"pagePath": "pages/my/my",
"text": "我的",
"iconPath": "./assets/tabBars/tabbar-4.png",
"selectedIconPath": "./assets/tabBars/tabbar-4-selected.png"
}
]
}
}
8. 模块封装
9. 设置环境变量
在实际开发中, 不同的开发环境, 调用的接口地址是不一样的。例如: 开发环境需要调用开发版的接口地址, 生产环境需要调用正式版的接口地址
小程序为我们提供了 wx.getAccountInfoSync()
接口, 来获取当前账号信息, 在账号信息中包含着 小程序的当前环境版本
环境版本 | 合法值 |
---|---|
开发板 | develop |
体验版 | trial |
正式版 | release |
miniprogram/utils/env.js
// 配置当前小程序项目的环境变量
// 获取小程序的账号信息
const {
miniProgram
} = wx.getAccountInfoSync()
// 获取小程序的版本
const {
envVersion
} = miniProgram
let env = {
baseURL: 'https://gmall-prod.atguigu.cn/mall-api'
}
switch (envVersion) {
// 开发版
case 'develop':
env.baseURL = 'https://gmall-prod.atguigu.cn/mall-api'
break;
// 体验版
case 'trial':
env.baseURL = 'https://gmall-prod.atguigu.cn/mall-api'
break;
// 正式版
case 'release':
env.baseURL = 'https://gmall-prod.atguigu.cn/mall-api'
break;
default:
env.baseURL = 'https://gmall-prod.atguigu.cn/mall-api'
break;
}
export {
env
}
miniprogram/utils/http.js
import WxRequest from './request'
import {
env
} from './env'
import {
getStorage,
clearStorage
} from './storage'
import {
modal,
toast
} from './extendAPI'
const wxr = new WxRequest({
baseURL: env.baseURL, // 替换环境变量的基准地址
timeout: 15000
})
wxr.interceptors.request = (config) => {
const token = getStorage('token')
if (token) {
config.header.token = token
}
return config
}
wxr.interceptors.response = async (response) => {
const {
isSuccess,
data
} = response
if (!isSuccess) {
wx.showToast({
title: '网络异常请重试',
icon: 'error'
})
return response
}
switch (data.code) {
case 200:
return data
case 208:
const res = await modal({
content: '鉴权失败, 请重新登录',
showCancel: false
})
if (res) {
clearStorage()
wx.navigateTo({
url: '/pages/login/login',
})
}
return Promise.reject(response)
default:
toast({
title: "程序出现异常, 请联系客服或稍后重试"
})
return Promise.reject(response)
}
}
export default wxr
10. 接口调用方式
在开发中, 会将所有的网络请求方法放置在 api
目录下统一管理, 然后按照模块功能来划分成对应的文件, 在文件中将接口封装成一个个方法单独导出, 例如:
miniprogram/api/index.js
// 导入封装的网络请求工具 http.js
import http from './utils/http'
export cont reqBannerData = () => http.get('/index/findBanner')
这样做有以下几个好处:
- 易于维护: 一个文件就是一个模块, 一个方法就是一个功能, 清晰明了, 查找方便
- 便于复用: 哪里使用, 哪里导入, 可以在任何一个业务组件中导入需要的方法
pages/index/index.js
import {reqSwiperData} from '@/api/index'
Page({
async onLoad() {
const res = await reqSwiperData()
console.log(res);
}
})