# 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 运行项目 - 运行的是后端服务器,目的是为了让小程序项目启动起来可以调用接口 ![](assets/01.png) 2. 启动 Hbuilder 编辑器,将路径 `学生资源\uniapp已完成代码\unishop01` 中的这个 `unishop01` 项目拖拽到 Hbuilder 的侧边栏 3. 打开项目中 `manifest.json` 文件,找到`微信小程序配置项`,将自己的小程序 appId 替换进去即可 ![](assets/02.png) 4. 点击一下侧边连的项目,点击 Hbuilder 顶部"运行",再点击"运行到终端",再点击"运行设置",打开运行项目的配置页面,配置小程序编辑器的路径 > 小程序是腾讯出的,只有"微信开发者工具"IDE有模拟器,Hbuilder 是没有模拟器的,写好代码之后最终代码运行还是再 "微信开发者工具" 当中运行,所以 Hbuilder 启动 "微信开发者工具" 需要配置 "微信开发者工具" 的安装目录 ![](assets/03.png) ![](assets/04.png) ![](assets/05.png) 5. "微信开发者工具"也需要配置,打开"微信开发者工具",在右上角有一个设置选项,打开设置,设置界面有个"安全"选项,打开"服务端口"选项 > 这一步就像我们手机上点击某一个连接要跳转至 "淘宝",手机会弹出提示框"是否要跳转至淘宝",淘宝这个软件只有允许其他程序调起,才能真的调起"淘宝"应用,如果淘宝应用不允许其他应用调起,是无法调用起来的 > > 我们这里,这个"服务端口"打开,就是允许其他程序调起 "微信开发者工具" ![](assets/06.png) 6. 在侧边栏,点击一下项目,点击顶部菜单"运行",选择"运行到小程序模拟器",再选择"微信开发者工具",此时应该就可以启动项目了 > 注意:如果是第一次启动项目,并且是 Hbuilder 最新版本,应该会去自动安装插件,需要一些时间,让程序自动安装即可 > > 如果是老版本 Hbuilder 那么插件需要自己安装,自己安装的步骤如下: > > ![](assets/07.png) > > ![](assets/08.png) > > ![](assets/09.png) > > ### 创建项目 在 Hbuilder 侧边栏右侧新建项目,新建一个空的uniapp项目,然后上传到 gitee 上,设置成开源,大家可以访问了 gitee地址: https://gitee.com/newsegmentfault/guigu_shop_0609 ![](assets/10.png) #### 目录介绍 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 ``` ###### 获取数据进行展示 ```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文件中进行配置 创建的时候 ![](assets/11.png) > 注意:勾选上"在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 ``` ## 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微信服务器推送支付结果给商家服务器端 ``` ![](assets/13.png) > 注意:图中所有和黄色有关的操作是我们前端需要关注的,其他的都不需要关注 参考文档: 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的过程要了解 所有面试相关的问题得能使用自己的话说出来