文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

小程序中怎么进行模块化处理

2023-06-22 06:41

关注

这篇文章主要介绍了小程序中怎么进行模块化处理,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。

ES6和commonJS的选择

首先在微信小程序中不论是 ES6 或者是 commonJS 模块化语法都是支持的,在传统的web项目中我个人是习惯统一使用 ES6 模块化语法进行开发的。

在最初我也是将小程序中所有的通用方法抽离成单独的文件,并使用exportexport default 导出,使用 import 引入。

注意点

但是!在实际开发中,小程序的js文件是不支持绝对路径引入的!这意味着如果你需要在你的页面中引入一个公用方法,你必须使用 ../../../xxx/xxx.js 的方式,当你同一个页面引入多个模块时,这种写法绝对会极大的打击你的开发热情。

解决方式

那我们该如何解决这么长的引入路径呢,在web项目中,我们常常会使用路径别名的方式,例如 webpackvite 中的 resolve.alias 来缩短引入的路径。

alias: {"@src":path.resolve("src"),

但是在原生微信小程序中,虽然可以通过 gulp 或者 webpack 等一些前端工程化的工具对小程序进行一些改造,但是作为一个开源项目我希望它的启动过程不需要太多额外配置。最好是能够使用原生的语法去实现。

最终我选择了在 app.js中新增一个require方法用于引入模块,这样在页面内引入模块时,我们只需要使用app的实例来进行模块引入,这样可以实现使用与app.js文件的相对路径来引入文件.

// app.jsApp({    require(path){        return path    }})

使用方式

// 使用基于app.js的相对路径来引入文件,这样就避免了写很多"../"const app = getApp()const upload = app.require("lib/upload")

当然这样做也不是特别方便,首先是代码提示的不健全,使用以上方式的话可能对于参数或者一些返回值的提示不到位,但是影响不大。如果之后我摸索出了其他比较好的实现方式再写一篇文章解析。其次是必须使用全局统一使用commonJS 的模块化语法啦,不过这一点的话问题不大。

单页面模块化

小程序中并没有提供特殊的模块化方式,比较常用的就是将一些方法抽离为单独的js文件,然后再引入。想要避免一个页面文件代码太长的话最好的方式是组件化,但是在小程序中,认为写组件真的是一件很不爽的事情。

小程序组件拥有自己的生命周期,而且引入时必须在页面json中提前定义,由于组件是挂在在shadow root节点上,如果想要和页面共享样式例如colorUI的全局样式还需要写入单独的配置项styleIsolation。整体开发体验相比vue而言比较割裂。

基于以上的一些个人看法,我在写小程序时比较少使用组件,如果是需要抽离wxml或者是js我通常使用以下的方法。

wxml模块化

在小程序中我通常使用 模板template 进行抽离复用,微信小程序模板文档 ,模板相较于组件抽离的仅仅是部分的页面,不包含功能部分的抽离。

以下是我抽离的一个模板,这是一个文章的列表项,它并没有什么单独的功能,但是代码很长并且却在很多页面中复用到,于是我将它进行了一个抽离。把样式都通过行内样式的方式写上,这样在哪里引入都是一样的样式。

<!-- 文章列表项 --><import src='./avatar' /><template name="post-item"><view class="margin padding-sm bg-white radius flex shadow " style="position: relative;height: 350rpx;border-radius: 10rpx;">        <!-- 背景蒙版 -->        <view style="position: absolute;top: 0;left: 0;width: 100%;height: 100%;border-radius: 10rpx;">                <image style="filter:blur(2px) grayscale(80%) opacity(80%)" lazy-load="{{true}}" src="{{imgList[0]}}" mode="aspectFill"></image>        </view>        <view style="position: absolute;top: 0;left: 0;width: 100%;height: 100%;background-color: rgba(30, 30, 30, 0.8);border-radius: 10rpx;">        </view>        <view style="z-index: 10;width: 100%;" class="text-white">                <!-- 文章 -->                <view class="text-xl  ">                        <text class="cu-tag margin-right-sm bg-color radius">{{topic}}</text>                        <text class="text-bold">{{title}}</text>                </view>                <!-- 文章内容 -->                <view class="margin-top-xs text-sm text-cut">{{content}}</view>                <view class="flex align-end justify-between margin-top">                        <!-- 文章图片 -->                        <view class="flex align-center">                                <view class="margin-xs" style="width: 120rpx;height: 120rpx;" wx:for="{{imgList}}" wx:key="{{index}}" wx:if="{{index < 3}}">                                        <image class="radius" src="{{item}}" mode="aspectFill"></image>                                </view>                        </view>                        <!-- 浏览量-点赞数 -->                        <view class="bg-color flex align-center text-white text-sm radius" style="padding: 4px 12px;">                                <view class="cuIcon-attention "></view>                                <view class="margin-left-xs">{{viewNum||0}}</view>                                <view class="cuIcon-like margin-left"></view>                                <view class="margin-left-xs">{{favorNum||0}}</view>                        </view>                </view>                <!-- 发布时间 -->                <view class="margin-top-xs flex align-center text-sm text-gray justify-between padding-lr-xs">                        <view class="flex align-center">                                <template is="avatar" data="{{size:45,avatarUrl:user.avatarUrl}}" />                                <view class="margin-left-xs">{{user.nickName}}</view>                        </view>                        <view>{{createTime}}</view>                </view>        </view></view></template>

在页面中使用的时候需要提前引入,由于可以引入多个模板,因此使用时需要使用 is属性 声明使用的是哪一个template,数据的话可以通过data属性传入,这里的示例是我将遍历的item解构后再赋值进去。

<!-- 某个页面 --><import src='../../template/post-item' /><template data="{{...item}}" is="post-item" />

当然使用template进行模块化进行抽离的模板代码可不能包涵太多的功能逻辑,具体的使用还是需要根据业务来噢。

js模块化

在小程序中最基本的js模块化就是直接抽离js文件,例如一些全局通用的方法,下面展示一个全局上传方法的封装

// lib/upload.js// 上传方法module.exports = async function upload(path) {return await wx.cloud.uploadFile({cloudPath: new Date().getTime() + path.substring(path.lastIndexOf(".")),filePath: path,})}
// pages/form/form.jsconst app = getApp()const upload = app.require("lib/upload")Page({async submit() {    wx.showLoading({            mask: true,            title: "发布中"    })    const imgList = []    for (let img of this.data.form.imgList) {            const uploadRes = await upload(img)            imgList.push(uploadRes.fileID)    }    // ...其他业务代码    }})

当然以上的办法对于通用方法来说很方便,但是对于与 页面操作的逻辑耦合性 很高的一些业务代码,这样子抽离并不方便。

在vue2中我们可以使用mixin的方法模块化代码,在vue3中我们可以使用hook的方式模块化代码,但是在小程序中并没有以上两者的支持,最初我想仿照 vue3的hook 方式进行页面js封装改造,但最终实现的效果不理想,于是选择了实现一个模仿vue2 mixin 的方法来实现模块化。

具体代码其他博主有实现过,因此我就直接拿来使用了,具体代码如下。如果不了解vue中mixin的使用方法的可以自行去官网看文档,这里不做过多介绍。

// mixin.js// 保存原生的 Page 函数const originPage = Page// 定义小程序内置的属性/方法const prop = ['data', 'properties', 'options']const methods = ['onLoad', 'onReady', 'onShow', 'onHide', 'onUnload', 'onPullDownRefresh', 'onReachBottom', 'onShareAppMessage', 'onPageScroll', 'onTabItemTap']Page = (options) => {  if (Array.isArray(options.mixins)) {    const mixins = options.mixins    delete options.mixins    mixins.forEach((mixin) => {      for (let [key, value] of Object.entries(mixin)) {        if (prop.includes(key)) {          // 混入属性          options[key] = {            ...value,            ...options[key]          }        } else if (methods.includes(key)) {          // 混入原生方法          const originFunc = options[key]          options[key] = function (...args) {            value.call(this, ...args)            return originFunc && originFunc.call(this, ...args)          }        } else {          // 混入普通方法          options = {            ...mixin,            ...options          }        }      }    })  }  originPage(options)}

实现的原理是改造小程序中的Page()函数,小程序的每一个页面都是通过调用Page({option})方法来实现的,在option参数中传入页面相关的data和声明周期函数及其他方法。

我们通过在Page方法的参数option中增加一个mixin属性,这个属性可以传入一个数组,数组即是每一个要混入的模块,每一个模块的结构其实与参数option是一样的,我们只需要将所有混入的模块与页面自身的option进行一个参数和方法的合并就能实现一个mixin的功能。

使用的方法是现在app.js中引入mixin.js

// app.jsrequire("./mixins.js")App({// ...其他代码})

然后我们写一个常规页面的js,业务代码大家不用看,主要关注Page的属性中多了一个mixins选项,而mixins数组中有一个topic模块。

// pages/form/form.jsconst app = getApp()const upload = app.require("lib/upload")const to = app.require("lib/awaitTo")const db = wx.cloud.database()Page({mixins: [require("./mixins/topic")],data: {user: wx.getStorageSync('user'),form: {title: "",topic: "",content: "",imgList: []}},chooseImg() {wx.chooseImage({count: 9 - this.data.form.imgList.length,sizeType: ['original'], //可以指定是原图还是压缩图,默认二者都有sourceType: ['album', 'camera'], //从相册选择success: (res) => {res.tempFilePaths = res.tempFilePathsif (this.data.form.imgList.length != 0) {this.setData({ "form.imgList": this.data.form.imgList.concat(res.tempFilePaths) })} else {this.setData({ "form.imgList": res.tempFilePaths })}}});},async delImg(e) {const index = e.currentTarget.dataset.indexconst temp = this.data.form.imgListtemp.splice(index, 1)this.setData({ "form.imgList": temp })}})

由于 topic 内都是关联性较强的属性与方法,因此就可以抽离出来,这样页面的js就会更加精简啦,如果有更多的代码就根据自己对于功能的判断进行抽离,然后放在页面对于mixin目录中即可!

// // pages/form/mixin/topic.jsconst db = wx.cloud.database()module.exports =  {    data:{        topic:{            flag:false,            list:[]        },    },    onLoad(options) {this.getTopic()    },    async getTopic(){const res = await db.collection("topic").get()this.setData({"topic.list":res.data})},clearTopic(){this.setData({"form.topic":""})},toggleTopic(e){        console.log(e.currentTarget.dataset)const flag = e.currentTarget.dataset.flagthis.setData({"topic.flag":flag})},}

注意点

但是使用mixin也有着与vue中同样的问题就是变量及方法的来源不好追溯,变量是在那个位置定义的比较难以定位,这时就更加依赖开发者的开发规范以及命名方式了,再不济也可以每一个方法写一个独有的注释嘛~

感谢你能够认真阅读完这篇文章,希望小编分享的“小程序中怎么进行模块化处理”这篇文章对大家有帮助,同时也希望大家多多支持编程网,关注编程网行业资讯频道,更多相关知识等着你来学习!

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯