属性顺序
词法分析器:不构建 DOM
annealer 不构建 DOM 或 XML 树。它找出每个起始标签(<tagname … > 或 />),并将属性列表拆分为名称/值对,只保留引号风格。
这种方式对纯 HTML 和 Vue 的非 XML 语法(@click、#default、v-bind:[dynamic])同样适用。它还能避免基于 DOM 或 XML 的解析带来的副作用,例如合并空白或将标签名和属性名转为小写。
原始文本元素、注释、{{ }} 插值、SFC 的 <script> 块、自定义块以及使用非 HTML 语言的 <template lang="…"> 会被跳过。
分类
每个属性都按其规范化键进行分类:
配置文件是按输出顺序排列的分组列表。每个分组都有 match 模式:精确名称,或以 * 结尾的前缀。属性会进入模式与其最具体地匹配的分组:精确名称优先于任何前缀,较长的前缀优先于较短的前缀。未匹配任何模式的属性进入唯一的 fallback 分组。
分组内的顺序由 sort 决定:
source:按书写顺序(默认)。alphabetical:按键名。listed:按match模式的顺序。
HTML 配置文件
为什么是这个顺序:
- 补充属性紧跟在
id/class之后。 它们为人类读者描述元素。id和class一起放在最前面,因为这是常见的惯用写法。 - ARIA 放在靠后的位置。 它为辅助技术提供
alt/title无法表达的额外元数据,而不是元素的主要描述。 - ARIA 遵循 WAI-ARIA:role → 可访问名称 → 描述 → 属性 → 状态。
data-*按字母顺序排列,因为它没有语义上的顺序。
Vue 配置文件
Vue 配置文件遵循 eslint-plugin-vue 的 vue/attributes-order 的默认顺序,因此其输出始终满足该规则:
第 8 层被拆分为先其他指令、后其他属性。这与 vue/attributes-order 中的 OTHER_DIRECTIVES → OTHER_ATTR 一致。HTML 的子排序在其他属性层级内部应用。
同名聚合
由于分类使用规范化键,同一属性的静态形式和绑定形式会得到相同的键,从而保持在一起。某个键第一次出现的位置决定其聚合簇的位置。无需任何特殊处理逻辑。
- 对于
class,静态形式排在绑定形式之前(class="item" :class="{ active }")。 - 对于其他名称,聚合簇保持源顺序。Vue 会合并
style,且后出现的声明优先;对于其他重复名称,Vue 只保留其中一个。重新排序可能改变行为。 v-model从不与同名的普通属性聚合(value="x" v-model="y")。它的键是v-model而非value,并且由于双向绑定是不同的概念,它保持在自己的层级中。
v-bind 展开
v-bind="object" 是一个边界。属性从不会跨越展开移动,因为这可能改变对象合并时哪个值优先。
例外是标记为 spreadSafe 的分组。它们是编译期指令(is、v-for、v-if/…、v-pre/v-once、自定义指令),从不与展开对象合并,因此可以跨越展开移动。其他所有属性都保持在各自的片段内。
规范化
Vue 配置文件启用了两种改写,在分类之前执行:
directiveShorthand:v-bind:foo→:foo,v-on:click→@click。hyphenateComponentProps:组件标签上的 camelCase 属性名 → kebab-case(:itemName→:item-name)。原生 SVG 和 MathML 元素不受影响。