#こんな人向け
Vue.jsを使っているうちに以下のような考えになった人
- TypeScriptでコンポーネントを書きたい
- .vueファイルに抵抗がある(フォーマッタ、補完がそのままじゃ効かないし、色々設定するのは疲れる)
- scoped cssはなくても大丈夫
前提知識
- Vue.js、TypeScriptがなんとなくわかる
やること
- コンポーネントをTypeScriptで書く。
- (ついでに)テンプレート部分はhtmlファイルに分ける。
使うもの
- vue
- vue-class-component
- vue-property-decorator
- webpack
vue-class-componentってなに?
TypeScript(.tsファイル)でコンポーネントが書けるようになる。
Componentデコレータをつけて、Vueを継承したクラスとして書く。
例えば、空のコンポーネントはこう。
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デコレータの中に書いていく。
import Vue from 'vue'
import Component from 'vue-class-component'
@Component({
props: {
hoge: String
}
})
class MyComponent extends Vue {
}
vue-property-decoratorを使うと、デコレータを使って書ける
クラスメンバとして書けるので、this.って打つと補完にでる(※嬉しい)
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も、デコレータを使うとこんなふうに書ける。
クラスメソッドとして書けるので、メソッド名を文字列で書かなくていい(※嬉しい)
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でビルドするための行を追記する。
{
// ...省略
"scripts": {
"build": "webpack"
},
// ...省略
}
tsconfig.jsonをつくって、追記する。
・importしたときに補完が効くようにする
・デコレータを使えるようにする
tsc --init
して、以下のとおり追記する。
{
"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の設定をしているのは、後ででてきますがテンプレート部分を別ファイルにするため。
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' // コンポーネントを使うときはこれを書く必要があるみたい
}
}
};
コンポーネントのファイルをつくる
クリックしたら”こんにちは”が"さようなら"に変わる。それだけ。
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 = 'さようなら'
}
}
<div>
<p @click="onClick">{{hoge}}</p>
</div>
コンポーネントの利用側をつくる
さっき作ったMyComponentを単に読み込んでいるだけ
import Vue from 'vue'
import MyComponent from './MyComponent'
window.onload = () => {
new Vue({
el: '#app',
components: {
MyComponent
}
})
}
<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!!!"と表示する処理を共通化する場合は以下のように書く。
import Vue from 'vue'
import Component from 'vue-class-component'
@Component
export default class ComponentBase extends Vue {
mounted(){
console.log('mouted!!!')
}
}
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でコンポーネントが作れた。ウレシス!