2023年终总结|电商小程序的种种

120 阅读5分钟

本人在一个创业公司负责全部的前端工作,所以说是光杆司令也颇为合理。

2023是我入职后的第一年,也是前端正式工作的第一年

去年年底左右结束实习,入职后写了一些React,之后马上就开始创建小程序的项目。

对于我来说可以写用户端这件事情,还是很令人兴奋的,毕竟可以写出漂亮的东西了。相信这也是每一个前端开发同学曾经的梦想,那就是写出来优美的页面。

历时将近一年的小程序项目

从0到一的开发了这个电商小程序,考虑到没有跨端需求,所以采用了原生开发

着手封装网络请求

项目使用了一个将微信API封装为支持异步使用的库wx-promise-pro,这样就可以优雅的使用异步调用微信的api了,简单的封装了一下网络请求。

考虑到页面样式并不通用,所以并未添加UI组件库。

自己封装的一些组件会参考借鉴Vant UI

我认为Vant相对成熟一些,也想知道对于特殊样式或功能,vantUI使用的是自己实现还是二次封装的微信API

其实Vant的源码看起来还是相对简单的。我有一些功能会将它的源码简化一下,封装到自己的里面,例如计时器、弹出框、树形选择框、骨架屏这些。

总体来看封装组件奉行几个思想

  • 单一职责原则

理论上来说组件应该只负责一种功能,有着单一明确的职责,有利于降低代码复杂度,提升组件的可维护性。

另一方面,我认为它和类在设计上比较相似,封装特定的功能、模块,提供清晰明确的目标。

  • 可配置性

提供适当的配置选项,使得组件可以适应不同的用例。包括属性、事件、样式等的配置。参考组件库中的这些配置来进行封装就好了。

  • 样式隔离

不想用CSS in JS来处理样式隔离的时候,可以采用简单的前缀命名

如果你不想重复写前缀可以在小程序中搭配wxs语法使用来为wxml文件中的类名添加前缀,并使用less语法&来为css样式类名添加前缀

<wxs module="text">
    module.exports = {
        classAdd: function (name) {
            return 'van-' + name
        }
    }
</wxs>
<view class="{{text.classAdd('title')}}">
    <view class="{{text.classAdd('title')}}__label">
        
    </view>
</view>
.van-title {
    color: rgb(var(--color-6));
    &__label {
        font-size: var(--title-1)px;
    }
}
  • 完善的文档

虽然我们的用户可能大多数会懂这些封装的组件,但是一个完善的文档会让人更快更准确的了解到这个组件的作用,背景,可能不需要多正式,最简单的就是在组件的文件夹中创建 README.md

  • 自由发挥的一些性能、组件通信

这些和你的业务有关了,一些业务相关组件需要去封装一些复用的业务逻辑,这类业务组件更加需要文档来帮助其他人理解。

了解CSS动画

没有做过CSS动画的时候,可能对这个名词有一些遥望此山高的感觉。

但其实动画很简单,只需要分解一下目标效果的轨迹、时间和变化方式(放大、旋转、拉伸)这些基本动作。

常用来做动画的两个属性

  • animation

定义一个帧动画,通过关键帧来指定动画在每个时刻的样式。可以定义动画的持续时间、播放次数、延迟时间、缓动函数等

animation配合transform使用可以生成绝大部分动画,例如旋转一个元素。

//  首次等待5s后 在1s内 匀速 旋转 360度 无限重复旋转的操作

.box {
    animation: light 1s linear forwards 5s;
}

@keyframes light {
    0% {
        transform: rotate(0deg);
    }
    100% {
        transform: rotate(360deg);
    }
}

(我们经常听到开启硬件加速来优化动画,其实我们使用transform就算是优化了,它可以替代比如margin这种用来布局的属性。)

  • transition

可以让一个或多个属性的变化在一段时间内平滑地过渡。可以定义过渡的持续时间、延迟时间、缓动函数等

transition主要应用元素的状态发生改变时,例如从未选中变为选中态,使其高亮过渡的更平滑。

这两个属性基本可以全部覆盖一般的业务需求了。

一个工具型的小程序

是用来处理订单的分拣打包配送的小程序,主要涉及了一些文件图片等信息的上传。

监听图片、文件上传腾讯云

对于上传文件和图片这里我写了一个behavior,它让我不用关心图片上传到云存储的逻辑,只需要管理用户上传的数据就好了。

  • 上传操作:监听了file文件列表,用户上传时设置状态为0,触发监听后将状态为0的对象做上传操作,并设置上传中的状态,上传成功后更新上传成功状态。
  • 页面显示:image组件显示本地路径图片,用户无需等待上传完成即可查看图片
import { fetchGetUrl } from "xxxx"

module.exports = Behavior({
    observers: {
    // 监听imgList(可以自定义,我项目中的图片数组都用的这个字段)
        imgList: function (imgList) {
            imgList && Array.isArray(imgList) && imgList.map((item, idx) => {
                if (item.upStatus === 0) {
                    this.upLoadImg(idx)
                }
            })
        }
    },
    methods: {
        upLoadImg(index) {
            const originUrl = this.data.imgList[index].originUrl;
            this.setData({
                [`imgList[${index}].upStatus`]: 1
            })
            const fileExtension = originUrl.indexOf('.') > -1 ? originUrl.split('.').pop() : '';
            // 获取云存储上传链接
            fetchGetUrl({ bucket: "IMG", extension: fileExtension }).then((res) => {
                const regex = /(.*?)\?/;
                const matches = res.match(regex);
                //触发上传函数
                putFile(originUrl, res).then(res => {
                    if (res.statusCode !== 200) {
                        wx.showModal({ title: '上传失败', content: JSON.stringify(res), showCancel: false });
                        this.setData({
                            [`imgList[${index}].upStatus`]: 3
                        })
                    }
                    this.setData({
                        [`imgList[${index}].upStatus`]: 2,
                        [`imgList[${index}].cosUrl`]: matches[1]
                    })
                })
            })
        }
    }
})
// putFile函数传入拍照或上传后生成的临时链接 和 上传的腾讯云链接
const putFile = async function (filePath, url) {
    var wxfs = wx.getFileSystemManager();
    try {
        let fileRes
        try {
            fileRes = wxfs.readFileSync(filePath);
        } catch (error) {
            wx.showToast({
                title: '读取文件失败',
                icon: 'none'
            })
        }
        const res = await wx.pro.request({
            url: url,
            method: 'PUT',
            header: {
                'content-type': 'image/' + filePath.split('.')[1]
            },
            data: fileRes,
        })
        return res
    } catch (error) {
        return Promise.reject(error)
    }
};

过程中中也遇到许多小程序的问题,例如隐私收集、位置授权、小程序本身未修复的bug等等导致的问题。都算按部就班的解决了。