Vue.jsでコメント投稿機能を作ってみた。

<h1>1.はじめに</h1>
今回はjavascriptのフレームワーク、Vue.jsを使って投稿機能を作ってみました。vue.jsを学ぶ際によく題材として使われるToDo管理リストに少し手を加えたもので、映画の感想と評価点を投稿するサイトをイメージして作りました。

<h2>2.環境</h2>
今回も前回に引き続き、VSCodeを使用して書いていきます。
またVue.jsは<a href="https://jp.vuejs.org/v2/guide/installation.html">Vue.js公式ページ</a>のCDNのリンクを直接HTML内のbodyタグの一番下に埋め込んで使います。

<h3>3.完成体</h3>
テキストボックスの中にコメントを打ち込み、隣の選択ボタンで星の数に応じた評価点を選択します。
<img width="1440" alt="スクリーンショット 2019-10-20 17.17.53.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/496032/ed013d49-a6d6-c1c6-3811-76c5b77915c6.png">
送信ボタンを押すと投稿が完了しました。ちなみに、テキストボックスの中身が未入力の状態で送信ボタンを押しても投稿はされません。
<img width="1440" alt="スクリーンショット 2019-10-20 17.18.10.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/496032/bd9fca0b-9823-730b-9457-6702b44dacf6.png">
二つ目の投稿をします。するとこの二つの投稿の評価数の平均を計算して評価点が３.５０になりました。
<img width="1440" alt="スクリーンショット 2019-10-20 17.18.47.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/496032/3d87b4a2-469b-4848-ad31-3f50e7faa944.png">
三つ目の投稿をしても同じように評価点の平均点を計算します。しかし割り切れない数などある為、toFixedメソッドを使って小数点第二位までしか表示されません。そして今回は各投稿の下にあるdeleteボタンを押すと、
<img width="1440" alt="スクリーンショット 2019-10-20 17.19.13.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/496032/88b06f35-565a-b029-25f1-54d927a41222.png">
コメントが一つ消されました。
<img width="1440" alt="スクリーンショット 2019-10-20 17.19.33.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/496032/796e85bd-624f-6b0d-17b4-6a0319860310.png">

次に送信ボタンの横に⬇︎⬆︎のボタンがありますが押すと、各投稿の評価点をフックに投稿を並び替えてくれます。⬇︎ボタンで評価の高い順、
<img width="1440" alt="スクリーンショット 2019-10-20 17.20.18.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/496032/3938742b-9fe5-896d-c79c-d25eac6d5a59.png">

⬆︎ボタンで評価の低い順です。
<img width="1440" alt="スクリーンショット 2019-10-20 17.20.28.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/496032/1e142db2-18c2-7db3-808c-b3bb8ddae3f2.png">


<h4>4.完成コード</h4>


```index.html
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>投稿</title>
</head>

<body>
    <div class="container" id="app" v-cloak>
        <h1>評価</h1>
        <div v-if="length">
            <h2>評価点 : {{averageScore}}</h2>
        </div>
        <form v-on:submit.prevent>
            <input type="textarea" v-model="comment">
            <select v-model="rate">
                <option value="0">☆☆☆☆☆</option>
                <option value="1">★☆☆☆☆</option>
                <option value="2">★★☆☆☆</option>
                <option value="3">★★★☆☆</option>
                <option value="4">★★★★☆</option>
                <option value="5">★★★★★</option>
            </select>
            <button v-on:click="submit">送信</button>
            <button v-on:click="sort">⬇︎</button>
            <button v-on:click="sortUp">⬆︎</button>
        </form>
        <div v-for="(comment , index) in comments">
            <ul>
            <li>満足度 : <span>{{'★'.repeat(comment.rate)}}</span></li>
            <p>コメント : <span>{{comment.comment}}</span></p>
            <button v-on:click="deleteItem(index)">delete</button>
            </ul>
            
        </div>
    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script src="main.js"></script>
</body>

</html>
```

```main.js


let app = new Vue({  //vueインスタンス生成
    el: '#app',　//id="app"が属性として使用されているタグ内で使える。(マウント)
    data: {
        comment: "",
        rate: 0,
        comments: [],
        sun: 0,
        length: false,  //使いたい変数達

    },
    methods: {  //各メソッドを格納。htmlを見てもらえると「v-on:click="メソッド名"」と記述されているところが複数箇所ありますが要素をクリックした際に下記のメソッドを実行するという意味です。
        submit: function () {
            if (this.comment == "") return;
            if (this.comment.length > 100) return;
            let commentItem = {
                comment: this.comment,
                rate: this.rate
            }
            this.comments.unshift(commentItem);
            this.sun = this.sun + Number(commentItem.rate)
            this.comment = ""
            this.rate = 0
            if (this.comments.length > 0) {
                this.length = true
            }
        },
        deleteItem: function (index) {
            this.sun = this.sun - Number(this.comments[index].rate);
            this.comments.splice(index, 1);
            if (this.comments.length < 1) {
                this.length = false
            }
        },
        sortUp:function(){
            let arr =  this.comments;
            arr.sort(function(a,b){
                if (a.rate > b.rate) return 1;
	            if (a.rate < b.rate) return -1;
	            return 0;
            })
            this.comments = arr;
        },
        sort:function(){
            let arr =  this.comments;
            arr.sort(function(a,b){
                if (a.rate > b.rate) return -1;
	            if (a.rate < b.rate) return 1;
	            return 0;
            })
            this.comments = arr;
        },
        

        
    },
    computed:{  //算出プロパティと言います。変数averageScoreをhtml側で呼び出すと
//自動的に関数内の処理を実行してくれます。他にも監視プロパティというものもありますが監視プロパティに比べて
//処理結果をキャッシュしてくれるというのが大きな特徴です。
        averageScore:function(){
            return (this.sun/this.comments.length).toFixed(2)
        }
        
    }

})

```

<h4>終わりに</h4>
以上です。今回は前回に比べてスッキリした解説でしたが実際に手を動かして興味のある方はコピぺしながら勉強をしていただけると幸いです。