Створення мультикореневих компонентів Vue.js

4 хв. читання

Загальним обмеженням в компонентних фреймворках, наприклад, Vue.js, є те, що кожен компонент повинен мати один кореневий елемент. Це означає, що все в певному компоненті має походити від одного елементу, ось так:

<template>
  <div> <!-- Корінь -->
    <span></span> <!-- тепер можна робити розгалуження -->
    <span></span>
  </div>
</template>

Спробуйте створити компонент з шаблоном на зразок цього:

<template>
  <span></span> <!-- два нащадки на верхньому рівні ієрархії! -->
  <span></span>
</template>

і ви отримаєте страшну помилку: Component template should contain exactly one root element. If you are using v-if on multiple elements, use v-else-if to chain them instead. (Шаблон компоненту має містити лише один кореневий елемент. Якщо ви використовуєте v-if для декількох елементів, використовуйте для їх скріплення v-else-if).

У переважній більшості випадків це обмеження не спричиняє проблем. Є два елементи, які повинні йти разом? Просто додайте ще один шар в ієрархію DOM та огорніть їх у div. Ніяких проблем.

Однак, існують певні ситуації, в яких ви не можете просто додати ще один шар ієрархії — ситуації, де структура DOM є дуже важливою. Наприклад, є два елементи <td>, які завжди мають йти поруч один з іншим. додайте один, і вам доведеться додати й інший. Логічно, вони є єдиним компонентом, але їх не можна просто огорнути в оболонку, оскільки для правильної роботи елементи <td> мають бути прямими потомками <tr>.

Рішення: функціональні компоненти

Рішення цієї проблеми полягає в особливостях імплементації Vue.js. Основна причина, чому Vue наразі не може підтримувати мультикореневі компоненти, полягає в механізмі рендерингу шаблонів — шаблони для компонентів парсяться в абстрактне синтаксичне дерево (AST), а воно потребує кореня!

Якщо ви обійдете рендеринг шаблонів, то зможете також обійти однокореневе обмеження.

Цей спосіб використовується доволі рідко, але цілком можливо реалізувати компонент Vue.js без шаблону взагалі, просто визначивши функцію render. Ці компоненти, відомі як функціональні компоненти, можуть використовуватися для безлічі цілей, включаючи рендеринг кількох коренів у одному компоненті.

Код

Для простоти, я написав кожен з моїх парних елементів <td> як власний однофайловий компонент, і потім просто огорнув їх у функціональний компонент, який їм обом передавав props.

/* paired-cell.js */
import FirstCell from '~/components/paired-cell/first-cell';
import SecondCell from '~/components/paired-cell/second-cell';

export default {
  functional: true,
  props: ['людина', 'місце', 'річ'],
  render(createElement, context) {
    const first = createElement(FirstCell, { props: context.props });
    const second = createElement(SecondCell, { props: context.props });

    return [first, second];
  },
};

FirstCell і SecondCell — стандартні однофайлові компоненти Vue, кожний з елементом <td> в ролі кореня. Але PairedCell інший — це чистий JavaScript файл, який експортує функціональний компонент.

Існують дві ключові різниці між функціональними й традиційними компонентами:

  1. Функціональні компоненти не зберігають стан (вони самі по собі не містять data, і тому їх виходи визначаються виключно переданими в них props).
  2. Не можна створити екземпляри функціональних компонентів. Це означає, що відсутній контекст this, і замість цього через об'єкт context передаються props та пов'язані змінні.

Подивіться на те, що робиться в коді далі — вказується, що компонент є функціональним, оголошується множина прийнятих props (людина, місце й річ) та визначається функція render, яка приймає два аргументи: createElement та context.

Ці два аргументи надаються Vue. createElement — функція, яка встановлює елемент у віртуальний DOM Vue. Ви можете напряму передати їй властивості елемента, але в цьому випадку я використовую її лише для рендеру підкомпонентів.

Другий аргумент містить контекст для компонента; у цьому прикладі єдина річ, про яку нам слід піклуватися — props, який ми передаємо, і який містить потомків, слоти, предка та багато чого іншого — все те, що вам знадобиться для реалізації компоненту.

Отже, розберемо те, що ми зробили — ми реалізували компонент, який приймає множину props, виділяє два дочірніх компоненти як нащадків, і повертає їх як масив. Мультикореневий компонент!

Помітили помилку? Повідомте автору, для цього достатньо виділити текст з помилкою та натиснути Ctrl+Enter
Codeguida 6.2K
Приєднався: 7 місяців тому
Коментарі (0)

    Ще немає коментарів

Щоб залишити коментар необхідно авторизуватися.

Вхід / Реєстрація