小程序高级电商前端第3周电商系统分类页面客服商品详情页面开发<三>----为你推荐实现

为你推荐实现:

概述:

接着https://www.cnblogs.com/webor2006/p/16645627.html继续往下学习,对于整个首页的功能,还差最后一个木有实现:

而这块也是最麻烦的,推荐的商品是需要分页加载的,效果如下:

而这里面需要实现一个瀑布流的列表布局效果,关于这块也是使用lin-ui组件来进行实现。

实现:

1、头图实现:

关于头图这块比较简单,而这次会使用一张本地的资源图,因为是不会变的,实际小程序开发中也会经常遇到使用本地图的情况,所以先将资源图导进来:

其该图片下载地址https://files.cnblogs.com/files/webor2006/title@interest.png.zip,然后将其显示在页面上:

具体的css样式设置:

预览一下:

2、瀑布流实现:

1、组件自定义性的终极方案:抽象节点的了解:

在前面我们也说了对于瀑布流的实现会使用lin-ui框架,所以咱们到官网上了解一下:https://doc.mini.talelin.com/,搜索一下:

其中可以看到它跟之前我们所使用的lin-ui的组件不太一样的是,采用了另一个技术来进行封装的:

所以接下来在正式使用它之前先来了解一下小程序抽象节点相关的知识,为更好的使用这个瀑布流组件打下良好的基础,更远地则是当你自己封装组件时则可在需要场景来使用抽象节点这样的一个技术:https://developers.weixin.qq.com/miniprogram/dev/framework/custom-component/generics.html

先来看一下官网的说明:

有时,自定义组件模板中的一些节点,其对应的自定义组件不是由自定义组件本身确定的,而是自定义组件的调用者确定的。这时可以把这个节点声明为“抽象节点”。

也就是组件中的内容是由开发者自己来定义的,这个内容就可以定义为一个抽象节点,回到咱们的这个瀑布流组件的场景,也就是该组件只提供了瀑布流组件的算法,也就是决定你提供的元素是怎么排列的,而具体元素的内容则由开发者自己来定义了,这样整个瀑布流组件就非常之灵活。

好,这些概念还是有些抽象,官网举了一个例子,咱们来理解理解:

例如,我们现在来实现一个“选框组”(selectable-group)组件,它其中可以放置单选框(custom-radio)或者复选框(custom-checkbox)

要你来定义组件,是不是得在组件中将单选框和复选框的控件都封装到组件里,然后给个参数让调用者来决定显示单选框或复选框?而如果是抽象节点的思想就可以这样定义:

其中,“selectable”不是任何在 json 文件的 usingComponents 字段中声明的组件,而是一个抽象节点。它需要在 componentGenerics 字段中声明:

这样就封装了一个带有抽象节点的组件了,接下来调用者使用该组件时就可以:

必须指定“selectable”具体是哪个组件,这样,在生成这个 selectable-group 组件的实例时,“selectable”节点会生成“custom-radio”组件实例。这样就达到一个控件类型由调用者来决定了。

2、抽象节点跟Slot插槽的区别?

在了解了小程序员抽象节点的概念之后,是不是感觉它跟之前https://www.cnblogs.com/webor2006/p/13197595.html所学习的Slot插槽很类似:

肯定它们两者是有区别的,下面来说明一下:

1、使用粒度:对于插槽来说,只需要写一段wxml代码既可,它的粒度是比较小的;而对于抽象节点,它必须让我们提供完整的一个组件,很明显它的粒度是比较大的。

2、使用难易度:对于插槽来说,使用简单,而对于抽象节点使用难度要大一些,毕竟要自己抽象一个组件【前提你得了解组件的定义】。

那第二点说到抽象节点的使用难度更大一些,那为啥要要推出它呢?是因为抽象节点很灵活,它把组件自定义的权限全部开放给了组件使用者,这也是为啥上面小标题说到这是一种组件自定义的终极方案,既然这么灵活那把组件都封装成这种抽象节点的形式呗,这是不行的,因为这种组件有了灵活性,但是缺少易用性,所以说,常规组件和抽象结点组件是有使用场景的。

3、思路整理:

在了解了抽象节点的概念之后,很明显我们在使用lin-ui的瀑布流组件时,咱们需要自定义每个列表项中的组件当作lin-ui的瀑布流组件的抽象节点,也就是:

思路也比较简单。

4、引入lin-ui的瀑布流组件:water-flow

接下来引入lin-ui的瀑布流组件:

接下来则可以在界面进行使用了,这里可以参考官网的使用示例:https://doc.mini.talelin.com/component/layout/water-flow.html 

所以咱们定义一下:

其中抽象节点的组件还木有新建,所以这里的组件名先空着。

5、新建抽象节点组件:

此时我们注册一下这个组件:

咱们就可以在瀑布流组件中这样来使用了:

6、智能推荐算法了解:

接下来则需要来编写这个商品推荐的组件了,而组件的前提是需要有数据,所以接下来需要从服务端来获取商品数据,而这个数据的标题是“为你推荐”:

很明显应该是根据用户的兴趣或者点击后台有一套智能推荐算法进行下发的对吧,关于智能推荐算法,做为web开发者很明显是不需要了解,它是另一门专业复杂的学科,所以这里其实也就是按照商品的时间顺序排列的一组数据,那如果要使用智能推荐,其实有一个比较简单的做法,这里简单了解一下,就是:给不同的商品打上不同的标签,然后再分析用户的点击记录,然后再根据点击记录跟标签进行一个对应,大概的估算出该用户用哪种标签是感兴趣的,然后再把这些标签所涉及到商品随机地组成一个列表推荐给用户,仅当一个了解。

7、数据准备:

先上https://course.talelin.com/lin/sleeve/3%20API%EF%BC%9ABanner.html#spu-%E5%95%86%E5%93%81文档查看一下API的说明:

其中由于它是需要支持分页的,所以对于所有需要分页的接口,需要加两个这个参数:

好,接下来则需要回到https://testapi.io/对这个推荐商品的mock数据进行一下创建,由于数据有限,这里我们每页只请求5条数据,这里先把第一页的mock数据的json贴出来:

{
    "total": 17,
    "count": 5,
    "page": 0,
    "total_page": 4,
    "items": [{
        "id": 23,
        "title": "双色牛仔裤",
        "subtitle": "秋冬新款,做一个Cool Boy",
        "img": "http://i2.sleeve.talelin.com/n11.png",
        "for_theme_img": "http://i1.sleeve.talelin.com/assets/702f2ce9-5729-4aa4-aeb3-921513327747.png",
        "price": "1399",
        "discount_price": null,
        "description": null,
        "tags": "",
        "sketch_spec_id": "1",
        "max_purchase_quantity": null,
        "min_purchase_quantity": null
    }, {
        "id": 10,
        "title": "碳素墨水",
        "subtitle": "虽然我们早已不再使用钢笔书写,但钢笔在纸上划过的笔触永远是键盘无法替代的。一只钢笔+一瓶墨水在一个安静的午后,写写内心的故事。",
        "img": "http://i2.sleeve.talelin.com/m24.png",
        "for_theme_img": "",
        "price": "80.00",
        "discount_price": "69.00",
        "description": null,
        "tags": "",
        "sketch_spec_id": null,
        "max_purchase_quantity": null,
        "min_purchase_quantity": null
    }, {
        "id": 3,
        "title": "抹茶小橡皮",
        "subtitle": "小作文写错了,用它擦一擦",
        "img": "http://i2.sleeve.talelin.com/m17.png",
        "for_theme_img": "https://gitee.com/lrelia7/sleeve-static/raw/master/theme/spu2.png",
        "price": "29.99",
        "discount_price": "17.00",
        "description": null,
        "tags": "一飞推荐",
        "sketch_spec_id": "1",
        "max_purchase_quantity": null,
        "min_purchase_quantity": null
    }, {
        "id": 15,
        "title": "多彩别针、回形针",
        "subtitle": "每盒70个,可爱多彩",
        "img": "http://i2.sleeve.talelin.com/m26.png",
        "for_theme_img": null,
        "price": "24",
        "discount_price": "19.9",
        "description": null,
        "tags": "三色可选",
        "sketch_spec_id": "1",
        "max_purchase_quantity": null,
        "min_purchase_quantity": null
    }, {
        "id": 14,
        "title": "Ins 复古小夹子(Mini)",
        "subtitle": "静静的,享受时光的流逝",
        "img": "http://i2.sleeve.talelin.com/m23.png",
        "for_theme_img": null,
        "price": "19.9",
        "discount_price": null,
        "description": null,
        "tags": "三色可选",
        "sketch_spec_id": null,
        "max_purchase_quantity": null,
        "min_purchase_quantity": null
    }]
}

其它页的数据这里就不贴了,自己可以根据情况来创建mock数据,接下来就回到testapi网站新建一个接口:

访问效果:

但是这里貌似没有发现如何来配置分页加载不同商品数据,所以,简单起见,这里就先整个假分页的数据,先把页面效果实现了,当然这里已加载完的状态从这个接口中体现不出来,到时可以程序改改条件模拟一下加载的效果,这里就不在mock数据上花太大精力了,精力主要花在如何实现上。 

9、定义spu.js:

数据已经准备好了,接下来则具体进行分页的处理,如之前Banner数据的获取是在model中进行定义了:

同样的,由于这个推荐数据是属于spu的,所以将这个数据的请求也封装到一个单独的spu.js中,所以新建它:

而对于分页的逻辑,其实是比较多的,上一页,下一页,是否已经滑到底了等,所以有必要将其封装起来,而不是将这个逻辑散步在各个页面当中,将其通用化。

9、Page对象封装:

1、思路整理:

接下来则来对分页的细节进行一个封装,其封装的最新效果先大概了解一下,目标明确之后实现起来思路也会清晰很多,先有一个Page类【有了ES6的类语法,对于class它具有天然的封装性】,然后它里面对外只提供一个特别简单的方法,就是获取下一页数据(getMoreData),然后最终由页面来调用,至于是否还有下一页,全定义在这个Page类当中。这里用文字描述可能比较抽象,下面具体来实现一下,等实现完了到时再回过头来看重温一下封装思路应该就有比较好的理解了。

2、新建Page类:

这里则在utils下新建一个paging.js:

3、对外定义getMoreData()来确认实现目标

 接下来,咱们对外先暴露一个方法:

 

这就是我们封装的目标,对外只暴露简单的调用接口,隐藏细节。

4、 定义分页属性:

目标明确之后,接下来则来慢慢填充实现细节,对于一个分类,通常会有一个服务端接口,请求的页码和每页的个数对吧,所以先来定义这三个属性:

而其中通常start是从0开始,count可以给个默认值:

5、加锁,避免重复请求:

对于下拉分页可能会频繁触底造成重复请求,当然这里可以从显示层来进行控制,比如触底时显示正在加载中阻止这种行为的发生,这里打算通过一个变量来进行控制,类似于人为加了一个锁,如下:

比较简单。 

6、发送请求:

接下来则需要进行接口的请求发送了,先定义一个方法:

而在发起请求的时候,看一下它需要的参数:

所以,很显然目前咱们在paging只对外暴露了一个url:

这个是不太合适的,所以这里将其改成一个js对象,以便请求的参数细节可以由调用方来进行控制,如下:

那接下来在发起请求时就可以把它传过去了:

但是!!!这样其实对于调用者是不太方便的,因为对于分页的场景我们是需要携带分页参数的:

最好将此细节封装,所以对req进行一下处理:

不过,这里写得有个bug可能会产生,就是:

因为每次调用此方法时,就会更新req.url,那么会造成参数不断的累加,解决起来也比较简单,就是保存一个原始req.url既可,改一下:

 好,接下来则可以调用它了:

接下来先来处理数据为空的情况:

接下来则需要判断一下是否还有下一页数据,其判断依据也比较简单,就是从服务器下发的这俩字段来进行判断:

具体逻辑如下:

最后还有一些细节需要处理一下:

最后咱们将此类导出去供其它外界进行调用:

10、调用Paging:

接下来咱们就可以来调用封装好的Paging进行分页数据的获取了,如下:

另外由于spu它涉及到的东西比较多,这里将spu.js细分一下,改个名称比较好一点:

接下来则回到home.js中来调用:

好,接下来则咱们运行看请求是否正常:

不过,这里是mock的一个固定的数据,分页不是动态的,木有关系,不影响功能的实现。

7、将数据显示在界面上:

有了数据之后,接下来就可以来处理商品界面的显示了,先来回忆一下当时我们采用的是lin-ui的water-flow组件来搭建的,它的每一个item是:

也就是指向的是这个组件:

所以,咱们先来编写界面布局:

接下来则需要在这个组件中定义一个属性,用来进行界面的渲染,如下:

接下来在图片显示时,就可以用这个属性了,如下:

好,目前界面上先简单设置一下,那现在的问题就是如何将我们请求的数据给传到这个组件当中的列表元素当中呢?这里需要这样做:

好,运行看一下:

那这里提出一个疑问,就是对于这句话:

为啥它这样调用,就可以将数据传到lin-ui的瀑布流组件上了呢?关于这个细节在未来再学。

总结:

由于篇幅比较长了,为你推荐的分页功能暂且先学到这,还是有很多知识点值得消化一下的,比如Paging的封装思想,如何将数据绑定到瀑布流组件上等,下次继续。

posted on 2023-02-08 12:38  cexo  阅读(129)  评论(0编辑  收藏  举报

导航