Edited at
Vue.js #4Day 24

TypeScriptではじめるVueコンポーネント(vue-class-component)

More than 1 year has passed since last update.


こんな人向け

Vue.jsを使っているうちに以下のような考えになった人


  • TypeScriptでコンポーネントを書きたい

  • .vueファイルに抵抗がある(フォーマッタ、補完がそのままじゃ効かないし、色々設定するのは疲れる)

  • scoped cssはなくても大丈夫


前提知識


  • Vue.js、TypeScriptがなんとなくわかる


やること


  • コンポーネントをTypeScriptで書く。

  • (ついでに)テンプレート部分はhtmlファイルに分ける。


使うもの


  1. vue

  2. vue-class-component

  3. vue-property-decorator

  4. webpack


vue-class-componentってなに?

TypeScript(.tsファイル)でコンポーネントが書けるようになる。

Componentデコレータをつけて、Vueを継承したクラスとして書く。

例えば、空のコンポーネントはこう。


hello.ts

import Vue from 'vue'

import Component from 'vue-class-component'

@Component
class MyComponent extends Vue{

}



書き方


  • data

    クラスの変数として書く


  • 算出プロパティ

    getterとして書く


  • メソッド

    普通にメソッドとして書く


  • ライフサイクルフック

    名前を合わせてメソッドとして書く


詳しくはvue-class-componentを見れば大体わかる感じ。


vue-property-decoratorってなに?

vue-class-componentではpropsなどはComponentデコレータの中に書いていく。


hello.ts

import Vue from 'vue'

import Component from 'vue-class-component'

@Component({
props: {
hoge: String
}
})
class MyComponent extends Vue {

}


vue-property-decoratorを使うと、デコレータを使って書ける

クラスメンバとして書けるので、this.って打つと補完にでる(※嬉しい)


hello.ts

import Vue from 'vue'

import Component from 'vue-class-component'
import { Prop } from 'vue-property-decorator';

@Component
class MyComponent extends Vue {

@Prop({ type: String })
hoge: string

}


$emitも、デコレータを使うとこんなふうに書ける。

クラスメソッドとして書けるので、メソッド名を文字列で書かなくていい(※嬉しい)


hello.ts

import Vue from 'vue'

import Component from 'vue-class-component'
import { Emit } from 'vue-property-decorator';

@Component
class MyComponent extends Vue {

@Emit()
change(newValue: string) { }

selectItem(val: string) {
this.change(val) // this.$emit('change', val) って書かなくていい
}
}


他にも使えるデコレータが用意されているので

詳しくはvue-property-decoratorを見れば大体わかる感じ。


とりあえずコンポーネント作ってみよう

実際に作ってみる。

違いはないかもしれないけどVSCodeを使う前提。


環境構築


適当にフォルダ作って、必要なものを入れる

npm init

npm install -S vue
npm install -S vue-class-component
npm install -S vue-property-decorator
npm install -D typescript
npm install -D webpack
npm install -D ts-loader
npm install -D html-loader
npm install -D @types/node


package.jsonの設定

webpackでビルドするための行を追記する。


package.json

{

// ...省略
"scripts": {
"build": "webpack"
},
// ...省略
}


tsconfig.jsonをつくって、追記する。

・importしたときに補完が効くようにする

・デコレータを使えるようにする

tsc --init

して、以下のとおり追記する。


tsconfig.json

{

"compilerOptions": {
// ...省略
"baseUrl": ".", // pathsを設定するときはbaseUrlの設定が必要
"paths": {
"vue": [
"/node_modules/vue/types/index"
],
"vue-class-component": [
"/node_modules/vue-class-component/lib/index"
],
"vue-property-decorator": [
"/node_modules/vue-property-decorator/lib/vue-property-decorator"
]
},
"experimentalDecorators": true, // デコレータを使うために必要
// ...省略
}
}


webpack.configをつくる

html-loaderの設定をしているのは、後ででてきますがテンプレート部分を別ファイルにするため。


webpack.config.js

module.exports = {

entry: __dirname + "/main.ts",
output: {
path: __dirname + '/dist',
filename: 'bundle.js'
},
module: {
loaders: [
{ test: /\.ts$/, loader: 'ts-loader' },
{ test: /\.html$/, loader: 'html-loader?minimize=false' },
]
},
resolve: {
extensions: ['.ts'],
modules: [
"node_modules"
],
alias: {
'vue$': 'vue/dist/vue.esm.js' // コンポーネントを使うときはこれを書く必要があるみたい
}
}
};


コンポーネントのファイルをつくる

クリックしたら”こんにちは”が"さようなら"に変わる。それだけ。


MyComponent.ts

import Vue from 'vue'

import Component from 'vue-class-component'

@Component({
template: require('./MyComponent.html') // html-loaderを使うと外部のhtmlファイルを読み込める
})
export default class MyComponent extends Vue {
// data
hoge : string = 'こんにちは'

// methods
onClick(){
this.hoge = 'さようなら'
}

}



MyComponent.html

<div>

<p @click="onClick">{{hoge}}</p>
</div>


コンポーネントの利用側をつくる

さっき作ったMyComponentを単に読み込んでいるだけ


main.ts

import Vue from 'vue'

import MyComponent from './MyComponent'

window.onload = () => {
new Vue({
el: '#app',
components: {
MyComponent
}
})
}



main.html

<html>

<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<script src="dist/bundle.js"></script>

<body>
<div id="app">
<my-component></my-component>
</div>
</body>

</html>



ビルドして動作確認

npm run build

main.htmlを開いてちゃんと動いたらOK


おまけ

vue-class-componentを使う時に知っておくと嬉しいこと


継承

各コンポーネントに共通処理があるとき、継承を使ってまとめられる。

例えば、mountedのタイミングでコンソールに"mounted!!!"と表示する処理を共通化する場合は以下のように書く。


ComponentBase.ts

import Vue from 'vue'

import Component from 'vue-class-component'

@Component
export default class ComponentBase extends Vue {

mounted(){
console.log('mouted!!!')
}

}



MyComponent.ts

import Vue from 'vue'

import Component from 'vue-class-component'
import ComponentBase from './ComponentBase';

@Component({
template: require('./MyComponent.html')
})
export default class MyComponent extends ComponentBase {
// data
hoge : string = 'こんにちは'

// methods
onClick(){
this.hoge = 'さようなら'
}

}



まとめ

TypeScriptでコンポーネントが作れた。ウレシス!