欢迎各位引航者访问卡拉彼丘WIKI,由于游客访问页面会有一定的页面旧版缓存,建议你登陆B站账号进行浏览,如果您觉得本WIKI有帮助到你,欢迎推荐给身边的引航者。
模块:ACandy/doc
这是模块:ACandy的文档页面
ACandy是一个构建HTML的Lua模块。利用Lua的语法糖和元表,ACandy提供了一个易用的方式来从Lua构建HTML。大概算是一个内部DSL。
瞄一瞄
local a = require "Module:ACandy"
local some = a.some
local example = a.Fragment {
a.h1["#top heading heading-1"] "Hello!",
a.div { class="container", style="margin: 0 auto;",
a.p {
"My name is ", a.dfn("ACandy"), ", a module for building HTML.",
a.br,
"Thank you for your visit.",
},
a.p "visitors:",
a.ul / some.li("Alice", "Bob", "Carol", "..."),
},
}
print(example)
输出(经过格式化,下同):
<h1 id="top" class="heading heading-1">Hello!</h1>
<div style="margin: 0 auto;" class="container">
<p>
My name is <dfn>ACandy</dfn>, a module for building HTML.<br>
Thank you for your visit.
</p>
<p>visitors:</p>
<ul>
<li>Alice</li>
<li>Bob</li>
<li>Carol</li>
<li>...</li>
</ul>
</div>
导入
local a = require("Module:ACandy")
建议使用a
来重命名acandy
,这是因为:
a
是ACandy的首字母;a
很短,打起来方便;a.xxx
可以理解为英语的“一个xxx”。
下文的a
均指代本模块。
创建元素
一个基本的例子如下:
local elem = a.p {
class="my-paragraph", style="color: #114514;",
"This sentence is inside a ", a.code("<p>"), " element.",
}
print(elem)
表的键值对和序列分别表示元素的属性和子结点,正如a.p
那样。若仅有一个子结点且不需要设置属性,可以直接将该结点作为函数参数,所以a.code("...")
和a.code({ "..." })
是等价的。
该代码的输出,格式化后(下同)如下。
<p class="my-paragraph" style="color: #114514;">
This sentence is inside a <code><p></code> element.
</p>
对于HTML元素,a.xxx
是不区分大小写的,因此a.div
、a.Div
、a.DIV
……是同一个值,它们都将变成<div></div>
。而对于其他元素,a.xxx
是大小写敏感的。
属性
通过表的键值对为元素提供属性。其中,键必须是合法的XML字符串(目前模块仅支持ASCII字符);值可以是以下内容:
nil
和false
表示没有此属性;true
表示此为布尔值属性,例如,a.script { async=true }
表示<script async></script>
;- 其余值,将会对其进行
tostring
,并转义其中的< > & "
。
子结点
通过表的序列部分为元素提供子结点。除nil
之外的值均可作为子结点。
元素、字符串、数字、布尔值等后文没有提到的值
在元素字符串化时,对这些值尝试tostring
,并转义其中的< > &
。如果不期望自动的转义,可以将内容放在a.Raw
。
在下面这个例子中,我们将三个元素(<p>
)作为<article>
的子结点,并分别将字符串、数字、布尔值作为<p>
的元素。结果显而易见。
local elem = a.article {
a.p "Lorem ipsum...", -- or `a.p { "Lorem ipsum..." }`
a.p(2), -- or `a.p { 2 }`
a.p(true), -- or `a.p { true }`
}
print(elem)
<article>
<p>Lorem ipsum...</p>
<p>2</p>
<p>true</p>
</article>
表
在元素字符串化时,表可能被当作序列,ACandy会递归地对序列中的元素尝试字符串化。
以下表将被视为序列:
- 未设置元表的表,如
{ 1, 2, 3 }
; - 由
a.Fragment
返回的表,如a.Fragment { 1, 2, 3 }
; - 元表的
"__acandy_fragment_like"
字段为true
的表,例如,可通过getmetatable(val).__acandy_fragment_like = true
使val
在字符串化时被视作序列。
除此之外的表(如a.p { 1, 2, 3 }
返回的表)会被直接通过tostring
转换为字符串,未定义__tostring
的表会引发错误。
local parts = {
"consectetur adipiscing elit, ",
"sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.",
}
local elem = a.div {
"Lorem ipsum dolor sit amet, ",
parts,
}
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
函数
可以将函数作为子结点,这相当于调用函数,并将返回值作为子结点,唯一的区别在于函数将被推迟到tostring
时调用。
local elem = a.ul {
a.li "item 1",
a.li {
function() -- function returning string
return "item 2"
end,
}
function() -- function returning element
return a.li "item 3"
end,
function() -- function returning sequence
local list = {}
for i = 4, 6 do
list[#list+1] = a.li("item "..i)
end
return list
end,
}
print(elem)
<ul>
<li>item 1</li>
<li>item 2</li>
<li>item 3</li>
<li>item 4</li>
<li>item 5</li>
<li>item 6</li>
</ul>
方括号语法(设置元素属性)
在方括号内放置字符串可以快速设置id
和class
。
local elem = a.div["#my-id my-class-1 my-class-2"] {
a.p "You know what it is.",
}
print(elem)
在方括号内放置表可以设置元素属性,不局限于id
和class
。这让复用属性变得更方便。
local attr = {
id="my-id",
class="my-class-1 my-class-2",
}
local elem = a.div[attr] {
a.p "You know what it is.",
}
print(elem)
上面两段代码的输出均为:
<div id="my-id" class="my-class-1 my-class-2">
<p>You know what it is.</p>
</div>
斜杠语法(元素链)
local syntax = <elem1> / <elem2> / <elem3>
local example = a.main / a.div / a.p { ... }
相当于
local syntax = <elem1>(<elem2>(<elem3>))
local example = a.main {
a.div {
a.p { ... }
}
}
前提是<elem1>
、<elem2>
不是空元素(如<br>
)或已构建元素。
local li_link = a.li / a.a
local elem = (
a.header["site-header"] / a.nav / a.ul {
li_link { href="/home", "Home" },
li_link { href="/posts", "Posts" },
li_link { href="/about", "About" },
}
)
print(elem)
<header class="site-header">
<nav>
<ul>
<li><a href="/home">Home</a></li>
<li><a href="/posts">Posts</a></li>
<li><a href="/about">About</a></li>
</ul>
</nav>
</header>
acandy.Fragment
Fragment 承载多个元素。a.Fragment
和普通表的仅有的区别就是:
- 设置了
__tostring
,可以得到HTML字符串; - 设置了
__index
,可以以类似面向对象的形式调用table.insert
、table.remove
等table
库中所有以表为第一个参数的方法。
可以通过a.Fragment()
或a.Fragment({})
创建一个空的Fragment。
当仅有一个元素时,a.Fragment(<值>)
与a.Fragment({ <值> })
等价。
例子:
local frag = a.Fragment {
a.p "第一段。",
a.p "第二段。",
}
frag:insert(a.p("第三段。"))
print(frag)
<p>第一段。</p>
<p>第二段。</p>
<p>第三段。</p>
acandy.Raw
a.Raw
用于使字符串在最终不被转义。它接收任意类型的值,并调用tostring
,存储于内部。
- 设置了
__tostring
,可以得到对应字符串; - 设置了
__concat
,可以连接两个由a.Raw
得到的对象。
例子:
local elem = a.ul {
a.li "foo <br> bar",
a.li(a.Raw "foo <br> bar"),
a.li(a.Raw("foo <b")..a.Raw("r> bar")),
a.li { a.Raw("foo <b"), a.Raw("r> bar") },
}
<ul>
<li>foo <br> bar</li>
<li>foo <br> bar</li>
<li>foo <br> bar</li>
<li>foo <br> bar</li>
</ul>
acandy.some
local frag1 = a.some.<tag>(<arg1>, <arg2>, ...)
local frag2 = a.some.<tag>[<attr>](<arg1>, <arg2>, ...)
相当于
local frag1 = a.Fragment {
a.<tag>(<arg1>),
a.<tag>(<arg2>),
...,
}
local frag2 = a.Fragment {
a.<tag>[<attr>](<arg1>),
a.<tag>[<attr>](<arg2>),
...,
}
例子:
local some = a.some
local items = a.ul(some.li['my-li']("item 1", "item 2"))
print(items)
<ul>
<li class="my-li">item 1</li>
<li class="my-li">item 2</li>
</ul>
元素实例属性
如果一个元素是a.div(...)
、a.div[...](...)
这类进行函数调用得出的元素,则称它为“已构建元素”;已构建元素作为元素链末端的元素时,该元素链同样返回一个已构建元素;而a.div
、a.div[...]
则不属于已构建元素。
对于一个已构建的元素elem
,它有如下属性。
elem.tag_name
:元素的标签名,可以重新赋值。elem.attributes
:一个表,存储着元素的所有属性,对此表的更改会生效于元素本身;不可重新赋值。elem.children
:一个Fragment,存储着元素的所有子结点,对此表的更改会生效于元素本身;不可重新赋值。elem.some_attribute
(some_attribute
为字符串):相当于elem.attributes.some_attribute
。elem[n]
(n
为整数):相当于elem.children[n]
。
例子:
local elem = a.ol { id="my-id",
a.li "item 1",
}
-- get
elem.tag_name --> "ol"
elem.children[1] --> a.li "item 1"
elem[1] == elem.children[1] --> true
elem.attributes.id --> "my-id"
elem.id == elem.attributes.id --> true
-- set
elem.tag_name = 'ul'
elem.children:insert(a.li "item 2")
elem[3] = a.li "item 3"
elem.attributes.id = "new-id"
elem.style = "color: blue;"
print(elem)
<ul id="new-id" style="color: blue;">
<li>item 1</li>
<li>item 2</li>
<li>item 3</li>
</ul>