在BWIKI中使用JS
阅读
2025-12-21更新
最新编辑:迦洛翎
阅读:
更新日期:2025-12-21
最新编辑:迦洛翎
如果对于内容有任何疑问,请在评论区留言或加入tools讨论群(717421103)进行讨论。
在BWIKI(基于MediaWiki搭建)中,通过 common、resourceLoader、gadget、widget 这四种方式引入 JavaScript 是前端开发的核心实用知识点。 对于支持CSS的资源加载方式,在额外使用CSS时也可选用。
以下将详细介绍它们的引入机制、适用用于bwiki的场景及缓存策略差异。
一、核心概念与在bwiki中的引入机制详解
这三种方式对应bwiki不同的资源管理体系,其本质和引入路径如下:
1. Common 方式(站点通用)
common 并非独立“功能模块”,而是bwiki核心的默认资源加载位置,通常指“全局通用脚本”,即通过 MediaWiki:Common.js 加载的通用JS。
- 修改 Common 需要用户具有界面管理员权限。
使用方式:
- 无需额外配置
- 直接编辑
MediaWiki:Common.js写入JS代码,等待缓存刷新即可生效,缓存刷新时间通常为30分钟。
2. ResourceLoader 方式(按需加载)
ResourceLoader 加载方式依赖 模板:ResourceLoader 与 ResourceLoader JS 代码的组合,ResourceLoader JS 代码通常存放在 Mediawiki:common.js 或 Widget:ResourceLoader,通过预设模板封装加载逻辑,同时结合JS脚本实现自动化资源(JS/CSS/模块)加载,适用于需要规范管理站内资源、避免重复加载的场景。
- 安装和修改调用JS页面需要界面管理员权限,调用现有JS无需特殊权限。 仅支持调用本站内的资源。
使用方式:
- 检查站点已经存在模板:
模板:ResourceLoader及 ResourceLoader JS代码 - 创建调用JS页面,如:
MediaWiki:test.js - 在调用JS页面中添加模板调用:
- 测试相关功能,或需要等待缓存刷新,缓存刷新时间通常为30分钟。
注意:
- “模板:JS” 及 “模板:CSS” 为 “模板:ResourceLoader” 派生模板,原理一致,若未生效请再次检查站点是否已存在 ResourceLoader JS代码(可在全局检索 insource:ResourceLoader)
ResourceLoader JS代码:
// 1. 等待jquery加载完成(依赖RLQ队列,确保jquery优先可用)
(window.RLQ = window.RLQ || []).push([["jquery"], function () {
$(document).ready(function () {
// 2. 遍历所有.resourceLoader元素(由模板生成)
$('.resourceLoader').each(function () {
var $x = $(this);
var text = $.trim($x.text()); // 获取“1”参数对应的资源标识
if (!text) return; // 无资源标识则跳过
// 3. 分支1:加载MediaWiki模块(isModule=true)
if ($x.data('isModule') === true) {
return mw.loader.load(text); // 直接调用MediaWiki加载器
}
// 4. 分支2:加载站内资源(JS/CSS),自动补充MediaWiki命名空间
var ns = text.match('^.*?:'); // 匹配是否包含命名空间(如MediaWiki:)
if (!ns) text = 'MediaWiki:' + text; // 无命名空间则补充
// 5. 子分支A:加载CSS
var mime = ($x.data('mime') || "text/javascript").toLowerCase();
if (mime == "text/css") {
if (text.slice(-4).toLowerCase() !== '.css') text += '.css'; // 补全.css后缀
// 拼接CSS加载URL并加载
return mw.loader.load("//wiki.biligame.com/ys/index.php?title=" + text + "&action=raw&ctype=text/css", "text/css");
}
// 6. 子分支B:加载JS(仅允许MediaWiki命名空间)
if (ns && ns[0].toLowerCase() !== 'mediawiki:') {
return console.log('ResourceLoader: 不允许加载MediaWiki以外的js脚本'); // 安全限制
}
if (text.slice(-3).toLowerCase() !== '.js') text += '.js'; // 补全.js后缀
// 拼接JS加载URL并加载
return mw.loader.load("//wiki.biligame.com/ys/index.php?title=" + text + "&action=raw&ctype=text/javascript", "text/javascript");
});
});
}]);
注意事项
- 权限限制:
模板:ResourceLoader和Widget:ResourceLoader的创建/修改需特殊权限(界面管理员、小部件编辑者),普通用户仅可调用,不可修改核心逻辑; - 资源路径:加载的JS/CSS必须存储在BWIKI的
MediaWiki:命名空间下,非该命名空间的资源会被拦截(安全限制); - 重复加载:模板通过
{{#varexists}}机制自动防止重复加载,但同一页面多次调用不同资源时,需确保资源标识(1参数)唯一,避免冲突。
3. Gadget 方式(全局组件)
Gadget 是基于 MediaWiki 的 Gadgets 扩展(BWIKI已安装) MediaWiki 专为可选启用的前端功能设计的资源体系,存储在 MediaWiki:Gadget-* 命名空间下。
- 添加或修改 Gadget 需要用户具有界面管理员权限。
- 管理员可以在“特殊:小工具”页面中查看已经安装的 Gadget 及其权限限制情况,可在此页面进行小工具的导出。
- 用户可在“特殊:设置”页面的“小工具”选项卡中自主开启/关闭功能。
注意:
- 因 BWIKI 页面缓存设计问题,会导致用户设置数据错乱,引起不必要的麻烦,因此不引导用户使用设置页面进行调整。
- 直接读取页面加载时的 userjs- 记录的数据(即通过 api options 写入的数据)也可能会出现读取错误数据的情况,如需使用请在使用时即时请求。
使用方式:
- 创建Gadget依赖文件:编辑bwiki的
MediaWiki:Gadget-Test.js、MediaWiki:Gadget-Test.css - 定义Gadget元数据:编辑bwiki的
MediaWiki:Gadgets-definition,格式如下:* TestGadget[ResourceLoader|Test.js|Test.css]
- 检查功能是否生效。第一次配置时可能会即时生效,如未生效或修改,需等待缓存刷新,缓存通常为30分钟。
建议默认启用或关闭,不引导用户通过设置页面进行开启/关闭,可以另作启用状态的读取与记录。 更多详细信息请参见 [Gadgets介绍]
4. Widget 方式(单页面嵌入)
Widget是基于 MediaWiki 的 Widget 扩展(BWIKI已安装)实现的可复用前端组件,支持在普通wiki页面嵌入HTML代码,Widget页面本质上是封装了HTML/CSS/JS的独立模块,通过在普通wiki页面使用 解析函数 test 加载。
- 添加或修改 Widget 需要用户具有管理员或小部件编辑者权限。
使用方式:
- 创建Widget定义页面: 在BWIKI中创建以
Widget:为命名空间的页面(如Widget:Test),页面内容需包含完整的HTML结构(可内嵌CSS和JS),示例:(注意:Widget页面中不能直接使用MediaWiki语法或嵌入页面。)<div class="test-widget"> <p>这是一个测试Widget</p> <button id="testBtn">点击我</button> </div> <style> .test-widget { padding: 10px; border: 1px solid #ccc; } #testBtn { background: #007bff; color: white; border: none; padding: 5px 10px; } </style> <script> document.getElementById('testBtn').addEventListener('click', function() { alert('Widget按钮被点击'); }); </script>
- 在普通页面中调用Widget: 在需要嵌入Widget的wiki页面中,使用解析函数
加载,例如调用上述小部件Widget名称出错: Unable to load template 'wiki:Widget名称'Widget:Test:{{#widget:Test}} - Widget参数传递(可选): 支持通过参数动态定制Widget内容,在调用时传入参数,示例:
{{#widget:Test|title=自定义标题|color=red}} - 生效与缓存刷新:新建Widget通常即时生效,修改Widget后,需在调用该Widget的页面执行缓存刷新(可通过页面URL后添加
?action=purge实现)。
在Widget定义页面中通过 <!--{$title|escape:'html'}--> 接收参数并使用(需注意避免XSS风险):
<p style="color: <!--{$title|escape:'html'}-->;">{{{title}}}</p>
Widget参数传递中的转义选项补充说明:
escape 选项用于指定参数在最终Widget中如何进行“转义”或编码处理。对所有参数进行转义以防止跨站脚本(XSS)漏洞至关重要。部分转义方法的防护效果有 限,通常应使用以下转义方式之一:escape:html、escape:url、escape:urlpathinfo 或 escape:javascript。
更多关于转义的详细信息可参考 Smarty官方文档。
二、在BWIKI中的适用场景对比
| 方式 | 核心特点 | 在bwiki中的适用场景 |
|---|---|---|
| Common | 全局生效、无需特殊配置 | 站点级通用功能(如页面样式修复、全局事件监听) |
| ResourceLoader | 按需加载、相对安全 | 需额外使用自定义JS/CSS的模板或普通页面 |
| Gadget | 按需启用、代码解耦、导入导出 | 非必需的通用功能(如编辑辅助工具);需要多个文件的复杂功能 |
| Widget | 组件化、可复用、嵌入页面 | 非全局、仅在特定页面生效的传统前端应用;页面内可复用的交互组件(如倒计时) |
对于不同特点的功能,可参考以下建议:
- 高频/全局/优先加载功能:优先选择
Common或Gadget,利用其早期加载优势 - 单页面/低频率功能:选择
Widget或ResourceLoader,按需加载减少全局资源消耗 - 复杂UI组件:优先用
Widget,方便使用 Vue 或 React 编写页面框架,适合封装独立交互单元
三、在bwiki中的加载执行顺序
在BWIKI中,不同JS引入方式的加载与执行顺序受资源类型、依赖关系及MediaWiki资源管理机制影响,具体顺序如下:
1. 核心加载流程(从请求到执行)
- 请求阶段
- 优先发起
Gadget资源请求 - 同步发起
Common脚本与jquery核心库的请求
- 优先发起
- 定义阶段(mw.loader.implement)
- 先完成
Gadget的资源定义 - 随后完成
jquery核心库的定义 - 最后完成
Common脚本的定义
- 先完成
- 执行阶段
jquery核心库优先执行(为后续脚本提供依赖)- 接着执行
Gadget脚本 - 若
Gadget中存在额外请求的脚本,多个Gadget的子脚本执行顺序不固定(受网络请求速度影响) - 最后执行
Common脚本 - 若
Common中存在额外请求的脚本,多个Common的子脚本执行顺序不固定(受网络请求速度影响,如ResourceLoader)
注意:
Common、Gadget、Widget脚本执行时,jquery可能未完全加载,注意控制执行顺序,依赖$(function())确保DOM就绪。Widget与其他几类脚本不同,已在页面代码返回时嵌入,执行时机受代码嵌入位置影响。ResourceLoader加载时机受功能实现代码位置及DOM顺序影响。
2. 特殊场景的加载顺序说明
- 依赖jquery的功能
Common和Gadget中默认jquery已加载,可直接使用,但需加入$(function())确保DOM就绪。Widget中的JS需通过RLQ队列(如(window.RLQ = window.RLQ || []).push([["jquery"], function () { ... }]))确保jquery就绪后执行
- DOM操作相关代码
无论哪种方式,涉及DOM元素操作的代码必须包裹在 $(function()) 或 $(document).ready() 中,确保在DOM解析完成后执行,避免元素未加载导致的错误。
- 优先加载需求
对页面展示有直接影响的功能(如样式修复、核心交互),建议使用 Common 或 Gadget 方式,利用其较早的执行顺序确保优先生效; Widget 和 ResourceLoader 更适合非优先加载的局部功能。
但对于极为特殊的情况,如widget:bugfix,使用 Mediawiki:Sitenotice 配合 Widget 的同步加载限制获得更优先的加载顺序。
四、加载 MediaWiki Module 的方式(mw.loader.using 与 RLQ)
在 MediaWiki 中,加载内置模块(如 jquery、mediawiki.util 等)需要严格控制依赖顺序,避免因模块未加载完成导致的脚本错误。mw.loader.using 和 RLQ(ResourceLoader Queue)是两种核心机制,分别适用于不同场景下的模块加载与执行控制。
1. mw.loader.using 方法(显式依赖加载)
mw.loader.using 是 MediaWiki 提供的用于显式声明依赖模块并在其加载完成后执行代码的方法,直接对接 ResourceLoader 系统(ResourceLoader 系统是Mediawiki后端模块加载系统,非前文介绍的ResourceLoader加载JS方式)。
基本语法
// 加载单个模块
mw.loader.using('模块名', function() {
// 模块加载完成后执行的代码
});
// 加载多个模块
mw.loader.using(['模块1', '模块2'], function() {
// 所有模块加载完成后执行的代码
});
// 支持 Promise 链式调用(推荐)
mw.loader.using(['jquery', 'mediawiki.util'])
.then(function() {
// 成功回调:模块加载完成后执行
})
.catch(function(error) {
// 失败回调:模块加载失败时执行
console.error('模块加载失败:', error);
});
常见使用场景
- 依赖核心模块的初始化逻辑:例如使用
mediawiki.api调用 MediaWiki API 时,需确保模块加载完成:mw.loader.using('mediawiki.api') .then(function() { var api = new mw.Api(); // 安全使用 mediawiki.api 模块 api.get({ action: 'query', meta: 'userinfo' }) .done(function(data) { console.log('用户信息:', data); }); });
- 多模块依赖管理:当脚本同时依赖
jquery和mediawiki.util时,可一次性声明:
mw.loader.using(['jquery', 'mediawiki.util'])
.then(function() {
var pageTitle = mw.util.getPageName(); // 使用 mediawiki.util
$('body').append('<p>当前页面:' + pageTitle + '</p>'); // 使用 jquery
});
特点
- 显式声明依赖:代码意图清晰,直接指定需要加载的模块;
- 支持 Promise:可通过
then/catch处理加载结果,便于异步逻辑编排; - 全局生效:适用于任何需要加载 MediaWiki 内置模块的场景(Common、Gadget、ResourceLoader 等)。
2. RLQ(ResourceLoader Queue)机制(队列式依赖管理)
RLQ 是 MediaWiki 资源加载系统中用于管理脚本执行顺序的队列机制,本质是一个全局任务数组,通过等待依赖模块加载完成后再执行对应任务,解决动态加载场景下的依赖时机问题(如 Widget 中的脚本)。
基本原理
- 本质:
window.RLQ是一个全局数组,用于存储待执行的任务,每个任务包含“依赖模块列表”和“执行函数”; - 执行逻辑:当依赖的模块全部加载完成后,MediaWiki 会自动触发队列中对应任务的执行,确保脚本在依赖就绪后运行;
- 核心作用:解决动态插入的脚本(如 Widget 中的 JS)因依赖未加载(如
$未定义)导致的错误。
基本使用语法
// 初始化 RLQ(若未定义则创建)
window.RLQ = window.RLQ || [];
// 向队列添加任务:[依赖模块数组, 执行函数]
RLQ.push([
["依赖模块1", "依赖模块2"], // 需等待的模块列表
function() { // 依赖满足后执行的函数
// 编写依赖模块的业务逻辑
}
]);
常见使用场景
- Widget 中依赖 jquery 的代码:Widget 脚本可能在 jquery 加载前执行,需通过 RLQ 等待:
(window.RLQ = window.RLQ || []).push([["jquery"], function() { // 安全使用 $ 或 jQuery $(document).ready(function() { $('#widgetBtn').click(function() { alert('Widget 按钮被点击'); }); }); }]);
- 嵌套依赖处理:当任务本身依赖其他模块时,可在内部嵌套 RLQ 任务:
(window.RLQ = window.RLQ || []).push([["jquery"], function() { console.log('jquery 已加载'); // 子任务依赖 mediawiki.util RLQ.push([["mediawiki.util"], function() { var pageName = mw.util.getPageName(); console.log('当前页面:', pageName); }]); }]);
注意事项
- 依赖模块名称准确性:需与 MediaWiki 内置模块名一致(如
jquery、mediawiki.api),错误名称会导致任务无法执行,可在控制台检查 mw.loader.moduleRegistry 对象; - 与 DOM 就绪配合:RLQ 仅确保模块加载完成,若涉及 DOM 操作,需用
$(document).ready()确保元素已解析; - 避免全局覆盖:
window.RLQ是全局变量,不可重定义或覆盖,否则会导致队列任务丢失。
通过合理搭配 mw.loader.using 和 RLQ,可有效管理 MediaWiki 模块的加载顺序,避免因依赖问题导致的脚本错误,确保功能稳定运行。
五、加载外部脚本的方式
请务必选择信任来源的外部脚本,避免引入恶意脚本影响站点安全。
在 MediaWiki:Common.js 中也可以通过 MW loader 方法、JS 原生方法、Jquery Ajax 异步加载外部脚本,具体补充如下:
1. MW loader 方法(mw.loader.load)加载外部脚本(建议使用)
MediaWiki 内置的 mw.loader 是专门的资源加载器,支持加载外部脚本及 MediaWiki 内部模块,更符合 MediaWiki 的资源管理规范。 mw.loader 的具体使用方式请查阅 官方文档 获取更多信息。 官方文档
示例代码:
// 加载外部脚本
mw.loader.load('//example.com/script.js')
// 加载 Mediawiki 空间或 User 空间下的js
mw.loader.load('//wiki.biligame.com/{sitename}/index.php?title=MediaWiki:{filename}.js&action=raw&ctype=text/javascript', 'text/javascript')
// 返回 Promise 对象,支持链式调用处理加载结果
mw.loader.getScript('//example.com/script.js')
.then(
function () { console.log('外部脚本加载成功'); },
function ( e ) { console.error('加载失败:' + e.message); }
)
特点:
- 语法简洁,多数站点使用
- 支持使用“getScript”方法处理成功/失败情况
2. JS 原生方法加载外部脚本
通过创建 <script> 标签的原生方式动态引入外部脚本,是最基础的加载方式,适用于简单场景。
示例代码:
var script = document.createElement('script');
script.src = '//example.com/script.js';
script.type = 'text/javascript';
script.async = true;
script.onload = function() { console.log('外部脚本加载完成'); };
script.onerror = function() { console.error('外部脚本加载失败'); };
document.head.appendChild(script);
特点:
- 完全基于浏览器原生 API
- 可通过
async或defer控制加载时机(async异步加载且加载完成后立即执行,defer异步加载但按顺序执行)
3. Jquery Ajax 方法加载外部脚本
借助 Jquery 的 getScript 方法(本质是 Ajax 请求+动态创建标签)加载脚本,更简洁且支持回调处理。
示例代码:
$(function() {
$.getScript('//example.com/script.js')
.done(function() { console.log('外部脚本加载成功'); })
.fail(function(jqXHR, textStatus, errorThrown) { console.error('加载失败:' + errorThrown); });
})
特点:
- 语法简洁,内置成功/失败回调
- 本质仍是动态创建
<script>标签,与原生方式类似 - 依赖 Jquery 环境(bwiki 通常默认加载 Jquery,可直接使用,但common执行时可能未完全加载Jquery,需要用
$(function() { })包裹Jquery代码保证正常执行)
六、其他建议
- Common:若在bwiki中的内容过大,建议拆分为独立资源模块(而非直接写在
Common.js),避免代码过长难以维护。 反面案例:用户因看不懂JS代码,误删除Mediawiki中的ResourceLoader依赖代码,导致相关功能失效。 - Widget:避免在Widget中编写大量页面使用的功能,且建议使用防止多次加载写法避免多次引用。 反面案例:在原神地图点位使用”Widget:嵌入视频”插入视频代码,但在B站修改视频传参规则后需要大量更新调用Widget的页面,较为繁琐。
通过在bwiki中合理选择以上方式,可实现“全局-可选-局部”的分层前端资源管理,兼顾缓存效率和功能灵活性。

沪公网安备 31011002002714 号