# guigu_shop_0609
**Repository Path**: newsegmentfault/guigu_shop_0609
## Basic Information
- **Project Name**: guigu_shop_0609
- **Description**: uniapp 小程序项目-电商项目-学习项目
- **Primary Language**: Unknown
- **License**: Not specified
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 1
- **Forks**: 0
- **Created**: 2022-12-21
- **Last Updated**: 2025-04-28
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# uni-app
## day01
uniapp 是使用 Hbuilder 编辑器开发的,所以要去下载一个 Hbuilder 编辑器,下载好安装即可
### 跑起来已完成的项目
1. 打开目录 `学生资源\uniapp已完成代码\guiguShop_server`,使用 cmd 命令行窗口打开
使用 npm i 安装依赖
node server.js 运行项目 - 运行的是后端服务器,目的是为了让小程序项目启动起来可以调用接口

2. 启动 Hbuilder 编辑器,将路径 `学生资源\uniapp已完成代码\unishop01` 中的这个 `unishop01` 项目拖拽到 Hbuilder 的侧边栏
3. 打开项目中 `manifest.json` 文件,找到`微信小程序配置项`,将自己的小程序 appId 替换进去即可

4. 点击一下侧边连的项目,点击 Hbuilder 顶部"运行",再点击"运行到终端",再点击"运行设置",打开运行项目的配置页面,配置小程序编辑器的路径
> 小程序是腾讯出的,只有"微信开发者工具"IDE有模拟器,Hbuilder 是没有模拟器的,写好代码之后最终代码运行还是再 "微信开发者工具" 当中运行,所以 Hbuilder 启动 "微信开发者工具" 需要配置 "微信开发者工具" 的安装目录



5. "微信开发者工具"也需要配置,打开"微信开发者工具",在右上角有一个设置选项,打开设置,设置界面有个"安全"选项,打开"服务端口"选项
> 这一步就像我们手机上点击某一个连接要跳转至 "淘宝",手机会弹出提示框"是否要跳转至淘宝",淘宝这个软件只有允许其他程序调起,才能真的调起"淘宝"应用,如果淘宝应用不允许其他应用调起,是无法调用起来的
>
> 我们这里,这个"服务端口"打开,就是允许其他程序调起 "微信开发者工具"

6. 在侧边栏,点击一下项目,点击顶部菜单"运行",选择"运行到小程序模拟器",再选择"微信开发者工具",此时应该就可以启动项目了
> 注意:如果是第一次启动项目,并且是 Hbuilder 最新版本,应该会去自动安装插件,需要一些时间,让程序自动安装即可
>
> 如果是老版本 Hbuilder 那么插件需要自己安装,自己安装的步骤如下:
>
> 
>
> 
>
> 
>
>
### 创建项目
在 Hbuilder 侧边栏右侧新建项目,新建一个空的uniapp项目,然后上传到 gitee 上,设置成开源,大家可以访问了
gitee地址: https://gitee.com/newsegmentfault/guigu_shop_0609

#### 目录介绍
uni.scss -- uniapp的常用scss变量
README.md -- 项目介绍文件 - 用来记笔记的
pages.json -- 就相当于是我们小程序中的 app.json 文件,页面的一些配置项都在这个文件中配置
manifest.json -- uniapp项目的配置文件
main.js -- 入口文件
index.html -- 整个页面的模板
App.vue -- 根组件,注意:这个根组件没有 template 内容,只有 script 和 style 内容,相当于是小程序的 app.js 和 app.wxss
.gitignore -- git 忽略文件
unpackage -- 是uniapp项目运行编译出来的文件夹,把uniapp的代码(vue2语法)编译成 小程序的代码(每当我们修改了uniapp代码保存的时候,都会进行编译,然后在"微信开发者工具"中进行实时更新)
static -- 文件夹中存放是是静态资源,把已完成项目 `unishop01` 中 static 文件夹中的内容直接粘贴到我们项目中
pages -- 存放我们写的页面
assets -- 笔记中的图片都存放在这个文件夹下
.hbuilderx -- hbuilder 编辑器的一个配置文件,不用管
> 注意:在项目中的 .vue 文件里面,即可以写 div 标签,也可以写 小程序组件,但是不要混用
>
> 这里我们之后采用 小程序的组件去书写
>
> 注意:
>
> 我们发现uniapp是使用vue语法写的,这个所有关于vue的东西都能用吗?
>
> 这里除了 vue-router 不能使用以外,其他的vue中的东西都能用,包括vuex,vue-router 不能用的原因是 vue是单页面应用,而小城去是页面的切换两个路由不是一套体系,所以 uniapp 不能使用 vue-router
### 首页
步骤:
1. 静态页面搭建
2. 初始化数据展示
3. 交互
#### 静态搭建
静态搭建的时候使用的是 stylus,stylus最大的特点就是使用 缩进 来控制样式,所以在写 stylus 的时候,一定要注意缩进
这里静态的搭建,主要练习的就是 flex 布局,如果对flex布局不熟悉的同学,下去一定要多练习一下flex布局
1. header
header 静态在书写的时候,页面的宽高不是 100%,并且 iconfont 的图标没有展示,需要在 App.vue 的 style 标签中 设置全局的样式
```html
App.vue文件
```
header 的其他样式,照常写即可
2. nav静态
使用 小程序原生的 scroll-view 组件,开启 flex 布局,进行样式调整
3. 主体内容
剩下的所有的内容都在 主体区域 内进行滚动,所以主体区域使用 scroll-view 组件,开启y轴方向的滚动
1. 轮播
使用 小程序原生 swiper 组件即可,swiper组件是有默认的宽高(宽375,高150)
2. 三个 icon
flex布局
3. 分类
flex布局
## day02
3. 主体内容
4. 楼层floor
flex布局,先把floor的静态搭建完毕,然后再抽离出一个公共的组件,在首页引入这个 floor组件进行使用
#### 初始化数据展示
##### 封装 request 函数
根目录下创建 `utils/request.js`
```js
import config from './config.js'
export default function request ({ url, data, method = 'get', timeout = 30000 }) {
return new Promise((resolve, reject) => {
// wx.request() // 这个原生的是可以用的,但是uni给wx原生的请求封装一次
// 我们使用uni发请求的方法(本质上是一样的)
uni.request({
url: config.host + url,
data,
method,
timeout,
success: (res) => {
resolve(res.data)
},
fail: (err) => {
reject(err)
}
})
})
}
```
`utils/config.js`
```js
export default {
host: 'http://localhost:3001'
}
```
##### 使用vuex
uni使用第三方包步骤:
1. 终端打开项目,执行 `npm init` ,初始化一个 `package.json` 文件
2. `npm i vuex@3`
注意: 我们是vue2版本,对应的vuex版本是 vuex3版本
vuex的使用步骤:
1. 安装
`npm i vuex@3`
2. 创建 `store/index.js` 配置store
```js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
import home from './modules/home.js'
export default new Vuex.Store({
// state,
// mutations,
// actions,
// getters,
modules: {
home
}
})
```
`store/modules/home.js` - 模块
```js
import request from '@/utils/request.js'
const state = {
homeData: {}, // 首页数据
}
const mutations = {
RECEIVE_HOMEDATA(state, homeData) {
state.homeData = homeData
}
}
const actions = {
async getHomeData({ commit }) {
try{
let result = await request({
url: '/getIndexData'
})
console.log('首页的数据', result)
commit('RECEIVE_HOMEDATA', result)
}catch(e){
console.error(e) // 控制台打印错误信息
return Promise.reject(e) // 将错误继续抛出,当前函数不中断promise链
}
}
}
const getters = {
}
export default {
namespaced: true, // 开启命名空间
state,
mutations,
actions,
getters
}
```
> 在vuex当中,分为普通仓库、模块化仓库、命名空间仓库
>
> 普通仓库,相当于把所有的数据直接放在一个仓库中
>
> 模块化仓库,相当于把仓库中的 state 分类模块,mutaions、actions、getters没有分模块化(可能会命名冲突)
>
> 命名空间仓库,相当于把剩下在 mutaions、actions、getters 也模块化了(state还是之前模块化的state,取值方式和模块化的取值一样样的,只有 mutaions、actions、getters 的取值方式发生了变化)
页面中要触发 actions
```js
import { mapActions } from 'vuex'
export default {
...
mounted() {
this.getHomeData(); // 触发actions
},
methods: {
// mapActions 参数一 是命名空间的名称 参数二是数组,数组中的成员是actions中的函数名
...mapActions('home', ['getHomeData'])
}
```
计算出来页面中使用的数据,放到getters中,映射到页面的 computed 中进行展示
```js
const getters = {
// nav数据
navList(state) {
return (state.homeData.kingKongModule || {}).kingKongList || [] // || 为了防止报错,做兼容
},
// 轮播没有数据,去网易严选上粘贴图片过来即可
// icon数据
iconList(state) {
return state.homeData.policyDescList || []
},
// floor数据
floorList(state) {
return state.homeData.categoryModule || []
}
}
```
#### 交互
nav点击有交互,当点击nav之后,下面的红线会跟着变,界面会跟着一块切换
红线使用类名来控制
```html
推荐
{{ nav.text }}
```
界面会跟着一块变,是整个主体区域中的内容发生了变化,要把主体区域中的内容进行切换
封装card组件用于展示"推荐"以外的nav内容
##### card 组件
静态搭建
```html
秋冬好物
人气好物放心买
男士南极人保暖内衣
299
男士南极人保暖内衣
299
男士南极人保暖内衣
299
男士南极人保暖内衣
299
男士南极人保暖内衣
299
```
###### 获取数据进行展示
```js
const state = {
......
cateList: [] // 首页其他模块数据
}
const mutations = {
......
RECEIVE_CATELIST(state, cateList) {
state.cateList = cateList;
}
}
const actions = {
......
async getCateList({ commit }) {
try{
let result = await request({
url: '/getIndexCateList'
})
console.log('首页分类的数据', result)
commit('RECEIVE_CATELIST', result)
}catch(e){
console.error(e)
return Promise.reject(e)
}
}
}
```
### tabbar
tabbar需要创建页面,在pages.json文件中进行配置
创建的时候

> 注意:勾选上"在pages.json中注册"选项,会自动在 项目中的 pages.json 中写上创建的页面
>
> 自己去配置 tabbar 选项
```json
"tabBar": {
"list": [
{
"pagePath": "pages/index/index",
"text": "首页",
"iconPath": "static/images/tabBar/tab-home.png",
"selectedIconPath": "static/images/tabBar/tab-home-current.png"
},
{
"pagePath": "pages/category/category",
"text": "分类",
"iconPath": "static/images/tabBar/tab-cate.png",
"selectedIconPath": "static/images/tabBar/tab-cate-current.png"
},
{
"pagePath": "pages/shopcart/shopcart",
"text": "购物车",
"iconPath": "static/images/tabBar/tab-cart.png",
"selectedIconPath": "static/images/tabBar/tab-cart-current.png"
},
{
"pagePath": "pages/center/center",
"text": "个人中心",
"iconPath": "static/images/tabBar/tab-my.png",
"selectedIconPath": "static/images/tabBar/tab-my-current.png"
}
]
}
```
### cate页面
静态页面搭建
初始化数据展示
`store/modules/category.js`
```js
import request from '@/utils/request.js'
const state = {
cateData: []
}
const mutations = {
RECEIVE_CATEDATA(state, cateData) {
state.cateData = cateData
}
}
const actions = {
async getCateData({ commit }) {
try{
let result = await request({
url: '/getCateGoryData'
})
commit('RECEIVE_CATEDATA', result)
}catch(e){
console.error(e)
return Promise.reject(e);
}
}
}
const getters = {}
export default {
namespaced: true, // 开启命名空间
state,
mutations,
actions,
getters
}
```
`pages/category/category.vue`
```js
{{ cate.name }}
{{ subCate.name }}
```
## day03
### 个人中心
个人中心页面将不再手动搭建页面,把已完成项目当中的页面粘贴过来,把涉及到数据和交互的地方删掉,我们自己写
登录页面也需要粘贴过来,个人中心点击头像的时候要跳转到登录页,进行登录获取个人的基本的信息,获取完成之后,返回个人中心页,展示个人信息即可
当个人中心页面已经有个人的基本的时候,不能够再次跳转 Login 页面
### 购物车
#### 静态页面展示
* 未登录展示 - 展示让用户登录
* 登录展示
* 购物车有商品展示 ----- 之研究有商品的
* 购物车没有商品展示
#### 初始化数据展示
购物车页面是没有接口的,需要我们自己造一些假数据,去商品列表中拿假数据
去首页的居家生活中拿数据,通过接口那后端的商品列表数据,放到store当中
1. 创建store,准备好store放数据
2
1. 发现首页nav中商品列表的数据是调用的 "/getIndexCateList" 接口
2
打开后端这个项目,找到 router 目录下的 index.js,找到这个接口
目的: 需要[了解]后端这个nodejs服务怎么写的?
达到效果: 可以自己在这个nodejs服务当中,复制粘贴出自己的接口
目的的意义: 后续在实战的时候,可能需要自己写接口,就拿着这个nodejs服务的架子,自己改接口,造一些数据
> 后端node项目介绍:
>
> koa是一个nodejs写后端服务的一个框架
>
> koa和express写法差不多,几乎可以说是一样的
>
> koa和express 的区别呢?
>
> koa 是由 express 原班人马打造,更小、更轻量化,更方便使用,本质上 express 和 koa 都是在写api接口
步骤:
找到 "/getIndexCateList" 接口的数据,粘贴两个商品的数据到store当中
注意: 这里粘过来的商品数据中是没有商品数量和选中状态的,我们需要手动给数据添加上这两个字段
```js
"isChecked": false, // 选中状态
"count": 7, // 商品数量
```
3. 展示数据
拿着store当中的数据映射到页面,进行展示
这里展示分为: 直接展示 和 间接展示(计算展示)
直接展示:
* 商品的列表
* 商品的选中状态 -- 我们自己手动添加的数据 isChecked
* 商品的数量 -- 我们自己手动添加的数据 count
间接展示(计算展示):
* 商品的全选状态
* 商品的选中个数
* 商品的合计金额
#### 交互
* 商品的选中 - 给每个商品选中位置绑定点击事件,切换商品的选中状态即可
* 商品数量的修改
* 全选
### 详情页
#### 静态页面搭建
从已完成项目中粘贴过来,把页面中的数据和交互删除静态就搭建好了
#### 初始化数据展示
从商品列表页携带参数到详情页
#### 交互
加入购物车交互逻辑:
需要判断在购物车中是否已有当前商品
如果购物车中有当前商品的话,此时购物车中的商品数量加1
如果购物车中没有当前商品的话,此时应该把当前商品添加到购物车中的数据
整个支付流程分为两大块,第一大块是 获取openId,第二大块是 支付流程
### 获取openId
什么是openId ?
当前用户在我们小程序当中的唯一标识 是 openId
openId 可以做什么事呢 ?
openId可以做一些隐私操作,例如: 支付
结论:支付之前一定要获取到 openId,如果没有openId的话 无法支付
如何获取 openId ?
使用 `wx.login()` 方法获取到登录凭证(code)。使用这个 code 可以换取 openId(换取有条件)
> 注意:
>
> 获取用户的基本信息,使用的是 `wx.getUserProfile()` 这个方法,这里值得是基本信息,用作展示的
>
> 而 `wx.login()` 是获取登录凭证的,用来换取openId的,而 openId 是支付的必要条件
步骤:
1. 小程序调用 `wx.login()` 获取登录凭证(code),登录凭证是用来换取 openId 的
2. 拿着登录凭证(code),发送请求到 开发者服务器(自己写的node后端),在后端服务器中获取到小程序传过来的登凭证(code) 加上 appId(小程序ID) 和 appSecret(小程序的密钥),调用腾讯的api `auth.code2Session` 这个接口,在我们后端的服务器接收到腾讯返回的 openId
> 注意:
>
> appId(小程序ID) 和 appSecret(小程序的密钥) 不能放到 前端小程序,用户可以拿到小程序的下载包反编译一下拿到 appSecret 就坏事了,所以 appSecret 必须放在服务器
3. 在后端拿着 openId 加密成 token 返回给 前端小程序,这样小程序就拿到了 token
> 注意:
>
> 这里不能直接把 openId 返回给前端小程序,如果这么做就相当于明文了,别人一旦截获到这个 openId 就可以拿着这个 openId 进行一些隐私操作
这里就已经完事了,但是后续需要验证一下 token,看一下token中有没有 openId,如果有可以进行支付等隐私操作
4. 携带上 token,发送请求到后端(node服务),对token进行解密,后端服务(node)可以验证 token 中的 openId 对不对,然后进行下一步业务逻辑
参考文档:
https://developers.weixin.qq.com/miniprogram/dev/api/open-api/login/wx.login.html
https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/login.html
https://developers.weixin.qq.com/miniprogram/dev/OpenApiDoc/user-login/code2Session.html
https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/login/auth.code2Session.html(这个可能打不开,用第三个,打不开的原因是腾讯的问题,之前是能打开的)
### 支付流程
支付必须是验证了商户的小程序才能做,我们这里的小程序是个人的,没办法做支付,只能讲一下支付的流程
注意:
支付之前必须获取到 openId,否则无法支付
步骤:
```js
1. 用户在小程序客户端下单(包含用户及商品信息)
2. 小程序客户端发送下单支付请求给商家服务器
3. 商家服务器同微信服务器对接获取唯一标识openID
4. 商家服务器根据openId生成商户订单(包含商户信息)
5. 商家服务器发送请求调用统一下单API获取预支付订单信息
接口地址:https://api.mch.weixin.qq.com/pay/unifiedorder
6. 商家对预支付信息签名加密后返回给小程序客户端
a)签名方式:MD5
b) 签名字段:小程序ID,时间戳,随机串,数据包,签名方式
c)参考地址:https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=7_7&index=3
7. 用户确认支付(鉴权调起支付)
a)API:wx.requestPayment()
8.微信服务器返回支付结果给小程序客户端9微信服务器推送支付结果给商家服务器端
```

> 注意:图中所有和黄色有关的操作是我们前端需要关注的,其他的都不需要关注
参考文档:
https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=7_4&index=3
小程序面试总结:
1. 页面之间的通信(5种)
* query传参
* 事件通道
* pubsub
* storage
* app实例传参
2. 分包三种
* 普通分包
* 独立分包
* 预下载分包
3. 支付流程(问的比较少)
重点: 获取openId的过程要了解
所有面试相关的问题得能使用自己的话说出来