2. Формат .sharq и директивы шаблона
.sharq — Single File Component
Каждый файл .sharq — это Vue-подобный SFC с тремя секциями:
| Секция | Роль |
|---|---|
<template> | UXML-разметка с директивами (v-if, :text, @click, …) |
<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. Предпочитайте USS-классы в<style>вместоelement.style.*в C#.
См. также 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-правила, компилируемые для этого компонента. Используйте BEM-классы для дочерних элементов (.card__title), а не сам корневой класс, если применяется scoping:
<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 работает для правил уровня root/host. Класс scope вешается только на корень, поэтому scoped-селекторы дочерних элементов (
.card__title) не совпадут с дочерними элементами. Для стилизации дочерних элементов используйте глобальный<style>с BEM-классами.
Root vs child стили
- Root/host-правила →
<style scoped>(.card→.card.s-hash, совпадает с корнем) или глобальный<style>. - Дочерние правила → глобальный
<style>с BEM-именами классов (.card__title) — эмитятся дословно, совпадают надёжно. - Обращение к компоненту извне, или переменные
:root→ сопутствующий unscoped USS (Resources/SusRuntime/Card.uss), автозагружается в рантайме.
Подробности: CSS Scoping.
Классы вместо C# style.*
| Делайте так | Не делайте так |
|---|---|
USS в <style> + AddToClassList / :class | element.style.width = 12f для статичного layout |
Модификаторные классы (.card--open) | Копирование тех же токенов в C# |
Используйте C# style.* только для рантайм-геометрии (resolvedStyle, GeometryChangedEvent) или разовых хостов вне компонента.
Инлайн-атрибут 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 обязателен для key-based diff (StrictVForKey).
: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 }' />