Как создавать необычные элементы списка в Astro

Как создавать необычные элементы списка в Astro

14 июня 2023 г.

Вы, наверное, видели много веб-сайтов, использующих крутые маркеры вместо обычных скучных. Как они это делают? Есть ли эффективный и простой способ создавать причудливые маркеры при написании действительно простого кода?

Ответ есть — с Astro это возможно. Вы можете просто написать уценку, и в результате получится хорошо отформатированный маркер, созданный с помощью SVG.

"Input: Contains normal markdown"

Output: Contains an SVG as the list item

Прежде чем мы начнем

Я предполагаю, что вы знаете, как использовать Astro и вы знаете, как интегрировать MDX в Astro. Если нет, не волнуйтесь. Просто следуйте инструкциям, и вы получите общее представление о том, как все работает, а затем выясните, как использовать Astro и MDX.

(Я собираюсь создать курс для него в ближайшее время, потому что Astro фантастический — это лучший генератор статических сайтов, который я когда-либо использовал).

Шаги

Если вы использовали Astro, вы, вероятно, можете сделать вывод об этих шагах из примера, который я показал вам выше.

Они:

  1. Вы создаете компонент <List>, который принимает ваши маркеры в содержимом <slot>.
  2. Вы берете эти маркеры в компоненте <List>.
  3. Вы просматриваете каждый элемент списка и добавляете SVG перед маркером.

Вот как выглядит разметка;

---
const { bullet } = Astro.props
---
<ul class='List'>
  {
    listItems.map(item => (
      <li>
        <!-- Your SVG here -->
        <Fragment set:html={item.innerHTML} />
      </li>
    ))
  }
</ul>

Самое замечательное в этом то, что вы можете добавлять дополнительные свойства, такие как fill, stroke и другие вещи, чтобы изменить SVG, чтобы он отображался с достаточной уникальностью.

Вот несколько примеров, когда я изменил fill SVG для Magical Dev School.

Я собираюсь показать вам, как создать простую версию, которая позволит вам вставить нужный вам SVG. Мы не будем рассматривать такие сложные вещи, как добавление fill и stroke и другие условия!

Схватка за пули в Astro

Astro позволяет получить содержимое элемента <slot> внутри вашего компонента.

Вы можете получить этот контент, вызвав функцию render. Вы увидите строку, содержащую HTML, который будет создан.

---
const html = await Astro.slots.render('default')
console.log(html)
---

Далее происходит волшебство

Вы можете проанализировать эту строку HTML и получить элементы списка — так же, как и стандартный document.querySelectorAll с помощью JavaScript.

Для этого вам нужно преобразовать строку HTML в структуру, подобную DOM.

Здесь можно использовать множество парсеров. Я выбрал для своих проектов node-html-parser. (Потому что это быстро).

---
import { parse } from 'node-html-parser'

const html = await Astro.slots.render('default')
const root = parse(html)
---

После синтаксического анализа HTML вы можете получить элементы списка с помощью querySelectorAll.

---
// ...

const listItems = root.querySelectorAll('li')
---

Затем вы можете сопоставить элементы списка и создать свой причудливый список.

---
// ...
---
<ul class='List'>
  {
    listItems.map(item => (
      <li>
        <!-- Your SVG goes here --> 
        <Fragment set:html={item.innerHTML} />
      </li>
    ))
  }
</ul>

Добавление SVG

Самый простой способ добавить SVG в компонент — использовать встроенные SVG.

Если вы хотите переключаться между различными типами элементов списка, вы можете попросить пользователя передать свойство bullet. Затем вы встраиваете другой SVG в зависимости от значения bullet.

---
const { bullet } = Astro.props
// ...
---

<ul class='List'>
  {
    listItems.map(item => (
      <li>
        { bullet === 'green-check' && <svg> ... </svg> }
        { bullet === 'red-cross' && <svg> ... </svg> }
        { bullet === 'star' && <svg> ... </svg> }
        <Fragment set:html={item.innerHTML} />
      </li>
    ))
  }
</ul>

Конечно, это не лучший способ...

Лучший способ добавить SVG

Лучше всего добавить SVG через компонент. Когда вы делаете это, вы можете просто передать SVG и позволить компоненту SVG обрабатывать логику SVG.

---
import SVG from './SVG.astro'
const { bullet } = Astro.props
// ...
---

<ul class='List'>
  {
    listItems.map(item => (
      <li>
        <SVG name={bullet} />
        <Fragment set:html={item.innerHTML} />
      </li>
    ))
  }
</ul>

Самый простой способ создать этот компонент SVG — встроить в него код SVG, как в примере, показанном выше.

---
// SVG component
const { name } = Astro.props
---

{ bullet === 'green-check' && <svg> ... </svg> }
{ bullet === 'red-cross' && <svg> ... </svg> }
{ bullet === 'star' && <svg> ... </svg> }

Но это не лучший способ, потому что вам все равно придется использовать условные операторы...

А SVG может быть заведомо большим и сложным, поэтому вместо этого вы создадите что-то громоздкое...

Лучший способ создать компонент SVG

Лучший способ:

  1. Храните SVG в папке svgs
  2. Захватите SVG из этой папки при передаче name в компонент <SVG>

Как это сделать, лучше оставить для другого урока, так как мы углубимся в другую тему.

Если вы хотите узнать, как я создаю компонент SVG, а также как я использую Astro и Svelte, прокрутите вниз и оставьте свой адрес электронной почты в форме ниже. Я хотел бы поделиться с вами больше!

Причудливая проверка

Что очень здорово в этом подходе, так это то, что вы даже можете использовать Astro для проверки типа bullet, который вы передаете в <List>, fill, штрих и другие нужные вам свойства.

Конечно, вы можете сделать это и с помощью Typescript. Я просто показываю вам, что вы можете использовать обычный JS, если хотите, чтобы все было просто.

const validators = {
  bullet: [{
    type: 'star', 
    fill: ['yellow', 'green', 'red', 'blue'],
    stroke: ['black', 'transparent'],
  }]
}

validate({ ...Astro.props })

function validate () {
  // Check props against validators
}

Вот и все!

Надеюсь, сегодня вы узнали что-то новое!

:::информация Первоначально опубликовано в моем блоге.

:::

Не стесняйтесь посетить его, если вы хотите, чтобы эти статьи доставлялись на вашу электронную почту из первых рук, когда они будут опубликованы! 🙂.


Оригинал