我们在2022年秋季版本中改造了灰机的导航条等组件。改造过程中,我们将一些功能暴露给了window对象,包括:

  • $message - toast消息组件
  • $dialog - 对话框组件
  • $loadingbar - 进度条组件
  • $notification - 通知组件(不是mediawiki的通知)
  • $cockpitUtil - 工具类

如需在页面加载后立即使用这些组件,请将调用上述组件的代码放在CHP.then()的回调函数中以等待组件加载完成。

  • CHP是Component Hook Promise的简称。这个Promise会在上述组件加载完成后兑现(fufill)并执行回调函数。
  • 在已兑现后再次注册回调函数会立即执行。请参考Promise相关文档
// 在页面加载后立即调用可能会报错,因为组件可能还没加载完成。
$message.info('爷活了!') // 报错
// 这种情况下需要等待CHP事件完成。
CHP.then(function(tools) {
    $message.info('爷活了!') // 无论如何都会正常运行(除非CHP爆炸而未能正常fufill)
})
// 如果该操作是页面加载后等待了一段时间才触发的(例如用户点了一个按钮),则无需等待CHP。
// 复制以下代码到控制台执行后点击下方按钮以进行测试。
$('#testButton').click(function(){
    $message.info('爷活了!') 
})
#testButton

<- 先复制上文最后一段代码到控制台才能点

上文中,CHP的回调函数的tools是一个包含本页所述所有组件的Object。

以下会对上述组件的使用方法做详细介绍。

message组件

生成一条toast信息。message预设了几种样式如下:

$message.info('info');
$message.success('success');
$message.loading('loading');
$message.error('error');
$message.warning('warning');
// 如果想写一个完全自定义内容的信息,可以使用:
$message.create('没有预设值的消息');
// 一次性隐藏所有消息
$message.destroyAll();

你可以在复制上述代码在控制台中查看效果。

参数

$message.info为例,该方法接受两个参数。第一个参数为消息本身(字符串),第二个参数为消息设置,可选。设置参数的节点如下:

节点名 类型 说明
closable boolean 是否显示一个关闭按钮
duration number 消息多长时间会自动关闭,毫秒
keepAliveOnHover boolean 在鼠标悬停在消息上时是否停止计时
onLeave 回调函数 信息开始消失时执行的回调
onAfterLeave 回调函数 信息完全消失(销毁)时执行的回调
onClose 回调函数 用户手工点击关闭按钮时的回调

返回值

上述方法均返回该消息的实例。你可以使用destroy方法销毁该实例。

// 创建一个永久不消失的消息
var testmsg = $message.info('永远不消失(不可能)',{duration:999999})
// 然后销毁它
testmsg.destroy()

dialog组件

创建一个对话框组件,类似confirm,但是不会中断页面中其他脚本的运行。

和message类似,dialog也自带若干种预设样式:

$dialog.info({
    title: '我是标题',
    content: 'info'
});
$dialog.success(); // 太长了不想写,下同
$dialog.warning();
$dialog.error();
$dialog.create();

参数

dialog接受一个object作为参数,该object的节点如下:

节点名 类型 说明
title string 标题
content string 内容
closable boolean 是否显示一个关闭按钮
blockScroll boolean 是否在弹出时禁用后边元素的滚动
closeOnEsc boolean 是否在点击esc的时候关闭
maskClosable boolean 点击模态浮层时是否关闭
positiveText string 确认按钮的文本,如果不填则不显示该按钮
onPositiveClick eventHandler(MouseEvent) 点击确认按钮的行为。该函数执行完成之后对话框会关闭。如果该函数返回false、resolve(false)、或者一个被reject的Promise对象,则不会关闭。
negativeText string 取消按钮的文本,如果不填则不显示该按钮
onNegativeClick eventHandler(MouseEvent) 点击取消按钮的行为。该函数执行完成之后对话框会关闭。如果该函数返回false、resolve(false)、或者一个被reject的Promise对象,则不会关闭。
onMaskClick 回调函数 点击浮层时的回调
onClose 回调函数 点击关闭按钮的行为。该函数执行完成之后对话框会关闭。如果该函数返回false、resolve(false)、或者一个被reject的Promise对象,则不会关闭。

示例:

$dialog.info({
    title: '我是标题',
    content: '我是内容',
    positiveText: '我就要这三个杯子中的大杯',
    onPositiveClick: function () {
        $message.error('抱歉先生这个是超大杯');
        // return false时dialog不会关闭
        return false
    },
    negativeText: '抽脸',
    onNegativeClick: function () {
        $message.success('罗老师别这样');
        // 不return false、resolve(false)、或者被reject的Promise时对话框不会关闭
    }
})

复制代码到控制台查看效果。

返回值

上述方法会返回dialog实例。使用destroy()方法可以销毁该实例。

loadingbar组件

在页面顶部返回一个进度条(虽然这个进度和实际进度无关)。提供三个方法,分别是:

  • $loadingbar.start()开始
  • $loadingbar.finish()结束
  • $loadingbar.error()报个错

上述方法均不需要参数,也不提供返回值。

notification组件

在右上方显示一个或多个通知。提供多种预设样式如下:

$notification.info({ content: '测一下' }); // 下同,懒得写了
$notification.warning({ content: '测一下' });
$notification.success({ content: '测一下' });
$notification.error({ content: '测一下' });
$notification.create({ content: '测一下' });
// 隐藏所有消息
$notification.destroyAll();

参数

上述方法(除了destroyAll)接受一个参数作为配置项。该配置项的节点如下:

节点名 类型 说明
closable boolean 是否显示一个关闭按钮
title string 标题
content string 内容
description string 描述
meta string 额外信息
keepAliveOnHover boolean 悬停时是否停止关闭计时。
duration number/undefined 自动关闭时间。如果不设置则不会自动关闭。
onClose 返回布尔型或resolve为布尔型的peromise的函数 关闭通知的回调。返回false或resolve(false)则不会关闭。
onLeave 回调函数 通知关闭时的回调
onAfterLeave 回调函数 通知完全关闭(动画完成)时的回调
onAfterEnter 回调函数 通知显示时的回调

示例:

$notification.success({
    title: '我是title',
    content: '我是content',
    meta: '我是meta',
    duration: 20000,
    onAfterEnter: function () { $message.info('您有新的短消息') },
    onClose: function () { $message.error('呵,男人') },
})

返回值

上述方法(除了destroyAll())均返回通知实例。你可以用destroy()方法销毁单个通知。


cockpitUtil - 工具

cockpitUtil包括了若干个工具。你可以通过$cockpitUtil访问到cockpitUtil节点。

  • 从2022年11月15日开始,你也可以通过mw.huijiApi获取到这个节点。

以下是列表:

axios

axios库,用于包装请求。访问官方文档获取说明。

你可以通过$cockpitUtil.axios或直接访问axios获取该组件,但必须位于CHP之后。

hotkeys

hotkeys-js库,可用于注册快捷键。访问官方文档获取使用说明。

hotkeys会在CHP事件之后挂载到window,你不需要通过$cockpitUtil.hotkeys访问。

hotkeys()接受两个或三个参数。

  • 第一个参数是需要注册的快捷键列表,字符串。
  • 第二个参数是回调函数,该函数会提供event和handler两个参数用于处理事件。
    • 从event可以拿到触发该时间的元素。从handler可以拿到实际触发事件的快捷键组合(因为快捷键可以是多个)。
  • 如果指定了第三个参数,则第三个参数为回调函数,而第二个参数则是参数配置。参数配置的可选节点如下:
{
    // 快捷键的“作用域”。使用hotkeys.setScope()来设置当前激活的作用域。除了'all'之外只能有一个生效的作用域。
    scope:'all', 
    // 触发事件的元素
    element:document.getElementById('someId'),
    // 是否在keyup时触发
    keyup:true,
    // 是否在keydown时触发
    keydown:true,
    // 组合快捷键中的连接符,默认为加号
    splitKey:'+',
    // 这个我也不知道是干嘛的
    capture:false,    
}

注册快捷键列表

hotkeys()的第一个参数是快捷键列表,多组快捷键使用逗号分隔,组合快捷键使用加号或者上文中提到的splitKey分隔。

hotkeys('a,b,c,ctrl+a',function(e,handler){
    $message.info('bingo!')
})

组合键支持以下参数:

  • ⇧, shift, option, ⌥, alt, ctrl, control, command,⌘
  • backspace, tab, clear, enter, return, esc, escape, space, up, down, left, right, home, end, pageup, pagedown, del, delete, f1 through f19, num_0 through num_9, num_multiply, num_add, num_enter, num_subtract, num_decimal, num_divide

也可以使用通配符*代表所有按键事件,但你可以通过访问hotkeys[按键名称]判断该键是否被按下,从而进行后续判断。

hotkeys('*', function() {
  if (hotkeys.shift) {
    console.log('shift is pressed!');
  }

  if (hotkeys.ctrl) {
    console.log('ctrl is pressed!');
  }

  if (hotkeys.alt) {
    console.log('alt is pressed!');
  }
});

关于scope

使用hotkeys.setScope()来设置当前生效的作用域。设置完成后,所有作用域不为all、且不为被设置的作用域的快捷键绑定均不会生效。

// 绑定一个带作用域的快捷键组合
hotkeys('ctrl+o, ctrl+alt+enter', 'issues', function(){
  console.log('do something');
});
hotkeys('o, enter', 'files', function(){
  console.log('do something else');
});

// 设置作用域为issues,此时只有作用域为all和issues的快捷键生效。
hotkeys.setScope('issues');
// 如果需要恢复则将作用域换回all。

// 还有这些方法可以用:
hotkeys.getScope(); // 获得当前作用域
hotkeys.deleteScope('issues'); // 删除所有作用域为issues的快捷键
hotkeys.deleteScope('issues','nobug'); // 将issues作用域的快捷键迁移到nobug作用域

删除快捷键绑定

hotkeys.unbind('a'); // 解除所有按键为a的快捷键绑定。如果不提供第二个参数,则解除的是当前作用域的绑定。
hotkeys.unbind('a','issues'); // 解除issues作用域、按键为a的绑定。
hotkeys.unbind('o,enter'); // 解除当前作用域的o和enter绑定
hotkeys.unbind(); // 解除所有绑定,BY FIRE BE PURGED


parseForm(data)

将一个object处理成FormData对象以用于post请求。

var formRaw = {
    inputText: 1,
    inputBoolean: true,
    inputArray: [1, 2, 3]
}
var formOutput = $cockpitUtil.parseForm(formRaw)

getSiteAvatar(prefix,size,modified?)

生成站点头像地址。

  • prefix:站点前缀
  • size: 尺寸,l/ml/m/s。默认值为l
  • modified:站点头像的更改时间,用于更新浏览器缓存。可选。

getUserAvatar(userId,size,modified?)

生成用户头像地址。

  • userid:用户ID。
  • size: 尺寸,l/ml/m/s。默认值为l
  • modified:用户头像的更改时间,用于更新浏览器缓存。可选。

getUserAvatarFromFileName(filename)

通过实际文件名生成用户头像地址,不建议使用。

getSiteUrl(prefix)

生成一个站点的url。

getUserUrl(username,prefix)

生成指向用户页的url。prefix为所在站点的前缀。

不建议使用,用户页即将废弃。

getPageUrl(title,prefix)

通过标题生成页面链接。title为完整页面标题。prefix为站点前缀。

getPageUrlById(pid,prefix)

同上,但是是通过pageId生成的链接。

getMedalAvatar(medalId,size)

生成成就图标的URL。medalId为成就ID,size为尺寸(l/ml/m/s。默认值为l)。

getGiftAvatar(giftId,size)

同上,但是是礼物。

jumpTo(url,target)

跳转到指定url。target为目标窗体名称,默认值为_blank,即新标签页。设置为_self可在当前标签页打开。

jumpToSite(prefix,target)

跳转到指定站点。

jumpToPage(title,target,prefix)

跳转到指定站点的指定页面。

jumpToPageId(pid,target,prefix)

跳转到指定站点的指定页面,但是使用pageId。

numberFriendly(value)

输入数字,生成数字的友好形式。例如大于1024显示为1K,两百万显示为2M。

如果不输入数字,则返回一个“-”

timestampToUTC8Date(timestamp)

输入时间戳(秒),返回东八区的时间,YY-MM-dd格式。

parseText(text)

将输入文本中的换行符替换为br以用于html输出。

sleep(t)

返回一个在t毫秒后resolve的promise。

注意,灰机的js加载器可能暂时不支持es6语法,因此请使用then进行后续操作。

async function wakeUp() {
    await $cockpitUtil.sleep(500);
    console.log('睡醒了');
    // 报错,因为mw不认得async也不认得await
}
// 替代写法
function wakeUp() {
    $cockpitUtil.sleep(500).then(function () {
        console.log('睡醒了');
    })
}

getCockpitUserUrl(userId)

生成指向指定用户的灰机驾驶室链接。

getCockpitSiteUrl(prefix)

生成指向指定站点的灰机驾驶室链接。

getImageUrl(fileName,prefix)

生成指向图片的原始地址的链接。例如:

$cockpitUtil.getImageUrl('Cockpit-logo-png.png','www')
// 返回:'https://huiji-public.huijistatic.com/www/uploads/b/b9/Cockpit-logo-png.png'

getImageThumb(fileName,prefix,width)

生成一张图片的指定尺寸的缩略图,返回地址。

注意,如果width大于图片的原始尺寸,则接口可能报错。

注意2,返回数据的contentType目前已知有问题。

高级功能

在$cockpitUtil中还包含了vue的h()函数。请参阅vue官方文档获取使用方式。

另外$cockpitUtil中还有一个renderIcon函数,可用于将图标组件包装成VNode。

实际上在上文中提到的配置项中,部分配置项接受VNode作为参数以进行更高级的内容渲染(比如在通知正文中添加html),请参考本文底部的naive-ui文档获取使用方式。

参考资料