[TypeScript] Vue.jsをTypeScriptで使ってみたい

2016/08/4

——-
追記2
うまくいったのでこっちの記事の方が良いです
>> [TypeScript] Vue.jsをTypeScriptで使ってみたい -> 成功した

——-
追記1

新しい記事かきました。たぶんこっちの方が良いと思います。
> [TypeScript] Vue.jsをTypeScriptで使ってみたい2

以下もとの記事
——-

こんにちは。きんくまです。
今回はVue.jsをTypeScriptで試してみたメモでございます。

>> 作ったデモです。ボタンを押すとメッセージが変わって、下のところはTODOリストです。
vue_ts_snapshot

TypeScriptは関数型っぽいソースの分け方じゃなくて、やっぱりMVCっぽいのがいいのかなと思ってます。わかりやすいし。
で、View部分を担当するのはいろいろあってReactとかもあるんだけど、JSの中にDOM書いていくのが自分的にどうにも嫌で、Vue.jsを試してみた次第です。

Vue.jsはGettings Startedを見る限りすぐにできそうでした。
> Getting Started

それで、これをTypeScriptからも使いたいと思って、Vueそのものをextendしてみたり、いろいろしたんだけれどもうまくいかなかったです。またネットを検索してみたんだけど、いろいろやり方はあるみたいだけど、もうちょっとTSそのままっぽい書き方がないかなと今回自己流に書いてみました。

まずはhtml部分です。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>vue</title>
    <link rel="stylesheet" href="css/sample.css" />
</head>
<body>
<div id="app">
    <h3>メッセージ</h3>
    <p>{{ message }}</p>
    <div class="message_button" v-on:click="changeMessage">click me</div>

    <h3>TODOリスト</h3>
    <div id="todo_input">
        <input id="editing_todo_message" v-model="editingTodoMessage">
        <div class="todo_add_button" v-on:click="addTodo"> + </div>
    </div>
    <ul id="todo_list">
        <li v-for="todo in todos" v-on:click="removeTodo($index, $event)">
            {{ todo.text }}
        </li>
    </ul>
</div>
<script src="js/jquery-1.11.2.min.js"></script>
<script src="js/vue.min.js"></script>
<script src="js/main.js"></script>
<script>
    $(function(){
        var main = new Main();
        main.init({

        });
    });
</script>
</body>
</html>

つぎにVueのTSファイルです

/// <reference path="./defs/vue.d.ts" />

class SampleVueModel {
    //メッセージ部分用
    message:string = "hello vue";
    count:number = 0;

    //TODO用
    todos:any[] = [];
    editingTodoMessage:string = '';

    countUp(){
        this.count++;
    }

    resetTodos(){
        this.todos = [];
    }

    addTodo(todoMessage:string){
        this.todos.push({
            text: todoMessage
        });
    }

    removeTodo(index:number){
        if(index + 1 > this.todos.length){
            console.log('index error');
            return;
        }
        this.todos.splice(index, 1);
    }
}

export default class SampleVueController{
    appVue:any;
    el:string = "#app";
    model:SampleVueModel;

    constructor(){
        this.model = new SampleVueModel();
        this.appVue = new Vue({
            el:this.el,
            data: this.model,
            methods:{
                changeMessage:(e)=>{ this.changeMessage(e); },
                addTodo:(e)=>{ this.addTodo(e); },
                removeTodo:(index, e)=>{ this.removeTodo(index, e);}
            }
        });
    }

    changeMessage(e){
        this.model.message = "hello vue " + this.model.count;
        this.model.countUp();
    }

    addTodo(e){
        this.model.addTodo(this.model.editingTodoMessage);
    }

    removeTodo(index, e){
        this.model.removeTodo(index);
    }
}

ポイントとしては、Vueそのものを継承するんじゃなくて vueをプロパティとしてもつControllerを作成するところと、vueのdataをModelとしてクラス化するところです。

Vue.jsは最初に new Vue({ ここに初期化処理 }) っていうふうにする必要があるみたいです。
Vueそのものを継承すると、その初期化のタイミングと TypeScriptのコンストラクタとsuperのタイミングがかみあわなくてうまくいかないみたいです。
なので、vueのコントローラーとしてクラスを作りました。

あと、 初期化処理に data というオブジェクトを入れてあげると2-wayバインディングができるみたいです。
APIのdataの項目を読むと「ゲッターセッターとかprototypeとか無視するよー」と書いているので、逆手をとって自前のModelクラスを突っ込んでみました。

>> #data

vueのmethods部分は渡し方をいろいろと試してみたけど、結局この書き方になりました。ちょっとめんどいけど、許容範囲という結論です。

こんな感じにやれば、TypeScriptとVue.jsは共存できそうかなと思いました。
まだまだ暑い日が続きますが、体調にお気をつけて!

>> 今回のソースコード一式です

LINEで送る
Pocket

自作iPhoneアプリ 好評発売中!
フォルメモ - シンプルなフォルダつきメモ帳
ジッピー電卓 - 消費税や割引もサクサク計算!

LINEスタンプ作りました!
毎日使える。とぼけたウサギ。LINEスタンプ販売中! 毎日使える。とぼけたウサギ

ページトップへ戻る