Your own markup
/docs/skill/vizen-own-markupcurrentМашинный перевод с английского
Платформа заменяет data на сервере И руки назад plain HTML. Нет. иностранный JavaScript это required для data в template scope, и это text это в page source, Поисковые системы могут видеть это. Компонент может также читать документированный public REST source в браузере (запись) sets: /docs/record-sets); такой text появляется after JavaScript и не является частью этой гарантии..
1. Два словаря
Замены print data: {{ shop.name }}, {{ p.price_text }}. Ключи есть attributes Добавление поведения или структуры: vz-for, vz-if, vz-add-to-cart, vz-toggle.
Полный список машин: GET /docs/vz-keys.json. Никогда не угадывай key — ан unknown vz- атрибут удаляется санитаром.
2.Что находится в scope
shop, menu, crumbs повсюду; product на product page; category и products на section page — и products В любом месте вставки имена productsCategoryId или productsIds.
`products` Это section's feed, live. Писать vz-for="p in products" и Вы получаете настоящий каталог rows — тот price ты print Это price тот cart обвинение, И он продолжает расти, когда owner Редактирует каталог. recent: до тех пор, пока 2026-08-20 не было product в списке scope В общем и целом, а custom row подразумеваемый Цены, введённые в document Рука за руку, которая начала врать в тот момент, когда что-то Если вы передумали, то у вас есть старые заметки, которые говорят: own Маркап замораживает цены, они выходят дата.
The feed загруженный Только когда ты document просит об этом, так page это never упоминания products За это ничего не платит. fields: /docs/own-markup §2. База fields: id, name, sku, price, price_text, old_price, old_price_text, url, preview, in_stock, promotion_name. До 48 rows.
preview уже является реципиентом path, так plain <img src="{{ p.preview }}"> это ноготь вместо ноготь multi-Мегабайтный оригинал. Не перестраивайте его вручную.
<article vz-for="p in products">
<img vz-src="p.preview" alt="">
<h3>{{ p.name }}</h3>
<span>{{ p.price_text }}</span>
<s vz-if="p.old_price_text">{{ p.old_price_text }}</s>
<button vz-add-to-cart="{{ p.id }}">Buy</button>
</article>Скидки и sets
Цены в The feed уже account для promotions — Сервер работает на каждом card Через двигатель, который cart использование. promotion_name Это rule который выстрелил, empty когда none делать.
Над product page, product.in_combos[] Позволь card Скажи, где product дешевле, с цифрами и готовыми строками side через side: item_price_text Что стоит внутри этого set, item_regular_price_text Сколько стоит в одиночку и item_times_cheaper_text это NUMERAL — Ты пишешь Слова вокруг него.
<div vz-for="c in product.in_combos">
<p vz-if="c.item_times_cheaper_text">In «{{ c.name }}» —
{{ c.item_price_text }} instead of {{ c.item_regular_price_text }}</p>
</div>item_times_cheaper_text это empty Если бы коэффициент превышал benefit, Так охраняя с vz-if Это все, что вам нужно для проверки честности. gift это item_price равный 0 — render Из этого, never Из соотношения.
Полный field Список и правила, стоящие за цифрами: GET /docs/vz-keys.json (scope.combos) и GET /docs/promotions для самого двигателя скидки.
Живите независимо от всего, что выше: vz-add-to-cart, vz-cart-count, vz-fav, vz-fav-count, vz-auth, vz-user-initial, vz-search (с предложениями), vz-variants — они keep Работать без script Ваша потребность code В любом случае? Слушайте vz:cart, vz:fav, vz:auth на document; never опрос API или строить /w/… Resizer URL (/docs/own-markup §4.0. Ссылки на вашу разметку открыты без page перезаряжать (header Остаться на месте) — re-init на vz:navigate, сделать Второй безвредный; vz-reload силе, full load для одного link. The active item Приходит отмеченный сервером — style a[aria-current], не JS class.
Все еще настоящая вилка. Платформа listing (vizen-widgets) приносить фильтры, paging и сортировочные средства контроля; own корма имеют products_page для page section и явные пики через productsIds (/docs/own-markup §2.Выбрать. own разметка для look, тот listing для машин, но уже не для свежести data.
3. Проверенные действия, которые вы не найдете в руководстве
- гнездиться `vz-for` Работает на трех уровнях глубины —
m in menu→c in m.children→g in c.children, Расширенный на сервере, SEO Вот так вот, мега- menu построенный; - `vz-if` бегать before Линия петли связана — с использованием псевдонимов Условия для ребенка. Path/negation, числовой-index испытания и внешние scope:
/docs/own-markup§4; - `vz-toggle` без value sets
vz-state="open"на самом узле. Это единственный способ создать клик-дропдаун без JS:.trigger[vz-state="open"] + .panel { … }; - `vz-toggle="#id"` sets Государство на a target Селектор — это модаль;
- `vz-gallery` читать `product.gallery` только Игнорировать
preview: ан empty Галерея ничего не рисует. - готовые модули вместо ваших own JavaScript — лайтбокс (
vz-lightbox, Также как зум наvz-galleryкорень, а product окно (vz-modal="modal:product:42"), cart, поиск, menu, переключаться, form button: Копировать фрагмент из/docs/modules; тотmodal:параметры находятся в/docs/webcoding§14.3;
Для group cards/selected attributes и live куратор rows, использовать /docs/own-markup §2. предпосылки доступа /docs/catalogue §8.3. Уровень 1-1 CSS/attribute ограничения: /docs/own-markup §4. Готовый миниатюрный fields и slot sizes: §6 Там полный category замена на snapshot, скоординированный refs откат: /docs/components §4.8. Проверить fields против GET /docs/vz-keys.json → scope: отсутствующий field cannot быть выполнено с помощью замены сервера — не изобретать vz- key или scope field (§4.8 шаг 2. Это не rule Задокументированный public REST source: отзывы, Q&A и другие galleries сохранено в виде записи sets Читать вместе с GET /record-sets (/docs/record-sets §4.4 — компонент, подкрепленный рекордом set).
4. "I Хотим этого block то look Уникальный маршрут - The Route
Каждый block с коробкой — платформа widget, а level-1 html block, а level-3 block с props.html.boxed: true — Внутрь втянутое в то же самое wrapper: div.vz-box (Альбом: The Background, padding, radius, и узел, который идет sticky) → div.vz-inner (тот content Коробка — она закрывает ваш width) → для kind: "html" в level 1, div.vz-radius, Теневой хозяин, который закрепляет ваш скидки и модальности по default. Перенесенная папка (level 3, unboxed) имеет none Из них: корневой элемент – это block, А вот оси, расположенные ниже, не имеют ничего. приземлиться на — style непосредственно корень, или set boxed: true first.
Выберите, сколько платформы wrapper Ты хочешь keep:
| Ты хочешь | Двигаться |
|---|---|
| а full переживать-layout — Ваша сетка, ваши точки останова, ничего из платформы не осталось | `props.wrapperClass: "my-hero"` → твой class Вы находитесь в группе, вы переделаете его из своего own CSS: .my-hero > .vz-inner { max-width: none; display: grid } |
| Одно поведение переключатель off — обрезка, width Крышка, воздух, стек | тот wrapper ось для него: props.overflow: "visible", props.blockWidth: "full", props.paddingSides, props.position: "sticky" … |
Оба написаны в корне. payload.props, Сестра-объект payload.kind — never рядом с kind внутри себя или внутри себя props.html / props.component. props.wrapperId Дает группе один id, для #anchors И для ваших писаний.
Предпочитает ось, когда ось может сделать это: она читается code который притягивает block, чтобы он выдержал изменения в разметке.
⚠️ Две вещи, которые делают Путь молчаливым, ничего не делают:
- level-1 CSS cannot Смотри. wrapper. Твой
<style>Жизнь внутри тени корень;.vz-box- Не в тему. - Поделиться CSS в layout папка (§6.2) или level 3 document в реальном page DOM. Уровень 3 нуждается в owner/admin; Флаг висит внутри production — еслиPOST /html-documents {level:3}Отказ в этом, сообщите об этом в owner Вместо того чтобы вернуться к level 1; - wrapperClass/wrapperId имена сбрасываются целыми, не очищаются. максимум 3 класса, один id, pattern
^[a-zA-Z_][a-zA-Z0-9_-]*$, И ничто не может начаться сvz-(Платформа's own Имя-пространство. name Просто не входитьclass=.
Author Классы не имеют required гладиатр prefix. Используйте own корень limit непреднамеренные изменения; wrapper fields и время выполнения attributes keep своих контрактов. Стабильные крючки, CSS границы, sticky и позиционирование: /docs/own-markup §§5.5,5.7,7.2 Прочитать матрицу before многообещающий fixed header.
Где находятся цифры live. Каждый default обоих wrapper Дивс, с file:line В магазине, который sets Он, будучи созданным в GET /docs/widgets → wrapper:
curl -s https://api.vizen.shop/docs/widgets | jq -r '
.wrapper.elements[] as $e | $e.defaults[]
| [$e.selector, .property, .value, (.when // "-"), .anchor.at] | @tsv'Полный рецепт, анти-path Поверхности, где sticky До сих пор не спросили: GET /docs/own-markup §5.
The block's own padding и radius есть ноль для kind: "html" — Платформа Ничего не добавляет вокруг себя design. Хочешь воздух? props.paddingSides явно.
5. Изображения
Написать обычный <img src> Указывая на shop file. Сервер переписывает его на сетчатка и добавляет srcset (640/1024/1600, Ты не строишь эти пути..
Но set `sizes` себя. Только вы знаете, насколько широка slot Без намека (Not A Mint) Сервер принимает full width И браузер делает самый большой шаг. card Ширина 268px, что означает 1600w вместо 640w. sizes это never переписанный, и ваш own srcset Отключает переписывание полностью.
Сфера охвата image fields есть уже рециркулирующие пути с 2026 по 08-20 — product.preview_url, product.gallery[].url, тот combo предварительные просмотры и products[].preview. Печатайте их, как они приходят; восстановление одной рукой - это то, как вы корабль multi-оригинал мегабайта.
⚠️ vz-src заполняются в *after* Сервер перезаписи запущен, поэтому ничего не перезаписывается. Это безопасно только потому, что scope fields Прибытие предварительно нарезанное — точка vz-src в URL твоей own Браузер получает именно то, что вы написали.
6. Сценарии
Уровень 3 отображает inline, в реальном page DOM. Сценарии, бегущие по прямому попаданию и after в-site link Кликните. Два правила.:
- never скрываться content за спиной script. Покажите это; пусть script декорация. приземление, cards Начало в
opacity: 0смотреть empty когда script делать не бегать; - Не полагайтесь на `DOMContentLoaded` — after в-site щелкните document это Уже загружено. Пишите. code Это работает, когда выполняется прямо сейчас.
Проверьте оба способа: прямой URL и клик из другого page.
6.1 Готовая папка → page из site (HTML проект)
Передача path Жизнь в мастерстве vizen-transfer и район GET /docs/transfer: папка = level-3 widget в реальном page DOM, Одна команда на каждый папка (node backend-3D/tools/html-transfer/transfer.mjs ./folder --page <slug>), Ничего не вырезали, нет path Переписано и договор о том, что платформа делает с твой file — тот wrapper .vz-body-{doc} с data-vz-base, тот head, CSS Scoping, общий каскад с витриной магазина's Префайт, сценарий перезапуска after мягкая навигация, охраняемая зона. Два факта остаются здесь, потому что они О ключах внутри папки:
- тот scope (
shop,menu,crumbs,product,category,products[]— сp.attrs/p.members/p.groupкогда block setsproductsAttributes/productsMode,/docs/own-markup§2) и каждыйvz-key §1-3 работать внутри перенесённой папки точно так же, как и в любой другой папке. другой level-3 document — Вот как двигается product page Показать реальный product; - ZIP (
POST /html-documents/{id}/releases/zip?publish=1) Создает релиз Только: document должны существовать и block Строится вручную, толькоtransfer.mjsсоздает document и навесить на block.
- Один механизм — освобождение. сценарий, ZIP, manual manifest и admin's "Страница code" Все окна заканчиваются релизом. text" на опубликованный page = частичный релиз, нет повторной загрузки проекта: найдите document id (
GET /html-documentsчерез name, илиGET /categories/by-slug/{slug}?company_id=…→content_blocks[].sections[].payload.props.html.html_document_id) → читать тот current чистая разметка отGET /html-documents/{id}→result.source.url(тот active освобождение'sindex.html, Без уже без head/body) → редактировать →POST /html-documents/{id}/releases {"base":"active","files":[{"path":"index.html","sha256":"…","size":N}],"note":"…"}→PUTтот bytes тоupload_url→POST …/releases/{rid}/publish. Каждый другой file Наследуется от active Альбом: Rollback Stays (POST …/rollback). Один image: Тот же звонок с этим path; удалять:"delete":["path"].index.htmlэто never дублированный (конвертер) изменения в его высвобождении) — нормально, а не error. - Полный рецепт и правила папки:
/docs/webcoding§2а.
6.2 Общее пространство CSS, шрифты и скрипты — The LAYOUT's папка
общий CSS принадлежит к layout Где она находится, там и изоляция., позиционирование и охрана pages, Используя матрицу в /docs/own-markup §7.2.
А. layout это group-container (group_type:"theme") Это также удерживает slots header/feed/body/footer для pages покрывает (vizen-chrome). Его папка является Механизм освобождения, предусмотренный в § 6.1, рассмотренный layout, не в какой-либо document id:
# which layouts the shop has — filter the list yourself, the API has no filter
curl -s -H "Authorization: Bearer $VZ" $API/content-blocks \
| jq '[.result[] | select(.group_type=="theme") | {id,name}] | sort_by(.id)' # earliest = "Основной"
node backend-3D/tools/html-transfer/transfer.mjs ./theme --theme 118 # folder → release → publish
curl -s -H "Authorization: Bearer $VZ" $API/themes/118/site | jq '{base, scope_class, icons_generated}'index.html Вот это скелета из site, не content: <head> nodes идти входить head каждого page, тот <body> class наклон page Корень, body content before </body>; <title>, <base>, <meta http-equiv> и <link rel=manifest> на них наносятся publish. Любой *.css В папке есть свои голый html, body и :root селекторы, предназначенные для .vz-theme-{doc} — тот class из page корень — так body {} и :root {--brand: …} являются предполагаемым способом то style тот site (соединение body.dark намеренно оставлены на реальном body). icon.png (или .jpg/.jpeg/.webp) генерировать icon-32/180/192/512.png и favicon.ico; твой own files Под этими именами never переписанный.
Конечные точки: GET /themes/{id}/site · POST …/site/releases · …/releases/zip · …/releases/{rid}/publish|validate · GET …/site/releases[/{rid}] · POST …/site/rollback. То же самое scopes и role § 6.1.Папа's обслуживание document Невидимая внутри /html-documents Отказывается от правок (THEME_DOCUMENT_PROTECTED); плохой id это 404 THEME_NOT_FOUND.
Две вещи, которые нужно планировать вокруг:
- Сценарии не работают в охраняемых зонах —
/cart,/checkout,/account,/wishlist,/orders,/coupons,/deals,/dashboardи все, что под Нет.head_html, нетfoot_html, нетwindow.VZ_THEME_BASE, и а level-3 header рендеринг без его сценариев. Стили, разметка иhiddenоставаться,data-*Нет, ключи выше keep Работать, оставлять zone это full перезарядка, как вхождение в один; - Навигация мягкая: after Каждая навигация и first load
documentполучатьCustomEvent('vz:navigate', {detail:{path}})— переживать-init из Перейдем к следующему. page с другой стороны layout это full перезаряжать.
Сценарии из layout Читать корень актива window.VZ_THEME_BASE (/_html/{doc}/{rid}/). Файлы из этого ACTIVE layout Также есть второй, неупорядоченный address — /_site/<path> — для ссылок, которые пережили релиз (an) email, Подпись, кто-то else's site); внутри site keep использовать /_html/{doc}/{rid}/…, который неизменен и кэширован навсегда.
Стили оформления в level-1 Тень, их order и editor Разница заключается в покрыты поверхностной матрицей в /docs/own-markup §7.2.
6.3 Компонент с параметрами — та же разметка на многих pages
Задать один вопрос before Вы пишете разметку: Это необходимо more не один раз? Если ответ "на пять" pages, с другой стороны heading И каждый раз рисовать", ан html widget Это неправильный объект — вы будете копировать. code, и шестой Редактировать будет шесть правок. компонент: Та же папка и тот же те же самые релизы, плюс schema параметров. owner заполняет values за вставка и never прикосновения code; ты publish а new Освобождение и все пять Вставки меняются сразу. Полная площадь: GET /docs/components.
Папка - это html папка плюс одна file. index.html, CSS, JS как always, и component.json рядом с ними — публикация релиза компонента без него отказываться.
{ "name": "Promo banner",
"params": [
{ "key": "title", "type": "text", "label": "Heading", "default": "Sale", "max": 80 },
{ "key": "image", "type": "image", "label": "Picture" },
{ "key": "sale", "type": "bool", "label": "Show the badge", "default": false },
{ "key": "size", "type": "select", "options": ["s", "m", "l"], "default": "m" } ] }Если вы знаете Shopify theme sections, Вы уже знаете это file: component.json это {% schema %}, params это settings, и type Названия карт один к одному (text→text, richtext→html, image_picker→image, url→link, checkbox→bool, select→select, number/range→number, color→color). product/collection Пока нет аналога — компонент's параметры являются values, Не задавать вопросы.
В разметке параметр является `{{key}}`, и а bool Также открывается а block:
<section class="promo">
<h2>{{title}}</h2>
{{#sale}}<span class="badge">-30%</span>{{/sale}}
<img src="{{image}}" alt="">
</section>Замена является Типичная и серверная-side: text ускользнула, html проходить через тот level-1 санитар, link/image Проверяется по белому списку схем, а select снаружи options и а color Это не то, что #hex становиться empty. Там Не сырой {{ }} на витрине магазина и а key Этого нет в schema отпечатки Ничего — как в разметке, так и в values вставки из.
TypeScript допускается в папке. Поставить app.ts рядом с index.html и Нажмите на тег в компилируемом соседе (<script type="module" src="app.js">) — Публикация собирает все *.ts В родную сестру *.js и держит source, так Следующий релиз можно построить из base=active. Ничего не складывается: каждый import должны решиться на a file Ветхий Завет, написанный с расширением Браузер будет приносить ("./util.js", never "./util.ts"). Нет. .tsx, нет npm импорта, нет source Отказ - это отказ. COMPONENT_TS_ERROR с file:line:col, или COMPONENT_TS_CONFLICT когда рукописный app.js уже сидят рядом с app.ts. И помните §4: level 1 санитарные полоски <script> из тот page В любом случае — live code нуждается в level-3 document, Точно так же как и html проект делать.
# create the document, upload the folder, publish and see the parsed schema
node backend-3D/tools/html-transfer/transfer.mjs ./banner --component --name "Promo banner"Надень его на page Это обычный section — тот values live в вставка, never разметка:
{ "type": "text", "payload": { "v": 2, "kind": "component",
"props": { "component": { "ref": 42, "params": { "title": "Autumn", "sale": true } } } } }ref Это document id; params Это квартира {key: value} - Написано в Любое другое гнездование level (props.params, ref рядом с kind) тот section только с неисправностями и ответами 200 — читать page, Не то status code.
Доставка new version изменения в каждой вставке. Загрузить а new освободить и publish: магазин вставок values, не разметка. value чей key исчезнувший из тот new schema это ignored, а параметр вставки never set возвращается к new default, и POST /html-documents/{id}/rollback Вернемся к предыдущему освобождение *Вместе с его own schema*. Ты never читать component.json через тот gateway Чтобы узнать, что компонент принимает: разобранный schema Возвращается на document (manifest, 64-я основа сырого JSON, рядом с active_release_id) и так далее Каждый выпуск (manifest как plain объект). active_release_id является честным test «Можно ли это сделать» — нет active Отпуск, без разметки и без schema.
7.Прежде чем закончить
vizen-troubleshoot - держит контрольный список приемки. - Минимальный: нетронутый pages Неизменно работают оба навигационных пути., template-scope text Присутствующий в сыром HTML, cart принимает a item. Записи, полученные в браузере (/docs/record-sets) Проверить ответ сети, отредактированный text, loading/empty государств и не staff-только data Эти записи не отображаются на сервере..
Исходник: https://api.vizen.shop/docs/skill/vizen-own-markup?full=1