免费获取学习方案
ARTICLE DETAIL

资讯详情

深耕编程基础知识与建站技术分享的一线实战洞察。

模块化用法

模块化用法 一、模块化的基本概念模块化就是把一整份代码按职责拆成若干独立文件每个文件只负责一件事对外通过固定接口暴露能力其它文件按需把能力取过来用。它要解决的是三个很具体的问题避免重复同一段逻辑如果写两遍修改时很容易只改到其中一处另一处被遗漏。界定边界文件一旦过长就很难判断改动某一行会影响到哪些地方。便于协作拆成模块之后不同的人可以各自负责不同的文件互不干扰。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.json2.2 四种模块来源pages/index/index.js 是整条链路的终点它一口气引用了四种不同来源的模块。这四种来源基本覆盖了小程序里全部的可能性#模块来源怎么拿到本项目对应1全局 App 实例getApp()app.appMsg / app.appFunc2跨目录自定义模块require(../../common/common)comm.comMsg / comm.comFunc3同目录自定义模块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.jsmy-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.jsbrownmsg2来自全局模块的函数app.jsbrownmsg3来自不同目录下模块的变量common/common.jsyellowmsg4来自不同目录下模块的函数common/common.jsyellowmsg5来自相同目录下不同模块的变量pages/index/my-index.jsaquamsg6来自相同目录下不同模块的变量原代码有误pages/index/my-index.jsaquamsg7来自本模块的变量pages/index/index.jsaquamarinemsg8来自本模块的函数pages/index/index.jsaquamarine4.2 页面结构与组件声明!-- pages/index/index.wxml -- navigation-bar titleWeixin back{{false}} colorblack background#FFF/navigation-bar scroll-view classscrollarea scroll-y typelist view classbox view classtitle引用来自不同模块的变量和函数/view view stylebackground-color: brown;{{msg1}}/view view stylebackground-color: brown;{{msg2}}/view view stylebackground-color: yellow;{{msg3}}/view view stylebackground-color: yellow;{{msg4}}/view view stylebackground-color: aqua;{{msg5}}/view view stylebackground-color: aqua;{{msg6}}/view view stylebackground-color: aquamarine;{{msg7}}/view view stylebackground-color: aquamarine;{{msg8}}/view /view /scroll-viewindex.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.jsrequire(../../common/common)app.js项目根目录require(./common/common)common/other.jsrequire(./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 模块。反过来只被一个页面用到、又只有几行代码的东西留在页面里就好——为了拆而拆只会让人多跳几个文件才能读懂逻辑
返回列表