還暦過ぎたエンジニアの挑戦

還暦過ぎても好奇心だけは忘れない エンジニア ひかるです

MENU

スイッチでランプを点けよう2【スイッチ】

こんな記事(ディシジョンテーブルのこと )で前置きが長くなってしまいましたが、
Vue.jsで簡単にブラウザ上の表示をコントロールできることに感激したので第2弾は
「3路スイッチの回路」
イメージです。


材料

  1. スイッチはwebで使えるスイッチ で紹介したマテリアルアイコンを使います。
    今回は2か所あります。

  2. 画像はランプがOFF状態の時のものとONの状態の時のものをソースの imgBathPath に指定したディレクトリに用意します。
    スイッチのon/offで画像を差し替えるので、onの画像とoffの画像は大きさを揃えておくのがポイントです。

ランプがOFFの時の画像 ランプ点灯時の画像
スイッチライン左上
スイッチライン左上
スイッチライン右上
スイッチライン右上

それぞれの画像の名称は何でもよいのですが、

on/offの画像の差し替え用共通メソッド

function imageColor(img, lightOn) {
    var suffix = lightOn ? '_on.png' : '_off.png';
    return imgBathPath + img + suffix;
}

を用意していますので、~_on.png、~_off.pngというような、対になる名前にしておきます。

imageColor(画像の名前の~の部分, ランプのon|off状態)

でその画像のpathを取得できるようにしておこうということです。


作り方

Vue.jsのdataの記述
  1. 状態を扱う変数の定義はいずれもbool値にしてtrue|falseで判断するようにしておきます
    1. lightOn : ランプが点いている(true)か点いていない(false)か 画像のパスを取得するときに使います。
    2. switchA_on : 図の左下のスイッチをswitchAとしてラインを右上がりの状態をon(true)とします。
    3. switchB_on : 同様に右下のスイッチをswitchBとします。
  2. 画像のsrc属性に使う変数をすべて用意し、初期状態はランプがoffの状態になるようにそれぞれ初期値を設定しておきます。
Vue.jsのmethods
  1. 用意するのは2つのスイッチがクリックされたときのメソッドです。
    単純にメソッド名はswitchAとswitchBにします。
  2. 2つとも同じような動きですので、その内容を switchA を例に書くと
    1. スイッチの状態を反転させる
      offの時にクリックされたらonに、onの時にクリックされたらoffにするということですが、こういう時のコードの書き方はお決まりの
      this.switchA_on = this.switchA_on === false;
      ですね。
    2. ランプの状態を反転させる
      スイッチのon/offとは連動していない3路スイッチですから別に書きますが、それに応じてそれぞれの画像も切り替えるので、それらは外部メソッド(lightSwitch)にしてVueの中ではコールするだけにします。

まとめるとソースはこんな感じになります

var switch2 = new Vue({
    el: '#switch2',
    data: {
        // 初期値
        lightOn: false,
        switchA_on: false,
        switchB_on: false,
        // src属性の初期値
        lamp: imageColor('110658', false),
        baseLine: imageColor('base2', false),
        baseLine1: imageColor('base_line', false),
        baseLine2: imageColor('base_line', false),
        switchA_off_img: imageColor('left', false),
        switchA_on_img: imageColor('right', false),
        switchB_off_img: imageColor('left', false),
        switchB_on_img: imageColor('right', false)
    },
    methods: {
        switchA: function(e) {
            // スイッチAをクリックした時
            this.switchA_on = this.switchA_on === false;
            lightSwitch();
        },
        switchB: function(e) {
            // スイッチBをクリックした時
            this.switchB_on = this.switchB_on === false;
            lightSwitch();
        },
    }
})

外部メソッドlightSwitch()のソース

function lightSwitch() {
    // ライトのon/off状態を切り替える
    switch2.lightOn = switch2.lightOn === false;
    
    // 中央の2本の線は一旦offの状態にしておく
    switch2.baseLine1 = imageColor('base_line', false);
    switch2.baseLine2 = imageColor('base_line', false);

    // ライトのon/off状態に応じて画像を変更する
    switch2.lamp = imageColor('110658', switch2.lightOn);
    switch2.baseLine = imageColor('base2', switch2.lightOn);
    if (switch2.switchA_on) {
        switch2.switchA_on_img = imageColor('right', switch2.lightOn);
        switch2.baseLine1 = imageColor('base_line', switch2.lightOn);
    } else {
        switch2.switchA_off_img = imageColor('left', switch2.lightOn);
        switch2.baseLine2 = imageColor('base_line', switch2.lightOn);
    }
    if (switch2.switchB_on) {
        switch2.switchB_on_img = imageColor('right', switch2.lightOn);
    } else {
        switch2.switchB_off_img = imageColor('left', switch2.lightOn);
    }
}

HTMLの記述

今回使用しているVue.jsの記法は3つです。

v-ifとv-else

スイッチとスイッチの画像のところで使用しました。
ちょっと注意すべきは v-ifとv-elseはどちらか一方しかDOM上には存在しないので、
うっかり存在しないほうの要素を参照しないようにすることです。

v-bind (省略形 :)

imgタグの属性に省略形で使用しました。
:src=(dataの変数名) で割り当てることができますのでHTMLが随分すっきりしますね。

v-on (省略形 @)

もちろんスイッチの要素に使用しました。
マテリアルアイコンの要素に省略形でクリック時に呼び出すメソッドを記述しました。
@click=(methodsのメソッド名)


最後に

全体のHTMLを含めたソース

<link rel="shortcut icon" href="https://blog.yutenji.biz/favicon">
<meta name="viewport" content="width=device-width,initial-scale=1">
<script src="vue.min.js"></script>
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
<style>
    [v-cloak] {
        display: none
    }

    body {
        font-family: "ヒラギノ角ゴ Pro W3", "Hiragino Kaku Gothic Pro", "メイリオ", Meiryo, Osaka, "MS Pゴシック", "MS PGothic", sans-serif;
    }

    h1 {
        font-size: 14px;
        margin: 0;
    }

    #diagram1 {
        z-index: 10;
        position: relative;
    }

    #diagram1 img {
        margin-top: 10px;
    }

    .materials {
        position: absolute;
        cursor: pointer;
        font-size: 40px;
    }

    #switchA_on {
        top: 174px;
        left: 35px;
    }

    #switchA_off {
        top: 192px;
        left: 37px;
    }

    #switchB_on {
        top: 193px;
        left: 258px;
    }

    #switchB_off {
        top: 175px;
        left: 261px;
    }

    #switch_A {
        top: 265px;
        left: 36px;
    }

    #switch_B {
        top: 265px;
        left: 264px;
    }

    .switch_name {
        position: absolute;
        width: 100px;
        font-size: 12px;
    }

    #switch_A_name {
        top: 300px;
        left: 24px;
    }

    #switch_B_name {
        top: 300px;
        left: 252px;
    }

    .switchLine {
        position: absolute;
        z-index: 0;
    }

    #line1 {
        top: 205px;
        left: 65px;
    }

    #line2 {
        top: 236px;
        left: 65px;
    }

    #lamp1 {
        position: absolute;
        z-index: 20;
        left: 145px;
        top: 43px;
    }

    #lamp1 img {
        height: 50px;
    }
</style>
<div>
    <h1>スイッチ2 (3路スイッチ)</h1>
    <div id="switch2">
        <div id="lamp1">
            <img :src="lamp">
        </div>
        <div id="line1" class="switchLine">
            <img :src="baseLine1">
        </div>
        <div id="line2" class="switchLine">
            <img :src="baseLine2">
        </div>

        <div class="switchLine">
            <div v-if="switchA_on" id="switchA_on" class="switchLine"><img :src="switchA_on_img"></div>
            <div v-else id="switchA_off" class="switchLine"><img :src="switchA_off_img"></div>
        </div>
        <div class="switchLine">
            <div v-if="switchB_on" id="switchB_on" class="switchLine"><img :src="switchB_on_img"></div>
            <div v-else id="switchB_off" class="switchLine"><img :src="switchB_off_img"></div>
        </div>

        <div id="switch_A" class="material-icons materials">
            <div v-if="switchA_on" @click="switchA">toggle_on</div>
            <div v-else @click="switchA">toggle_off</div>
        </div>
        <div id="switch_A_name" class="switch_name">スイッチA</div>

        <div id="switch_B" class="material-icons materials">
            <div v-if="switchB_on" @click="switchB">toggle_on</div>
            <div v-else @click="switchB">toggle_off</div>
        </div>
        <div id="switch_B_name" class="switch_name">スイッチB</div>

        <div id="diagram1">
            <img :src="baseLine">
        </div>
    </div>
</div>
<script>
    var imgBathPath = '../../img/diagram/';
    var switch2 = new Vue({
        el: '#switch2',
        data: {
            // 初期値
            lightOn: false,
            switchA_on: false,
            switchB_on: false,
            // src属性の初期値
            lamp: imageColor('110658', false),
            baseLine: imageColor('base2', false),
            baseLine1: imageColor('base_line', false),
            baseLine2: imageColor('base_line', false),
            switchA_off_img: imageColor('left', false),
            switchA_on_img: imageColor('right', false),
            switchB_off_img: imageColor('left', false),
            switchB_on_img: imageColor('right', false)
        },
        methods: {
            switchA: function(e) {
                // スイッチAをクリックした時
                this.switchA_on = this.switchA_on === false;
                lightSwitch();
            },
            switchB: function(e) {
                // スイッチBをクリックした時
                this.switchB_on = this.switchB_on === false;
                lightSwitch();
            },
        }
    })

    function lightSwitch() {
        // ライトのon/off状態を切り替える
        switch2.lightOn = switch2.lightOn === false;
        // 中央の2本の線は一旦offの状態にしておく
        switch2.baseLine1 = imageColor('base_line', false);
        switch2.baseLine2 = imageColor('base_line', false);

        // ライトのon/off状態に応じて画像を変更する
        switch2.lamp = imageColor('110658', switch2.lightOn);
        switch2.baseLine = imageColor('base2', switch2.lightOn);
        if (switch2.switchA_on) {
            switch2.switchA_on_img = imageColor('right', switch2.lightOn);
            switch2.baseLine1 = imageColor('base_line', switch2.lightOn);
        } else {
            switch2.switchA_off_img = imageColor('left', switch2.lightOn);
            switch2.baseLine2 = imageColor('base_line', switch2.lightOn);
        }
        if (switch2.switchB_on) {
            switch2.switchB_on_img = imageColor('right', switch2.lightOn);
        } else {
            switch2.switchB_off_img = imageColor('left', switch2.lightOn);
        }
    }

    function imageColor(img, lightOn) {
        var suffix = lightOn ? '_on.png' : '_off.png';
        return imgBathPath + img + suffix;
    }
</script>

も載せておきます。💦

動的なページを作るときにVue.jsを使うとHTMLがすっきりして、エンジニアとデザイナーの仕事の棲み分けがはっきりするかもしれませんね。