Uncategorized

機能ごとにページを分ける

現場1画面に集約されてしまっているため
機能ごとにページを分けていきます

ステップ2:ルーティングの設定

src ディレクトリに router フォルダを作成し、その中に index.js ファイルを作成します。このファイルでルーティングの設定を行います。

src/router/index.js の記述:

JavaScript

import { createRouter, createWebHistory } from "vue-router";
import PomodoroTimer from "../components/PomodoroTimer.vue";
import PomodoroCalendar from "../components/PomodoroCalendar.vue";

const routes = [
  {
    path: "/",
    name: "Home",
    component: PomodoroTimer,
  },
  {
    path: "/calendar",
    name: "Calendar",
    component: PomodoroCalendar,
  },
];

const router = createRouter({
  history: createWebHistory(),
  routes,
});

export default router;

解説:

  • createRoutercreateWebHistory を Vue Router からインポートします。createWebHistory() はブラウザの履歴 API を使用したルーティングモードです。
  • PomodoroTimer.vuePomodoroCalendar.vue をそれぞれのコンポーネントのパスからインポートします。
  • routes 配列でパスとコンポーネントの対応を定義します。
    • / パスには PomodoroTimer コンポーネントを割り当て、名前を Home とします。これがトップ画面になります。
    • /calendar パスには PomodoroCalendar コンポーネントを割り当て、名前を Calendar とします。これがカレンダー画面になります。
  • createRouter 関数に historyroutes を渡してルーターインスタンスを作成します。
  • 作成したルーターインスタンスを export default router; でエクスポートします。

ステップ3:main.js の修正

作成したルーターを Vue アプリケーションに組み込むために、src/main.js を修正します。

src/main.js の修正:

JavaScript

import { createApp } from "vue";
import App from "./App.vue";

import router from "./router"; // ルーターをインポート

const app = createApp(App);
app.use(router); // ルーターを Vue アプリケーションに登録
app.mount("#app");

解説:

  • import router from './router'; で作成したルーターインスタンスをインポートします。
  • app.use(router); で Vue アプリケーションにルーターを登録します。これにより、<router-link><router-view> などのルーティング関連コンポーネントが使用できるようになります。

ステップ4:App.vue の修正

App.vue を修正して、ルーティングの切り替えを行うための <router-view> コンポーネントと、画面遷移のためのリンク <router-link> を追加します。

src/App.vue の修正:

HTML

<template>
  <div>
    <nav>
      <router-link to="/">タイマー</router-link> |
      <router-link to="/calendar">カレンダー</router-link>
    </nav>
    <router-view></router-view>
  </div>
</template>

<script>
export default {
  name: 'App',
};
</script>

<style>
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}

nav {
  padding: 30px;
}

nav a {
  font-weight: bold;
  color: #2c3e50;
  text-decoration: none;
}

nav a.router-link-exact-active {
  color: #42b983;
}
</style>

1 解説:  

1. github.com

github.com

  • <nav> タグ内に、<router-link to="/">タイマー</router-link><router-link to="/calendar">カレンダー</router-link> を追加しました。
    • <router-link to="..."> は、指定されたパスへのリンクを生成するコンポーネントです。クリックすると、Vue Router が対応するコンポーネントを表示します。
    • to="/": ルートパス(トップ画面)へのリンクを作成します。
    • to="/calendar": /calendar パス(カレンダー画面)へのリンクを作成します。
  • <router-view></router-view>: 現在のルートに対応するコンポーネントがレンダリングされる場所です。URL が / であれば PomodoroTimer が、/calendar であれば PomodoroCalendar がここに表示されます。
  • <style> タグでは、ナビゲーションのスタイルと、アクティブなリンクのスタイルを設定しています。

上記の編集を行ったことでページを遷移できるようになった

追加 -カレンダー画面でタイマーを非表示にする

修正方針:

  1. App.vue で作業終了時に受け取ったログを calendarWorkLogs に保持する。
  2. PomodoroCalendarpropsworkLogs を監視し、変更があった場合に内部の calendarWorkLogs を更新する。 これにより、App.vue から渡された新しいログがカレンダーに反映されます。

追加前のコード (App.vue<script> 部分):

JavaScript

import PomodoroTimer from "./components/PomodoroTimer.vue";
import PomodoroCalendar from "./components/PomodoroCalendar.vue";
import { useRoute } from "vue-router";
import { ref } from "vue";

export default {
  name: "App",
  components: {
    PomodoroTimer,
    PomodoroCalendar,
  },
  setup() {
    const route = useRoute();
    const calendarRef = ref(null); // PomodoroCalendar コンポーネントの参照
    const calendarWorkLogs = ref([]); // (一旦保持用として残しますが、直接メソッドを呼ぶため必須ではありません)

    const handleWorkFinished = (logData) => {
      console.log("App.vue で作業終了イベントを受け取りました:", logData);
      if (route.path === "/calendar" && calendarRef.value) {
        calendarRef.value.addWorkLog(logData); // カレンダーコンポーネントの addWorkLog を直接呼び出す
      } else {
        calendarWorkLogs.value.push(logData); // カレンダーが非表示の場合は一旦保持
      }
    };

    return { route, calendarRef, calendarWorkLogs, handleWorkFinished };
  },
  mounted() {
    // ページロード時や画面遷移時に、保持しているログをカレンダーに反映
    this.$watch(
      () => this.$route.path,
      (newPath) => {
        if (
          newPath === "/calendar" &&
          this.calendarRef &&
          this.calendarWorkLogs.value.length > 0
        ) {
          this.calendarWorkLogs.value.forEach((log) => {
            this.calendarRef.addWorkLog(log);
          });
          this.calendarWorkLogs.value = []; // 反映後にクリア
        }
      },
      {} // ウォッチャーオプション(今回は不要ですが、Prettierの整形に合わせて記述)
    );
  },
};

追加後のコード (App.vue<script> 部分):

JavaScript

import PomodoroTimer from "./components/PomodoroTimer.vue";
import PomodoroCalendar from "./components/PomodoroCalendar.vue";
import { useRoute } from "vue-router";
import { ref } from "vue";

export default {
  name: "App",
  components: {
    PomodoroTimer,
    PomodoroCalendar,
  },
  setup() {
    const route = useRoute();
    const calendarWorkLogs = ref([]); // カレンダーに渡す作業ログ

    const handleWorkFinished = (logData) => {
      console.log("App.vue で作業終了イベントを受け取りました:", logData);
      calendarWorkLogs.value.push(logData); // 作業終了時にログを calendarWorkLogs に追加
    };

    return { route, calendarWorkLogs, handleWorkFinished };
  },
};

追加後のコード (PomodoroCalendar.vue<script> 部分):

JavaScript

export default {
  name: "PomodoroCalendar",
  props: {
    workLogs: {
      type: Array,
      default: () => [],
    },
  },
  data() {
    const today = new Date();
    const currentYear = today.getFullYear();
    const currentMonth = today.getMonth() + 1;
    return {
      year: currentYear,
      month: currentMonth,
      daysOfWeek: ["日", "月", "火", "水", "木", "金", "土"],
      todayDate: today.getDate(),
      todayMonth: currentMonth,
      todayYear: currentYear,
      calendarWorkLogs: [...this.workLogs], // props の値を初期値として使用
    };
  },
  watch: {
    workLogs(newWorkLogs) {
      this.calendarWorkLogs = [...newWorkLogs]; // props が更新されたら data も更新
    },
  },
  computed: {
    daysInMonth() {
      return new Date(this.year, this.month, 0).getDate();
    },
    firstDayOfMonth() {
      return new Date(this.year, this.month - 1, 1).getDay();
    },
    calendarGrid() {
      const grid = [];
      let week = [];
      let dayCounter = 1;
      for (let i = 0; i < this.firstDayOfMonth; i++) {
        week.push(null);
      }
      while (dayCounter <= this.daysInMonth) {
        week.push(new Date(this.year, this.month - 1, dayCounter));
        if (week.length === 7) {
          grid.push(week);
          week = [];
        }
        dayCounter++;
      }
      while (week.length < 7 && week.length > 0) {
        week.push(null);
      }
      if (week.length > 0) {
        grid.push(week);
      }
      return grid;
    },
  },
  methods: {
    isToday(date) {
      return (
        date &&
        date.getDate() === this.todayDate &&
        date.getMonth() + 1 === this.todayMonth &&
        date.getFullYear() === this.todayYear
      );
    },
    getWorkLogsForDate(date) {
      if (!date) {
        return [];
      }
      const formattedDate = `${date.getFullYear()}-${(date.getMonth() + 1)
        .toString()
        .padStart(2, "0")}-${date.getDate().toString().padStart(2, "0")}`;
      return this.calendarWorkLogs.filter((log) => log.date === formattedDate);
    },
  },
};
</script>

追加後の変更点と説明:

1. App.vue<script> の変更:

  • 変更前: handleWorkFinished でカレンダーが表示されている場合に calendarRef.value.addWorkLog(logData) を直接呼び出し、そうでない場合は calendarWorkLogs.value.push(logData) で保持していました。また、mounted フックで画面遷移時に保持しているログをカレンダーに反映しようとしていました。
  • 変更後: handleWorkFinished では、常に 受け取った logDatacalendarWorkLogs.value.push(logData) で保持するように変更しました。カレンダーが表示されているかどうかに関わらず、作業ログは calendarWorkLogs に蓄積されます。mounted フックとその関連コードを削除しました。

変更の理由:

  • カレンダーコンポーネントのメソッドを親コンポーネントから直接呼び出すのは、コンポーネント間の依存性を高めるため、よりデータバインディングの仕組みに沿った形に変更します。
  • 画面遷移時にログを反映する処理は、propswatch を使うことでよりリアクティブに実現できます。

2. PomodoroCalendar.vue<script> の変更:

  • 変更前: propsworkLogs を受け取っていましたが、その値が変更されても自動的にカレンダーの表示は更新されませんでした。
  • 変更後: watch オプションを追加し、workLogs props が変更されたときに、内部の calendarWorkLogs[...newWorkLogs] で更新するようにしました。

追加の理由:

  • props は親コンポーネントから子コンポーネントへデータを渡すための仕組みです。App.vuecalendarWorkLogs が更新されると、PomodoroCalendarworkLogs props も自動的に更新されます。
  • watch を使うことで、workLogs props の変更を監視し、変更があった場合にカレンダーの表示に必要な calendarWorkLogs を更新することで、画面がリアクティブに更新されます。

これらの変更を加えることで、タイマーが終了すると App.vuecalendarWorkLogs が更新され、その変更が PomodoroCalendarworkLogs props を通じて監視され、カレンダーの表示が更新されるようになります。

-Uncategorized