豆腐とコンソメ

豆腐とコンソメ

もろもろのプログラム勉強記録

Vue.jsで遊ぶ(2)

日記

正しいものを学ぼうとしているのだけれども、絶対に正しいというものはなくって、今の状況(要件だったり、納期だったり、環境だったり、自分の実力だったり)を考えみて、自分はこうすべきだと思ったと言えるようになればいいのかなと最近思った。


前回からの続き

www.tohuandkonsome.site

だいぶ時間が空いてしまいましたが、前回からの続きです。

前回は、こんなコードを書きました。

前回のindex.html

<h1>スタイルをバインドする</h1>
<div class="box1" @click="sayHello" v-bind:style="styleObject">box1</div>
<div class="box2" @click="sayHello" v-bind:style="styleObject">box2</div>

前回のapp.js

let box1 = new Vue({
    el:'.box1',
    data: {
        pointX:0
        styleObject:{
            transform: 'translateX('+this.pointX+'px)'
        },
    methods:{
        //index.htmlもsayHelloからこれにメソッドをかえてるよ!
        moveRight:function(event){
            this.pointX++;
            this.styleObject.transform = convertTranslate(this.pointX);
        },
    }
})

//文字列「translateX(value)」を返す関数
function convertTranslate(value)
{
    return  'translate(' + value + 'px)'
}

//box2はここでは関係ない

これをブラウザでみると、以下ように箱をクリックすると、それが右に動くというどうしようもないものが見れます。

f:id:konoemario:20171114220952p:plain:w500


今回やりたいこと

box1をクリックするとbox1とbox2も動くということをやってみたいと思います。

f:id:konoemario:20171114221854j:plain:w500


修正案:右に動くという値を共有する

まっさきに思いついたのがこちらです。
クリックするたびにカウントアップされるpointXをbox1とbox2で共有してあげます。

共有する値はオブジェクト型じゃないと、box1とbox2でそれぞれ値を持ってしまうので注意が必要ですね。

修正したapp.js

//box1とbox2で値を共有する
let globalData = {pointX:sharePointX};

let box1 = new Vue({
    el:'.box1',
    data: {
        pointX:globalData,
        styleObject:{
            transform: 'translateX(0px)'
        },
      },
    methods:{
        moveRight:function(event){
            this.pointX.pointX++
            console.log(this.pointX.pointX);
            this.styleObject.transform = convertTranslate(this.pointX.pointX);
        },
    },
})

let box2 = new Vue({
    el:'.box2',
    data: {
        pointX:globalData,
        styleObject:{
            transform: 'translateX(0px)'
        },
      },
    methods:{
        moveRight:function(event){
            this.styleObject.transform = convertTranslate(this.pointX.pointX);
        },
    }
    
})

//文字列「translateX(value)」を返す関数は省略  

さて、こちらを実行すると、、、

うまくいきません。

box1をクリックしてもbox2が右に動くことはありません。

値が共有できていないのでは?というとそういうわけでもなさです。

というのも、box2をクリックすると、思い出したかのように今までbox1でカウントアップした分の値でbox2が右に動きます。

どうやら、box2はbox1によってpointXが変更されたとしても、その変化に気づくようにはなってないのだと思います。

f:id:konoemario:20171114222905j:plain:w500

こういうことをしたい場合、どうしたらよいのでしょうか。


修正案:公式のアドバイスに従う

ちゃんと公式に書いてありました。

jp.vuejs.org

ときどき、互いに親子関係ではない2つのコンポーネントが互いに通信する必要があるかもしれません。簡単なシナリオとして、空の Vue インスタンスを中心のイベントバスとして使用することができます:

どうも空っぽのVueインスタンスを作って、コンポーネントのときに学んだコンポーネント間のデータやらイベントのやりとりの方法を使うことでうまくできるみたいです。

今一度のapp.js

//イベントバス用のVueインスタンス
var bus = new Vue();

let box1 = new Vue({
    el:'.box1',
    data: {
        pointX:globalData,
        styleObject:{
            transform: 'translateX(0px)'
        },
      },
    methods:{
        moveRight:function(event){
            this.pointX.pointX++
            console.log(this.pointX.pointX);
            this.styleObject.transform = convertTranslate(this.pointX.pointX);
            //ugoiteyo発火!
            bus.$emit('ugoiteyo')
        },
    },
})


let box2 = new Vue({
    el:'.box2',
    data: {
        pointX:globalData,
        styleObject:{
            transform: 'translateX(0px)'
        },
      },
    methods:{
        moveRight:function(event){
            this.styleObject.transform = convertTranslate(this.pointX.pointX);
        },
    },
    created:function(){
        //ugoiteyoイベントリスナー
        bus.$on('ugoiteyo', this.moveRight);
    }
})
  • box1をクリックすると、イベント「ugoiteyo」が発火する
  • box2のイベントリスナー「ugoiteyo」が動く

こんな感じで、今度はやりたいことを実現できました!


とはいえ

こんな面倒なことはせずに、HTMLの構成を以下のように、box1とbox2を包んであげる要素「boxes」を置いて、

index.html

 <!--これでいいじゃない -->
 <div class="boxes">
      <div class="box1" @click="moveRight" v-bind:style="styleObject">box1</div>
      <div class="box2" @click="moveRight" v-bind:style="styleObject">box2</div>

Vueインスタンスのセレクタも「boxes」をしてあげれば、やりたいことはできちゃいますね。

app.js

let boxes = new Vue({
    el:'.boxes',
    data: {
        pointX:0,
        styleObject:{
            transform: 'translateX(0px)'
        },
      },
    methods:{
        moveRight:function(event){
            this.pointX++
            console.log(this.pointX);
            this.styleObject.transform = convertTranslate(this.pointX);
        },
    },
})