🕌

vue.jsで気になっているポイントメモ

2021/08/05に公開

dataの中身を変更する方法

前々から気になってはいたのですが、このdataの中で定義されて値ってどうやって変更するんだろう?となっていました。

returnで値と変数を定義できるみたいです。
ageの変数のところでもあるのですが、
キャストすることによってnumberやstringといった型定義もすることが可能になると。
なるほどな。

<script lang="ts">
  import { defineComponent } from "vue";

  export default defineComponent({
    name: "App",
    components: {},
    data() {
      return {
        name: "Link",
        age: 25 as number | string,
      };
    },
    methods: {
      changeName(name: string) {
        this.name = name;
      },
      changeAge(age: string | number) {
        this.age = age;
      },
    },
  });
</script>

reactiveやtoRefs

こんな感じで使うこともできるみたいです。
へぇ〜となっています。

    setup() {
      const state = reactive({
        name: "Link",
        age: 25 as string | number,
      });

      return { ...toRefs(state) };
    },

refを使うとき

これだと変な意識することなくできそうな感じはする
useStateみたいな使い方かな?とは思っています。

      const name = ref("Link");
      const age = ref<number | string>(25);

      return { name, age };

interfaceを使うとsetupで定義するときに間違った情報が入らないようにできる

型定義して

interface Job {
  title: string;
  location: string;
  salary: number;
  id: string;
}

export default Job;

呼び出して

 import Job from "./types/job";

セットアップができるみたい。

    setup() {
      const jobs = ref<Job[]>([
        {
          title: "farm worker",
          location: "lon lon ranch",
          salary: 30000,
          id: "1",
        },
        {
          title: "quarryman",
          location: "death mountain",
          salary: 40000,
          id: "2",
        },
        {
          title: "flute player",
          location: "the lost woods",
          salary: 35000,
          id: "3",
        },
        { title: "fisherman", location: "lake hylia", salary: 21000, id: "4" },
        {
          title: "prison guard",
          location: "gerudo valley",
          salary: 32000,
          id: "5",
        },
      ]);
      return { jobs };
    },
    

基礎とコアコンセプト - Vue による DOM インタラクション

リロード対策?

<form v-on:submit.prevent> = event.preventDefault

マウント?

const app = Vue.createApp({})
app.mount("#id")

inputと引数

<input type="text v-on:input="setName($event, "lastName") />

setName(event, lastName) {
  this.name = event.target.value + " " + lastName;
}

右クリック

<button v-on:click.right="sample">sample</button>

enterキーでのイベント

<input
 type="text"
 v-on:input="setName($event, 'Matsumoto')"
 v-on:keyup.enter="confirmInput"
/>

ページ呼び出し時に一回のみ実行

<p v-once>Starting Counter: {{ counter }}</p>

v-bind:valueとv-on:inputを混ぜた書き方

<input type="text" v-model="name" />

computed
この時は()をつけないようにする

<p>Your Name: {{ fullname }}</p>

computed: {
  fullname() {
    console.log("Running again...");
    if (this.name === "") {
      return "";
    }
    return this.name + " " + "Matsumoto";
  },
},

watch
dataで作った値の変更を確認して関数を実行できるらしいで。
例えばカウントダウンタイマーとかで使えるみたい。
ポモドーロタイマーとか簡単にできそう。

data() {
    return {
      name: "",
      lastName: "",
      fullname: "",
    };
  },
  watch: {
    name(value) {
      if (value === "") {
        this.fullname + "";
      } else {
        this.fullname = value;
      }
    },
    lastName(value) {
      if (value === "") {
        this.fullname = "";
      } else {
        this.fullname = this.name + " " + value;
      }
    },
  },

methods

computed

watch

短縮

v-on = @
v-bind = :
v-on:click = @click
v-on:click.right = @click.right
v-bind:value = :value

ボタンを押したら色が変わる

<div
  class="demo"
  :style="{borderColor: boxASelected ? 'red': '#ccc'}"
  @click="boxSelected('A')"
></div>

動的なクラス変更

<div
  class="demo"
  :class="{active: boxASelected}"
  @click="boxSelected('A')"
></div>

配列でも可能

<div
  :class="['demo',{active: boxBSelected}]"
  @click="boxSelected('B')"
></div>

ここまでのまとめ

Vueは、ステップではなくゴールを定義するために使用できる(宣言的アプローチ

Vueを "el "でHTML要素に接続する。Vueは、接続されたテンプレートに基づいて、実際のDOMをレンダリングする

補間({{}})やv-bind(":")ディレクティブでデータを束ねることができます。

v-on("@")でイベントをリッスンします。

バインドされたデータが変更されると、Vueが実際のDOMを更新する

計算されたプロパティとウォッチャーにより、データの変更に対応可能

ダイナミックCSSクラスとインラインスタイルバインディングは、Vueでサポートされています。

Vueには、効率的なバインディングのための複数の特殊構文(オブジェクトベース、配列ベース)が用意されています。

条件付きコンテンツとリストのレンダリング

v-if

<p v-if="goals.lenghth === 0">
  No goals have been added yet - please start adding some!
</p>
<ul v-else-if="goals.lenthg > 0">
  <li>Goal</li>
</ul>
<p v-else>...</p>

v-for

<li v-for="goal in goals">{{goal}}</li>
<li v-for="(goal, index) in goals">{{goal}} - {{ index }}</li>
<li v-for="(value, key, index) in {name: 'Max', age: 31}">
  {{ key }}: {{ value }} - {{ index }}
</li>
<li v-for="num in 10">{{num}}</li>

<li v-for="(goal, index) in goals" @click="removeGoal(index)">
  {{goal}} - {{ index }}
</li>

removeGoal(index) {
 this.goals.splice(index, 1);
},

key

<li
  v-for="(goal, index) in goals"
  :key="goal"
  @click="removeGoal(index)"
>
  <p>{{goal}} - {{ index }}</p>
  <input type="text" @click.stop />
</li>

ここのまとめ

条件付きコンテンツ

V-if(およびv-show)では、特定の条件を満たした場合にのみコンテンツを表示することができます。

v-ifは、v-elseおよびv-else-ifと組み合わせることができます(直接の兄弟要素でのみ可能です)。

リスト

v-forは、複数の要素を動的にレンダリングするために使用できます。

V-forのバリエーション

値、値とインデックス、または値、キーとインデックスを抽出することができます

v-forとv-ifが必要な場合は、同じ要素には使用しないでください。代わりにv-if付きのラッパーを使用してください。

キー

VueはDOM要素を再利用してパフォーマンスを最適化しています。
これは、要素に状態が含まれている場合、バグにつながる可能性があります。

Vueがリストコンテンツに属する要素を識別できるように、key属性を一意の値にバインドします。

htmlのコード内で計算式を使用する場合は一度タグ内に書き込んでからcomputedメソッドを使うといいかも
cssのパーセンテージによる動的な変化や回数によってボタン有効化など・・・

<div class="healthbar__value" :style="monsterBarStyles"></div>
<div class="healthbar__value" :style="playerBarStyles"></div>
<button :disabled="mayUseSpecialAttack" @click="specialAttackMonster">

computed: {
    monsterBarStyles() {
      return { width: this.monsterHealth + "%" };
    },
    playerBarStyles() {
      return { width: this.playerHealth + "%" };
    },
    mayUseSpecialAttack() {
      return this.currentRound % 3 !== 0;
    },
  },

ref

<input type="text" ref="userText" />
setText() {
  this.message = this.$ref.userText.value;
},

1つの大きな接続されたユーザーインターフェースを構築する場合には、通常、複数のVueアプリを使用しません。

なぜでしょうか?

なぜなら、Vueアプリは互いに独立しており、実際には互いに通信できないからです。それを実現するための「ハック」はあるかもしれませんが、アプリ間でデータを共有したり、アプリBで何かが起こったときにアプリAで何かを更新したりするような、優れた「公式」の方法はありません。

一方、コンポーネントは、すぐに分かるように、それらの間でデータを交換できる特定の通信メカニズムを提供します。したがって、複数のコンポーネントを保持する1つのルートアプリで作業すれば、1つの接続されたUIを構築することができます。

シングルページアプリケーションを採用する理由はデータのやり取りのメリットが含まれている。

ここからはvue-cliを使った時のポイント

コンポーネント間でのデータの受け渡し
JavaScriptではキャメルケースになるのに対して(最初は小文字で区切りを大文字)
HTMLの部分ではケバブケースにする

<script>
export default {
  props: ["name", "phoneNumber", "emailAddress"],
};
</script>
<friend-contact
  name="Maunel Lorenz"
  phone-number="01234 78992"
  email-address="manuel@localhost.com"
></friend-contact>
<friend-contact
  name="JulieJones"
  phone-number="0987 654321"
  email-address="julie@localhost.com"
></friend-contact>

propsで受け取ったデータを変更する
方法としては受け取ったデータをその中で格納してしまえばOK

props: ["name", "phoneNumber", "emailAddress", "isFavorite"],
  data() {
    return {
      detailsAreVisible: false,
      friendIsFavorite: this.isFavorite,
    };
  },

受け取ったデータを別のところに格納しているので受け取ったデータではなく別の内容を変更しているのと同意義になるはず。

toggleFavorite() {
    if (this.friendIsFavorite === "1") {
    this.friendIsFavorite = "0";
    } else {
    this.friendIsFavorite = "1";
    }
},

トグルがイメージしやすかった

<h2>{{ name }} {{ friendIsFavorite === "1" ? "(Favorite)" : "" }}</h2>

propの定義
オブジェクトでtypeやrequiredなど色々定義できる

props: {
    id: {
      type: String,
      required: true,
    },
    name: { type: String, required: true },
    phoneNumber: { type: String, required: true },
    emailAddress: { type: String, required: true },
    isFavorite: { type: Boolean, required: false, default: false },
    // validator: function(value) {
    //   return value === "1" || value === "0";
    // },
  },

コンポーネント通信の概要

コンポーネントは、それらを組み合わせてUIを構築するために使用されます
コンポーネントは「親子関係」を構築し、「一方向性」のデータフローを用いて通信を行う

props
「プロップ」は、親コンポーネントから子コンポーネントへデータを渡すために使用されます。
プロップは事前に定義しておく必要があり、場合によっては非常に詳細に定義しておく必要があります(タイプ、必須など)。

カスタムイベント(子⇒親)

"カスタム・イベント" は、親コンポーネントのメソッドを起動するために ($emit を通して) 発信されます。
カスタム・イベントは、呼び出されたメソッドで使用されるデータを運ぶことができます。

プロビデンス・インジェクション

複数のコンポーネント間でデータを受け渡す必要がある場合(パススルー)、provide/injectを使用することができます。
親コンポーネントでデータを提供し、それを子コンポーネントに注入します。

https://v3.ja.vuejs.org/guide/component-provide-inject.html#provide-inject\

slot

コンポーネントの中身を渡すことができる
テキストだけでなくHTMLタグも同様

v-slot
下記のように短縮形も可能

<template #default>

Discussion