vue.js

Vue.jsで〇〇なときどう書く?

はじめに

Vue.jsを書いている時に、「〇〇なときどう書いたっけな?」と困ることがあったりするので、備忘録として残していくだけの記事です。
では始めていきましょう。

前提

ここで紹介するVueファイルを構成するソースコードは、 Pug / TypeScript / Scss とします。
また、UIコンポーネントにElementUIを採用しています。

ソースコード

githubにPushしてます。
https://github.com/ryo-is/vue-demo-sample

1. onClickやonChangeで関数を呼びたいとき

@click や @change を使う。
この @hoge というのは v-on:hoge 表記の省略形です。

1-1. ClickEvent

下記の例では、ボタンをクリックすると countNumber を1ずつ増やしています。

template
.click-event
  .child-title ClickEvent デモ
  el-row
    el-col(:span="16")
      el-button(@click="addCount") カウントアップ
    el-col(:span="2")
      .count-number {{ countNumber }}
script
import { Component, Vue } from "vue-property-decorator";

@Component({})
export default class ClickEventComponent extends Vue {
  public countNumber: number = 0;

  public addCount() {
    this.countNumber += 1;
  }
}

1-2. ChangeEvent

セレクトボックスの選択肢を変更した時にテキストの内容 ( selectedText ) を書き換えています。

template
.change-event
  .child-title ChangeEvent デモ
  el-row
    el-col(:span="16")
      el-select(v-model="selectItem" @change="changeItem")
        el-option(label="Apple" value="Apple") Apple
        el-option(label="Banana" value="Banana") Banana
        el-option(label="Orange" value="Orange") Orange
    el-col(:span="4")
      .select-text {{ selectedText }}
script
import { Component, Vue } from "vue-property-decorator";

@Component({})
export default class ChangeEventComponent extends Vue {
  public selectItem: string = "";
  public selectedText: string = "";

  public changeItem() {
    this.selectedText = this.selectItem;
  }
}

2. 要素の表示 / 非表示を切り替えたいとき

v-showv-if を使う。

2-1. v-show の場合

ボタンをクリックした時に displayFlag を切り替えています。
trueなら display:block 、falseなら display:none となります。

template
.v-show
  .child-title v-showによる表示/非表示切り替え
  .button-area
    el-button(@click="displayFlag=!displayFlag") 切り替えボタン
  img.logo-img(v-show="displayFlag" alt="" src="../../assets/logo.png")
script
import { Component, Vue } from "vue-property-decorator";

@Component({})
export default class vShowComponent extends Vue {
  public displayFlag: boolean = true;
}

2-2. v-if の場合

v-show とは少し違って条件式を書くことができるので、表示/非表示の状態を、割と自由に設定することができます。
下記の例では、ボタンをクリックした時に displayFlagindicate または hide に切り替えています。
indicate なら display:blockhide なら display:none となります。

template
.v-if
  .child-title v-ifによる表示/非表示切り替え
  .button-area
    el-button(@click="changeDisplayFlag") 切り替えボタン
  img.logo-img(v-if="displayFlag==='indicate'" alt="" src="../../assets/logo.png")
script
import { Component, Vue } from "vue-property-decorator";

@Component({})
export default class vIfComponent extends Vue {
  public displayFlag: string = "indicate";

  public changeDisplayFlag() {
    if (this.displayFlag === "indicate") {
      this.displayFlag = "hide";
    } else {
      this.displayFlag = "indicate";
    }
  }
}

3. 要素の表示 / 非表示にアニメーションを付けたいとき

transition を使う。
transitionとは、Vueがデフォルトで用意してくれている、 DOM からアイテムが追加、更新、削除されたときにトランジション効果を適用するための方法です。
先程の v-show のソースコードを少し書き換えます。

template
.v-show
  .child-title v-show デモ
  .button-area
    el-button(@click="displayFlag=!displayFlag") 切り替えボタン
  transition(name="image-transition")
    img.logo-img(v-show="displayFlag" alt="" src="../../assets/logo.png")

transitionのnameで渡している値 (上記のソースコード内で言う image-transition ) が、Styleの image-transition-enter-active に対応するので、Styleを調整するときは下記のように書くことができます。

style
.v-show {
  .image-transition-enter-active,
  .image-transition-leave-active {
    transition: all .5s;
  }

  .image-transition-enter,
  .image-transition-leave-to {
    opacity: 0;
    transform: translateY(-10px);
  }
}

4. 要素を繰り替えし生成したいとき

v-for を使う。
下記の例では ["Apple", "Banana", "Orange"] という文字列をli要素として生成しています。

template
.v-for
  .child-title v-for デモ
  ul.list-items
    li(v-for="item in listItems" :key="item") {{ item }}
script
import { Component, Vue } from "vue-property-decorator";

@Component({})
export default class vForComponent extends Vue {
  public listItems: string[] = ["Apple", "Banana", "Orange"];
}

5. inputの要素を変数に保存したいとき

v-model を使う。
下記の例では、テキストエリアに入力した値を、別要素のテキストとして表示しています。

template
.v-model
  .child-title v-model デモ
  el-row
    el-col(:span="10")
      el-input(v-model="inputText")
    el-col(:span="14")
      .input-text {{ inputText }}
script
import { Component, Vue } from "vue-property-decorator";

@Component({})
export default class vModelComponent extends Vue {
  public inputText: string = "";
}

6. 親Componentの関数を子Componentから呼び出したいとき

$emit を使う。
下記の例では、子Componentのボタンをクリックしたら、親Componentのテキストを非表示にしたり、表示したりしています。

子Component

template(ChildComponent)
.emit
  .child-title $emit デモ
  el-button(@click="$emit('changeTitleDisplay')") タイトル表示/非表示

親Component

template(ParentComonent)
.home
  .title(v-show="titleDisplay") {{ homeTitle }}
  emitComponent(v-on:changeTitleDisplay="changeTitleDisplay")
script(ParentComonent)
import { Component, Vue } from "vue-property-decorator";
import emitComponent from "@/components/emit/Emit.vue";

@Component({
  components: {
    emitComponent,
  },
})
export default class Home extends Vue {
  public homeTitle: string = "Vue Demo Sapmle";
  public titleDisplay: boolean = true;

  public changeTitleDisplay() {
    this.titleDisplay = !this.titleDisplay;
  }
}

7. 動的にclassを切り替えたいとき

v-bind:class を使う。
下記の例では、タイトルのClassを変更することで、文字色を変更しています。

template
.change-class
  .child-title(v-bind:class="fontColorClass") Change Class デモ
  el-button(@click="changeFontColor('red')") 赤色に変更
  el-button(@click="changeFontColor('yellow')") 黄色に変更
  el-button(@click="changeFontColor('normal')") 元に戻す
script
import { Component, Vue } from "vue-property-decorator";

@Component({})
export default class ChangeClassComponent extends Vue {
  public fontColorClass: string = "normal-font-color";

  public changeFontColor(color: string) {
    this.fontColorClass = color + "-font-color";
  }
}
style
.change-class {
  .red-font-color {
    color: red;
  };

  .yellow-font-color {
    color: yellow;
  }
}

8. 子Componentに値を渡したいとき

Prop を使う。
下記の例では、親Componentから子Componentに直接テキストを渡したり、インスタンス変数を渡したりしています。

子Component

template(ChildComponent)
.prop
  .child-title Prop デモ
  .prop-text {{ propText }}
  .prop-value {{ propValue }}
script(ChildComponent)
import { Component, Vue, Prop } from "vue-property-decorator";

@Component({})
export default class PropComponent extends Vue {
  @Prop() public propText: string;
  @Prop() public propValue: string;
}

親Component

template(ParentComponent)
.home
  propComponent(:prop-text="'Propで値を子Componentに渡す'", :prop-value="propValue")
script(ParentComponent)
import { Component, Vue } from "vue-property-decorator";
import propComponent from "@/components/prop/Prop.vue";

@Component({
  components: {
    propComponent,
  },
})
export default class Home extends Vue {
  public propValue: string = "インスタンス変数を子Componentに渡す";
}

9. 親Componentから子Componentを識別したいとき (2019/01/10 追記)

ref を使う。
親コンポーネントの template に子コンポーネントを読み込むときに ref 属性を定義すると vm.$refs で子コンポーネントを識別することができます。
ただ注意が必要なのが created() の段階ではまだ子コンポーネントがインスタンス化されていないので取得できません。 mounted() やClickなどのイベントなどで取得しましょう。
下記の例では子コンポーネントの変数を取得して、標準出力しています。

子Component

template(ChildComponent)
.ref
  .child-title Ref デモ
script(ChildComponent)
import { Component, Vue } from "vue-property-decorator";

@Component({})
export default class RefComponent extends Vue {}

親Component

template(ParentComponent)
.home
  refComponent(ref="refDemo")
script(ParentComponent)
import { Component, Vue } from "vue-property-decorator";
import refComponent from "@/components/ref/Ref.vue";

@Component({
  components: {
    refComponent,
  },
})
export default class Home extends Vue {
  public created() {
    const refDemoComponent: refComponent = this.$refs.refDemo as refComponent;
    console.log(refDemoComponent); // undefined
  }

  public mounted() {
    const refDemoComponent: refComponent = this.$refs.refDemo as refComponent;
    console.log(refDemoComponent);
  }
}

10. 親Componentから子Componentの関数を呼びたいとき (2019/01/10 追記)

ref を使う。
「9. 親Componentから子Componentを識別したいとき」と同じように ref を使っていきます。
下記の例では親Componentの mounted() のタイミングで、子Componentのメソッドを呼び出して、変数に代入しています。
途中型宣言がうまくできなくてやむなく any を使っています…ここきれいに型宣言できる方法知っている方いたら、コメントいただけると幸いです。

子Component

template(ChildComponent)
.ref
  .child-title Ref デモ
script(ChildComponent)
import { Component, Vue, Prop } from "vue-property-decorator";

@Component({})
export default class RefComponent extends Vue {
  public sampleText: string = "Refのデモです";

  public returnText(): string {
    return this.sampleText;
  }
}

親Component

template(ParentComponent)
.home
  refComponent(ref="refDemo")
  .ref-demo-text {{ refDemoText }}
script
import { Component, Vue } from "vue-property-decorator";
import refComponent from "@/components/ref/Ref.vue";

@Component({
  components: {
    refComponent,
  },
})
export default class Home extends Vue {
  public refDemoText: string = "";

  public mounted() {
    const refDemoComponent: any = this.$refs.refDemo; // ここの型宣言がうまくできなかった…
    this.refDemoText = refDemoComponent.returnText();
  }
}

11. Propの変数が更新されたら子Componentも更新したいとき (2019/01/10 追記)

ref を使う。
「9. 親Componentから子Componentを識別したいとき」と同じように ref を使っていきます。
というよりは「10. 親Componentから子Componentの関数を呼びたいとき」の応用です。
下記の例では、親Componentのテキストボックスの内容(refInputText)をpropで子Componentの値(refText)に渡していて、 refInputText を更新した時に、子Componentの updateRefText() を呼び出して refText を更新しています。

子Component

template(ChildComponent)
.ref
  .child-title Ref デモ
  .ref-input-text {{ refText }}
script(ChildComponent)
import { Component, Vue, Prop } from "vue-property-decorator";

@Component({})
export default class RefComponent extends Vue {
  @Prop() public refText: string;

  public sampleText: string = "Refのデモです";

  public updateRefText(newText: string) {
    this.refText = newText;
  }
}

親Component

template(ParentComponent)
.home
  refComponent(ref="refDemo")
  el-row
    el-col(:span="10")
      el-input(v-model="refInputText" @change="changeRefInputText")
    el-col(:span="14")
      .ref-demo-text {{ refDemoText }}
script(ParentComponent)
import { Component, Vue } from "vue-property-decorator";
import refComponent from "@/components/ref/Ref.vue";

@Component({
  components: {
    refComponent,
  },
})
export default class Home extends Vue {
  public refDemoText: string = "";

  public mounted() {
    const refDemoComponent: any = this.$refs.refDemo;
    this.refDemoText = refDemoComponent.returnText();
  }

  public changeRefInputText() {
    const refDemoComponent: any = this.$refs.refDemo;
    refDemoComponent.updateRefText(this.refInputText);
  }
}

さいごに

これからも「〇〇なときどう書いたっけな?」と困ることがあったら随時アップデートしていこうと思います!
ではまた!!