@dxtmisha/wiki 0.24.3 → 0.25.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +7 -7
- package/src/classes/WikiStorybookItem.ts +24 -0
- package/src/media/descriptions/wikiDescriptions.ts +28 -0
- package/src/media/descriptions/wikiDescriptionsAccordion.ts +158 -0
- package/src/media/descriptions/wikiDescriptionsActionSheet.ts +211 -0
- package/src/media/descriptions/wikiDescriptionsActions.ts +161 -0
- package/src/media/descriptions/wikiDescriptionsAnchor.ts +42 -0
- package/src/media/descriptions/wikiDescriptionsArrow.ts +181 -0
- package/src/media/descriptions/wikiDescriptionsBlock.ts +97 -0
- package/src/media/descriptions/wikiDescriptionsButton.ts +0 -1
- package/src/media/descriptions/wikiDescriptionsCell.ts +2 -1
- package/src/media/descriptions/wikiDescriptionsChipGroup.ts +168 -0
- package/src/media/descriptions/wikiDescriptionsDialog.ts +182 -0
- package/src/media/descriptions/wikiDescriptionsField.ts +2 -0
- package/src/media/descriptions/wikiDescriptionsImage.ts +41 -6
- package/src/media/descriptions/wikiDescriptionsInput.ts +257 -0
- package/src/media/descriptions/wikiDescriptionsMenu.ts +123 -0
- package/src/media/descriptions/wikiDescriptionsModal.ts +145 -0
- package/src/media/descriptions/wikiDescriptionsMotionTransform.ts +2 -6
- package/src/media/descriptions/wikiDescriptionsSelect.ts +209 -0
- package/src/media/descriptions/wikiDescriptionsSelectValue.ts +78 -0
- package/src/media/descriptions/wikiDescriptionsTextareaAutosize.ts +50 -0
- package/src/media/descriptions/wikiDescriptionsTooltip.ts +89 -0
- package/src/media/functional/en/conversions.mdx +67 -0
- package/src/media/functional/en/dataUtils.mdx +25 -0
- package/src/media/functional/en/datetimeRef.mdx +1 -1
- package/src/media/functional/en/eventRef.mdx +1 -1
- package/src/media/functional/en/executionUtils.mdx +58 -0
- package/src/media/functional/en/geoFlagRef.mdx +1 -1
- package/src/media/functional/en/geoIntlRef.mdx +1 -1
- package/src/media/functional/en/geoRef.mdx +2 -2
- package/src/media/functional/en/meta.mdx +1206 -0
- package/src/media/functional/en/metaManager.mdx +376 -0
- package/src/media/functional/en/metaOg.mdx +694 -0
- package/src/media/functional/en/metaTwitter.mdx +853 -0
- package/src/media/functional/en/reactive.mdx +40 -0
- package/src/media/functional/en/refTypes.mdx +1 -1
- package/src/media/functional/en/useApiRef.mdx +5 -5
- package/src/media/functional/en/useMeta.mdx +431 -0
- package/src/media/functional/en/validationUtils.mdx +11 -0
- package/src/media/functional/ru/conversions.mdx +67 -0
- package/src/media/functional/ru/dataUtils.mdx +25 -0
- package/src/media/functional/ru/datetimeRef.mdx +2 -2
- package/src/media/functional/ru/eventRef.mdx +1 -1
- package/src/media/functional/ru/executionUtils.mdx +58 -0
- package/src/media/functional/ru/geoFlagRef.mdx +1 -1
- package/src/media/functional/ru/geoIntl.mdx +2 -2
- package/src/media/functional/ru/geoIntlRef.mdx +1 -1
- package/src/media/functional/ru/geoRef.mdx +2 -2
- package/src/media/functional/ru/listTypes.mdx +1 -1
- package/src/media/functional/ru/meta.mdx +1330 -0
- package/src/media/functional/ru/metaManager.mdx +376 -0
- package/src/media/functional/ru/metaOg.mdx +694 -0
- package/src/media/functional/ru/metaTwitter.mdx +853 -0
- package/src/media/functional/ru/reactive.mdx +40 -0
- package/src/media/functional/ru/refTypes.mdx +2 -2
- package/src/media/functional/ru/useApiRef.mdx +5 -5
- package/src/media/functional/ru/useMeta.mdx +431 -0
- package/src/media/functional/ru/validationUtils.mdx +11 -0
- package/src/media/mdx/Accordion/accordion.en.mdx +59 -0
- package/src/media/mdx/Accordion/accordion.ru.mdx +59 -0
- package/src/media/mdx/Accordion/slots.en.mdx +6 -0
- package/src/media/mdx/Accordion/slots.ru.mdx +6 -0
- package/src/media/mdx/Accordion/wikiMdxAccordion.ts +25 -0
- package/src/media/mdx/ActionSheet/actionSheet.en.mdx +61 -0
- package/src/media/mdx/ActionSheet/actionSheet.ru.mdx +61 -0
- package/src/media/mdx/ActionSheet/touchClose.en.mdx +21 -0
- package/src/media/mdx/ActionSheet/touchClose.ru.mdx +21 -0
- package/src/media/mdx/ActionSheet/wikiMdxActionSheet.ts +25 -0
- package/src/media/mdx/Actions/actions.en.mdx +48 -0
- package/src/media/mdx/Actions/actions.ru.mdx +48 -0
- package/src/media/mdx/Actions/flexible.en.mdx +19 -0
- package/src/media/mdx/Actions/flexible.ru.mdx +19 -0
- package/src/media/mdx/Actions/list.en.mdx +50 -0
- package/src/media/mdx/Actions/list.ru.mdx +50 -0
- package/src/media/mdx/Actions/wikiMdxActions.ts +31 -0
- package/src/media/mdx/Anchor/anchor.en.mdx +34 -0
- package/src/media/mdx/Anchor/anchor.ru.mdx +34 -0
- package/src/media/mdx/Anchor/expose.go.en.mdx +6 -0
- package/src/media/mdx/Anchor/expose.go.ru.mdx +6 -0
- package/src/media/mdx/Anchor/hide.en.mdx +28 -0
- package/src/media/mdx/Anchor/hide.ru.mdx +28 -0
- package/src/media/mdx/Anchor/isCopy.en.mdx +23 -0
- package/src/media/mdx/Anchor/isCopy.ru.mdx +23 -0
- package/src/media/mdx/Anchor/scroll.en.mdx +34 -0
- package/src/media/mdx/Anchor/scroll.ru.mdx +35 -0
- package/src/media/mdx/Anchor/wikiMdxAnchor.ts +43 -0
- package/src/media/mdx/Arrow/arrow.en.mdx +33 -0
- package/src/media/mdx/Arrow/arrow.ru.mdx +33 -0
- package/src/media/mdx/Arrow/wikiMdxArrow.ts +19 -0
- package/src/media/mdx/Block/block.en.mdx +42 -0
- package/src/media/mdx/Block/block.ru.mdx +42 -0
- package/src/media/mdx/Block/wikiMdxBlock.ts +19 -0
- package/src/media/mdx/ChipGroup/chipGroup.en.mdx +51 -0
- package/src/media/mdx/ChipGroup/chipGroup.ru.mdx +51 -0
- package/src/media/mdx/ChipGroup/selected.en.mdx +50 -0
- package/src/media/mdx/ChipGroup/selected.ru.mdx +50 -0
- package/src/media/mdx/ChipGroup/wikiMdxChipGroup.ts +25 -0
- package/src/media/mdx/Dialog/buttons.en.mdx +45 -0
- package/src/media/mdx/Dialog/buttons.ru.mdx +45 -0
- package/src/media/mdx/Dialog/dialog.en.mdx +66 -0
- package/src/media/mdx/Dialog/dialog.ru.mdx +65 -0
- package/src/media/mdx/Dialog/events.en.mdx +63 -0
- package/src/media/mdx/Dialog/events.ru.mdx +63 -0
- package/src/media/mdx/Dialog/states.en.mdx +58 -0
- package/src/media/mdx/Dialog/states.ru.mdx +57 -0
- package/src/media/mdx/Dialog/wikiMdxDialog.ts +37 -0
- package/src/media/mdx/Field/arrows.en.mdx +22 -6
- package/src/media/mdx/Field/arrows.ru.mdx +22 -6
- package/src/media/mdx/Field/slots.en.mdx +0 -13
- package/src/media/mdx/Field/slots.ru.mdx +0 -13
- package/src/media/mdx/Image/img-tag.en.mdx +105 -0
- package/src/media/mdx/Image/img-tag.ru.mdx +105 -0
- package/src/media/mdx/Image/wikiMdxImage.ts +6 -0
- package/src/media/mdx/Input/currency.en.mdx +38 -0
- package/src/media/mdx/Input/currency.ru.mdx +38 -0
- package/src/media/mdx/Input/date.en.mdx +53 -0
- package/src/media/mdx/Input/date.ru.mdx +53 -0
- package/src/media/mdx/Input/input.en.mdx +143 -0
- package/src/media/mdx/Input/input.ru.mdx +71 -0
- package/src/media/mdx/Input/mask.en.mdx +30 -0
- package/src/media/mdx/Input/mask.ru.mdx +30 -0
- package/src/media/mdx/Input/number.en.mdx +41 -0
- package/src/media/mdx/Input/number.ru.mdx +41 -0
- package/src/media/mdx/Input/type.en.mdx +26 -0
- package/src/media/mdx/Input/type.ru.mdx +26 -0
- package/src/media/mdx/Input/wikiMdxInput.ts +49 -0
- package/src/media/mdx/Menu/event.updateValue.en.mdx +29 -0
- package/src/media/mdx/Menu/event.updateValue.ru.mdx +30 -0
- package/src/media/mdx/Menu/expose.navigation.en.mdx +12 -0
- package/src/media/mdx/Menu/expose.navigation.ru.mdx +12 -0
- package/src/media/mdx/Menu/navigation.en.mdx +56 -0
- package/src/media/mdx/Menu/navigation.ru.mdx +56 -0
- package/src/media/mdx/Menu/slots.control.en.mdx +65 -0
- package/src/media/mdx/Menu/slots.control.ru.mdx +65 -0
- package/src/media/mdx/Menu/slots.en.mdx +2 -24
- package/src/media/mdx/Menu/slots.ru.mdx +2 -24
- package/src/media/mdx/Menu/wikiMdxMenu.ts +27 -3
- package/src/media/mdx/Modal/differences.en.mdx +130 -0
- package/src/media/mdx/Modal/differences.ru.mdx +65 -0
- package/src/media/mdx/Modal/modal.en.mdx +63 -0
- package/src/media/mdx/Modal/modal.ru.mdx +63 -0
- package/src/media/mdx/Modal/wikiMdxModal.ts +25 -0
- package/src/media/mdx/MotionTransform/expose.motionTransformElement.en.mdx +13 -0
- package/src/media/mdx/MotionTransform/expose.motionTransformElement.ru.mdx +14 -0
- package/src/media/mdx/MotionTransform/wikiMdxMotionTransform.ts +6 -0
- package/src/media/mdx/Select/select.en.mdx +69 -0
- package/src/media/mdx/Select/select.ru.mdx +69 -0
- package/src/media/mdx/Select/wikiMdxSelect.ts +19 -0
- package/src/media/mdx/SelectValue/selectValue.en.mdx +64 -0
- package/src/media/mdx/SelectValue/selectValue.ru.mdx +64 -0
- package/src/media/mdx/SelectValue/wikiMdxSelectValue.ts +19 -0
- package/src/media/mdx/TextareaAutosize/textarea-autosize.en.mdx +65 -0
- package/src/media/mdx/TextareaAutosize/textarea-autosize.ru.mdx +65 -0
- package/src/media/mdx/TextareaAutosize/wikiMdxTextareaAutosize.ts +19 -0
- package/src/media/mdx/Tooltip/event.tooltip.en.mdx +7 -0
- package/src/media/mdx/Tooltip/event.tooltip.ru.mdx +8 -0
- package/src/media/mdx/Tooltip/slot.control.en.mdx +14 -0
- package/src/media/mdx/Tooltip/slot.control.ru.mdx +14 -0
- package/src/media/mdx/Tooltip/tooltip.en.mdx +34 -0
- package/src/media/mdx/Tooltip/tooltip.ru.mdx +34 -0
- package/src/media/mdx/Tooltip/wikiMdxTooltip.ts +31 -0
- package/src/media/mdx/Window/classes.ru.mdx +1 -1
- package/src/media/mdx/event/events.actions.en.mdx +44 -0
- package/src/media/mdx/event/events.actions.ru.mdx +44 -0
- package/src/media/mdx/event/events.inputStandard.en.mdx +6 -0
- package/src/media/mdx/event/events.inputStandard.ru.mdx +6 -0
- package/src/media/mdx/event/wikiMdxEvent.ts +20 -8
- package/src/media/mdx/expose/expose.descriptionId.en.mdx +6 -0
- package/src/media/mdx/expose/expose.descriptionId.ru.mdx +6 -0
- package/src/media/mdx/expose/expose.id.en.mdx +6 -0
- package/src/media/mdx/expose/expose.id.ru.mdx +6 -0
- package/src/media/mdx/expose/expose.labelId.en.mdx +6 -0
- package/src/media/mdx/expose/expose.labelId.ru.mdx +6 -0
- package/src/media/mdx/expose/wikiMdxExpose.ts +18 -0
- package/src/media/mdx/slot/body.en.mdx +6 -0
- package/src/media/mdx/slot/body.ru.mdx +6 -0
- package/src/media/mdx/slot/headline.en.mdx +7 -0
- package/src/media/mdx/slot/headline.ru.mdx +6 -0
- package/src/media/mdx/slot/leading.en.mdx +7 -0
- package/src/media/mdx/slot/leading.ru.mdx +7 -0
- package/src/media/mdx/slot/secondary.en.mdx +5 -0
- package/src/media/mdx/slot/secondary.ru.mdx +5 -0
- package/src/media/mdx/slot/trailing.en.mdx +7 -0
- package/src/media/mdx/slot/trailing.ru.mdx +7 -0
- package/src/media/mdx/slot/wikiMdxSlot.ts +30 -0
- package/src/media/mdx/style/isSkeleton.en.mdx +2 -2
- package/src/media/mdx/style/isSkeleton.ru.mdx +2 -2
- package/src/media/mdx/value/v-model-selected.en.mdx +28 -0
- package/src/media/mdx/value/v-model-selected.ru.mdx +28 -0
- package/src/media/mdx/value/v-model.en.mdx +26 -0
- package/src/media/mdx/value/v-model.ru.mdx +26 -0
- package/src/media/mdx/value/wikiMdxValue.ts +24 -3
- package/src/media/mdx/wikiMdx.ts +29 -1
- package/src/media/props/wiki.ts +42 -0
- package/src/media/props/wikiActions.ts +43 -0
- package/src/media/props/wikiActionsInclude.ts +62 -0
- package/src/media/props/wikiAnchor.ts +84 -0
- package/src/media/props/wikiAria.ts +102 -0
- package/src/media/props/wikiArrow.ts +24 -0
- package/src/media/props/wikiArrowInclude.ts +45 -0
- package/src/media/props/wikiBarsInclude.ts +80 -0
- package/src/media/props/wikiChipGroup.ts +39 -0
- package/src/media/props/wikiDialog.ts +34 -0
- package/src/media/props/wikiField.ts +0 -21
- package/src/media/props/wikiFieldCounterInclude.ts +78 -0
- package/src/media/props/wikiForm.ts +248 -0
- package/src/media/props/wikiHook.ts +20 -0
- package/src/media/props/wikiIcon.ts +3 -3
- package/src/media/props/wikiIconInclude.ts +319 -0
- package/src/media/props/wikiImage.ts +71 -19
- package/src/media/props/wikiInformation.ts +160 -0
- package/src/media/props/wikiInput.ts +34 -0
- package/src/media/props/wikiListItem.ts +20 -0
- package/src/media/props/wikiMask.ts +0 -10
- package/src/media/props/wikiMaskInclude.ts +54 -0
- package/src/media/props/wikiMenu.ts +0 -10
- package/src/media/props/wikiMotionTransform.ts +0 -10
- package/src/media/props/wikiOption.ts +113 -0
- package/src/media/props/wikiSelect.ts +68 -0
- package/src/media/props/wikiSelectValue.ts +30 -0
- package/src/media/props/wikiStatus.ts +29 -41
- package/src/media/props/wikiStyle.ts +154 -243
- package/src/media/props/wikiTechnical.ts +65 -0
- package/src/media/props/wikiText.ts +57 -0
- package/src/media/props/wikiTooltip.ts +53 -0
- package/src/media/props/wikiValue.ts +14 -203
- package/src/media/props/wikiWindow.ts +0 -31
- package/src/styles/storybookStyle.scss +3 -1
- package/src/types/storybookTypes.ts +26 -4
|
@@ -0,0 +1,1330 @@
|
|
|
1
|
+
import {Meta} from '@storybook/addon-docs/blocks'
|
|
2
|
+
|
|
3
|
+
<Meta title='@dxtmisha/functional/ru/Classes/Meta'/>
|
|
4
|
+
|
|
5
|
+
# Класс Meta
|
|
6
|
+
|
|
7
|
+
Унифицированный класс для управления всеми типами мета-тегов: стандартные HTML, Open Graph и Twitter Card. Предоставляет единый интерфейс для работы с SEO-оптимизацией и социальными сетями, автоматически синхронизируя изменения между всеми платформами.
|
|
8
|
+
|
|
9
|
+
## Основные возможности
|
|
10
|
+
|
|
11
|
+
- **Унифицированный API** — одна точка входа для всех типов мета-тегов
|
|
12
|
+
- **Автоматическая синхронизация** — изменения в Meta автоматически применяются к Open Graph и Twitter Card
|
|
13
|
+
- **Управление заголовком** — поддержка суффикса для заголовка страницы (например, "Заголовок - Название сайта")
|
|
14
|
+
- **Полная интеграция** — объединяет MetaManager, MetaOg и MetaTwitter
|
|
15
|
+
- **Упрощенный интерфейс** — сокращает количество кода для установки мета-тегов
|
|
16
|
+
- **Поддержка keywords** — работа с ключевыми словами в виде строки или массива
|
|
17
|
+
- **Robots директивы** — управление индексацией и crawling
|
|
18
|
+
- **SSR совместимость** — генерация HTML для серверного рендеринга
|
|
19
|
+
|
|
20
|
+
## Конструктор
|
|
21
|
+
|
|
22
|
+
### `constructor`
|
|
23
|
+
|
|
24
|
+
Создает экземпляр Meta с интегрированной поддержкой Open Graph и Twitter Card. Автоматически инициализирует внутренние экземпляры MetaOg и MetaTwitter.
|
|
25
|
+
|
|
26
|
+
```javascript
|
|
27
|
+
import { Meta } from '@dxtmisha/functional'
|
|
28
|
+
|
|
29
|
+
// Создание единого менеджера мета-тегов
|
|
30
|
+
const meta = new Meta()
|
|
31
|
+
|
|
32
|
+
// Класс автоматически управляет:
|
|
33
|
+
// - Стандартными HTML мета-тегами (description, keywords, author, robots, canonical)
|
|
34
|
+
// - Open Graph тегами (og:title, og:description, og:image, og:url, og:site_name, og:locale)
|
|
35
|
+
// - Twitter Card тегами (twitter:card, twitter:title, twitter:description, twitter:image, twitter:site)
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Методы получения данных
|
|
39
|
+
|
|
40
|
+
### `getTitle`
|
|
41
|
+
|
|
42
|
+
Получает заголовок страницы без суффикса.
|
|
43
|
+
|
|
44
|
+
**Возвращает:** `string` — заголовок страницы
|
|
45
|
+
|
|
46
|
+
```javascript
|
|
47
|
+
const meta = new Meta()
|
|
48
|
+
|
|
49
|
+
// Установить заголовок с суффиксом
|
|
50
|
+
meta.setSuffix('Мой Сайт')
|
|
51
|
+
meta.setTitle('Главная страница')
|
|
52
|
+
|
|
53
|
+
// document.title = "Главная страница - Мой Сайт"
|
|
54
|
+
|
|
55
|
+
// Получить чистый заголовок (без суффикса)
|
|
56
|
+
const title = meta.getTitle()
|
|
57
|
+
// "Главная страница"
|
|
58
|
+
|
|
59
|
+
// Использование в навигации
|
|
60
|
+
const breadcrumb = meta.getTitle()
|
|
61
|
+
|
|
62
|
+
// Проверка наличия
|
|
63
|
+
if (meta.getTitle()) {
|
|
64
|
+
console.log('Заголовок установлен')
|
|
65
|
+
}
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### `getKeywords`
|
|
69
|
+
|
|
70
|
+
Получает мета-тег keywords.
|
|
71
|
+
|
|
72
|
+
**Возвращает:** `string` — ключевые слова через запятую
|
|
73
|
+
|
|
74
|
+
```javascript
|
|
75
|
+
const meta = new Meta()
|
|
76
|
+
|
|
77
|
+
const keywords = meta.getKeywords()
|
|
78
|
+
// "веб-разработка, javascript, vue, react"
|
|
79
|
+
|
|
80
|
+
// Преобразование в массив
|
|
81
|
+
const keywordsArray = keywords.split(', ')
|
|
82
|
+
|
|
83
|
+
// Проверка наличия ключевого слова
|
|
84
|
+
if (meta.getKeywords().includes('javascript')) {
|
|
85
|
+
console.log('Страница про JavaScript')
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Использование для фильтрации
|
|
89
|
+
const tags = meta.getKeywords().split(', ')
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### `getDescription`
|
|
93
|
+
|
|
94
|
+
Получает мета-тег description.
|
|
95
|
+
|
|
96
|
+
**Возвращает:** `string` — описание страницы
|
|
97
|
+
|
|
98
|
+
```javascript
|
|
99
|
+
const meta = new Meta()
|
|
100
|
+
|
|
101
|
+
const description = meta.getDescription()
|
|
102
|
+
// "Полное руководство по веб-разработке"
|
|
103
|
+
|
|
104
|
+
// Проверка длины
|
|
105
|
+
if (meta.getDescription().length > 160) {
|
|
106
|
+
console.warn('Описание слишком длинное для Google')
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// Использование в превью
|
|
110
|
+
const preview = meta.getDescription().substring(0, 100)
|
|
111
|
+
|
|
112
|
+
// Для структурированных данных
|
|
113
|
+
const schema = {
|
|
114
|
+
description: meta.getDescription()
|
|
115
|
+
}
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
### `getImage`
|
|
119
|
+
|
|
120
|
+
Получает URL изображения Open Graph.
|
|
121
|
+
|
|
122
|
+
**Возвращает:** `string` — URL изображения
|
|
123
|
+
|
|
124
|
+
```javascript
|
|
125
|
+
const meta = new Meta()
|
|
126
|
+
|
|
127
|
+
const imageUrl = meta.getImage()
|
|
128
|
+
// "https://example.com/images/preview.jpg"
|
|
129
|
+
|
|
130
|
+
// Предзагрузка
|
|
131
|
+
const img = new Image()
|
|
132
|
+
img.src = meta.getImage()
|
|
133
|
+
|
|
134
|
+
// Использование в шаринге
|
|
135
|
+
const shareData = {
|
|
136
|
+
title: meta.getTitle(),
|
|
137
|
+
text: meta.getDescription(),
|
|
138
|
+
image: meta.getImage()
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// Проверка наличия
|
|
142
|
+
if (!meta.getImage()) {
|
|
143
|
+
console.warn('Изображение для социальных сетей не установлено')
|
|
144
|
+
}
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
### `getCanonical`
|
|
148
|
+
|
|
149
|
+
Получает канонический URL.
|
|
150
|
+
|
|
151
|
+
**Возвращает:** `string` — канонический URL
|
|
152
|
+
|
|
153
|
+
```javascript
|
|
154
|
+
const meta = new Meta()
|
|
155
|
+
|
|
156
|
+
const canonicalUrl = meta.getCanonical()
|
|
157
|
+
// "https://example.com/page"
|
|
158
|
+
|
|
159
|
+
// Проверка совпадения с текущим URL
|
|
160
|
+
if (meta.getCanonical() !== window.location.href) {
|
|
161
|
+
console.log('Canonical URL отличается от текущего')
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// Использование для редиректов
|
|
165
|
+
const canonical = meta.getCanonical()
|
|
166
|
+
|
|
167
|
+
// Для sitemap
|
|
168
|
+
const url = meta.getCanonical()
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
### `getRobots`
|
|
172
|
+
|
|
173
|
+
Получает значение мета-тега robots.
|
|
174
|
+
|
|
175
|
+
**Возвращает:** `MetaRobots` — директива для роботов
|
|
176
|
+
|
|
177
|
+
```javascript
|
|
178
|
+
const meta = new Meta()
|
|
179
|
+
|
|
180
|
+
const robots = meta.getRobots()
|
|
181
|
+
// "index, follow"
|
|
182
|
+
|
|
183
|
+
// Проверка индексации
|
|
184
|
+
if (meta.getRobots().includes('noindex')) {
|
|
185
|
+
console.log('Страница не должна индексироваться')
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// Условная логика
|
|
189
|
+
const isIndexable = !meta.getRobots().includes('noindex')
|
|
190
|
+
|
|
191
|
+
// Для отладки
|
|
192
|
+
console.log('Robots directive:', meta.getRobots())
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
### `getAuthor`
|
|
196
|
+
|
|
197
|
+
Получает мета-тег author.
|
|
198
|
+
|
|
199
|
+
**Возвращает:** `string` — имя автора
|
|
200
|
+
|
|
201
|
+
```javascript
|
|
202
|
+
const meta = new Meta()
|
|
203
|
+
|
|
204
|
+
const author = meta.getAuthor()
|
|
205
|
+
// "Иван Иванов"
|
|
206
|
+
|
|
207
|
+
// Отображение информации об авторе
|
|
208
|
+
console.log(`Автор: ${meta.getAuthor()}`)
|
|
209
|
+
|
|
210
|
+
// Для структурированных данных
|
|
211
|
+
const articleSchema = {
|
|
212
|
+
author: {
|
|
213
|
+
name: meta.getAuthor()
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// Проверка авторства
|
|
218
|
+
if (meta.getAuthor()) {
|
|
219
|
+
console.log('У контента есть автор')
|
|
220
|
+
}
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
### `getSiteName`
|
|
224
|
+
|
|
225
|
+
Получает название сайта Open Graph.
|
|
226
|
+
|
|
227
|
+
**Возвращает:** `string` — название сайта
|
|
228
|
+
|
|
229
|
+
```javascript
|
|
230
|
+
const meta = new Meta()
|
|
231
|
+
|
|
232
|
+
const siteName = meta.getSiteName()
|
|
233
|
+
// "Мой Блог"
|
|
234
|
+
|
|
235
|
+
// Использование в заголовке
|
|
236
|
+
document.title = `${meta.getTitle()} | ${meta.getSiteName()}`
|
|
237
|
+
|
|
238
|
+
// Для брендинга
|
|
239
|
+
const brandName = meta.getSiteName()
|
|
240
|
+
|
|
241
|
+
// В футере
|
|
242
|
+
const footerText = `© 2024 ${meta.getSiteName()}`
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
### `getLocale`
|
|
246
|
+
|
|
247
|
+
Получает локаль Open Graph.
|
|
248
|
+
|
|
249
|
+
**Возвращает:** `string` — локаль (например, 'ru_RU')
|
|
250
|
+
|
|
251
|
+
```javascript
|
|
252
|
+
const meta = new Meta()
|
|
253
|
+
|
|
254
|
+
const locale = meta.getLocale()
|
|
255
|
+
// "ru_RU"
|
|
256
|
+
|
|
257
|
+
// Определение языка
|
|
258
|
+
const language = meta.getLocale().split('_')[0] // "ru"
|
|
259
|
+
|
|
260
|
+
// Использование для i18n
|
|
261
|
+
if (meta.getLocale().startsWith('ru')) {
|
|
262
|
+
console.log('Русскоязычный контент')
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
// Для hreflang
|
|
266
|
+
const lang = meta.getLocale().replace('_', '-').toLowerCase()
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
### `getOg`
|
|
270
|
+
|
|
271
|
+
Получает экземпляр MetaOg для расширенных операций с Open Graph.
|
|
272
|
+
|
|
273
|
+
**Возвращает:** `MetaOg` — экземпляр класса MetaOg
|
|
274
|
+
|
|
275
|
+
```javascript
|
|
276
|
+
const meta = new Meta()
|
|
277
|
+
|
|
278
|
+
// Получить доступ к MetaOg
|
|
279
|
+
const og = meta.getOg()
|
|
280
|
+
|
|
281
|
+
// Использовать специфичные методы Open Graph
|
|
282
|
+
og.setType(MetaOpenGraphType.article)
|
|
283
|
+
|
|
284
|
+
// Доступ ко всем методам MetaOg
|
|
285
|
+
og.getType() // 'article'
|
|
286
|
+
|
|
287
|
+
// Установка дополнительных OG тегов
|
|
288
|
+
meta.getOg().setType(MetaOpenGraphType.video)
|
|
289
|
+
|
|
290
|
+
// Цепочка вызовов
|
|
291
|
+
meta.getOg()
|
|
292
|
+
.setType(MetaOpenGraphType.article)
|
|
293
|
+
.setLocale('ru_RU')
|
|
294
|
+
|
|
295
|
+
// Использование для специфичных настроек
|
|
296
|
+
const setupArticle = () => {
|
|
297
|
+
meta.setTitle('Статья')
|
|
298
|
+
meta.setDescription('Описание')
|
|
299
|
+
|
|
300
|
+
// Специфичные настройки Open Graph
|
|
301
|
+
meta.getOg().setType(MetaOpenGraphType.article)
|
|
302
|
+
}
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
### `getTwitter`
|
|
306
|
+
|
|
307
|
+
Получает экземпляр MetaTwitter для расширенных операций с Twitter Card.
|
|
308
|
+
|
|
309
|
+
**Возвращает:** `MetaTwitter` — экземпляр класса MetaTwitter
|
|
310
|
+
|
|
311
|
+
```javascript
|
|
312
|
+
const meta = new Meta()
|
|
313
|
+
|
|
314
|
+
// Получить доступ к MetaTwitter
|
|
315
|
+
const twitter = meta.getTwitter()
|
|
316
|
+
|
|
317
|
+
// Использовать специфичные методы Twitter Card
|
|
318
|
+
twitter.setCard(MetaTwitterCard.summaryLargeImage)
|
|
319
|
+
|
|
320
|
+
// Доступ ко всем методам MetaTwitter
|
|
321
|
+
twitter.getCard() // 'summary_large_image'
|
|
322
|
+
|
|
323
|
+
// Установка дополнительных Twitter тегов
|
|
324
|
+
meta.getTwitter().setCard(MetaTwitterCard.player)
|
|
325
|
+
|
|
326
|
+
// Цепочка вызовов
|
|
327
|
+
meta.getTwitter()
|
|
328
|
+
.setCard(MetaTwitterCard.summaryLargeImage)
|
|
329
|
+
.setCreator('@author')
|
|
330
|
+
|
|
331
|
+
// Использование для специфичных настроек
|
|
332
|
+
const setupVideo = () => {
|
|
333
|
+
meta.setTitle('Видео')
|
|
334
|
+
meta.setDescription('Описание видео')
|
|
335
|
+
|
|
336
|
+
// Специфичные настройки Twitter Card
|
|
337
|
+
meta.getTwitter().setCard(MetaTwitterCard.player)
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
// Установка creator (не доступен через Meta напрямую)
|
|
341
|
+
meta.getTwitter().setCreator('@john_doe')
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
## Методы установки данных
|
|
345
|
+
|
|
346
|
+
### `setTitle`
|
|
347
|
+
|
|
348
|
+
Устанавливает заголовок страницы с автоматическим добавлением суффикса и обновляет Open Graph и Twitter Card.
|
|
349
|
+
|
|
350
|
+
**Параметры:**
|
|
351
|
+
- `title: string` — заголовок страницы (без суффикса)
|
|
352
|
+
|
|
353
|
+
**Возвращает:** `this` — для цепочечных вызовов
|
|
354
|
+
|
|
355
|
+
```javascript
|
|
356
|
+
const meta = new Meta()
|
|
357
|
+
|
|
358
|
+
// Установить суффикс (обычно название сайта)
|
|
359
|
+
meta.setSuffix('Мой Сайт')
|
|
360
|
+
|
|
361
|
+
// Установить заголовок
|
|
362
|
+
meta.setTitle('Главная страница')
|
|
363
|
+
// document.title = "Главная страница - Мой Сайт"
|
|
364
|
+
// og:title = "Главная страница - Мой Сайт"
|
|
365
|
+
// twitter:title = "Главная страница - Мой Сайт"
|
|
366
|
+
|
|
367
|
+
// Без суффикса
|
|
368
|
+
const meta2 = new Meta()
|
|
369
|
+
meta2.setTitle('Страница без суффикса')
|
|
370
|
+
// document.title = "Страница без суффикса"
|
|
371
|
+
|
|
372
|
+
// Динамическое обновление
|
|
373
|
+
router.afterEach((to) => {
|
|
374
|
+
meta.setTitle(to.meta.title)
|
|
375
|
+
})
|
|
376
|
+
|
|
377
|
+
// Для разных страниц
|
|
378
|
+
meta.setTitle('О компании')
|
|
379
|
+
meta.setTitle('Контакты')
|
|
380
|
+
meta.setTitle('Блог')
|
|
381
|
+
|
|
382
|
+
// Цепочка вызовов
|
|
383
|
+
meta
|
|
384
|
+
.setTitle('Новая страница')
|
|
385
|
+
.setDescription('Описание страницы')
|
|
386
|
+
```
|
|
387
|
+
|
|
388
|
+
### `setKeywords`
|
|
389
|
+
|
|
390
|
+
Устанавливает мета-тег keywords. Принимает строку или массив.
|
|
391
|
+
|
|
392
|
+
**Параметры:**
|
|
393
|
+
- `keywords: string | string[]` — ключевые слова
|
|
394
|
+
|
|
395
|
+
**Возвращает:** `this` — для цепочечных вызовов
|
|
396
|
+
|
|
397
|
+
```javascript
|
|
398
|
+
const meta = new Meta()
|
|
399
|
+
|
|
400
|
+
// Строка
|
|
401
|
+
meta.setKeywords('веб-разработка, javascript, vue, react')
|
|
402
|
+
|
|
403
|
+
// Массив
|
|
404
|
+
meta.setKeywords(['веб-разработка', 'javascript', 'vue', 'react'])
|
|
405
|
+
// Результат: "веб-разработка, javascript, vue, react"
|
|
406
|
+
|
|
407
|
+
// Из данных страницы
|
|
408
|
+
const page = {
|
|
409
|
+
tags: ['javascript', 'tutorial', 'web']
|
|
410
|
+
}
|
|
411
|
+
meta.setKeywords(page.tags)
|
|
412
|
+
|
|
413
|
+
// Динамическое добавление
|
|
414
|
+
const existingKeywords = meta.getKeywords().split(', ')
|
|
415
|
+
const newKeywords = [...existingKeywords, 'новое', 'ключевое', 'слово']
|
|
416
|
+
meta.setKeywords(newKeywords)
|
|
417
|
+
|
|
418
|
+
// Условное добавление
|
|
419
|
+
const keywords = ['web']
|
|
420
|
+
if (isJavaScriptArticle) {
|
|
421
|
+
keywords.push('javascript')
|
|
422
|
+
}
|
|
423
|
+
meta.setKeywords(keywords)
|
|
424
|
+
|
|
425
|
+
// Примечание: хотя keywords менее важны для SEO,
|
|
426
|
+
// они могут использоваться внутренним поиском
|
|
427
|
+
```
|
|
428
|
+
|
|
429
|
+
### `setDescription`
|
|
430
|
+
|
|
431
|
+
Устанавливает мета-тег description.
|
|
432
|
+
|
|
433
|
+
**Параметры:**
|
|
434
|
+
- `description: string` — описание страницы
|
|
435
|
+
|
|
436
|
+
**Возвращает:** `this` — для цепочечных вызовов
|
|
437
|
+
|
|
438
|
+
```javascript
|
|
439
|
+
const meta = new Meta()
|
|
440
|
+
|
|
441
|
+
// Установка описания
|
|
442
|
+
meta.setDescription('Полное руководство по веб-разработке с примерами кода и практическими заданиями')
|
|
443
|
+
|
|
444
|
+
// Из данных контента
|
|
445
|
+
meta.setDescription(article.excerpt)
|
|
446
|
+
|
|
447
|
+
// Обрезка длинного текста
|
|
448
|
+
const longDescription = article.content
|
|
449
|
+
const shortDescription = longDescription.substring(0, 160)
|
|
450
|
+
meta.setDescription(shortDescription)
|
|
451
|
+
|
|
452
|
+
// Удаление HTML тегов
|
|
453
|
+
const plainText = article.html.replace(/<[^>]*>/g, '')
|
|
454
|
+
meta.setDescription(plainText.substring(0, 160))
|
|
455
|
+
|
|
456
|
+
// Цепочка
|
|
457
|
+
meta
|
|
458
|
+
.setDescription('Описание страницы')
|
|
459
|
+
.setKeywords(['web', 'dev'])
|
|
460
|
+
|
|
461
|
+
// Рекомендации:
|
|
462
|
+
// - Google отображает ~155-160 символов
|
|
463
|
+
// - Yandex отображает ~150-160 символов
|
|
464
|
+
// - Должно содержать ключевые слова
|
|
465
|
+
// - Должно быть уникальным для каждой страницы
|
|
466
|
+
```
|
|
467
|
+
|
|
468
|
+
### `setImage`
|
|
469
|
+
|
|
470
|
+
Устанавливает изображение для Open Graph и Twitter Card одновременно.
|
|
471
|
+
|
|
472
|
+
**Параметры:**
|
|
473
|
+
- `image: string` — URL изображения
|
|
474
|
+
|
|
475
|
+
**Возвращает:** `this` — для цепочечных вызовов
|
|
476
|
+
|
|
477
|
+
```javascript
|
|
478
|
+
const meta = new Meta()
|
|
479
|
+
|
|
480
|
+
// Установка изображения
|
|
481
|
+
meta.setImage('https://example.com/images/preview.jpg')
|
|
482
|
+
// Обновляет og:image и twitter:image
|
|
483
|
+
|
|
484
|
+
// Абсолютный URL
|
|
485
|
+
const imageUrl = new URL('/images/social-preview.jpg', window.location.origin).href
|
|
486
|
+
meta.setImage(imageUrl)
|
|
487
|
+
|
|
488
|
+
// Из данных контента
|
|
489
|
+
meta.setImage(article.coverImage)
|
|
490
|
+
|
|
491
|
+
// Fallback изображение
|
|
492
|
+
meta.setImage(page.image || '/images/default-preview.jpg')
|
|
493
|
+
|
|
494
|
+
// Для разных страниц
|
|
495
|
+
if (isHomePage) {
|
|
496
|
+
meta.setImage('/images/home-preview.jpg')
|
|
497
|
+
} else if (isArticle) {
|
|
498
|
+
meta.setImage(article.image)
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
// Цепочка
|
|
502
|
+
meta
|
|
503
|
+
.setImage('https://example.com/image.jpg')
|
|
504
|
+
.setTitle('Заголовок')
|
|
505
|
+
|
|
506
|
+
// Рекомендуемый размер: 1200x630 px
|
|
507
|
+
// Минимальный размер: 600x315 px
|
|
508
|
+
// Форматы: JPG, PNG, WebP
|
|
509
|
+
```
|
|
510
|
+
|
|
511
|
+
### `setCanonical`
|
|
512
|
+
|
|
513
|
+
Устанавливает канонический URL и автоматически обновляет og:url и twitter:url.
|
|
514
|
+
|
|
515
|
+
**Параметры:**
|
|
516
|
+
- `canonical: string` — канонический URL
|
|
517
|
+
|
|
518
|
+
**Возвращает:** `this` — для цепочечных вызовов
|
|
519
|
+
|
|
520
|
+
```javascript
|
|
521
|
+
const meta = new Meta()
|
|
522
|
+
|
|
523
|
+
// Установка canonical
|
|
524
|
+
meta.setCanonical('https://example.com/page')
|
|
525
|
+
// Обновляет:
|
|
526
|
+
// - <link rel="canonical" href="https://example.com/page">
|
|
527
|
+
// - og:url = "https://example.com/page"
|
|
528
|
+
// - twitter:url = "https://example.com/page"
|
|
529
|
+
|
|
530
|
+
// Текущий URL
|
|
531
|
+
meta.setCanonical(window.location.href)
|
|
532
|
+
|
|
533
|
+
// Очистка параметров
|
|
534
|
+
const cleanUrl = `${window.location.origin}${window.location.pathname}`
|
|
535
|
+
meta.setCanonical(cleanUrl)
|
|
536
|
+
|
|
537
|
+
// Для пагинации (все страницы указывают на первую)
|
|
538
|
+
meta.setCanonical('https://example.com/articles')
|
|
539
|
+
|
|
540
|
+
// Для SPA
|
|
541
|
+
router.afterEach((to) => {
|
|
542
|
+
const url = `https://example.com${to.path}`
|
|
543
|
+
meta.setCanonical(url)
|
|
544
|
+
})
|
|
545
|
+
|
|
546
|
+
// Для дублирующего контента
|
|
547
|
+
meta.setCanonical(originalArticleUrl)
|
|
548
|
+
|
|
549
|
+
// Цепочка
|
|
550
|
+
meta
|
|
551
|
+
.setCanonical('https://example.com/page')
|
|
552
|
+
.setTitle('Заголовок')
|
|
553
|
+
```
|
|
554
|
+
|
|
555
|
+
### `setRobots`
|
|
556
|
+
|
|
557
|
+
Устанавливает мета-тег robots для управления индексацией.
|
|
558
|
+
|
|
559
|
+
**Параметры:**
|
|
560
|
+
- `robots: MetaRobots` — директива robots
|
|
561
|
+
|
|
562
|
+
**Возвращает:** `this` — для цепочечных вызовов
|
|
563
|
+
|
|
564
|
+
```javascript
|
|
565
|
+
import { Meta, MetaRobots } from '@dxtmisha/functional'
|
|
566
|
+
|
|
567
|
+
const meta = new Meta()
|
|
568
|
+
|
|
569
|
+
// Разрешить индексацию (по умолчанию)
|
|
570
|
+
meta.setRobots(MetaRobots.indexFollow)
|
|
571
|
+
// <meta name="robots" content="index, follow">
|
|
572
|
+
|
|
573
|
+
// Запретить индексацию
|
|
574
|
+
meta.setRobots(MetaRobots.noindexNofollow)
|
|
575
|
+
// <meta name="robots" content="noindex, nofollow">
|
|
576
|
+
|
|
577
|
+
// Индексировать, но не следовать по ссылкам
|
|
578
|
+
meta.setRobots(MetaRobots.indexNofollow)
|
|
579
|
+
|
|
580
|
+
// Не индексировать, но следовать по ссылкам
|
|
581
|
+
meta.setRobots(MetaRobots.noindexFollow)
|
|
582
|
+
|
|
583
|
+
// Запретить кэширование
|
|
584
|
+
meta.setRobots(MetaRobots.noarchive)
|
|
585
|
+
|
|
586
|
+
// Не показывать сниппет
|
|
587
|
+
meta.setRobots(MetaRobots.nosnippet)
|
|
588
|
+
|
|
589
|
+
// Условная установка
|
|
590
|
+
if (isDraftPage) {
|
|
591
|
+
meta.setRobots(MetaRobots.noindexNofollow)
|
|
592
|
+
} else {
|
|
593
|
+
meta.setRobots(MetaRobots.indexFollow)
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
// Для закрытых страниц
|
|
597
|
+
meta.setRobots(MetaRobots.noindexNofollow)
|
|
598
|
+
|
|
599
|
+
// Для страниц с дублирующимся контентом
|
|
600
|
+
meta.setRobots(MetaRobots.noindex)
|
|
601
|
+
```
|
|
602
|
+
|
|
603
|
+
### `setAuthor`
|
|
604
|
+
|
|
605
|
+
Устанавливает мета-тег author.
|
|
606
|
+
|
|
607
|
+
**Параметры:**
|
|
608
|
+
- `author: string` — имя автора
|
|
609
|
+
|
|
610
|
+
**Возвращает:** `this` — для цепочечных вызовов
|
|
611
|
+
|
|
612
|
+
```javascript
|
|
613
|
+
const meta = new Meta()
|
|
614
|
+
|
|
615
|
+
// Установка автора
|
|
616
|
+
meta.setAuthor('Иван Иванов')
|
|
617
|
+
|
|
618
|
+
// Из данных пользователя
|
|
619
|
+
meta.setAuthor(article.author.name)
|
|
620
|
+
|
|
621
|
+
// Полное имя
|
|
622
|
+
meta.setAuthor(`${user.firstName} ${user.lastName}`)
|
|
623
|
+
|
|
624
|
+
// Для блога
|
|
625
|
+
meta.setAuthor(post.author)
|
|
626
|
+
|
|
627
|
+
// Условная установка
|
|
628
|
+
if (article.author) {
|
|
629
|
+
meta.setAuthor(article.author.name)
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
// Цепочка
|
|
633
|
+
meta
|
|
634
|
+
.setAuthor('Иван Иванов')
|
|
635
|
+
.setTitle('Статья')
|
|
636
|
+
.setDescription('Описание')
|
|
637
|
+
|
|
638
|
+
// Для структурированных данных
|
|
639
|
+
meta.setAuthor(author.name)
|
|
640
|
+
```
|
|
641
|
+
|
|
642
|
+
### `setSiteName`
|
|
643
|
+
|
|
644
|
+
Устанавливает название сайта для Open Graph и Twitter Card одновременно.
|
|
645
|
+
|
|
646
|
+
**Параметры:**
|
|
647
|
+
- `siteName: string` — название сайта
|
|
648
|
+
|
|
649
|
+
**Возвращает:** `this` — для цепочечных вызовов
|
|
650
|
+
|
|
651
|
+
```javascript
|
|
652
|
+
const meta = new Meta()
|
|
653
|
+
|
|
654
|
+
// Установка названия сайта
|
|
655
|
+
meta.setSiteName('Мой Блог')
|
|
656
|
+
// Обновляет og:site_name и twitter:site
|
|
657
|
+
|
|
658
|
+
// Из конфигурации
|
|
659
|
+
meta.setSiteName(config.siteName)
|
|
660
|
+
|
|
661
|
+
// Константа
|
|
662
|
+
const SITE_NAME = 'WebDev Journal'
|
|
663
|
+
meta.setSiteName(SITE_NAME)
|
|
664
|
+
|
|
665
|
+
// Для брендинга
|
|
666
|
+
meta.setSiteName('TechBlog')
|
|
667
|
+
|
|
668
|
+
// Один раз при инициализации
|
|
669
|
+
const meta = new Meta()
|
|
670
|
+
meta.setSiteName('Мой Сайт')
|
|
671
|
+
meta.setSuffix('Мой Сайт')
|
|
672
|
+
|
|
673
|
+
// Цепочка
|
|
674
|
+
meta
|
|
675
|
+
.setSiteName('Название Сайта')
|
|
676
|
+
.setTitle('Главная')
|
|
677
|
+
|
|
678
|
+
// Рекомендации:
|
|
679
|
+
// - Краткое и узнаваемое
|
|
680
|
+
// - Соответствует бренду
|
|
681
|
+
// - Используется в социальных сетях
|
|
682
|
+
```
|
|
683
|
+
|
|
684
|
+
### `setLocale`
|
|
685
|
+
|
|
686
|
+
Устанавливает локаль для Open Graph.
|
|
687
|
+
|
|
688
|
+
**Параметры:**
|
|
689
|
+
- `locale: string` — локаль в формате language_TERRITORY
|
|
690
|
+
|
|
691
|
+
**Возвращает:** `this` — для цепочечных вызовов
|
|
692
|
+
|
|
693
|
+
```javascript
|
|
694
|
+
const meta = new Meta()
|
|
695
|
+
|
|
696
|
+
// Установка русской локали
|
|
697
|
+
meta.setLocale('ru_RU')
|
|
698
|
+
|
|
699
|
+
// Другие локали
|
|
700
|
+
meta.setLocale('en_US') // Английский (США)
|
|
701
|
+
meta.setLocale('en_GB') // Английский (Великобритания)
|
|
702
|
+
meta.setLocale('uk_UA') // Украинский
|
|
703
|
+
meta.setLocale('de_DE') // Немецкий
|
|
704
|
+
meta.setLocale('fr_FR') // Французский
|
|
705
|
+
|
|
706
|
+
// Автоматическое определение
|
|
707
|
+
const userLocale = navigator.language.replace('-', '_')
|
|
708
|
+
meta.setLocale(userLocale)
|
|
709
|
+
|
|
710
|
+
// Из настроек i18n
|
|
711
|
+
meta.setLocale(i18n.locale.replace('-', '_'))
|
|
712
|
+
|
|
713
|
+
// Условная установка
|
|
714
|
+
const locale = isRussian ? 'ru_RU' : 'en_US'
|
|
715
|
+
meta.setLocale(locale)
|
|
716
|
+
|
|
717
|
+
// При смене языка
|
|
718
|
+
const changeLanguage = (lang) => {
|
|
719
|
+
const localeMap = {
|
|
720
|
+
'ru': 'ru_RU',
|
|
721
|
+
'en': 'en_US',
|
|
722
|
+
'de': 'de_DE'
|
|
723
|
+
}
|
|
724
|
+
meta.setLocale(localeMap[lang])
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
// Цепочка
|
|
728
|
+
meta
|
|
729
|
+
.setLocale('ru_RU')
|
|
730
|
+
.setSiteName('Мой Сайт')
|
|
731
|
+
```
|
|
732
|
+
|
|
733
|
+
### `setSuffix`
|
|
734
|
+
|
|
735
|
+
Устанавливает суффикс для автоматического добавления к заголовку страницы.
|
|
736
|
+
|
|
737
|
+
**Параметры:**
|
|
738
|
+
- `suffix?: string` — суффикс заголовка (необязательный)
|
|
739
|
+
|
|
740
|
+
```javascript
|
|
741
|
+
const meta = new Meta()
|
|
742
|
+
|
|
743
|
+
// Установка суффикса
|
|
744
|
+
meta.setSuffix('Мой Сайт')
|
|
745
|
+
meta.setTitle('Главная')
|
|
746
|
+
// document.title = "Главная - Мой Сайт"
|
|
747
|
+
|
|
748
|
+
// Из конфигурации
|
|
749
|
+
meta.setSuffix(config.siteName)
|
|
750
|
+
|
|
751
|
+
// Удаление суффикса
|
|
752
|
+
meta.setSuffix()
|
|
753
|
+
meta.setTitle('Страница')
|
|
754
|
+
// document.title = "Страница"
|
|
755
|
+
|
|
756
|
+
// Условная установка
|
|
757
|
+
if (showBranding) {
|
|
758
|
+
meta.setSuffix('Название Сайта')
|
|
759
|
+
}
|
|
760
|
+
|
|
761
|
+
// Разные суффиксы для разных разделов
|
|
762
|
+
if (isBlog) {
|
|
763
|
+
meta.setSuffix('Блог | Мой Сайт')
|
|
764
|
+
} else {
|
|
765
|
+
meta.setSuffix('Мой Сайт')
|
|
766
|
+
}
|
|
767
|
+
|
|
768
|
+
// Обычно устанавливается один раз при инициализации
|
|
769
|
+
const initMeta = () => {
|
|
770
|
+
const meta = new Meta()
|
|
771
|
+
meta.setSuffix('Мой Сайт')
|
|
772
|
+
meta.setSiteName('Мой Сайт')
|
|
773
|
+
return meta
|
|
774
|
+
}
|
|
775
|
+
|
|
776
|
+
// Примечание: суффикс добавляется автоматически
|
|
777
|
+
// в формате: "Заголовок - Суффикс"
|
|
778
|
+
```
|
|
779
|
+
|
|
780
|
+
### `html`
|
|
781
|
+
|
|
782
|
+
Генерирует полный HTML для всех мета-тегов, включая Open Graph и Twitter Card.
|
|
783
|
+
|
|
784
|
+
**Возвращает:** `string` — HTML-строка со всеми мета-тегами
|
|
785
|
+
|
|
786
|
+
```javascript
|
|
787
|
+
const meta = new Meta()
|
|
788
|
+
|
|
789
|
+
// Настройка мета-тегов
|
|
790
|
+
meta.setSuffix('Мой Сайт')
|
|
791
|
+
meta.setSiteName('Мой Сайт')
|
|
792
|
+
meta.setLocale('ru_RU')
|
|
793
|
+
meta
|
|
794
|
+
.setTitle('Статья')
|
|
795
|
+
.setDescription('Описание статьи')
|
|
796
|
+
.setKeywords(['веб', 'javascript'])
|
|
797
|
+
.setImage('https://example.com/image.jpg')
|
|
798
|
+
.setCanonical('https://example.com/article')
|
|
799
|
+
.setAuthor('Иван Иванов')
|
|
800
|
+
|
|
801
|
+
// Получить HTML всех мета-тегов
|
|
802
|
+
const metaHTML = meta.html()
|
|
803
|
+
|
|
804
|
+
// Результат включает:
|
|
805
|
+
// - Стандартные HTML мета-теги (description, keywords, author, canonical)
|
|
806
|
+
// - Open Graph теги (og:title, og:description, og:image, og:url, og:site_name, og:locale)
|
|
807
|
+
// - Twitter Card теги (twitter:title, twitter:description, twitter:image, twitter:site)
|
|
808
|
+
|
|
809
|
+
// Использование в SSR (Server-Side Rendering)
|
|
810
|
+
// Express.js
|
|
811
|
+
app.get('/page', (req, res) => {
|
|
812
|
+
const meta = new Meta()
|
|
813
|
+
meta
|
|
814
|
+
.setTitle('Заголовок страницы')
|
|
815
|
+
.setDescription('Описание')
|
|
816
|
+
.setImage('https://example.com/og-image.jpg')
|
|
817
|
+
|
|
818
|
+
const html = `
|
|
819
|
+
<!DOCTYPE html>
|
|
820
|
+
<html>
|
|
821
|
+
<head>
|
|
822
|
+
<meta charset="UTF-8">
|
|
823
|
+
${meta.html()}
|
|
824
|
+
<title>Заголовок - Сайт</title>
|
|
825
|
+
</head>
|
|
826
|
+
<body>
|
|
827
|
+
<h1>Контент</h1>
|
|
828
|
+
</body>
|
|
829
|
+
</html>
|
|
830
|
+
`
|
|
831
|
+
|
|
832
|
+
res.send(html)
|
|
833
|
+
})
|
|
834
|
+
|
|
835
|
+
// Next.js getServerSideProps
|
|
836
|
+
export async function getServerSideProps() {
|
|
837
|
+
const meta = new Meta()
|
|
838
|
+
meta
|
|
839
|
+
.setTitle('Статья')
|
|
840
|
+
.setDescription('Описание статьи')
|
|
841
|
+
|
|
842
|
+
return {
|
|
843
|
+
props: {
|
|
844
|
+
metaTags: meta.html()
|
|
845
|
+
}
|
|
846
|
+
}
|
|
847
|
+
}
|
|
848
|
+
|
|
849
|
+
// Nuxt.js (в composable)
|
|
850
|
+
const meta = new Meta()
|
|
851
|
+
meta.setTitle('Страница')
|
|
852
|
+
|
|
853
|
+
const metaHTML = meta.html()
|
|
854
|
+
// Вставить в head через useHead() или в шаблон
|
|
855
|
+
|
|
856
|
+
// Преимущества метода html():
|
|
857
|
+
// - Автоматическое экранирование специальных символов
|
|
858
|
+
// - Объединяет все три типа мета-тегов (standard, OG, Twitter)
|
|
859
|
+
// - Готово для вставки в серверный шаблон
|
|
860
|
+
// - Безопасно от XSS атак
|
|
861
|
+
```
|
|
862
|
+
|
|
863
|
+
## Практические примеры
|
|
864
|
+
|
|
865
|
+
### Полная настройка страницы
|
|
866
|
+
|
|
867
|
+
```javascript
|
|
868
|
+
import { Meta, MetaRobots } from '@dxtmisha/functional'
|
|
869
|
+
|
|
870
|
+
const meta = new Meta()
|
|
871
|
+
|
|
872
|
+
// Настройка при инициализации приложения
|
|
873
|
+
meta.setSuffix('Мой Сайт')
|
|
874
|
+
meta.setSiteName('Мой Сайт')
|
|
875
|
+
meta.setLocale('ru_RU')
|
|
876
|
+
|
|
877
|
+
// Настройка конкретной страницы
|
|
878
|
+
meta
|
|
879
|
+
.setTitle('Полное руководство по веб-разработке')
|
|
880
|
+
.setDescription('Изучите веб-разработку с нуля: HTML, CSS, JavaScript, фреймворки и инструменты')
|
|
881
|
+
.setKeywords(['веб-разработка', 'html', 'css', 'javascript', 'руководство'])
|
|
882
|
+
.setImage('https://example.com/images/web-dev-guide.jpg')
|
|
883
|
+
.setCanonical('https://example.com/guides/web-development')
|
|
884
|
+
.setAuthor('Иван Иванов')
|
|
885
|
+
.setRobots(MetaRobots.indexFollow)
|
|
886
|
+
|
|
887
|
+
// Результат:
|
|
888
|
+
// <title>Полное руководство по веб-разработке - Мой Сайт</title>
|
|
889
|
+
// <meta name="description" content="Изучите веб-разработку...">
|
|
890
|
+
// <meta name="keywords" content="веб-разработка, html, css, javascript, руководство">
|
|
891
|
+
// <meta name="author" content="Иван Иванов">
|
|
892
|
+
// <meta name="robots" content="index, follow">
|
|
893
|
+
// <link rel="canonical" href="https://example.com/guides/web-development">
|
|
894
|
+
// <meta property="og:title" content="Полное руководство... - Мой Сайт">
|
|
895
|
+
// <meta property="og:description" content="Изучите веб-разработку...">
|
|
896
|
+
// <meta property="og:image" content="https://example.com/images/web-dev-guide.jpg">
|
|
897
|
+
// <meta property="og:url" content="https://example.com/guides/web-development">
|
|
898
|
+
// <meta property="og:site_name" content="Мой Сайт">
|
|
899
|
+
// <meta property="og:locale" content="ru_RU">
|
|
900
|
+
// <meta property="twitter:title" content="Полное руководство... - Мой Сайт">
|
|
901
|
+
// <meta property="twitter:description" content="Изучите веб-разработку...">
|
|
902
|
+
// <meta property="twitter:image" content="https://example.com/images/web-dev-guide.jpg">
|
|
903
|
+
// <meta property="twitter:site" content="Мой Сайт">
|
|
904
|
+
```
|
|
905
|
+
|
|
906
|
+
### Интеграция с Vue Router
|
|
907
|
+
|
|
908
|
+
```javascript
|
|
909
|
+
import { Meta } from '@dxtmisha/functional'
|
|
910
|
+
|
|
911
|
+
const meta = new Meta()
|
|
912
|
+
|
|
913
|
+
// Инициализация
|
|
914
|
+
meta.setSuffix('Мой Сайт')
|
|
915
|
+
meta.setSiteName('Мой Сайт')
|
|
916
|
+
meta.setLocale('ru_RU')
|
|
917
|
+
|
|
918
|
+
// Обновление при смене роута
|
|
919
|
+
router.afterEach((to) => {
|
|
920
|
+
meta
|
|
921
|
+
.setTitle(to.meta.title || 'Страница не найдена')
|
|
922
|
+
.setDescription(to.meta.description || '')
|
|
923
|
+
.setKeywords(to.meta.keywords || [])
|
|
924
|
+
.setCanonical(`https://example.com${to.path}`)
|
|
925
|
+
|
|
926
|
+
// Изображение если есть
|
|
927
|
+
if (to.meta.image) {
|
|
928
|
+
meta.setImage(to.meta.image)
|
|
929
|
+
}
|
|
930
|
+
|
|
931
|
+
// Автор если есть
|
|
932
|
+
if (to.meta.author) {
|
|
933
|
+
meta.setAuthor(to.meta.author)
|
|
934
|
+
}
|
|
935
|
+
})
|
|
936
|
+
|
|
937
|
+
// Определение мета в роутах
|
|
938
|
+
const routes = [
|
|
939
|
+
{
|
|
940
|
+
path: '/',
|
|
941
|
+
component: Home,
|
|
942
|
+
meta: {
|
|
943
|
+
title: 'Главная',
|
|
944
|
+
description: 'Добро пожаловать на наш сайт',
|
|
945
|
+
keywords: ['главная', 'сайт'],
|
|
946
|
+
image: '/images/home.jpg'
|
|
947
|
+
}
|
|
948
|
+
},
|
|
949
|
+
{
|
|
950
|
+
path: '/about',
|
|
951
|
+
component: About,
|
|
952
|
+
meta: {
|
|
953
|
+
title: 'О нас',
|
|
954
|
+
description: 'Информация о нашей компании',
|
|
955
|
+
keywords: ['о нас', 'компания'],
|
|
956
|
+
image: '/images/about.jpg'
|
|
957
|
+
}
|
|
958
|
+
}
|
|
959
|
+
]
|
|
960
|
+
```
|
|
961
|
+
|
|
962
|
+
### Интеграция с React
|
|
963
|
+
|
|
964
|
+
```javascript
|
|
965
|
+
import { Meta } from '@dxtmisha/functional'
|
|
966
|
+
import { useEffect } from 'react'
|
|
967
|
+
|
|
968
|
+
const meta = new Meta()
|
|
969
|
+
|
|
970
|
+
// Инициализация в App.js
|
|
971
|
+
function App() {
|
|
972
|
+
useEffect(() => {
|
|
973
|
+
meta.setSuffix('Мой Сайт')
|
|
974
|
+
meta.setSiteName('Мой Сайт')
|
|
975
|
+
meta.setLocale('en_US')
|
|
976
|
+
}, [])
|
|
977
|
+
|
|
978
|
+
return <Router />
|
|
979
|
+
}
|
|
980
|
+
|
|
981
|
+
// Компонент страницы
|
|
982
|
+
function ArticlePage({ article }) {
|
|
983
|
+
useEffect(() => {
|
|
984
|
+
meta
|
|
985
|
+
.setTitle(article.title)
|
|
986
|
+
.setDescription(article.excerpt)
|
|
987
|
+
.setKeywords(article.tags)
|
|
988
|
+
.setImage(article.coverImage)
|
|
989
|
+
.setCanonical(`https://example.com/articles/${article.slug}`)
|
|
990
|
+
.setAuthor(article.author.name)
|
|
991
|
+
|
|
992
|
+
return () => {
|
|
993
|
+
// Очистка при размонтировании (опционально)
|
|
994
|
+
}
|
|
995
|
+
}, [article])
|
|
996
|
+
|
|
997
|
+
return <div>{/* контент */}</div>
|
|
998
|
+
}
|
|
999
|
+
|
|
1000
|
+
// Custom hook для мета-тегов
|
|
1001
|
+
function useMeta(metaData) {
|
|
1002
|
+
useEffect(() => {
|
|
1003
|
+
if (metaData.title) meta.setTitle(metaData.title)
|
|
1004
|
+
if (metaData.description) meta.setDescription(metaData.description)
|
|
1005
|
+
if (metaData.keywords) meta.setKeywords(metaData.keywords)
|
|
1006
|
+
if (metaData.image) meta.setImage(metaData.image)
|
|
1007
|
+
if (metaData.canonical) meta.setCanonical(metaData.canonical)
|
|
1008
|
+
if (metaData.author) meta.setAuthor(metaData.author)
|
|
1009
|
+
}, [metaData])
|
|
1010
|
+
}
|
|
1011
|
+
|
|
1012
|
+
// Использование hook
|
|
1013
|
+
function BlogPost({ post }) {
|
|
1014
|
+
useMeta({
|
|
1015
|
+
title: post.title,
|
|
1016
|
+
description: post.excerpt,
|
|
1017
|
+
keywords: post.tags,
|
|
1018
|
+
image: post.image,
|
|
1019
|
+
author: post.author.name
|
|
1020
|
+
})
|
|
1021
|
+
|
|
1022
|
+
return <article>{/* контент */}</article>
|
|
1023
|
+
}
|
|
1024
|
+
```
|
|
1025
|
+
|
|
1026
|
+
### Динамическое обновление из API
|
|
1027
|
+
|
|
1028
|
+
```javascript
|
|
1029
|
+
import { Meta } from '@dxtmisha/functional'
|
|
1030
|
+
|
|
1031
|
+
const meta = new Meta()
|
|
1032
|
+
|
|
1033
|
+
// Загрузка страницы из API
|
|
1034
|
+
async function loadPage(pageId) {
|
|
1035
|
+
const response = await fetch(`/api/pages/${pageId}`)
|
|
1036
|
+
const page = await response.json()
|
|
1037
|
+
|
|
1038
|
+
// Обновление всех мета-тегов
|
|
1039
|
+
meta
|
|
1040
|
+
.setTitle(page.title)
|
|
1041
|
+
.setDescription(page.description)
|
|
1042
|
+
.setKeywords(page.keywords)
|
|
1043
|
+
.setImage(page.image)
|
|
1044
|
+
.setCanonical(page.url)
|
|
1045
|
+
.setAuthor(page.author)
|
|
1046
|
+
|
|
1047
|
+
return page
|
|
1048
|
+
}
|
|
1049
|
+
|
|
1050
|
+
// Обработка разных типов контента
|
|
1051
|
+
async function updateMetaForContent(contentType, contentId) {
|
|
1052
|
+
const content = await fetchContent(contentType, contentId)
|
|
1053
|
+
|
|
1054
|
+
switch (contentType) {
|
|
1055
|
+
case 'article':
|
|
1056
|
+
meta
|
|
1057
|
+
.setTitle(content.title)
|
|
1058
|
+
.setDescription(content.excerpt)
|
|
1059
|
+
.setKeywords(content.tags)
|
|
1060
|
+
.setImage(content.coverImage)
|
|
1061
|
+
.setAuthor(content.author.name)
|
|
1062
|
+
break
|
|
1063
|
+
|
|
1064
|
+
case 'product':
|
|
1065
|
+
meta
|
|
1066
|
+
.setTitle(content.name)
|
|
1067
|
+
.setDescription(content.description)
|
|
1068
|
+
.setKeywords([content.category, ...content.tags])
|
|
1069
|
+
.setImage(content.images[0])
|
|
1070
|
+
break
|
|
1071
|
+
|
|
1072
|
+
case 'video':
|
|
1073
|
+
meta
|
|
1074
|
+
.setTitle(content.title)
|
|
1075
|
+
.setDescription(content.synopsis)
|
|
1076
|
+
.setImage(content.thumbnail)
|
|
1077
|
+
break
|
|
1078
|
+
}
|
|
1079
|
+
}
|
|
1080
|
+
```
|
|
1081
|
+
|
|
1082
|
+
### SSR (Server-Side Rendering)
|
|
1083
|
+
|
|
1084
|
+
```javascript
|
|
1085
|
+
import { Meta } from '@dxtmisha/functional'
|
|
1086
|
+
|
|
1087
|
+
// Express.js сервер
|
|
1088
|
+
app.get('/article/:id', async (req, res) => {
|
|
1089
|
+
const article = await getArticle(req.params.id)
|
|
1090
|
+
|
|
1091
|
+
const meta = new Meta()
|
|
1092
|
+
meta.setSuffix('Мой Блог')
|
|
1093
|
+
meta.setSiteName('Мой Блог')
|
|
1094
|
+
meta.setLocale('ru_RU')
|
|
1095
|
+
|
|
1096
|
+
meta
|
|
1097
|
+
.setTitle(article.title)
|
|
1098
|
+
.setDescription(article.excerpt)
|
|
1099
|
+
.setKeywords(article.tags)
|
|
1100
|
+
.setImage(article.coverImage)
|
|
1101
|
+
.setCanonical(`https://example.com/article/${article.id}`)
|
|
1102
|
+
.setAuthor(article.author.name)
|
|
1103
|
+
|
|
1104
|
+
const html = `
|
|
1105
|
+
<!DOCTYPE html>
|
|
1106
|
+
<html lang="ru">
|
|
1107
|
+
<head>
|
|
1108
|
+
<meta charset="UTF-8">
|
|
1109
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
1110
|
+
<title>${article.title} - Мой Блог</title>
|
|
1111
|
+
${meta.html()}
|
|
1112
|
+
</head>
|
|
1113
|
+
<body>
|
|
1114
|
+
<article>${article.content}</article>
|
|
1115
|
+
</body>
|
|
1116
|
+
</html>
|
|
1117
|
+
`
|
|
1118
|
+
|
|
1119
|
+
res.send(html)
|
|
1120
|
+
})
|
|
1121
|
+
|
|
1122
|
+
// Next.js
|
|
1123
|
+
export async function getServerSideProps({ params }) {
|
|
1124
|
+
const article = await getArticle(params.id)
|
|
1125
|
+
|
|
1126
|
+
const meta = new Meta()
|
|
1127
|
+
meta.setSuffix('Мой Блог')
|
|
1128
|
+
meta
|
|
1129
|
+
.setTitle(article.title)
|
|
1130
|
+
.setDescription(article.excerpt)
|
|
1131
|
+
.setKeywords(article.tags)
|
|
1132
|
+
.setImage(article.coverImage)
|
|
1133
|
+
|
|
1134
|
+
return {
|
|
1135
|
+
props: {
|
|
1136
|
+
article,
|
|
1137
|
+
metaHtml: meta.html()
|
|
1138
|
+
}
|
|
1139
|
+
}
|
|
1140
|
+
}
|
|
1141
|
+
```
|
|
1142
|
+
|
|
1143
|
+
### Управление robots для разных сценариев
|
|
1144
|
+
|
|
1145
|
+
```javascript
|
|
1146
|
+
import { Meta, MetaRobots } from '@dxtmisha/functional'
|
|
1147
|
+
|
|
1148
|
+
const meta = new Meta()
|
|
1149
|
+
|
|
1150
|
+
// Функция определения robots директивы
|
|
1151
|
+
function setRobotsForPage(pageType, pageStatus) {
|
|
1152
|
+
switch (pageType) {
|
|
1153
|
+
case 'article':
|
|
1154
|
+
if (pageStatus === 'published') {
|
|
1155
|
+
meta.setRobots(MetaRobots.indexFollow)
|
|
1156
|
+
} else if (pageStatus === 'draft') {
|
|
1157
|
+
meta.setRobots(MetaRobots.noindexNofollow)
|
|
1158
|
+
}
|
|
1159
|
+
break
|
|
1160
|
+
|
|
1161
|
+
case 'search':
|
|
1162
|
+
// Страницы поиска не индексируем
|
|
1163
|
+
meta.setRobots(MetaRobots.noindexFollow)
|
|
1164
|
+
break
|
|
1165
|
+
|
|
1166
|
+
case 'login':
|
|
1167
|
+
case 'admin':
|
|
1168
|
+
// Закрытые страницы
|
|
1169
|
+
meta.setRobots(MetaRobots.noindexNofollow)
|
|
1170
|
+
break
|
|
1171
|
+
|
|
1172
|
+
case 'pagination':
|
|
1173
|
+
// Страницы пагинации
|
|
1174
|
+
meta.setRobots(MetaRobots.noindexFollow)
|
|
1175
|
+
break
|
|
1176
|
+
|
|
1177
|
+
default:
|
|
1178
|
+
meta.setRobots(MetaRobots.indexFollow)
|
|
1179
|
+
}
|
|
1180
|
+
}
|
|
1181
|
+
|
|
1182
|
+
// Условная логика
|
|
1183
|
+
if (isUserAuthenticated && isPrivatePage) {
|
|
1184
|
+
meta.setRobots(MetaRobots.noindexNofollow)
|
|
1185
|
+
} else {
|
|
1186
|
+
meta.setRobots(MetaRobots.indexFollow)
|
|
1187
|
+
}
|
|
1188
|
+
```
|
|
1189
|
+
|
|
1190
|
+
### Использование расширенных возможностей Open Graph и Twitter Card
|
|
1191
|
+
|
|
1192
|
+
```javascript
|
|
1193
|
+
import { Meta, MetaOpenGraphType, MetaTwitterCard } from '@dxtmisha/functional'
|
|
1194
|
+
|
|
1195
|
+
const meta = new Meta()
|
|
1196
|
+
|
|
1197
|
+
// Базовая настройка через Meta
|
|
1198
|
+
meta
|
|
1199
|
+
.setTitle('Видео: Введение в JavaScript')
|
|
1200
|
+
.setDescription('Полное видео руководство по JavaScript для начинающих')
|
|
1201
|
+
.setImage('https://example.com/images/js-video-thumb.jpg')
|
|
1202
|
+
.setCanonical('https://example.com/videos/js-intro')
|
|
1203
|
+
|
|
1204
|
+
// Расширенная настройка Open Graph через getOg()
|
|
1205
|
+
meta.getOg()
|
|
1206
|
+
.setType(MetaOpenGraphType.videoMovie) // Тип: видео
|
|
1207
|
+
.setLocale('ru_RU')
|
|
1208
|
+
|
|
1209
|
+
// Расширенная настройка Twitter Card через getTwitter()
|
|
1210
|
+
meta.getTwitter()
|
|
1211
|
+
.setCard(MetaTwitterCard.player) // Карточка с плеером
|
|
1212
|
+
.setCreator('@javascript_guru') // Автор видео
|
|
1213
|
+
|
|
1214
|
+
// Комбинированная настройка для разных типов контента
|
|
1215
|
+
const setupContentMeta = (content) => {
|
|
1216
|
+
// Общие настройки
|
|
1217
|
+
meta
|
|
1218
|
+
.setTitle(content.title)
|
|
1219
|
+
.setDescription(content.description)
|
|
1220
|
+
.setImage(content.image)
|
|
1221
|
+
.setCanonical(content.url)
|
|
1222
|
+
|
|
1223
|
+
// Специфичные настройки в зависимости от типа
|
|
1224
|
+
switch (content.type) {
|
|
1225
|
+
case 'article':
|
|
1226
|
+
meta.getOg().setType(MetaOpenGraphType.article)
|
|
1227
|
+
meta.getTwitter().setCard(MetaTwitterCard.summaryLargeImage)
|
|
1228
|
+
if (content.author?.twitter) {
|
|
1229
|
+
meta.getTwitter().setCreator(content.author.twitter)
|
|
1230
|
+
}
|
|
1231
|
+
break
|
|
1232
|
+
|
|
1233
|
+
case 'video':
|
|
1234
|
+
meta.getOg().setType(MetaOpenGraphType.videoMovie)
|
|
1235
|
+
meta.getTwitter().setCard(MetaTwitterCard.player)
|
|
1236
|
+
break
|
|
1237
|
+
|
|
1238
|
+
case 'product':
|
|
1239
|
+
meta.getOg().setType(MetaOpenGraphType.product)
|
|
1240
|
+
meta.getTwitter().setCard(MetaTwitterCard.summaryLargeImage)
|
|
1241
|
+
break
|
|
1242
|
+
|
|
1243
|
+
case 'music':
|
|
1244
|
+
meta.getOg().setType(MetaOpenGraphType.musicSong)
|
|
1245
|
+
meta.getTwitter().setCard(MetaTwitterCard.player)
|
|
1246
|
+
break
|
|
1247
|
+
}
|
|
1248
|
+
}
|
|
1249
|
+
|
|
1250
|
+
// Использование
|
|
1251
|
+
setupContentMeta({
|
|
1252
|
+
type: 'video',
|
|
1253
|
+
title: 'JavaScript Tutorial',
|
|
1254
|
+
description: 'Learn JavaScript from scratch',
|
|
1255
|
+
image: 'https://example.com/thumb.jpg',
|
|
1256
|
+
url: 'https://example.com/videos/js-tutorial',
|
|
1257
|
+
author: {
|
|
1258
|
+
twitter: '@instructor'
|
|
1259
|
+
}
|
|
1260
|
+
})
|
|
1261
|
+
|
|
1262
|
+
// Доступ к специфичным методам
|
|
1263
|
+
const getFullMetaInfo = () => {
|
|
1264
|
+
return {
|
|
1265
|
+
// Через Meta
|
|
1266
|
+
title: meta.getTitle(),
|
|
1267
|
+
description: meta.getDescription(),
|
|
1268
|
+
image: meta.getImage(),
|
|
1269
|
+
|
|
1270
|
+
// Через MetaOg
|
|
1271
|
+
ogType: meta.getOg().getType(),
|
|
1272
|
+
ogLocale: meta.getOg().getLocale(),
|
|
1273
|
+
|
|
1274
|
+
// Через MetaTwitter
|
|
1275
|
+
twitterCard: meta.getTwitter().getCard(),
|
|
1276
|
+
twitterCreator: meta.getTwitter().getCreator()
|
|
1277
|
+
}
|
|
1278
|
+
}
|
|
1279
|
+
```
|
|
1280
|
+
|
|
1281
|
+
## Рекомендации по использованию
|
|
1282
|
+
|
|
1283
|
+
### Инициализация
|
|
1284
|
+
Установите общие параметры один раз при запуске приложения:
|
|
1285
|
+
```javascript
|
|
1286
|
+
const meta = new Meta()
|
|
1287
|
+
meta.setSuffix('Название Сайта')
|
|
1288
|
+
meta.setSiteName('Название Сайта')
|
|
1289
|
+
meta.setLocale('ru_RU')
|
|
1290
|
+
```
|
|
1291
|
+
|
|
1292
|
+
### Обновление при навигации
|
|
1293
|
+
Обновляйте мета-теги при смене страницы:
|
|
1294
|
+
```javascript
|
|
1295
|
+
router.afterEach((to) => {
|
|
1296
|
+
meta
|
|
1297
|
+
.setTitle(to.meta.title)
|
|
1298
|
+
.setDescription(to.meta.description)
|
|
1299
|
+
.setCanonical(`https://example.com${to.path}`)
|
|
1300
|
+
})
|
|
1301
|
+
```
|
|
1302
|
+
|
|
1303
|
+
### Длина текста
|
|
1304
|
+
- **Title:** до 60 символов (без суффикса)
|
|
1305
|
+
- **Description:** 150-160 символов
|
|
1306
|
+
- **Keywords:** 10-15 ключевых слов
|
|
1307
|
+
|
|
1308
|
+
### Обязательные теги
|
|
1309
|
+
Минимально необходимые мета-теги:
|
|
1310
|
+
- Title (через `setTitle`)
|
|
1311
|
+
- Description (через `setDescription`)
|
|
1312
|
+
- Canonical (через `setCanonical`)
|
|
1313
|
+
- Image для социальных сетей (через `setImage`)
|
|
1314
|
+
|
|
1315
|
+
### Изображения
|
|
1316
|
+
- Размер: 1200×630 px (оптимально)
|
|
1317
|
+
- Формат: JPG, PNG, WebP
|
|
1318
|
+
- Максимум: 8 MB
|
|
1319
|
+
|
|
1320
|
+
## Примечания
|
|
1321
|
+
|
|
1322
|
+
- Класс объединяет функциональность MetaManager, MetaOg и MetaTwitter
|
|
1323
|
+
- Изменения в Meta автоматически применяются ко всем связанным мета-тегам
|
|
1324
|
+
- Суффикс добавляется только к document.title и социальным тегам
|
|
1325
|
+
- Метод `html()` наследуется от MetaManager и генерирует HTML для всех управляемых тегов
|
|
1326
|
+
- Класс совместим с SSR — проверяет наличие DOM перед доступом к document
|
|
1327
|
+
- Keywords менее важны для современного SEO, но могут использоваться для внутреннего поиска
|
|
1328
|
+
- Для расширенной работы с Open Graph используйте напрямую `meta.og`
|
|
1329
|
+
- Для расширенной работы с Twitter Card используйте напрямую `meta.twitter`
|
|
1330
|
+
|