ミックスイン

ミックスインは、Vueコンポーネント間で共通のロジックを共有するための機能です。

ミックスイン
記法

const ミックスイン名 = {
 =============
 ミックスインの定義
 =============
};

<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>ミックスインについて</title>
    <link rel="stylesheet" href="./main.css" />
  </head>
  <body>
    <div id="app">
      <div class="title">{{ title }}</div>
      <div class="task-input">
        <input v-model="newTask" placeholder="新しいタスクを入力してください" />
        <select v-model="taskListType">
          <option value="main">メインタスクリスト</option>
          <option value="sub">サブタスクリスト</option>
        </select>
        <button class="task-input-btn" @click="addTask">追加</button>
      </div>
      <task-list
        :tasks="mainTasks"
        title="メインタスクリスト"
        @remove-task="removeTask"
      ></task-list>
      <task-list
        :tasks="subTasks"
        title="サブタスクリスト"
        @remove-task="removeTask"
      ></task-list>
    </div>
    <!-- CDN -->
    <script src="CDNのURL"></script>
    <script src="./main.js"></script>
  </body>
</html>
// ミックスインの定義
const taskMixin = {
  methods: {
    toggleTask(id) {
      const task = this.tasks.find((task) => task.id === id);
      task.completed = !task.completed;
    },
    removeTask(id) {
      this.$emit("remove-task", id);
    },
  },
};

// タスクリストコンポーネントの定義
const TaskList = {
  mixins: [taskMixin],
  props: ["tasks", "title"],
  template: `
    <div class="task-list">
      <div class="list-title">{{ title }}</div>
      <ul>
        <li v-for="task in tasks" :key="task.id">
          <span class="task-name">{{ task.name }}</span> <span :class="{ 'completed': task.completed }">{{ task.completed ? '完了' : '未完了' }}</span>
          <button @click="toggleTask(task.id)" class="toggle-button">切り替え</button>
          <button @click="removeTask(task.id)" class="delete-button">削除</button>
        </li>
      </ul>
    </div>
  `,
};

// メインアプリケーションの定義
const app = Vue.createApp({
  components: {
    TaskList,
  },
  data() {
    return {
      title: "タスク管理システム",
      newTask: "",
      taskListType: "main",
      mainTasks: [
        { id: 1, name: "タスク1", completed: false },
        { id: 2, name: "タスク2", completed: true },
      ],
      subTasks: [{ id: 3, name: "タスク3", completed: false }],
    };
  },
  methods: {
    addTask() {
      if (this.newTask.trim()) {
        const newTask = {
          id: Date.now(),
          name: this.newTask.trim(),
          completed: false,
        };
        if (this.taskListType === "main") {
          this.mainTasks.push(newTask);
        } else {
          this.subTasks.push(newTask);
        }
        this.newTask = "";
      }
    },
    removeTask(id) {
      this.mainTasks = this.mainTasks.filter((task) => task.id !== id);
      this.subTasks = this.subTasks.filter((task) => task.id !== id);
    },
  },
});
app.mount("#app");
.app-body {
  font-family: Arial, sans-serif;
  background-color: #f8f9fa;
  padding: 20px;
}

.title {
  font-size: 24px;
  color: #007bff;
  margin-bottom: 20px;
  text-align: center;
}

.task-input {
  display: flex;
  justify-content: center;
  margin-bottom: 20px;
}

.task-input input {
  width: 300px;
  padding: 10px;
  margin-right: 10px;
  border: 1px solid #dee2e6;
  border-radius: 5px;
}

.task-input select {
  padding: 10px;
  margin-right: 10px;
  border: 1px solid #dee2e6;
  border-radius: 5px;
}

.task-input button {
  background-color: #007bff;
  color: #ffffff;
  border: none;
  padding: 10px 15px;
  border-radius: 5px;
  cursor: pointer;
}

.task-input button:hover {
  background-color: #0056b3;
}

.task-list {
  background-color: #ffffff;
  border: 1px solid #dee2e6;
  border-radius: 5px;
  padding: 15px;
  margin-bottom: 20px;
  box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
}

.list-title {
  font-size: 20px;
  margin-bottom: 10px;
  color: #495057;
}

.task-list ul {
  list-style-type: none;
  padding: 0;
}

.task-list li {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 10px;
  border-bottom: 1px solid #dee2e6;
}

.task-list li:last-child {
  border-bottom: none;
}

.task-name {
  flex-grow: 1;
}

.completed {
  color: green;
}

.task-list button {
  color: #ffffff;
  border: none;
  padding: 5px 10px;
  border-radius: 3px;
  cursor: pointer;
  margin-left: 5px;
}

.toggle-button {
  background-color: #28a745;
  color: #ffffff;
  border: none;
  padding: 5px 10px;
  border-radius: 3px;
  cursor: pointer;
  margin-left: 5px;
}

.toggle-button:hover {
  background-color: #218838;
}

.delete-button {
  background-color: #dc3545;
  color: #ffffff;
  border: none;
  padding: 5px 10px;
  border-radius: 3px;
  cursor: pointer;
  margin-left: 5px;
}

.delete-button:hover {
  background-color: #c82333;
}
出力結果
{{ title }}