見出し画像

【ワンピースで覚えるNuxt】ルーティング


ルーティング

Vue Routerではファイルにルーティング情報を追加するが、Nuxtでは不要

NuxtPageタグ

Vue RouterのRouterViewタグに当たるもの
ルートタグで使用不可(別タグで囲む)

画面用のコンポーネント

pagesフォルダに格納
ファイル構造がパスになる(ファイルシステムルータ)
ルート => index.vue

リンク生成

NuxtLinkタグ

リンク先をto属性(v-bind:to)で指定
name: ルーティング名

character/characterList.vue
=> character-characterList(ルーティング名)

ルートパラメータ

[ルートパラメータ名].vue

/character/characterDetail/:id
=> character/characterDetail/[id].vue

useRoute()

ルートオブジェクトを取得

paramsプロパティでパラメータをゲット

ルートパラメータのリンク

リンクにparamsを埋め込む

character/characterDetail/[id].vue
=> character-characterDetail-id, params: {id: id}

ルーティングの制御

ルータオブジェクト useRouter()

pushメソッドで指定の場所へ遷移

app.vue

<script setup lang="ts">
//型定義をインポートするときは import type
import type {Character} from "@/interfaces";
//キャラクターリストデータ。
useState<Map<number, Character>>(
  "characterList", //ステート名
  (): Map<number, Character> => { //初期値を生成
    const characterListInit = new Map<number, Character>();
    characterListInit.set(1, {id: 1, name: "ルフィ", bounty: 100000000});
    characterListInit.set(2, {id: 2, name: "ゾロ", bounty: 60000000});
    return characterListInit;
  }
);//characterListでデータの取り出しが可
</script>

<template>
  <header>
    <h1>ワンピース</h1>
  </header>
  <main>
    <NuxtPage/>
  </main>
</template>

<style>
main {
  border: black 5px solid;
  padding: 10px;
}
#breadcrumbs ul li {
  display: inline;
  list-style-type: none;
}
#breadcrumbs ul {
  padding-left: 0px;
}
#breadcrumbs ul li:before {
  content: " > ";
}
#breadcrumbs ul li:first-child:before {
  content: none;
}
</style>

pages/index.vue

<template>
  <h1>TOP</h1>
  <nav id="breadcrumbs">
    <ul>
      <li>TOP</li>
    </ul>
  </nav>
  <section>
    <p>
      <!-- <NuxtLink to="/character/characterList"> -->
      <NuxtLink v-bind:to="{name: 'character-characterList'}">
        キャラクターの設定はこちらから
      </NuxtLink>
    </p>
  </section>
</template>

pages/character/characterList.vue

<script setup lang="ts">
import type {character} from "@/interfaces";

//キャラクターリストをステートから取得。
const characterList = useState<Map<number, Character>>("characterList");
</script>

<template>
  <h1>キャラクター設定</h1>
  <nav id="breadcrumbs">
    <ul>
      <li><NuxtLink v-bind:to="{name: 'index'}">TOP</NuxtLink></li>
      <li>キャラクターリスト</li>
    </ul>
  </nav>
  <section>
    <h2>キャラクターリスト</h2>
    <p>
      追加は<NuxtLink v-bind:to="{name: 'character-characterAdd'}">こちら</NuxtLink>から
    </p>
    <section>
      <ul>
        <li
          v-for="[id, character] in characterList"
          v-bind:key="id">
          <NuxtLink v-bind:to="{name: 'character-characterDetail-id', params: {id: id}}">
            No:{{id}} {{character.name}}
          </NuxtLink>
        </li>
      </ul>
    </section>
  </section>
</template>

pages/character/characterAdd.vue

<script setup lang="ts">
import type {character} from "@/interfaces";

//ルータオブジェクトを取得。
const router = useRouter();
// router.push() => 指定の居場所へ
// router.back() => 履歴上で1つ前の画面

//キャラクターリストをステートから取得。
const characterList = useState<Map<number, Character>>("characterList");
//入力データと同期させるCharacterオブジェクトの用意。
const character: Character = reactive(
  {
    id: 0,
    name: "",
    bounty: 0,
  }
);
//登録ボタンが押された時の処理。
const onAdd = (): void => {
  characterList.value.set(character.id, character);
  router.push({name: "character-characterList"});
};
</script>

<template>
  <h1>キャラクター設定</h1>
  <nav id="breadcrumbs">
    <ul>
      <li><NuxtLink v-bind:to="{name: 'index'}">TOP</NuxtLink></li>
      <li><NuxtLink v-bind:to="{name: 'character-characterList'}">キャラクターリスト</NuxtLink></li>
      <li>キャラクター追加</li>
    </ul>
  </nav>
  <section>
    <h2>キャラクター追加</h2>
    <p>
      情報を入力し、登録ボタンをクリックしてください。
    </p>
    <form v-on:submit.prevent="onAdd">
      <table>
        <tr>
          <td>
            <label for="addId">No:</label>
          </td>
          <td>
            <input type="number" id="addId" v-model.number="character.id" required>
          </td>
        </tr>
        <tr>
          <td>
            <label for="addName">名前:</label>
          </td>
          <td>
            <input type="text" id="addName" v-model="character.name" required>
          </td>
        </tr>
        <tr>
          <td>
            <label for="addBounty">懸賞金:</label>
          </td>
          <td>
            <input type="number" id="addBounty" v-model.number="character.bounty" required>
          </td>
        </tr>
      </table>
      <br>
      <button type="submit">登録</button>
    </form>
  </section>
</template>

pages/character/characterDetail/[id].vue

<script setup lang="ts">
import type {Character} from "@/interfaces";

//ルートオブジェクト(ルートに関する情報を取得)を取得。
const route = useRoute();
// route.name => character-characterDetail-id
// route.path => /character/characterDetail/1
// route.params => { id: 1 }

//キャラクターリストをステートから取得。
const characterList = useState<Map<number, Character>>("characterList");
//キャラクターリストから該当キャラクターを取得。
const character = computed(
  (): Character => {
    const id = Number(route.params.id);
    return characterList.value.get(id) as Character;
  }
);
</script>

<template>
  <h1>キャラクター設定</h1>
  <nav id="breadcrumbs">
    <ul>
      <li><NuxtLink v-bind:to="{name: 'index'}">TOP</NuxtLink></li>
      <li><NuxtLink v-bind:to="{name: 'character-characterList'}">キャラクターリスト</NuxtLink></li>
      <li>キャラクター詳細情報</li>
    </ul>
  </nav>
  <section>
    <h2>キャラクター詳細情報</h2>
    <table>
      <tr>
        <td>No:</td>
        <td>{{character.id}}</td>
      </tr>
      <tr>
        <td>名前:</td>
        <td>{{character.name}}</td>
      </tr>
      <tr>
        <td>懸賞金:</td>
        <td>{{character.bounty}}ベリー</td>
      </tr>
    </table>
  </section>
</template>

この記事が気に入ったらサポートをしてみませんか?