BETA

jQueryで実装した「いいね」機能をVue.jsで作り直す。

投稿日:2020-02-06
最終更新:2020-02-06

コードの改善余地はありそうな気はするんだけれど、とりあえず、jQueryからVue.jsに置き換えることができたので、自分用の備忘録。
新旧コード(Blade側は該当箇所のみ)、変更点の説明の順。

元のコード(HTML(Blade))

<th scope="row"><i style="color:#5D99FF" id="{{ $fund_info->id }}" class="star  
@if($fund_info->user_id !== NULL) fas fa-star @else far fa-star @endif  
"></i></th>  

元のコード(jQuery)

<script src="https://code.jquery.com/jquery-3.3.1.js"></script>  
<script>  
    $('.star').on('click', clickHandler);  
    function clickHandler(event){  
        var clicked_fund_id = $(this).attr('id');  
        var getURL = '/home/changelike?fund_id=' + clicked_fund_id;  
        console.log('clicked');  
        $.ajax({  
            url: getURL,  
            type: 'GET',  
            dataType: 'text',  
            context: $(this)  
        })  
        .done(function(data, textStatus, jqXHR){  
            if(data === 'ON'){  
                this.attr('class', 'fas fa-star');  
            } else if(data === 'OFF'){  
                this.attr('class', 'far fa-star');  
            } else {  
                console.log(data);  
            }  

            console.log('Ajax Succeeded');  
        })  
        .fail(function(jqXHR, textStatus, errorThrown){  
            console.log('Ajax Failed');  
        });  
    };  
</script>  

新コード(HTML(Blade))

<th scope="row">  
@if(!empty($fund_info->user_id))  
    <like-component :fund-id="{{ $fund_info->id }}" :user-id="true"></like-component>  
@else  
    <like-component :fund-id="{{ $fund_info->id }}" :user-id="false"></like-component>  
@endif  
</th>  

新コード(Vue.js)

<template >  
<i v-on:click="changeLike" :id="fundId" :class="[isActive === true ? 'fas fa-star' : 'far fa-star']" style="color:#5D99FF"></i>  
</template>  

<script>  
    export default {  
        props:["fundId", "userId"],  
        data : function(){  
            return {  
                isActive: this.userId  
            }  
        },  
        methods: {  
            changeLike: function(event){  
                var clicked_fund_id = event.currentTarget.getAttribute('id');  
                var getURL = '/home/changelike?fund_id=' + clicked_fund_id;  
                console.log('clicked');  
                $.ajax({  
                    url: getURL,  
                    type: 'GET',  
                    dataType: 'text',  
                    context: this  
                })  
                .done(function(data, textStatus, jqXHR){  
                    if(data === 'ON'){  
                        this.isActive = true;  
                    } else if(data === 'OFF'){  
                        this.isActive = false;  
                    } else {  
                        console.log(data);  
                    }       
                    console.log('Ajax Succeeded');  
                })  
                .fail(function(jqXHR, textStatus, errorThrown){  
                    console.log('Ajax Failed');  
                });                  
            }  
        }  
    }  
</script>  

いいね機能の概説

ページアクセス時に、そのユーザーがいいね済みかどうかを判定し、いいね済みなら、塗り潰しのいいねマークがつき、いいねしてないなら塗り潰されてないいいねマークが表示される。
ページが表示されてからは、塗り潰されてないマークをクリックすると、塗りつぶしマーク(いいね済み状態)に変化。塗りつぶされてるマークをクリックすると、塗りつぶされていないマーク(いいねされてない状態)に変わる。Ajaxを使ってるので非同期。

コードの変更点(Vue.jsの特徴と交えて)

・LaravelのControllerからBladeに渡された値をVue.jsで使うには、Blade側でのv-bindと、Vue側でのpropsおよびv-bindが必要。
ControllerからBladeに渡された$fund_info->idをVueの<template>内に埋め込むためには、まずBlade側でv-bindする。ということで、

:fund-id="{{ $fund_info->id }}"  

をタグの中に書く。(v-bindの省略記法を利用。)
そして、Vue側の<script>内にて

props:["fundId", "userId"],  

を設定することでBladeからの値を受け取り、<template>内でv-bindすることでVueの<template>に渡せる。ということで、

:id="fundId"  

を書く。userIdは条件分岐用に使いたかったので、trueとfalseとして渡す。

:user-id="true"  

:user-id="false"  

※Blade側ではuser-idというようにハイフンで記述しているが、Vue側ではuserIdというようにキャメル記法で受け取る形になる点に注意。
 
・Blade側からVue.jsに値を渡すときに変数にNULLが含まれるケースでは、判定に使えない。
Blade側のコンポーネントでは三項演算子を使って、下記の通りにしたかったが、

<like-component :fund-id="{{ $fund_info->id }}" :user-id="[{{ $fund_info->user_id }} !== NULL ? 'true' : 'false']"></like-component>  

変数の中身がNULLの場合は、そもそも何も表示されなくなり下記画像の通り、判定不能を受ける(なんか初歩的なミスをしている気がするところではある・・・。)ので、Bladeの@ifディレクティブで制御した。

・クリックハンドラーはv-on:click=“関数名”
v-on:click=“関数名”の関数名のところに直接コードを書いても良いが、Ajaxを用いるためコードが長くなるので、関数名を書き、関数内容は、<script>のmethodsに書くことにした。クリックされた要素を受け取るにはmethods内に書く関数の引数にeventを書く。

<i v-on:click="changeLike"  

methods: {    
    changeLike: function(event){   

・attrは使えない
クリックした要素のclassとかidを取るためにattrを利用しようとしたが、attrはjQuery用らしく、今回は使えなかった。(attrは存在しないfunctionです、とエラー。)
そのため、getAttributeを使うことにした。

var clicked_fund_id = event.currentTarget.getAttribute('id');   

・訪問時の判定
Propsで受け取ったuserId判定(true or false)をdataのisActiveに代入し、

props:["fundId", "userId"],    
data : function(){    
    return {    
        isActive: this.userId    
    }    
},  

※dataには関数を記述しないといけないルールがある(公式ドキュメントに理由の記述もあり)ので関数内で値をセット。

<template>内のclassにisActiveをv-bind。
isActiveがtrueなら塗りつぶしマーク、falseなら塗りつぶされていないマークが表示されるように三項演算子を記述。これで訪問時に、いいね済みなら塗りつぶしマークがつくし、いいねしてないなら塗りつぶされていないマークが出る。

:class="[isActive === true ? 'fas fa-star' : 'far fa-star']"  

※後述の「クリックしていいねの切り替え」に関わってくるが、propsのuserIdを直接、<template>内の<i>のクラスにbindして、クリックによってuserIdの値を切り替えようとすると、propsの値は変えるな、dataを使え、とエラーが出るので、dataにisActiveとして代入している。

・クリックしていいねの切り替え
いいねマークをクリックしたときに、isActiveのTrueFalseの切り替えで、いいねを切り替える。

真偽値を反転させる簡単なやり方は’!’を使うこと。

変数 = !変数  

とすれば真偽値を逆転できるので、クリックされたら、真偽値反転ロジックが動くようにする。=クリックされたらいいねマークが変わる。

ただ、Ajaxで返り値を受け取っただけで真偽値を変えるようにすると、データベースのデータと不整合が起きるかもしれないので(データベースに反映できていないのに、返り値が返ってきたからいいねを更新する、というような状況は避けたいので)、返り値を確認した上で、いいねの切り替えを行うようにONOFF判定を入れた。(Ajaxのアクセス先が返すデータの内容は、データベースの操作内容と結果によって"ON"か"OFF"か"不正なリクエスト"になるようにしているので、Ajaxの受け取った内容によって条件を分岐)

if(data === 'ON'){    
    this.isActive = true;    
} else if(data === 'OFF'){    
    this.isActive = false;    
} else {    
    console.log(data);    
}  

ちなみに、Ajaxでは引数でcontextとして呼び出し元(this)を挿入することができたが、そういう指定ができない場合は、たぶんbind(this)を後ろにつける必要がある。Javascriptでは無名関数内でthisを使うと、windowオブジェクトを示すらしいので、bindをつけないとthisが指し示す内容が想定と異なってしまう。

$.ajax({  
    url: getURL,  
    type: 'GET',  
    dataType: 'text',  
    context: this  
})  

あとはapp.jsにこのコンポーネントを登録して、npm run devを流すだけ。

終わり

LaravelのController→LaravelのBlade→Vue.jsの<script>→Vue.jsの<template>というデータの受け渡しの流れの理解にとても時間がかかった・・・。
そしてデバッグはconsole.logだけじゃなく、chromeのvue-devtoolsのインストールが必須。

どこかで各プログラミング言語の特徴が載っていたが、JavaScriptの説明が「毎日○ァックと叫びたい場合」とあったが、そんな感覚・・・。その分、動いてくれた時は嬉しいけど。

技術ブログをはじめよう Qrunch(クランチ)は、プログラマの技術アプトプットに特化したブログサービスです
駆け出しエンジニアからエキスパートまで全ての方々のアウトプットを歓迎しております!
or 外部アカウントで 登録 / ログイン する
クランチについてもっと詳しく

この記事が掲載されているブログ

あろはの技術ブログ

よく一緒に読まれる記事

0件のコメント

ブログ開設 or ログイン してコメントを送ってみよう