风袖电商小程序笔记第一周【走进Web全栈工程师】
购买了慕课网7七月老师的Java全栈课程,本着花了钱就认真学,在这里分周做笔记,也写一下这个过程遇到的坑(毕竟是一个6年前的课程了),怎么解决的,好在以后方便查看(我可不想看第二遍,也看不下去)
2025.11.25补充:还是需要重新完善一下内容,方便以后看懂,或者完全依靠看文章就可以把项目写完……
Java全栈序章
及时当勉励,岁月不待人
与以往的课程不同,Java全栈课程是把主流的Web技术串在一起,做一个真正的产品——前端的数据均有CMS控制
整个课程分4个阶段:第一阶段小程序,第二阶段小程序后端API,第三阶段CMS后端API,第四阶段CMS前端;有一种前后后前的开发流程;(小程序-C端API-CMS前端-CMS-API;)
课程覆盖小程序、Vue、Java和Spring Boot等知识面;
课程中的CMS的远比C端开发难,CMS会涉及到权限的访问和数据的修改等;先行体验CMS:CMS地址:
http://sleeve.7yue.pro(旧的不能访问);新访问地址:http://sleeve.talelin.com/既能做一个有成就感的大项目又能学习技术;课程比较均衡:小程序-Java Spring Boot-Vue3-CMS
长期课程规划与前置要求
非快餐课,长期维护,后续可能增加第二期,比如Spring Cloud;
前置基础要求:
- 小程序要求:JS、CSS、小程序基础、自定义组件、ES6、Promise;(不管基础跟着项目走、自学自补、参考《纯正商业应用微信小程序实战》)
- Java&Java SpringBoot:良好的Java语法基础(注解、接口、类、IOC),MySQL的基础知识
- Vue:有良好的小程序基础Vue其实就差不多的,初中高级Vue技术点会讲到
第一次作业(风袖细节分析)
研究线上风袖小程序的功能,制作思维导图;
重点:SKU和SPU的设计;
举例1:默认SKU和选择SKU:在淘宝一般都是逛的心态,所以一般不会有默认SKU(当然2025年淘宝是默认SKU的),需要用户自己去选择,而在京东,SKU一般是默认选择好的,用户看中就下单(2025年京东也是以SKU为主);
举例2:SKU的规格数量计算:在一些产品上,比如衣服,有3个颜色,每一个颜色都有3个图案,每一个图案有3个尺码,但是其中一个颜色的一个图案库存是0,这个时候就不能让用户去选择这个图案,包括这个图案下面的所有尺码,其他图案可以正常选择;
举例3:SKU可以被反选;
举例4:SKU要选择完整才可以购买和加入购物车,否则会提示你需要再选择哪个规格,并且阻止你加购物车或者购买,比如上面衣服例子,只选择颜色和图案,不选尺码,点击加购物车就会提示你请选择尺码;
举例5:在库存充足的情况下显示库存多少,在库存紧缺的时候,显示仅剩XX件并且标红,营造商品火爆的氛围;
举例6:在库存只有7件的时候,可以加购7件,但是写到8件,下方的加入购物车或者立即下单就会变成暂时缺货并且禁止点击;
举例7:可视规格->SKU图片
思维导图:

小程序注册与新建项目
微信公众平台:https://mp.weixin.qq.com/cgi-bin/loginpage?url=/cgi-bin/home/t=home/index&lang=zh_CN
获取AppID(小程序ID):开发与服务-开发管理-开发者ID
一定要写自己的AppID,否则一些微信接口可能后续无法使用。
首页布局详尽分析
主要分析首页的主题Theme和Banner:(为什么这里需要分析和区分这些,因为这些在后面的数据库设计会提到,这里的规划和数据库相关,具体可以参考第三周的———-学会抽象来简化数据库表设计)
每周上新有两个,但是Banner的每周上新,每一张图片可以跳转到主题或者商品详情页上去,
而主题只需要多了一个查看更多,并且只需要一张入口图,就可以跳转到不同的商品详情页。
第二次作业(LinUI瀑布流)
LinUI开源地址:https://github.com/TaleLin/lin-ui
LinUI文档:https://doc.mini.talelin.com/
- 安装:
1 | npm init |
执行成功后,会在根目录里生成项目依赖文件夹 node_modules/lin-ui (小程序IDE的目录结构里不会显示此文件夹)。
然后用小程序官方IDE打开我们的小程序项目,找到 工具 选项,点击下拉选中 构建npm ,等待构建完成即可。
根目录创建components文件夹放自定义组件,创建l-demo文件夹放l-demo自定义组件。
l-demo.js
在properties添加data,属性值Object来接受父组件传递的数据
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21// components/l-demo/l-demo.js
Component({
/**
* 组件的属性列表
*/
properties: {
data:Object//接受父组件传递的数据
},
/**
* 组件的初始数据
*/
data: {
},
/**
* 组件的方法列表
*/
methods: {
},
})l-demo.json
引入组件l-card和l-price
1
2
3
4
5
6
7{
"component": true,
"usingComponents": {
"l-card":"/miniprogram_npm/lin-ui/card/index",
"l-price":"/miniprogram_npm/lin-ui/price/index"
}
}l-demo.wxml
自定义组件基本结构,这里使用到l-card和l-price这两个组件,一定要引入(当时没有引入l-pric导致显示不了价格)
这里还需要注意data.XXXX里面不能为空,否则会警告,解决方式就是后面加上|| ‘’
1
2
3
4
5
6
7
8
9<l-card full type="cover" image="{{data.image|| ''}}" title="{{data.title|| ''}}" l-class="life-container" l-img-class="life-img" l-title-class="life-title" bindtap="onProduct">
<view class='life-product-contianer'>
<view class='art-content'>{{data.describe}}</view>
<view class='price-container'>
<l-price unit="¥" value="{{data.count|| ''}}" value-color="#ad0e11" unit-color="#ad0e11" value-size="36"></l-price>
<l-price l-class="del-price" unit="¥" value="{{data.delCount|| ''}}" value-color="#ad0e11" unit-color="#ad0e11" deleted del-color="#666" value-color="#666" unit-color="#666"></l-price>
</view>
</view>
</l-card>l-demo.wxss
自定义组件样式
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38/* demo.wxss */
.life-container {
width: 350rpx ;
padding: 0 0 20rpx 0 ;
background-color: #fff ;
box-shadow: 0px 8rpx 20rpx 0px rgba(9, 36, 66, 0.04) ;
border-radius: 16rpx ;
overflow: hidden;
margin-bottom: 20rpx;
}
.life-img {
width: 350rpx ;
height: 380rpx ;
}
.life-product-contianer {
padding: 0 10rpx;
display: flex;
flex-direction: column;
}
.life-title {
margin-left: 10rpx ;
}
.tag {
height: 30rpx ;
line-height: 30rpx ;
}
.art-content {
font-size: 28rpx;
color: #999;
margin-top: 15rpx;
display: flex;
flex-wrap: wrap;
}在根目录创建文件夹img,存放一张名为demo.png的图片
修改page/index页面
index.js
这里需要注意:/img/demo.png,要写相对路径不能写绝对路径
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96// pages/index/index.js
Page({
/**
* 页面的初始数据
*/
data: {
demo:[{
image: '/img/demo.png',
title: '显瘦中长款系带风衣',
describe: '柔软顺滑、上身挺括显瘦,垂坠飘逸、不易皱好打理。',
count: '888',
delCount: '666'
},
{
image: '/img/demo.png',
title: '显瘦中长款系带风衣',
describe: '柔软顺滑、上身挺括显瘦,垂坠飘逸、不易皱好打理。柔软顺滑、上身挺括显瘦,垂坠飘逸、不易皱好打理。',
count: '888',
delCount: '666'
},
{
image: '/img/demo.png',
title: '显瘦中长款系带风衣',
describe: '柔软顺滑、上身挺括显瘦,垂坠飘逸、不易皱好打理。',
count: '888',
delCount: '666'
},
{
image: '/img/demo.png',
title: '显瘦中长款系带风衣',
describe: '柔软顺滑、上身挺括显瘦,垂坠飘逸、不易皱好打理。',
count: '888',
delCount: '666'
}]
},
/**
* 生命周期函数--监听页面加载
*/
onLoad(options) {
wx.lin.renderWaterFlow(this.data.demo, false ,()=>{
console.log('渲染成功')
})
},
/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady() {
},
/**
* 生命周期函数--监听页面显示
*/
onShow() {
},
/**
* 生命周期函数--监听页面隐藏
*/
onHide() {
},
/**
* 生命周期函数--监听页面卸载
*/
onUnload() {
},
/**
* 页面相关事件处理函数--监听用户下拉动作
*/
onPullDownRefresh() {
},
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom() {
},
/**
* 用户点击右上角分享
*/
onShareAppMessage() {
}
})index.json
引入组件这里引入了瀑布流和自定义两个组件,可以在index页面使用
1
2
3
4
5
6{
"usingComponents": {
"l-water-flow":"/miniprogram_npm/lin-ui/water-flow/index",
"l-demo":"/components/l-demo/l-demo",
}
}index.wxml
使用自定义组件:
1
<l-water-flow generic:l-water-flow-item="l-demo"/>
至此使用linui瀑布流基本结束!
项目必须是动态的CMS可控
- 一个真实可用的项目,不会在本地写死图片和数据的,比如首页的活动图片,今天可能是这个活动,后天是另外活动,图片数据这些都是可以变化的,一切都是由后端的CMS决定的。比如现在的淘宝、京东都是这样,想要修改什么,只需要后台修改就可以;
- 这样做的好处个人觉得是可以软更新,快速更新,当然这里不只是指电商,电商和小程序是不得不这样操作的,小程序不可能给你那么多图片写死在上面,小程序对包的大小是有限制的,那可以用外链?可以是可以,但是这个链接写死在代码,以后更改只能又重新修改上传代码非常麻烦,电商更是如此,电商不可能总是那几张图片的,每天每周都有可能更新价格图片等;除了小程序和电商这种业务,一般的APP其实也可以这样做,只不过对带宽的要求更高,因为每一步操作都需要去请求后端数据;好处就是不用用户去重新下载更新app;
WebStorm开发小程序必备设置(废弃)
不使用WebStorm来开发小程序,改用为vscode,这里使用的是大前端Brian老师的vscode插件,可以在根目录创建.prettierrc文件,就可以实现文件保存自动格式化的功能:
.prettierrc
1 | { |
临时补充:appkey的申请
之前的是http://7yue.pro 现在改为:https://talelin.unna.com.cn 其实截止2025年已经废弃;最新的还是https://talelin.com/
appkey申请课程补充资料
- 打开:https://talelin.com/course 注册登录,获取开发者key,需要使用慕课网ID;
- 慕课网ID在https://www.imooc.com/user/setbindsns 头像下可以获取;
- 课程API文档:https://course.talelin.com/lin/sleeve/
调用服务端API获取数据
获取了appid,这里做第一次请求数据,根目录下创建config文件夹,config文件夹下创建config.js文件,作为配置文件
config\config.js
1 | const config = { |
一个完整的网络get请求:
pages\home\home.js
1 | onLoad(options) { |
小程序开发前必备配置
需要开启不校验合法域名、web-view(业务域名)、TLS版本以及 HTTPS 证书
配置文件与第一次调用服务端API
上面写了config配置文件,接下来用这个配置文件来完成调用后端的API接口,并在首页显示折扣图片
pages\home\home.js
1 | // pages/home/home.js |
pages\home\home.wxml
1 |
|
业务对象的重要性
对于前端page的js文件应该承担什么样的工作,page文件下的wxss写样式,wxml写骨架,json写页面的配置,一般情况下,js应该是写逻辑的,但是page下的js不应该把逻辑写在里面,因为这会导致代码混论,后期难以维护;页面的JS应该写数据绑定,可以理解为view视图层和业务逻辑之间的桥梁,或者说是中间层
后端常见的分层结构->MVC,页面的JS很像C->Controller,Controller不应该写业务,Model写业务,Model可以分Model、Logic、Service
前端虽然不用像后端那样有严格的分层,但是最少也得分出一层Model层来写业务
Model层按照业务类型来写
上面是视频里面的大概意思,但是按照我的想法,其实就是一个数据接口请求的逻辑,负责处理请求数据的一些操作;在后面还会学习到wxs,这个也是js,但是是属于页面上的逻辑
在根目录创建model文件夹,创建theme.js文件,存放获取主题的业务逻辑。
model\theme.js
1 | import { config } from "../../config/config"; |
封装HTTP请求
上面的theme.js是有问题的,this.setData不能直接在model使用,所以需要改写:
model\theme.js
1 | //业务对象 |
pages\home\home.js
1 | /** |
第一次封装:
在utils文件夹下新建http.js文件
utils\http.js
1 | import { config } from "../config/config"; |
重写theme.js
model\theme.js
1 | //业务对象 |
三层调用:home.js调用Theme.js,Theme.js调用http.js;这里回调函数里面又有回调函数,看着很混乱,后续需要再优化……
小程序中使用async和await的难点分析
处理异步最基本的方式是callback,进阶一点的是使用promise,最后是async await;上面的封装就是使用最基础的callback回调函数的方式;
这节中将使用async/await封装,async/await是基于promise;async 声明一个函数是异步的,await 等待一个Promise完成,并返回结果;但是截止2025年11月7号,微信小程序的网络请求接口也不支持返回promise,所以需要封装一个函数,让微信小程序的网络请求接口支持返回promise,
使用LinUI Promisic 让小程序内置API支持promise
在LinUI 有一个函数库Promisic,可以让微信小程序的网络请求接口支持返回promise。具体用法:
utils/util.js
1 | const promisic = function (func) { |
utils/http.js
1 | import { config } from "../config/config"; |
model/theme.js
1 | import { Http } from "../utils/http"; |
home.js
1 | /** |
将回调函数全部替换为async和await
在上一节中已经替换。
获取banner数据
上面已经封装了http,也让微信小程序的网络请求接口支持返回promise,可以直接使用async/await的写法,那接下来写banner数据的获取就简单多了
model\banner.js
1 | import { Http } from "../utils/http"; |
pages\home\home.js
1 | // pages/home/home.js |
pages\home\home.wxml
1 |
|
主要添加了Banner这个业务对象来请求Banner数据,对home.js进行了优化,把初始化数据统一写到一个函数里面。然后在onLoad的时候调用,优化了themeA和bannerB命名,需要在home.wxml修改为themeA.entrance_img,
banner轮播图实现与插槽的基本使用
获取到banner数据后,接下来完成banner的展示:
pages\home\home.wxml
1 |
|
pages\home\home.wxss
1 | /* pages/home/home.wxss */ |
这里主要使用到微信小程序内置的swiper组件,由于轮播图数量是后端决定,所以这里需要用到for循环,indicator-dots是显示圆点,indicator-active-color=”#157658” 设置圆点颜色,autoplay自动播放,circular循环播放
npm的Semver语法规则
接下来需要完成的是首页的六宫格,这里需要考虑的一点,这个项目是真实的项目,大都是由CMS控制的,这样做的好处是,可以“软更新”,说回九宫格,以后这里可能是3个分类,或者12个分类,都要确保这个宫格是均分的,所以这里就需要使用LinUI的组件,所以这节也不是讲的是LinUI组件的安装与使用,安装与使用在下一节课,六宫格实现的章节在随后。
- 安装nodejs LTS版本(建议使用nvm)视频安装版本:node=>10.16.0,npm=>6.9.0
- 项目根目录 npm init
- 安装LinUI:npm install lin-ui
- 执行成功后,会在根目录里生成项目依赖文件夹
node_modules/lin-ui(小程序IDE的目录结构里不会显示此文件夹)。
然后用小程序官方IDE打开我们的小程序项目,找到工具选项,点击下拉选中构建npm,等待构建完成即可。
Semver语义化版本:
- 主版本号:当你做了不兼容的 API 修改,
- 次版本号:当你做了向下兼容的功能性新增,
- 修订号:当你做了向下兼容的问题修正
package.json
1 | "dependencies": { |
^0.9.13向上箭头是指当这个组件次要版本升级的时候,在重新安装的时候会自动安装最新的次要版本,如最新的是0.10.1,那这里虽然写的是0.9.13,实际安装的是最新的0.10.1,如果只是想升级到最新的修订号,可以写号,如 `”lin-ui”: “0.9.13”`
LinUI安装、主题色配置与按需加载
具体参考文档;https://doc.mini.talelin.com/start/
LinUI Grid组件构建六宫格(上)
根目录创建components文件夹,存放自定义组件,新建category-grid文件夹,编写自定义组件
想要使用linui的 Grid组件,首先需要引入,所以这里可以在app.json下全局引入这个组件
1 | { |
LinUI Grid组件构建六宫格(中)
自定义组件的图片和文字是由后端决定的,那也就是这里需要发送一次请求,有两种方式,一种是在自定义组件的jS去请求接口,这样方便,另外一种是由调用方去请求接口,相对复杂一点,但是严谨,也确保自定义组件的纯粹性;这里采用第二种;
创建category业务对象接口
model\category.js
1 | import { Http } from "../utils/http"; |
home页面发送请求
pages\home\home.js
1 | /** |
注册自定义组件:
1 | { |
骨架,子组件接受grid数据
pages\home\home.wxml
1 | <s-category-grid grid="{{grid}}"></s-category-grid> |
子组件接受数据:
components\category-grid\index.js
1 | /** |
自定义子组件骨架:
components\category-grid\index.wxml
1 | <!--comment4--> |
至此,六宫格的数据请求和显示已经完成,接下来是完成六宫格的样式
LinUI Grid组件构建六宫格(下)
自定义组件不能直接设置class,如需要设置,需要使用外部样式类,插槽可以自定义内容,外部样式类可以自定义样式
components\category-grid\index.wxml
1 |
|
components\category-grid\index.wxss
grid-item设置width是为了点击区域扩大
1 | /* components/category-grid/index.wxss */ |
组件设计与linui使用的几个非常重要原则
必须在组件的灵活性和易用性之间做出一个选择,找到一个平衡点:
- 越是灵活的组件,易用性就越差(复杂度高),越是简单的组件,灵活性和定制性就不够
- 组件的默认值应该选在一个 能普遍适应50%,否则不是一个好用的组件,每一个组件都需要自定义非常繁琐。
组件到底意义是什么:
- 组件从三方面:样式、骨架、业务逻辑上对代码进行封装,方便开发者在日后复用样式、骨架、业务逻辑
组件必须要提供给用户的几个特点与方法:
组件必须允许用户通过某种方式对组件进行“自定义”,不能自定义或者自定义很弱的组件不是一个好的组件设计,自定义通常包括以下3种:
- 对样式自定义
- 对骨架自定义
- 对业务逻辑自定义
从现有技术手段。对于以上的自定义,微信小程序提供了以下几种方式来支持自定义:
- 外部样式类(对样式自定义)
- Slot插槽(对骨架自定义)
- 业务逻辑(Behavior行为,一般通过预设好的几种方式,然后给组件传参数选择)
但是正如课程中所谈到,业务逻辑自定义存在以下2个问题:
- Behavior依然繁琐
- 组件的业务逻辑自定义其实从某种角度来讲,是一个伪命题
为什么是伪命题,因为组件A之所以是组件A,而不是组件B,正是由于他自己独特的业务逻辑,如果改变了业务逻辑,那么组件A可能就不应该是组件A了,所以,组件对于业务逻辑性的自定义有待商榷
没有明确理由不要固定高和宽
页面布局的时候,如果不加宽高就能实现的效果,那建议就不加,让页面自适应,因为加了之后不好修改。
- 固定宽高,必须要有理由,比如为了点击时间的区域更大
- 固定宽高,弊端就是版本更迭繁琐,修改和维护不方便
- 固定宽高,数值难以确定
周总结
在这一周内,主要完成了HTTP的封装,让让微信小程序的网络请求接口支持返回promise,引入LinUI组件,完成首页的顶部图片,轮播图和六宫格;
其中重点是学习封装HTTP请求、promise和小程序中使用async和await
就项目本身而言,其实讲解到的内容很少,主要时长都是对内容深度的探讨,对涉及到项目整体宽度反而较少。