Vue - это потрясающий фреймворк, который уже довольно давно набирает популярность в сообществе Open Source. Он заимствует (или крадет, в зависимости от того, кого вы спросите) некоторые из лучших функций самых популярных на сегодняшний день фреймворков, включая Angular, Polymer и React. Одной из таких функций, взятых из React, является возможность писать разметку для компонентов с использованием JSX.

TypeScript - не менее потрясающий надмножество JavaScript, предназначенное для добавления в язык необязательной статической типизации. Это также добавляет большую ценность в виде TSX или Typed JSX. В этой статье описывается, как получить лучшее из обоих миров: написание компонентов Vue с использованием TypeScript и TSX.

Если вы освоили искусство чтения кода, вот исходный код.

Установка

Выполните следующие команды в корне проекта:

# Install through NPM... 
npm i vue vue-class-component vue-property-decorator
npm i babel-core babel-plugin-jsx-v-model babel-plugin-syntax-jsx babel-plugin-transform-vue-jsx babel-preset-latest fuse-box typescript -D
# ... or Yarn
yarn add vue vue-class-component vue-property-decorator
yarn add babel-core babel-plugin-jsx-v-model babel-plugin-syntax-jsx babel-plugin-transform-vue-jsx babel-preset-latest fuse-box typescript -D

Я не буду вдаваться в подробности того, что делают все эти зависимости, но наиболее важные из них, которые вы не часто видите:

  • блок предохранителей - наш чрезвычайно быстрый и простой упаковщик
  • vue-property-decorator - некоторые декораторы, упрощающие определение компонентов, свойств и т. д.
  • babel-plugin-transform-vue-jsx - преобразует наш Vue JSX для использования функции createElement Vue. Эта функция немного отличается от React.

Конфигурация

Для краткости, единственными двумя частями, используемыми для настройки, будут файлы tsconfig.json и fuse.js. Создайте файл tsconfig.json и добавьте следующее:

{
    "compilerOptions": {
        "target": "es2015",
        "module": "commonjs",
        "allowSyntheticDefaultImports": true,
        "experimentalDecorators": true,
        "lib": [
            "es2016",
            "dom"
        ],
        "jsx": "preserve",
        "noUnusedLocals": true,
        "noUnusedParameters": true
    }
}

Здесь важно отметить сохранение JSX. Это сделано для того, чтобы Babel мог обрабатывать JSX-транспиляцию.

Затем создайте файл fuse.js и добавьте следующее:

const { FuseBox, BabelPlugin, WebIndexPlugin } = require('fuse-box')
const fuse = FuseBox.init({
    sourceMaps: true,
    homeDir: './src',
    output: 'dist/$name.js',
    plugins: [
        BabelPlugin({
            config: {
                presets: ['latest'],
                plugins: ['jsx-v-model', 'transform-vue-jsx']
            }
        }),
        WebIndexPlugin({ template: './src/index.html' })
    ]
})
fuse.dev()
fuse.bundle('app.js').instructions('>index.ts').watch()
fuse.run()

Обратите внимание на использование плагина transform-vue-jsx, описанного ранее. Если вы не знакомы с FuseBox, прочтите об этом здесь. Это должно быть довольно просто, особенно если вы знакомы с webpack.

Написание некоторых компонентов

Завершив настройку, создайте компонент в src / components. Назовите его App.tsx и добавьте следующее:

import * as Vue from 'vue'
import { Component, Watch } from 'vue-property-decorator'
@Component
export default class extends Vue {
  text = ''
  render() {
    return (
      <div>
         <input type="text" placeholder="Input your name" v-model={this.text} />
      </div>
    )
  }
  @Watch('text')
  onInput() {
    console.log(this.text)
  }
}

Если вы не знакомы с vue-property-decorator, в этой статье есть отличное объяснение его использования. Декоратор Component используется для определения компонента Vue, а декоратор Watch используется для подписки на изменения свойства text. Также обратите внимание на использование v-model. Было бы невозможно использовать плагин jsx-v-model.

В каталоге src создайте файлы index.ts и index.html. Добавьте в index.ts следующее:

import App from './components/App'
import * as Vue from 'vue'
new Vue({
    el: 'main',
    render: h => h(App)
})

А затем добавьте код в index.html:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Vue TSX Example</title>
</head>
<body>
    <main></main>
    $bundles
</body>
</html>

Теперь мы можем запустить наше приложение с помощью node fuse.js и получить быструю победу.

Вы также должны увидеть текст, введенный в поле ввода в консоли браузера.

Теперь давайте немного продвинемся и добавим в пример дочерний компонент. Создайте еще один компонент под названием Hello.tsx и добавьте следующее:

import * as Vue from 'vue'
import { Component, Prop } from 'vue-property-decorator'
@Component
export default class extends Vue {
  @Prop() name
  render() {
    if (this.name)
      return (
        <div>
          Hello {this.name}!!!
        </div>
      )
    return <div>What's your name?</div>
  }
}

Синтаксис должен быть похож на App.tsx. Незначительная разница заключается в использовании декоратора Prop. Это позволяет компоненту получать свойство имени от своего родителя.

Наконец, измените App.tsx, чтобы он выглядел следующим образом:

import * as Vue from 'vue'
import { Component, Watch } from 'vue-property-decorator'
import Hello from './Hello'
@Component
export default class extends Vue {
  text = 'World'
  render() {
    return (
      <div>
        <Hello name={this.text} />
        <input type="text" placeholder="Input your name" v-model={this.text} />
        </div>
    )
  }
  @Watch('text')
  onInput() {
    console.log(this.text)
  }
}

После добавления компонента Hello в функцию рендеринга обновите страницу в браузере, и вы увидите следующее:

Заключение

Подход использования Vue с файлами .tsx - это отклонение от нормы, но это также идеальный союз, который сохраняет неизменной цель Vue, связанную с одним файлом, при этом оставляя небольшой багаж на этом пути (шаблон / скрипт / style теги и т.п.).

Надеюсь, вы сочтете эту статью полезной. Теперь у вас есть полностью работающий пример со всем, что вам нужно, чтобы быть по-настоящему опасным. Удачных трасс !!!

Источники

Написание функций рендеринга Vue.js на JSX

Используйте тонкости шаблона Vue.js в компонентах JSX

Написание компонентов на основе классов с помощью Vue.js и TypeScript