优惠券的一些基本概念:
在上一次小程序高级电商前端第1周走进Web全栈工程师<四>----自定义组件与Lin UI的小试牛刀已经使用Lin-UI完成了商品类别的展示,接下来则来实现它了:
在正式实现之前,先来对“优惠券”的一些基本概念有一个大致的了解,这个很容易理解呀,就是在买商品的时候可以拿它来抵钱进行消费嘛,是的,但是从优惠券的设计实现角度的话还是相当复杂的,当然主要是体现在服务端,由于咱们学习的目标是全栈,所以就不区分前端和后端了,提前多了解一些有益无害,主要说明如下几点:
1、优惠券它本身是分类型的,比如:满减、折扣。另外它使用的话也是有条件的:比如该券是否是全场券,还是说该券只能使用在某种商品分类下。
2、对于前端来说还需要判断优惠券的过期时间,而这个过期时间有可能是固定一个周期来使用,也有可能是当用户领了之后才开始核算有效期,多少天之后该券则失效之类的。
3、优惠券的领取和使用是两个完全不同的概述,切记不要混为一谈了,这个在之后再来体会。
4、所有的优惠券是通过活动来下发给用户的,也叫优惠券活动,一般有这在个信息:start_time、end_time,另外活动是可以动态上下架的,所以还需要有一个online是否在线的属性。
5、对于优惠券还需要有一些状态管理,如领取状态、是否使用、是否过期。
优惠券入口:
api:
如上面理论描述,这里的优惠券其实是以活动的形式来发放的,所以上官网3. API清单 | Lin Books查看一下API文档:
其实还有另一个类似的API:
很明显对于首页优惠券入口只需要显示入口图片既可,所以调用第一个不包含优惠券活动的API就可以了。
新建model:
其方法命名为啥叫getHomeLocationD呢?这块在之前有解释过,因为我们要获取的这个优惠券位于首页页面的第D个位置,所以就这么一种约定来命名啦。说到这块的命名,咱们目前有一处不太规范的地方正好将其改正了:
在IDE中重命名很简单,如下:
很顺其自然的操作对吧,但是!!!在js中,当你的代码足够复杂之后,这样的重命名可能会改错,也就是不该改的地方也改了,但是如果用java的话这样改是一点问题都不会有,因为可能用反射精准的帮你全部改正确,所以这一点需要知道,有这种风险存在。
发起http请求:
import {Http} from "../utils/http";
class Activity {
static locationD = 'a-2'
static async getHomeLocationD() {
return await Http.request({
url: `activity/name/${Activity.locationD}`
})
}
}
export {
Activity
}
其中注意一个细节:
这里暂且这么滴,接着在home.js中调用一下:
mock数据准备一下:
{
"id": 2,
"title": "夏日好礼送不停",
"entrance_img": "http://i2.sleeve.talelin.com/m14.png",
"online": true,
"remark": "限服装、鞋、文具等商品",
"start_time": null,
"end_time": null
}
界面图片显示:
此时回到home.wxml中:
此时运行看一下效果:
背景颜色到底怎么设置?
不过跟预期的效果还是有一些差别,第一是优惠券入口跟上面的分类是有一个间距的,这个比较容易,加一下margin就可以了:
但是!!!跟预期效果还是有区别的:
对于这个间距的实现有两个思路:
1、这个间距用view来实现,然后给它设置成一个灰色背景,很显然这种方式最low,是最不值得推荐的,因为列表的其它块也有类似的间距。
2、让整个页面弄成灰底,这是推荐的。
方式一:只针对home页面进行单独设置
这里要注意了,别小看了这个背景的设置,其实它的坑还是不少的,先来上微信开放文档中找到页面配置中设置背景颜色相关的属性:
这里为了看得比较明显,先设置成一个纯黑背景色,但是你会看到看不到效果,这是因为需要将它部署在真机上然后有下拉刷新效果时才能看到,这里截个图,大概这个背景色会体现在这里:
很显然目前这种方式达不到我们的要求,所以先把这个配置给去掉,再来想其它办法,第二个办法就是对home页面的根view元素进行背景色设定,如下:
运行背景色确实是有了,但你会发现好多问题:
下面一个个来进行解决,通过解决这些问题也能收获很多。
1、顶部多出来一个间隔:
这个坑非常不好找,原因是我们在新建小程序工程时微信就内置了container这样名称的样式,如下:
所以咱们将微信内置的这个css样式给去掉就好了,再预览效果:
2、为啥顶部主题与banner之间多出来一个间距?
看图说话:
这是因为小程序的图片标签会自带一个间距,解决的话,需要这样:
此时再来看一下间距就消除了:
3、分类六宫格整体为啥都黑了?
如上图也可以发现,咱们的分类宫格全黑了,是因为默认情况下此控件的背景是透明的,所以这里回到宫格组件下将其背景设置成白色既可:
此时再运行:
4、消除优惠券的底部间距:
同样的,对image添加一个这个属性既可:
运行:
但是你会看到优惠券底部还是有一些小黑背景,这个就跟图片的资源有关了,不影响大局先忽略了。
至此就达到了我们想要的灰间距的目的了,但是!!!有以下几个缺点:
- 需要每个页面都要设置背景,达不到一个全局化的配置;
- 只有内容区域设置了背景,全局页面木有。
这是啥意思呢?咱们切换一下iphone的机型预览,换分辨率更大一点的,就能看出来了:
方式二:全局背景设置
基于上面方式一的缺点,接下来再来寻找更优的一种设置全局背景的方法,先来将我们给home内容区域设置的背景色给去掉:
然后全局页面的背景色如何设置呢?其思路也很简单,就是找到一个rootView,像android中的每个页面的rootView不是一个DectorView么?同样的思路,这里需要使用到小程序工具上的这个界面来寻找rootView:
所以,咱们就可以针对这个page元素进行背景色的设置了,如下:
此时再来看效果:
嗯,完美,此时把背景色改为正常的灰色就可以了,如下:
此时整体再瞅一眼效果:
页面到底是否应该合并HTTP请求?
每周上新效果概述:
接下来则需要来实现每周上新了:
而它是属于一个主题,在之前咱们已经用过一个主题了:
准备API:
那先来准备请求这个主题的方法:
思考接口合并的场景:
在继续往下编写之前,这里思考一下,对于首页列表可能会有多个主题的数据要获取,针对这种场景其实存在一个接口合并粒度的问题,主要是有如下几种做法:
1、每一个主题的数据都发送一个http;
2、整个Home页面只发送一个http,然后一次性下发所有的数据;
3、有选择的把部分http请求合并成一个;
其实参考的指标主要是从以下几个角度来思考:
a、HTTP的请求数量;
b、HTTP会涉及到多少次的数据库查询;
c、接口的灵活性,接口的可维护性;
下面则分上面三个场景来分析一下:
1、每一个主题的数据都发送一个http;
- a、HTTP的请求数量;【很多】
- b、HTTP会涉及到多少次的数据库查询;【很多】
- c、接口的灵活性,接口的可维护性;【很灵活】
2、整个Home页面只发送一个http,然后一次性下发所有的数据;
- a、HTTP的请求数量;【只有一次,性能好 】
- b、HTTP会涉及到多少次的数据库查询;【一次http只会涉及到一次查询,而且不会重复】
- c、接口的灵活性,接口的可维护性;【灵活性最差】
3、有选择的把部分http请求合并成一个;
- a、HTTP的请求数量;【会相应减少】
- b、HTTP会涉及到多少次的数据库查询;【会相应减少】
- c、接口的灵活性,接口的可维护性;【这个得看怎么合】
其中把哪些接口合并成一个呢?其主要考虑的指标是它:
也就是看接口合并之后,能给服务器减少多少次的数据库查询,回到咱们的主题的接口来看,很显然可以通过一条SQL就可以查出所有的主题来对吧,所以是非常适合进行合并的。那为啥在做接口合并时主要看“b、HTTP会涉及到多少次的数据库查询;”这个指标呢?因为Web应用里最耗性能的就是IO,也就是属于IO密集型,与之对应的还有一个CPU密集型,像音视频的编解码之类的就是属于这种的,这块大致了解一下。
函数式编程概述:
更改获取多个主题的方法:
基于上面所分析的,咱们需要将主题获取的的逻辑更改一下,如下:
import {Http} from "../utils/http";
class Theme {
static locationA = 't-1'
static locationE = 't-2'
static locationF = 't-3'
static locationH = 't-4'
static async getThemes() {
const names = `${Theme.locationA},${Theme.locationE},${Theme.locationF},${Theme.locationH}`
this.themes = await Http.request({
url: `theme/by/names`,
data: {
names
}
})
}
}
export {
Theme
}
由于首页还有其它的一些主题,这里一次性的全定义了。
home.js中getHomeLocationA()逻辑进行修改:
接下来则回到home.js中调用一下获取所有主题的API:
接下来则需要从所有主题中找到对应主题的数据,这里当然可以进行json数组遍历来找,但是更好的一种方式是使用函数式编程,类似于Java8中Stream相关的遍历过滤集合的操作,具体如下:
此时这里有两个小细节待优化:
而关于==和===的区别可以参考一下它:js中==和===区别 - 果感 - 博客园
另外还有一个细节:
改为:
类可以保存数据,但对象可以保存状态:
目前咱们的代码还是不够优,先来看一下代码:
其实这些常量已经在Theme已经定义过了:
另外对于调用方还需要知道每一个theme数据获取的条件细节,这块很明显可以用面向对象的思路来对其进行封装一下,另外关于面向对象这里先抛出一句话:“类和对象本身就具有保存数据的功能,其中类能保存数据,但是不能保存状态;类的对象是既能保存数据又能保存状态”,怎么来理解呢?举例说明一下:
static的这些变量可以看到肯定是类具备保存数据的功能的,但是它能保存状态么?很显然是不行的,因为说到状态肯定是该属性是能变的,而如果像这样:
很显然类的对象是保存状态了,因为不同的对象,同样的 属性保存了2个数据的状态, 那对比一下类,为啥它就不能保存状态呢?看下面的代码:
请问一下此时a的值能同时保存1和2么?很显然只能保存2,所以类是可以保存数据,但是不能保存状态的。
重构Theme:
接下来就可以用面向对象的思想对咱们的Theme的数据获取这块给重构一下了,如下:
import {Http} from "../utils/http";
class Theme {
static locationA = 't-1'
static locationE = 't-2'
static locationF = 't-3'
static locationH = 't-4'
themes = []
async getThemes() {
const names = `${Theme.locationA},${Theme.locationE},${Theme.locationF},${Theme.locationH}`
this.themes = await Http.request({
url: `theme/by/names`,
data: {
names
}
})
}
getHomeLocationA() {
return this.themes.find(t => t.name === Theme.locationA)
}
getHomeLocationE() {
return this.themes.find(t => t.name === Theme.locationE)
}
getHomeLocationF() {
return this.themes.find(t => t.name === Theme.locationF)
}
getHomeLocationH() {
return this.themes.find(t => t.name === Theme.locationH)
}
}
export {
Theme
}
其中对于Theme对象,只需要请求一次服务器之后再拿各个主题都是从缓存中拿了?所以调用方也作相应的调整:
准备Mock数据:
在运行之前记得先准备mock数据:
[
{
"id": 1,
"title": "清凉一夏,折扣季",
"description": "秋天是金色的。麦穗是金色的,秋阳是金色的。虽然冬快至,但宜人的温度总是让我们心情愉快#我们为您精选了一系列秋冬折扣商品,慢慢挑选吧~",
"name": "t-1",
"entrance_img": "http://i2.sleeve.talelin.com/m2.png",
"extend": null,
"internal_top_img": "http://i2.sleeve.talelin.com/m33.png",
"title_img": "",
"tpl_name": "janna",
"online": true
},
{
"id": 5,
"title": "风袖甄选",
"description": "甄选",
"name": "t-3",
"entrance_img": "http://i2.sleeve.talelin.com/m9.png",
"extend": null,
"internal_top_img": "http://i2.sleeve.talelin.com/m11.png",
"title_img": "",
"tpl_name": "diana",
"online": true
},
{
"id": 6,
"title": "时尚穿搭",
"description": "帅点才有女朋友",
"name": "t-4",
"entrance_img": "http://i2.sleeve.talelin.com/m10.png",
"extend": null,
"internal_top_img": "http://i2.sleeve.talelin.com/m12.png",
"title_img": "",
"tpl_name": "irelia",
"online": true
}
]
然后将此json替换到原mock接口中返回值中既可:
关注个人公众号,获得实时推送