Syntax Specification
大多数涉及消息的地方都可以使用消息元素,例如:
- 消息相关的机器人 API
- 指令和中间件的返回值
- 本地化文件的翻译条目
本节将介绍这些地方传入字符串时所用到的语法规范。
语法
消息元素的语法与 HTML 类似,但是不完全相同。
字符
你可以在消息元素内使用任何字符。不过部分特殊字符需要转义:
原始字符 | 转义写法 |
---|---|
" | " |
& | & |
< | < |
> | > |
根据上下文的不同,有些字符可能不需要被转义或使用其他的转义方式。
除此以外,你可以使用十进制或十六进制转义任何字符。例如 '
也可以被书写成 '
或 '
。
标签
使用一对尖括号包裹元素名,加上可选的属性、闭合指示符,就构成了一个标签。
元素名由小写字母、数字和连字符组成,且必须以字母开头。在元素名前后添加 /
表示这是一个结束标签或自闭合标签,没有 /
符号时则表示这是一个起始标签:
<tag>
一个起始标签</tag>
一个结束标签<tag/>
一个自闭合标签
属性
起始或自闭合标签的元素名后接受可选的属性列表。每个属性必须形如以下形式:
key
key="value"
(此时value
中的"
需要被转义)key='value'
(此时value
中的'
需要被转义)
下面是一段示例:
<tag foo="1" bar/>
元素
一个元素要么是自闭合标签,要么由一对同名的起始标签和结束标签构成。元素的内容指起始标签和结束标签中间的部分,可以包含文本内容或其他元素。对于自闭合标签,元素的内容为空。下面是一段示例:
<parent>
text content
<child/>
</parent>
当存在未配对的元素时,将自动视为文本内容的一部分。文本内容前后如果存在包含换行符的连续空白字符,则会被忽略。这意味着下面两段代码是等价的:
<tag>
<foo> bar
<!-- comment -->
</tag>
<tag><foo> bar</tag>
注释
使用成对的 <!--
和 -->
插入一段注释。注释中的部分不会被渲染。
插值
在本地化条目中我们在上述规范的基础上额外允许插值语法。插值语法通过一对花括号 {}
声明,其可能出现在属性值或元素内容中。当表示属性值时,花括号将取代引号的作用。
插值语法中的内容会被解析为一个取值表达式,其结果会被转换为字符串后插入到原始字符串中。下面是一段示例:
<tag foo={bar}>
{baz}qux
</tag>
当传入 { bar: 1, baz: 2 }
时,上述消息元素将会被解析为:
<tag foo="1">
2qux
</tag>
这里的取值表达式会有别于 JavaScript 表达式,它实际相当于传入对象的一个属性路径。例如当传入数组 ['a', 'b']
时,取值表达式 {0}
将会被解析为 a
(而不是 0
)。
对比
与 HTML 的区别
下面列举出了一些消息元素与 HTML 语法上的区别:
- 没有空元素,所有元素都必须手动闭合
- 未配对的元素被视为文本内容的一部分
与 JSX 的区别
在大部分使用场景下,我们都推荐直接使用 JSX,这会拥有更好的编辑器支持。你可以对比下面三种写法,它们是等价的:
import { h } from 'koishi'
ctx.middleware((session) => {
return '你好呀,' + h('at', { id: session.userId })
})
ctx.middleware((session) => {
return `<>
你好呀,
<at id="${session.userId}"/>
</>`
})
ctx.middleware((session) => {
return <>
你好呀,
<at id={session.userId}/>
</>
})
而在本地化条目中,你将无法使用 JSX,此时就需要使用带插值的消息元素了。例如:
welcome: 你好呀,<at id={userId}/>
ctx.middleware((session) => {
return session.text('welcome', session)
})
下面列举出了一些插值的消息元素与 JSX 语法上的区别:
- 使用
<!--
和-->
作为注释,而不是{/*
和*/}
{}
内只能是取值表达式,而不能是任意 JavaScript 表达式或其他元素