2. .sharq 格式与模板指令
.sharq — 单文件组件
每个 .sharq 文件都是一个 类 Vue 的 SFC,包含三个部分:
| 部分 | 作用 |
|---|---|
<template> | 带指令(v-if、:text、@click……)的 UXML 标记 |
<script> | C# 字段、方法、Prop<T>、生命周期 |
<style> | 该组件的 USS 样式(可选 scoped) |
<template> … </template>
<script> … </script>
<style> … </style> <!-- global USS for this file -->
<style scoped> … </style> <!-- isolated USS (this component only) -->样式写在
.sharq里。 优先在<style>中使用 USS 类,而不是在 C# 里用element.style.*。
另见 CSS Scoping —— 对 root 选择器很重要。
完整示例
<!-- Card.sharq -->
<template>
<ui:VisualElement $MainElement class="card">
<ui:Label v-if="ShowTitle" :text="Title" class="card__title" />
<ui:Label v-show="ShowSubtitle" :text="Subtitle" class="card__subtitle" />
<ui:VisualElement v-for="item in Items" :key="item.Id" class="card__row">
<ui:Label :text="item.Name" />
<ui:Label :text="item.Description" />
</ui:VisualElement>
<ui:Button @click="OnCardClicked" class="card__button" />
<slot name="footer" />
</ui:VisualElement>
</template>
<script>
$using UnityEngine;
$using System.Collections.Generic;
public class CardItem
{
public int Id;
public string Name;
public string Description;
}
public string Title = "Card Title";
public string Subtitle = "This is a subtitle";
public bool ShowTitle = true;
public bool ShowSubtitle = true;
public List<CardItem> Items = new()
{
new CardItem { Id = 1, Name = "Feature A", Description = "First feature" },
new CardItem { Id = 2, Name = "Feature B", Description = "Second feature" },
};
private void OnCardClicked()
{
ShowSubtitle = !ShowSubtitle;
Items.Add(new CardItem { Id = Items.Count + 1, Name = "New", Description = "Added" });
}
</script>
<style>
/* Child selectors — scoping works correctly after compile */
.card__title {
font-size: 18px;
color: white;
-unity-font-style: bold;
}
.card__subtitle {
font-size: 14px;
color: rgba(255, 255, 255, 0.7);
margin-top: 4px;
}
.card__row {
flex-direction: row;
margin-top: 8px;
}
.card__button {
margin-top: 12px;
height: 36px;
}
</style>编译器会生成:
Card.g.cs—— C# 组件Card.g.uss(以及/或 scoped/static USS)—— 来自<style>的样式
请编辑 .sharq 源文件,不要编辑生成的文件。
样式部分(<style>)
这是格式中的一等公民 —— 与 <template>、<script> 同等重要。
全局 <style>
为该组件编译的 USS 规则。应用 scoping 时,请使用 BEM 风格的子元素类(.card__title), 而不是根类本身:
<style>
.card__title { font-size: 18px; }
</style><style scoped>
为每个选择器追加一个唯一的 .s-{hash} 类,并只把该类加到组件的根元素上 (参见 CSS Scoping):
<style scoped>
.card { flex-grow: 1; }
.card:hover { opacity: 0.9; }
</style>Scoped 适用于根/host 级别的规则。scope 类只加在根元素上,因此 scoped 的 子元素选择器(
.card__title)不会匹配子元素。若要给子元素设置样式, 请使用带 BEM 类名的全局<style>。
Root 样式与子元素样式
- Root/host 规则 →
<style scoped>(.card→.card.s-hash,匹配根元素)或全局<style>。 - 子元素规则 → 全局
<style>配合 BEM 类名(.card__title)—— 原样输出,匹配可靠。 - 从外部定位该组件,或使用
:root变量 → 伴生的 unscoped USS (Resources/SusRuntime/Card.uss),运行时自动加载。
详情参见:CSS Scoping。
优先使用类,而非 C# 的 style.*
| 推荐做法 | 不推荐做法 |
|---|---|
在 <style> 中写 USS + AddToClassList / :class | 用 element.style.width = 12f 做静态布局 |
修饰符类(.card--open) | 把同样的令牌复制到 C# 里 |
只有在处理运行时几何信息(resolvedStyle、GeometryChangedEvent)或组件外的一次性宿主时, 才使用 C# 的 style.*。
内联 style="…" 属性
不同于 <style> 部分。属性样式会被编译为静态 USS 类(并去重):
<ui:VisualElement style="flex-grow: 1; font-size: 24px; color: white;" />对于任何可复用的内容,优先使用 <style> 部分。
$using —— 命名空间
类似于 C# 的 using。放在 <script> 的顶部;编译器会把它们输出到生成的 .g.cs 中:
$using UnityEngine;
$using System.Collections.Generic;$MainElement —— 根元素
标记哪个元素就是该组件本身。如果不标记,Sharq 会把内容包裹进一个空的 VisualElement。
<!-- Root = Label -->
<ui:Label $MainElement :text="Greeting" />
<!-- Root = VisualElement -->
<ui:VisualElement $MainElement class="wrapper" />模板指令
v-if —— 条件渲染
元素会从层级结构中添加/移除(BindVisibility)。
<ui:Label v-if="IsVisible" :text="Message" />v-show —— 通过 display 隐藏
元素保留在 DOM 中;在 DisplayStyle.Flex / None 之间切换。
<ui:Label v-show="IsActive" :text="Status" />v-for —— 列表
<ui:VisualElement v-for="person in People" :key="person.Id" class="row">
<ui:Label :text="person.Name" />
<ui:Label :text="person.Role" />
</ui:VisualElement>key-based diff(StrictVForKey)要求必须提供 :key。
:text —— 文本绑定
<ui:Label :text="Greeting" />text="literal" —— 静态文本
<ui:Button text="Click Me" @click="OnClick" />@click / @event —— 事件处理
<ui:Button @click="OnButtonClick" text="Click me" />支持的事件:click、mouseenter、mouseleave、change。
:class —— 响应式类
<ui:VisualElement :class='{ "card--open": IsOpen }' />