[Разработка веб-сайтов, JavaScript, IT-стандарты, VueJS, TypeScript] Vue 3: CompositionAPI + Typescript эксперименты
Автор
Сообщение
news_bot ®
Стаж: 6 лет 9 месяцев
Сообщений: 27286
В прошлой статье меня упрекнули, что я при живом Vue 3 пишу про "устаревший" Vue 2. Отговорившись тем, что Vue 3 еще не production-ready, я понемногу начал его смотреть и изучать. И поскольку я заядлый любитель типизации и различных фичей с сахарком, то рассматривать Vue 3 с его новеньким CompositionAPI в статье именно с этой точки зрения. А заодно поэкспериментируем и попробуем написать свой типизированный store, организовать компоненты в стиле <script setup> и подружить его с typescript и eslint, а также напишем небольшой компонент на TSX в качестве еще одного эксперимента. Весь код приложения.
РемаркаАвтор пишет всего второй пост, фидбек в комментарии или ЛС - приветствуется! Первый пост про Vue 2 и его типизацию на Typescript можете прочитать здесь, в большие проекты это все еще актуально.Что глобально нового во Vue 3?В общем и целом команда разработки фреймворка в этом релизе постаралась максимально упростить работу с реактивностью, улучшить возможности декомпозиции логики на более мелкие части и в дополнение к этому дала буст к производительности (но тестировать это я буду в следующий раз).Как Vue 3 поможет типизации?CompositionAPI позволит уйти от привычного всем Vuex, который очень сложно нормально типизировать (в другой статье я попытался максимально легко и полноценно это сделать - и все равно остались серьезные проблемы). Большая часть трудностей касается логики actions Vuex - в разных модулях могут быть экшены с одинаковым названием, поэтому Vuex не может гарантировать тип возвращаемых значений из них. Основные библиотеки для типизации Vuex давно перешли на модульность - импортируете себе конкретный модуль и напрямую через его инстанс совершаете все манипуляции, без навешивания чего-либо на Vue прототип. Поэтому в этой статье попробуем написать замену Vuex.Также во vue 3 можно уйти от class-components, которые сильно улучшали типизацию во vue 2, а все писать прямо в <script lang="ts" setup> и полностью типизировать состояние, методы, хуки и тп, новые возможности setup позволят типизировать сигнатуры Emit ивентов (правда, только со стороны "детей").Какие проблемы остались?Типизация в темплейтах - головная боль Vue, которой нет в не любимом мной реакте. Эта типизация касается как различных циклов и слотов, так и props, eventHandlers на кастомные компоненты, их типизация доступна только внутри компонентов-детей. Попробуем это решить с помощью TSX и новым setup'ом.Создание проектаЯ использовал vite для создания проекта, дополнительные настройки - typescript (vite template vue-ts), в дополнение установил eslint с рекомендованными Vue пресетами, со следующим отключенный правилом, позже объясню его значимость:
'@typescript-eslint/no-unused-vars': 'off', // uses in new <script setup>
Вы можете использовать Vue 3 откуда угодно, важно лишь его наличие и typescript.Хранилище данных (store)Я давно хотел это сделать вместо Vuex встроить кастомное хранилище на новых Ref и Reactive апи. В ходе раздумий принял решение архитектурно сохранить вид "как Vuex", что означает соблюдение следующих принципов:
- Модульность (куда же без нее)
- Разбиение на те же составляющие для работы с данными
Каждый слой будет отвечать за те же действия, что и аналогичный в Vuex:
- State - класс с статичными полями, каждое обернуто в соответствии с типом в Ref (для примитивов) или Reactive (для объектов, массивов и т.п.)
- Mutations - класс, который напрямую взаимодействует со State, состояние меняется только с помощью мутаций, они также не доступны в открытом апи модуля (так как все манипуляции со стором должны идти через actions)
- Actions - бизнес логика модулей, под собой вызывает мутации
- Getters - получение данных из состояния с необходимыми изменениями и кэшированием (например - отфильтрованный массив элементов, но если нужен просто сам массив целиком - читайте его сразу из стейта)
Мои мысли касались идеи по упрощению логики взаимодействия со стором - убрать мутации и изменять состояние откуда угодно, но я подумал, что это отказ от принципов Vue разделения слоев данных и отодвинул эту идею. Стоит отметить, что это касается именно хранилища данных, если вы будете делать аналоги миксинов для двух соседних компонентов (уже не в сторе) - меняйте данные согласно другим принципам (зачастую - как вы хотите), но я считаю, что в сторе стоит соблюдать некоторую разграниченность зон ответственности разных архитектурных частей.Код хранилища данных (store)
/**
* @file src/store/index.ts
* @author Artem Shuvaev
* @version 1.0.0
* @fileoverview Entry point of store
*/
import habrModule from './modules/habrModule'
export { habrModule }
/**
* @file src/store/modules/habrModule/index.ts
* @author Artem Shuvaev
* @version 1.0.0
* @fileoverview Entry of store module
*/
import state from './state'
import getters from './getters'
import actions from './actions'
export default {
state,
getters,
actions
}
/**
* @file src/store/modules/habrModule/state.ts
* @author Artem Shuvaev
* @version 1.0.0
* @fileoverview State for store example with new Ref and Reactive Vue3
*/
import { ref, reactive } from 'vue'
export default class State {
/**
* Example string ref (reactive)
*/
static strExample = ref('string example')
/**
* Example number ref (reactive)
*/
static numberExample = ref(0)
/**
* Example string reactive
*/
static objExample = reactive({
property: 'property string',
})
}
/**
* @file src/store/modules/habrModule/mutations.ts
* @author Artem Shuvaev
* @version 1.0.0
* @fileoverview Mutations for store example with new Ref and Reactive Vue3
*/
import State from './state'
export default class Mutations {
/**
* Set to state new string
* @param value
*/
static setString (value: string): void {
State.strExample.value = value
}
/**
* Increate the number in state
*/
static increaseNumber (): void {
State.numberExample.value++
}
}
/**
* @file src/store/modules/habrModule/getters.ts
* @author Artem Shuvaev
* @version 1.0.0
* @fileoverview Getters for store example with new Ref and Reactive Vue3
*/
import type { Ref } from 'vue'
import State from './state'
export default class Getters {
/**
* Test getter with cache
* @deprecated must use readonly and state proxy if not need any business logic
*/
static get strExample(): Ref<string> {
return State.strExample
}
}
Компонент в новом синтаксисе setupГлавной "фичой" которую я хотел посмотреть и потрогать во Vue 3 является новый способ написания компонентов, и если вы подумали о новом defineComponent - то вы немного ошиблись. В 3 мажорной версии, как известно, введен новый способ описания логики - внутри специальной функции setup. Что-то типо такого.
<script>
export default {
props: {
title: String
},
setup(props) {
console.log(props.title)
}
}
</script>
Но недавно я открыл для себя возможность другого, более "сахарного" приема для этой функции:
<script setup>
// all from SETUP here
</script>
Что это дает? Упрощение и этим все сказано! В сочетании с новым Composition API это позволит дробить компоненты до условной бесконечности, ну и писать немножко проще. Для экспериментов над Vue 3 я выбрал его как основной стиль написания компонентов, но в дополнение ниже я приведу пример компонента на TSX. Что из минусов? К сожалению, редакторы кода (а заодно и eslint) не видят использования переменных из этого скрипта в темплейте - это может привести к действительно не используемым переменным. Также нужно быть осторожными с формированием таких компонентов. Vue не декларирует как вы должны их писать, поэтому важно договориться в команде/проекте об особенностях данного стиля написания. А еще это экспериментальная фича, и надо помнить об этом (как и сказано выше - рубрика - эксперименты!)Ниже можете увидеть мои мысли в реализации примера, но я сделал это из собственной головы, если вы придумаете другую реализацию (например, некоторые объявляют состояние компонента единым объектом, как во Vue 2 и оборачивает его в Reactive - это тоже жизнеспособный подход, возможно даже лучше моего), не поленитесь рассказать о ней в комментариях, пожалуйста!Но в целом это новый полноценный способ декларации скриптов компонента, который имеет право на жизнь и мне лично понравился, надеюсь его будут поддерживать и стабилизируют, а я точно буду его использовать как минимум в личных проектах.Код - App.vue
<template>
<div>
<!-- Main body -->
<div class="main">
<h5>App.vue</h5>
String from store: {{ readonlyStringFromStore }}
<div>
<button @click="increaseCounter">Counter: {{ counter }}</button>
</div>
</div>
<!-- /Main body -->
<TheHelloWorldComponent :counter="counter" @customEvent="increaseCounter" />
<TheTestComponent :counter="counter" @click="increaseCounter" />
</div>
</template>
<script lang="ts" setup>
/**
* @file src/App.vue
* @author Artem Shuvaev
* @version 1.0.0
* @fileoverview Entry Vue example file for it's project
*/
import { ref, onMounted, readonly, defineAsyncComponent } from 'vue'
import { habrModule } from './store'
/* Components */
// Vue + new setup script example component
const TheHelloWorldComponent = defineAsyncComponent(
() => import('./components/TheHelloWorldComponent.vue')
)
// Vue + new setup and TSX render example
const TheTestComponent = defineAsyncComponent(
() => import('./components/TheTestComponent/index')
)
/* Data */
// must be readonly cause of state proxying
const readonlyStringFromStore = readonly(habrModule.state.strExample)
// simple reactive variable
const counter = ref(0)
/* Hooks */
onMounted(() => {
habrModule.actions.setString('changed from App.vue string')
})
/* Methods */
/**
* Increase local reactive counter
*/
const increaseCounter = () => {
counter.value++
}
</script>¬
<style lang="css">
@import 'styles.css';
</style>
<style lang="css" scoped>
.main {
background-color: aquamarine;
padding: 5vh;
}
</style>
Я знаю, что отображение после публикации полетело к чертям, так что очень извиняюсь, вот ссылка на гитхабВзаимодействие детей с родителямиВыше приведен пример компонента-родителя, внутри которого есть пара детей, для примера (поскольку в интернете еще не так много документации об этой особенности) я приведу полноценный компонент с использованием props, имитирующий события в родителя и взаимодействующий с хранилищем данных.Из новых особенностей тут - можно типизировать emit полноценно, вместе с полезной нагрузкой, лучше чем при использовании class-components во Vue 2.
Неверный тип payload, это ли не чудо типизации?Код TheHelloWorldComponent
<template>
<div class="hello">
<h5>TheHelloWorldComponent</h5>
Now counter is {{ props.counter }}
<div>
<button @click="emitCustomEvent">
Emit custom event (increase counter)
</button>
<button @click="changeString">Change string in store</button>
</div>
</div>
</template>
<script lang="ts" setup>
/**
* @file /src/components/TheHelloWorldComponent.vue
* @fileoverview Child component example with using new setup, emits, store etc
* @author Artem Shuvaev
* @version 1.0.0
*/
import { defineEmit, defineProps } from 'vue'
import { habrModule } from '../store'
/* Props */
const props = defineProps({
counter: {
type: Number,
required: true,
},
})
/* Emits */
// Define emits signatures,
// I don't know but signatures works only with null as output type (instead VOID or UNDEFINED)
const emit = defineEmit({
customEvent: null,
customEvent2: (payload: { test: string }) => null,
})
/* Methods */
/**
* Call dispatch of store module
*/
const changeString = () =>
habrModule.actions.setString('changed from HelloWorld.vue')
/**
* @emits customEvent
*/
const emitCustomEvent = () => emit('customEvent')
// it's typed payload!
const emitCustomEvent2 = () =>
emit('customEvent2', {
test: 'string',
})
</script>
<style lang="css" scoped>
.hello {
background-color: lightsteelblue;
padding: 5vh;
margin-top: 5vh;
}
</style>
Закуска - TSX компонентДа, я люблю типизацию, а что мешает полноценной типизации во Vue? Правильно - template, это красивая и очень удобная нотация написания компонентов as html, но я хочу туда подсветку, ошибки не в консоли браузера, а в редакторе кода. Есть ли решение? Да, пойти к React и попросить оттуда tsx. Работает ли это во Vue 3? Да, и еще лучше чем во втором! Работает ли это с сахарным сетапом, как выше? Нет, но возможно я неправильно его готовил, если подскажите в комментариях - буду очень благодарен. Из воды выше - писать необходимо "как обычно", через defineComponent, но в setup нужно возвращать не переменные, которые будут использоваться в темплейте, а сам темплейт в стиле tsx. И вот что у меня получилось.
/**
* @file /src/components/TheTestComponents/index.tsx
* @fileoverview Test component with using TSX rendering in setup function
* @author Artem Shuvaev
* @version 1.0.0
*/
import { defineComponent } from 'vue'
import styles from './styles.module.css'
export default defineComponent({
name: 'TheTestComponent',
props: {
counter: {
type: Number,
default: 0,
},
},
emits: {
click: null,
},
setup(props, { emit }) {
/** Methods */
/**
* Simple click handler
* @emits click
*/
const onClickHandler = () => emit('click')
/** Rendering */
return () => (
<div class={styles.test}>
<h5>TheTestComponent</h5>
<div>Now counter is: {props.counter}</div>
<button onClick={onClickHandler}>Emit click (increase counter)</button>
</div>
)
},
})
Это уже стабильно и полностью поддерживается => практически готово к продакшену (в ногу с самим Vue 3). Удобно ли это? С точки зрения типизации - абсолютный рай по сравнению с template. По-vue'шному ли это? Не особенно, но чего не сделаешь ради 100% автоподсказок в коде.ЗаключениеЯ перечитал весь текст выше много раз, но морали в нем нет и не будет. Я изучал и экспериментировал над новой версией своего любимого фреймворка и буду продолжать это интересное занятие, чего и вам советую. Но надеюсь, что мои эксперименты кому-то помогут! Код приложения.Нравится ли мне Vue 3? Конечно, это ускорение, новые возможности реактивности и многое другое. Что вызывает сомнения - много вариаций написания приложений, как будто это React, а ведь именно от этой парадигмы "каждое приложение - уникально" Vue и пытался отойти при создании, рекомендуя использовать только экосистемные библиотеки и реализации (роутер, стор и тому подобное). Это своего рода строгий Golang во фронтенде, его код, написанной в далекой и жаркой Индии в соответствии со стайл-гайдами и линтерами будет понятен каждому стартаперу в Долине, а экосистема имеет в себе все необходимое и одинакова для всех, не нужно выбирать - просто пишите код! И я боюсь, что с новым релизом мы отдалимся от этого. Плохо ли это - покажет время и путь развития, который предложат нам создатели фреймворка.А вам нравится Vue 3? Планируете скорый переход на него в проде, или еще годик пусть поварится в домашнем проекте?P.S.Если что - извиняюсь за код в статье, я не придумал, как его оформить красивее, а эти различия в отображениях синтаксиса меня добили, а заодно за материал и его подачу, получилось сумбурно, но я надеюсь интересующимся будет полезно.
Объясните мне, почему код на хабре имеет разную подсветку при написании, в черновиках и после публикации? Это фишка нового редактора или я что-то не понимаю? Причем кардинальные различия. Я понимаю, что я скармливаю не JS, а полноценный Vue файл, но различия в парсинге ключевых слов и комментариев, в редакторе новый и модный, а в самих публикациях старый и глупенький парсер?Скрины
Черновик публикации
Редактор статьи
===========
Источник:
habr.com
===========
Похожие новости:
- [JavaScript, ReactJS, TypeScript] Готовим селекторы в Redux
- [JavaScript, Программирование, Node.JS] Как управлять несколькими потоками в Node JS (перевод)
- [JavaScript, API, Стандарты связи] Консорциум Всемирной паутины принял стандарт Web Audio в качестве официального
- [JavaScript] Первая программа для семилетки
- [JavaScript, Программирование, Тестирование веб-сервисов, Машинное обучение] В закладки: репозитории с книгами, шпаргалками, ресурсами по дизайну и не только (перевод)
- [JavaScript, Программирование, Алгоритмы, Обработка изображений, Машинное обучение] Как мы создали Web приложение для определения лиц и масок для Google Chrome (часть 2) (перевод)
- [JavaScript, Учебный процесс в IT, Удалённая работа] История о том, как я иду к должности JS разработчика через обучение на курсах в Skillbox
- [Разработка веб-сайтов, JavaScript] Идеальный инструмент для создания прогрессивных веб-приложений или Все, что вы хотели знать о Workbox. Часть 2
- [Разработка веб-сайтов, TypeScript] Карманная книга по TypeScript. Часть 8. Модули (перевод)
- [Разработка веб-сайтов, JavaScript] Идеальный инструмент для создания прогрессивных веб-приложений или Все, что вы хотели знать о Workbox. Часть 1
Теги для поиска: #_razrabotka_vebsajtov (Разработка веб-сайтов), #_javascript, #_itstandarty (IT-стандарты), #_vuejs, #_typescript, #_vue, #_typescript, #_vuejs3, #_vuejs, #_frontend, #_frontendrazrabotka (frontend-разработка), #_eslint, #_javascript, #_vuex, #_vuextypescript, #_razrabotka_vebsajtov (
Разработка веб-сайтов
), #_javascript, #_itstandarty (
IT-стандарты
), #_vuejs, #_typescript
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 06:35
Часовой пояс: UTC + 5
Автор | Сообщение |
---|---|
news_bot ®
Стаж: 6 лет 9 месяцев |
|
В прошлой статье меня упрекнули, что я при живом Vue 3 пишу про "устаревший" Vue 2. Отговорившись тем, что Vue 3 еще не production-ready, я понемногу начал его смотреть и изучать. И поскольку я заядлый любитель типизации и различных фичей с сахарком, то рассматривать Vue 3 с его новеньким CompositionAPI в статье именно с этой точки зрения. А заодно поэкспериментируем и попробуем написать свой типизированный store, организовать компоненты в стиле <script setup> и подружить его с typescript и eslint, а также напишем небольшой компонент на TSX в качестве еще одного эксперимента. Весь код приложения. РемаркаАвтор пишет всего второй пост, фидбек в комментарии или ЛС - приветствуется! Первый пост про Vue 2 и его типизацию на Typescript можете прочитать здесь, в большие проекты это все еще актуально.Что глобально нового во Vue 3?В общем и целом команда разработки фреймворка в этом релизе постаралась максимально упростить работу с реактивностью, улучшить возможности декомпозиции логики на более мелкие части и в дополнение к этому дала буст к производительности (но тестировать это я буду в следующий раз).Как Vue 3 поможет типизации?CompositionAPI позволит уйти от привычного всем Vuex, который очень сложно нормально типизировать (в другой статье я попытался максимально легко и полноценно это сделать - и все равно остались серьезные проблемы). Большая часть трудностей касается логики actions Vuex - в разных модулях могут быть экшены с одинаковым названием, поэтому Vuex не может гарантировать тип возвращаемых значений из них. Основные библиотеки для типизации Vuex давно перешли на модульность - импортируете себе конкретный модуль и напрямую через его инстанс совершаете все манипуляции, без навешивания чего-либо на Vue прототип. Поэтому в этой статье попробуем написать замену Vuex.Также во vue 3 можно уйти от class-components, которые сильно улучшали типизацию во vue 2, а все писать прямо в <script lang="ts" setup> и полностью типизировать состояние, методы, хуки и тп, новые возможности setup позволят типизировать сигнатуры Emit ивентов (правда, только со стороны "детей").Какие проблемы остались?Типизация в темплейтах - головная боль Vue, которой нет в не любимом мной реакте. Эта типизация касается как различных циклов и слотов, так и props, eventHandlers на кастомные компоненты, их типизация доступна только внутри компонентов-детей. Попробуем это решить с помощью TSX и новым setup'ом.Создание проектаЯ использовал vite для создания проекта, дополнительные настройки - typescript (vite template vue-ts), в дополнение установил eslint с рекомендованными Vue пресетами, со следующим отключенный правилом, позже объясню его значимость: '@typescript-eslint/no-unused-vars': 'off', // uses in new <script setup>
/**
* @file src/store/index.ts * @author Artem Shuvaev * @version 1.0.0 * @fileoverview Entry point of store */ import habrModule from './modules/habrModule' export { habrModule } /**
* @file src/store/modules/habrModule/index.ts * @author Artem Shuvaev * @version 1.0.0 * @fileoverview Entry of store module */ import state from './state' import getters from './getters' import actions from './actions' export default { state, getters, actions } /**
* @file src/store/modules/habrModule/state.ts * @author Artem Shuvaev * @version 1.0.0 * @fileoverview State for store example with new Ref and Reactive Vue3 */ import { ref, reactive } from 'vue' export default class State { /** * Example string ref (reactive) */ static strExample = ref('string example') /** * Example number ref (reactive) */ static numberExample = ref(0) /** * Example string reactive */ static objExample = reactive({ property: 'property string', }) } /**
* @file src/store/modules/habrModule/mutations.ts * @author Artem Shuvaev * @version 1.0.0 * @fileoverview Mutations for store example with new Ref and Reactive Vue3 */ import State from './state' export default class Mutations { /** * Set to state new string * @param value */ static setString (value: string): void { State.strExample.value = value } /** * Increate the number in state */ static increaseNumber (): void { State.numberExample.value++ } } /**
* @file src/store/modules/habrModule/getters.ts * @author Artem Shuvaev * @version 1.0.0 * @fileoverview Getters for store example with new Ref and Reactive Vue3 */ import type { Ref } from 'vue' import State from './state' export default class Getters { /** * Test getter with cache * @deprecated must use readonly and state proxy if not need any business logic */ static get strExample(): Ref<string> { return State.strExample } } <script>
export default { props: { title: String }, setup(props) { console.log(props.title) } } </script> <script setup>
// all from SETUP here </script> <template>
<div> <!-- Main body --> <div class="main"> <h5>App.vue</h5> String from store: {{ readonlyStringFromStore }} <div> <button @click="increaseCounter">Counter: {{ counter }}</button> </div> </div> <!-- /Main body --> <TheHelloWorldComponent :counter="counter" @customEvent="increaseCounter" /> <TheTestComponent :counter="counter" @click="increaseCounter" /> </div> </template> <script lang="ts" setup> /** * @file src/App.vue * @author Artem Shuvaev * @version 1.0.0 * @fileoverview Entry Vue example file for it's project */ import { ref, onMounted, readonly, defineAsyncComponent } from 'vue' import { habrModule } from './store' /* Components */ // Vue + new setup script example component const TheHelloWorldComponent = defineAsyncComponent( () => import('./components/TheHelloWorldComponent.vue') ) // Vue + new setup and TSX render example const TheTestComponent = defineAsyncComponent( () => import('./components/TheTestComponent/index') ) /* Data */ // must be readonly cause of state proxying const readonlyStringFromStore = readonly(habrModule.state.strExample) // simple reactive variable const counter = ref(0) /* Hooks */ onMounted(() => { habrModule.actions.setString('changed from App.vue string') }) /* Methods */ /** * Increase local reactive counter */ const increaseCounter = () => { counter.value++ } </script>¬ <style lang="css"> @import 'styles.css'; </style> <style lang="css" scoped> .main { background-color: aquamarine; padding: 5vh; } </style> Неверный тип payload, это ли не чудо типизации?Код TheHelloWorldComponent <template>
<div class="hello"> <h5>TheHelloWorldComponent</h5> Now counter is {{ props.counter }} <div> <button @click="emitCustomEvent"> Emit custom event (increase counter) </button> <button @click="changeString">Change string in store</button> </div> </div> </template> <script lang="ts" setup> /** * @file /src/components/TheHelloWorldComponent.vue * @fileoverview Child component example with using new setup, emits, store etc * @author Artem Shuvaev * @version 1.0.0 */ import { defineEmit, defineProps } from 'vue' import { habrModule } from '../store' /* Props */ const props = defineProps({ counter: { type: Number, required: true, }, }) /* Emits */ // Define emits signatures, // I don't know but signatures works only with null as output type (instead VOID or UNDEFINED) const emit = defineEmit({ customEvent: null, customEvent2: (payload: { test: string }) => null, }) /* Methods */ /** * Call dispatch of store module */ const changeString = () => habrModule.actions.setString('changed from HelloWorld.vue') /** * @emits customEvent */ const emitCustomEvent = () => emit('customEvent') // it's typed payload! const emitCustomEvent2 = () => emit('customEvent2', { test: 'string', }) </script> <style lang="css" scoped> .hello { background-color: lightsteelblue; padding: 5vh; margin-top: 5vh; } </style> /**
* @file /src/components/TheTestComponents/index.tsx * @fileoverview Test component with using TSX rendering in setup function * @author Artem Shuvaev * @version 1.0.0 */ import { defineComponent } from 'vue' import styles from './styles.module.css' export default defineComponent({ name: 'TheTestComponent', props: { counter: { type: Number, default: 0, }, }, emits: { click: null, }, setup(props, { emit }) { /** Methods */ /** * Simple click handler * @emits click */ const onClickHandler = () => emit('click') /** Rendering */ return () => ( <div class={styles.test}> <h5>TheTestComponent</h5> <div>Now counter is: {props.counter}</div> <button onClick={onClickHandler}>Emit click (increase counter)</button> </div> ) }, }) Объясните мне, почему код на хабре имеет разную подсветку при написании, в черновиках и после публикации? Это фишка нового редактора или я что-то не понимаю? Причем кардинальные различия. Я понимаю, что я скармливаю не JS, а полноценный Vue файл, но различия в парсинге ключевых слов и комментариев, в редакторе новый и модный, а в самих публикациях старый и глупенький парсер?Скрины Черновик публикации Редактор статьи =========== Источник: habr.com =========== Похожие новости:
Разработка веб-сайтов ), #_javascript, #_itstandarty ( IT-стандарты ), #_vuejs, #_typescript |
|
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 06:35
Часовой пояс: UTC + 5