news 2026/10/24 5:18:21

模块化用法

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
模块化用法

一、模块化的基本概念

模块化就是把一整份代码按职责拆成若干独立文件,每个文件只负责一件事,对外通过固定接口暴露能力,其它文件按需把能力取过来用。

它要解决的是三个很具体的问题:

避免重复:同一段逻辑如果写两遍,修改时很容易只改到其中一处,另一处被遗漏。

界定边界:文件一旦过长,就很难判断改动某一行会影响到哪些地方。

便于协作:拆成模块之后,不同的人可以各自负责不同的文件,互不干扰。

1.1 小程序用的是 CommonJS,不是 ES6 模块

这是最容易搞错的一点。小程序里写模块用 module.exports(或 exports),取模块用 require;不是 ES6 的 import / export。

动作

小程序写法(CommonJS)

不能这样写(ES6)

暴露

module.exports = {...}

export default {...}

引入

const m = require('路径')

import m from '路径'

1.2 模块化只有两个动作

动作

代码

说明

出口(暴露)

module.exports = {...}

本文件把哪些变量、函数交给外部使用

入口(引入)

const m = require('路径')

把别的模块的出口拿到手,赋给一个变量

拿到手之后,就可以像用普通对象一样使用它:m.comMsg、m.comFunc()。

二、miniprogram-6 的模块版图

这个项目的规模很小,但把小程序里常见的模块形态都覆盖到了,因此很适合用来讲模块化。

2.1 目录结构

miniprogram-6 ├── app.js # 小程序入口,全局模块 ├── app.json # 全局配置(注册页面、窗口样式) ├── app.wxss # 全局样式 ├── common │ └── common.js # 跨目录的公共模块 ├── components │ └── navigation-bar │ ├── navigation-bar.js │ ├── navigation-bar.json │ ├── navigation-bar.wxml │ └── navigation-bar.wxss ├── pages │ └── index │ ├── index.js # 页面逻辑:引用模块 │ ├── index.json # 声明使用 navigation-bar 组件 │ ├── index.wxml # 页面结构 │ ├── index.wxss # 页面样式 │ └── my-index.js # 与 index.js 同目录的模块 ├── project.config.json ├── project.private.config.json └── sitemap.json

2.2 四种模块来源

pages/index/index.js 是整条链路的终点,它一口气引用了四种不同来源的模块。这四种来源基本覆盖了小程序里全部的可能性:

#

模块来源

怎么拿到

本项目对应

1

全局 App 实例

getApp()

app.appMsg / app.appFunc

2

跨目录自定义模块

require('../../common/common')

comm.comMsg / comm.comFunc

3

同目录自定义模块

require('my-index.js')

myIndeX.myIndexMsg 等

4

本模块内部定义

const / function 直接写

indexMsg / indexFunc

三、四种模块来源逐一拆解

3.1 全局模块:app.js + getApp()

app.js 里用 App() 注册的是整个小程序唯一的全局实例,它上面的属性和方法任何页面都能取到:

// app.js App({ appMsg:'来自全局模块的变量', appFunc(){ return '来自全局模块的函数' } })

页面里用 getApp() 拿到这个实例:

// pages/index/index.js const app = getApp() console.log(app.appMsg) // 来自全局模块的变量 console.log(app.appFunc()) // 来自全局模块的函数

注意:getApp() 是全局函数,不需要 require。

适用场景:登录态、全局配置、设备信息这类「整个小程序只有一份」的数据。不要滥用:全局变量一多,就很难追查是谁改了它。

3.2 跨目录模块:common/common.js

这是最常见的模块形态——把公共逻辑抽到单独目录,再 require 进来:

// common/common.js const comMsg = '来自不同目录下模块的变量' function comFunc(){ return '来自不同目录下模块的函数' }
//导出模块的变量和函数 module.exports = { comMsg, comFunc }

页面里用相对路径引入:

// pages/index/index.js const comm = require('../../common/common') console.log(comm.comMsg) // 来自不同目录下模块的变量 console.log(comm.comFunc()) // 来自不同目录下模块的函数

路径怎么数:index.js 在 pages/index/ 下,要回到项目根目录需要退两级,所以是 ../../,再进入 common/。require 的路径是相对于当前文件的,不是相对于项目根目录——这是最容易写错的地方。

3.3 同目录模块:pages/index/my-index.js

my-index.js 和 index.js 在同一个目录里,直接用文件名引入:

// pages/index/my-index.js const myIndexMsg = '来自相同目录下不同模块的变量' function myIndexFunc(){ return '来自相同目录下不同模块的变量' } module.exports = { myIndexMsg, myIndexFunc }
// pages/index/index.js const myIndeX = require('my-index.js')

这种直接写文件名的写法与微信官方文档「同一包内调用」的示例一致(官方示例写的是 require('common.js'))。

上面这段 my-index.js 里有一个实际存在的笔误:myIndexFunc() 返回的是「变量」而不是「函数」。为了如实反映项目现状这里保留原样,正确写法见第六节。

3.4 本模块内部:直接定义

不需要跨文件复用的内容,就在文件里直接定义,不必为了「模块化」而模块化:

// pages/index/index.js const indexMsg = '来自本模块的变量' function indexFunc(){ return '来自本模块的函数' }

四、页面如何把四种模块拼起来

pages/index/index.js 会把四种来源的模块全部引入,并把结果显示到页面上:

// pages/index/index.js const indexMsg = '来自本模块的变量' function indexFunc(){ return '来自本模块的函数' } const app = getApp() const comm = require('../../common/common') const myIndeX = require('my-index.js') Page({ data:{ msg1:'index.js模块引用'+app.appMsg, msg2:'index,js模块引用'+app.appFunc(), msg3:'index.js模块引用'+comm.comMsg, msg4:'index.js模块引用'+comm.comFunc(), msg5:'index.js模块引用'+myIndeX.myIndexMsg, msg6:'index.js模块引用'+myIndeX.myIndexFunc(), msg7:'index.js模块引用'+indexMsg, msg8:'index.js模块引用'+indexFunc() } })

4.1 八个结果分别来自哪个模块

页面用 msg1 到 msg8 八个变量展示结果,并用不同背景色区分来源:

变量

运行时结果

来源模块

背景色

msg1

来自全局模块的变量

app.js

brown

msg2

来自全局模块的函数

app.js

brown

msg3

来自不同目录下模块的变量

common/common.js

yellow

msg4

来自不同目录下模块的函数

common/common.js

yellow

msg5

来自相同目录下不同模块的变量

pages/index/my-index.js

aqua

msg6

来自相同目录下不同模块的变量(原代码有误)

pages/index/my-index.js

aqua

msg7

来自本模块的变量

pages/index/index.js

aquamarine

msg8

来自本模块的函数

pages/index/index.js

aquamarine

4.2 页面结构与组件声明

<!-- pages/index/index.wxml --> <navigation-bar title="Weixin" back="{{false}}" color="black" background="#FFF"></navigation-bar> <scroll-view class="scrollarea" scroll-y type="list"> <view class="box"> <view class="title">引用来自不同模块的变量和函数</view> <view style="background-color: brown;">{{msg1}}</view> <view style="background-color: brown;">{{msg2}}</view> <view style="background-color: yellow;">{{msg3}}</view> <view style="background-color: yellow;">{{msg4}}</view> <view style="background-color: aqua;">{{msg5}}</view> <view style="background-color: aqua;">{{msg6}}</view> <view style="background-color: aquamarine;">{{msg7}}</view> <view style="background-color: aquamarine;">{{msg8}}</view> </view> </scroll-view>

index.wxml 用到的 navigation-bar 不是内置组件,而是一个自定义组件,必须在 index.json 里声明后才能使用:

// pages/index/index.json { "usingComponents": { "navigation-bar": "/components/navigation-bar/navigation-bar" } }

这里又体现了一次模块化:components/navigation-bar/ 目录下的四个文件(.js / .json / .wxml / .wxss)组成了一个自带结构与样式的独立模块,页面只需要一行声明就能复用它的全部能力。

五、三个必须记住的要点

5.1 路径是相对当前文件的

require 的路径以当前文件所在目录为起点。同样是引入 common.js,在不同位置写法完全不同:

当前文件位置

正确的引入写法

pages/index/index.js

require('../../common/common')

app.js(项目根目录)

require('./common/common')

common/other.js

require('./common')

5.2 模块只会被执行一次

require 同一个模块多次,拿到的都是同一个对象(单例)。这意味着模块里的 const 只初始化一次,可以放心用它做缓存或共享状态。

5.3 模块导出的是一个对象

不管用哪种写法,最终暴露出来的都是一个对象,所以使用方永远是「模块名.成员名」:

module.exports = { comMsg, comFunc } // 导出

const comm = require('...') // 引入

comm.comMsg // 使用:点出成员

六、通读项目后发现的问题

6.1 my-index.js 的函数返回了错误的文字(建议修)

myIndexFunc() 应该返回「函数」,但实际返回的是「变量」,导致页面上 msg6 显示为「来自相同目录下不同模块的变量」,和它上面那行 msg5 一模一样,读者会以为这两行是同一个东西。

// pages/index/my-index.js —— 当前代码(有误)

const myIndexMsg = '来自相同目录下不同模块的变量'

function myIndexFunc(){

return '来自相同目录下不同模块的变量' // ← 应为「函数」

}

修改为:

const myIndexMsg = '来自相同目录下不同模块的变量'

function myIndexFunc(){

return '来自相同目录下不同模块的函数' // ← 改为「函数」

}

七、什么时候该拆模块

模块化不是越多越好。出现下面任一情况,就该考虑拆:

• 同一段逻辑出现在两个以上文件里:抽成公共模块。

• 一个文件超过两百行,且能明确分成几块:按块拆开。

• 有纯粹的、与页面无关的工具函数(日期格式化、金额计算):放 common/ 或 utils/。

• 有需要复用界面和交互的:用自定义组件(components/),而不是普通 JS 模块。

反过来,只被一个页面用到、又只有几行代码的东西,留在页面里就好——为了拆而拆,只会让人多跳几个文件才能读懂逻辑

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/24 5:18:02

Hyperframes超帧技术:实现高质量视频插帧与慢动作重建

1. 为什么我会在视频项目里盯上 hyperframes先交代一下背景。上个月我在处理一批运动相机素材&#xff0c;45分钟的骑行视频&#xff0c;想把其中几段高速冲坡镜头做成慢动作。常规做法是直接把 30fps 插到 120fps&#xff0c;可我试了几个开源插帧模型之后&#xff0c;发现它们…

作者头像 李华
网站建设 2026/10/24 5:18:21

DeepSeek本地部署与集成方案选型对比:从命令行到可视化与办公插件

DeepSeek本地部署并非只有一种路径。从搜索结果看&#xff0c;社区已经形成了从命令行到可视化界面&#xff0c;再到办公插件集成的多种方案。不同方案在安装复杂度、交互体验和适用场景上差异明显&#xff0c;选型时需要结合自身技术背景和实际需求。 基础层&#xff1a;Ollam…

作者头像 李华
网站建设 2026/10/24 5:17:04

2_tp_csdn

BSP调试#12&#xff1a;TP&#xff08;全志T527&#xff09;# BSP调试#12&#xff1a;TP&#xff08;全志T527&#xff09; 调试前 触摸调试前需要了解 Linux Input 子系统的基本框架以及数据上报流程。Linux Input 子系统分为 3 层 &#xff0c;从底层硬件到上层应用链路如下&…

作者头像 李华
网站建设 2026/10/24 5:17:16

纯数学表达式实现布尔逻辑与条件分支

纯数学表达式实现布尔逻辑与条件分支一年前的奇思妙想&#xff08;ai让我发的呀&#xff09;&#xff1a;尝试不依赖任何编程语言的控制流&#xff08;if-else, while&#xff09;&#xff0c;仅使用纯数学公式&#xff08;四则运算、绝对值、最大值函数&#xff09;&#xff0…

作者头像 李华