Skip to content

Разметка блоков и портов ​

<VisualLinker> находит свои блоки и порты в вашей собственной разметке. Пометить их можно тремя способами — директивами v-vl-block/v-vl-port, обычными data-vl-* атрибутами и пропом blocks компонента — и все три наполняют один и тот же реестр, так что их можно свободно смешивать в одной диаграмме.

Регистрация ​

Глобальная регистрация компонента и обеих директив:

ts
import { createApp } from 'vue'
import { VisualLinkerPlugin } from '@macrulez/visual-linker-vue'

createApp(App).use(VisualLinkerPlugin).mount('#app')

…или импорт в каждом компоненте — в <script setup> vVlBlock/vVlPort автоматически становятся v-vl-block/v-vl-port:

ts
import { VisualLinker, vVlBlock, vVlPort } from '@macrulez/visual-linker-vue'

С модулем Nuxt обе директивы регистрируются за вас, в том числе на сервере.

v-vl-block ​

Помечает любой элемент — на любой глубине, внутри любого компонента-обёртки — как блок.

vue
<div v-vl-block="'b13'">…</div>
<div
  v-vl-block="{ id: 'b13', draggable: true, dragHandle: '.title', dragBounds: 'container' }"
>…</div>

Просто строка — сокращение для { id }.

Опции ​

id ​

string · обязательна

Id блока, на который ссылаются соединения через from.blockId/to.blockId.

linker ​

string · по умолчанию: — (ближайший объемлющий <VisualLinker>)

Закрепляет блок за <VisualLinker name="…"> с этим именем, где бы тот ни находился на странице.

draggable ​

boolean · по умолчанию: берётся из config.blocks.draggable

dragHandle ​

string | Ref | геттер | HTMLElement · по умолчанию: — (весь блок)

CSS-селектор внутри блока или template ref/геттер/элемент.

dragBounds ​

'container' | string | Ref | геттер | HTMLElement | DragBoundsInset · по умолчанию: берётся из config.blocks.drag.bounds

Смотрите Перетаскивание. Строка-селектор ищется по всему документу.

portSpread ​

boolean | { gap?: number; padding?: number } · по умолчанию: берётся из config.ports.spread

Разводит соединения, делящие сторону порта этого блока — смотрите Разведение соединений по порту.

highlightable ​

boolean · по умолчанию: берётся из config.interaction.highlight

Наведение на этот блок подсвечивает его соединения. См. Визуальные состояния.

v-vl-port ​

Помечает элемент как порт соединения. Точка порта измеряется на этом элементе; порт принадлежит ближайшему предку, зарегистрированному как блок, если только block не указывает блок явно.

vue
<div v-vl-block="'b13'">
  <div v-vl-port="{ id: 'row1', side: ['left', 'right'], anchorBlockId: 'b13' }">Строка 1</div>
</div>

<!-- явная привязка к блоку, из любого места в области -->
<span v-vl-port="{ id: 'out', block: 'b13' }" />

Просто строка — сокращение для { id }.

Опции ​

id ​

string · обязательна

Id порта, на который ссылаются соединения через from.portId/to.portId.

block ​

string · по умолчанию: — (ближайший блок-предок)

Id блока-владельца.

linker ​

string · по умолчанию: — (ближайший объемлющий <VisualLinker>)

То же, что linker у v-vl-block.

side ​

'top' | 'right' | 'bottom' | 'left' | 'auto' | FixedSide[] · по умолчанию: 'auto'

offset ​

number · по умолчанию: 0.5

Положение вдоль стороны, 0..1.

anchorBlockId ​

string · по умолчанию: — (не задано)

anchorEl ​

Ref | геттер | HTMLElement · по умолчанию: — (не задано)

side, offset, anchorBlockId и anchorEl значат ровно то же, что у PortDescriptor ядра — смотрите Блоки и порты.

spread ​

boolean | { gap?: number; padding?: number } · по умолчанию: берётся из portSpread блока

Собственное разведение порта, как у PortDescriptor ядра — смотрите Разведение соединений по порту.

Data-атрибуты ​

Вообще без JavaScript — удобно для серверной или сторонней разметки:

АтрибутНа элементеЗначение
data-vl-block="id"блокрегистрирует элемент как блок
data-vl-draggableблок""/"true" → перетаскиваемый, "false" → нет
data-vl-highlightableblock""/"true" → подсвечивает свои соединения, "false" → нет
data-vl-drag-handle=".sel"блокручка перетаскивания, селектор внутри блока
data-vl-drag-bounds="container"блокcontainer или CSS-селектор элемента-ограничителя
data-vl-port="id"портрегистрирует порт на ближайшем блоке вокруг него
data-vl-port-block="id"порт…или явно на этом блоке
data-vl-side="left right"портодна сторона или список кандидатов через пробел/запятую
data-vl-offset="0.3"портположение вдоль стороны, 0..1
data-vl-anchor="id"портanchorBlockId — точка рисуется на границе этого блока
data-vl-port-spread="24 8"блокportSpread: "" включено, "false" выключено или gap [padding]
data-vl-spread="false"портсобственный spread порта, те же значения
data-vl-linker="name"блок/портзакрепляет элемент за <VisualLinker name="…"> с этим именем

Директивы сами записывают на элемент data-vl-block/data-vl-port (плюс data-vl-port-block/data-vl-linker, если заданы), так что один проход по DOM находит и элементы с директивами, и элементы с атрибутами. Все имена атрибутов также экспортируются константой VL_ATTR.

Проп blocks ​

Для рефов, которые хранятся в <script>, или элементов, на которые нельзя добавить атрибуты:

ts
const cardRef = useTemplateRef('card')
const blocks = [
  { id: 'a', el: cardRef, ports: [{ id: 'p', target: rowRef }] }, // template ref
  { id: 'b', el: '#legacy-widget' }, // CSS-селектор
  { id: 'c', draggable: false }, // без el: доп. конфигурация для блока, помеченного в шаблоне
]

Все поля — в описании пропа blocks.

Приоритет ​

Для одного и того же id блока поле из пропа blocks побеждает опции директивы, а те — data-атрибуты. Порт, заданный в пропе blocks, сохраняет приоритет над помеченным портом с тем же id на этом блоке.

Какому <VisualLinker> принадлежит элемент ​

  • явное имя data-vl-linker/linker побеждает;
  • иначе элемент принадлежит ближайшему объемлющему <VisualLinker> — так вложенные инстансы никогда не забирают блоки друг у друга;
  • элемент вне всех <VisualLinker> принадлежит только инстансам со scope="page".

Если на странице несколько инстансов со scope="page", дайте каждому name и закрепляйте элементы явно.

Живое обнаружение ​

Блоки и порты, добавленные, удалённые или перепомеченные позже — v-if, v-for, сторонняя разметка, выставляющая атрибуты, — подхватываются автоматически: компонент следит за изменениями data-vl-* в своей области (во всём <body> при scope="page"), а директивы сами уведомляют его об изменении опций, которые не отражаются в атрибутах. Повторный проход, не нашедший ничего нового, движок не трогает.

Перетаскивание и инлайн-стили ​

Сдвиг при перетаскивании применяется через отдельное CSS-свойство translate, поэтому он складывается с любой transform, которая уже есть у блока. Избегайте строковой привязки :style на перетаскиваемом блоке — Vue заменяет весь инлайн-стиль при каждом изменении этой строки и вместе с ним стирает сдвиг. Привязка :style объектом безопасна.

SSR ​

Директивы выводят свои data-vl-* атрибуты и при серверном рендеринге, так что разметка находится ещё до гидратации. Движок и его слой отрисовки существуют только на клиенте, после монтирования.