YouTip LogoYouTip

Vue3 Taskhub

## Vue3 Task Management System (Taskhub) In this tutorial, we will build a comprehensive **Vue 3 Task Management System (Taskhub)**. This hands-on project is designed to consolidate your knowledge of Vue 3 and its modern ecosystem by building a production-ready application. * **Core Features**: Interactive task board, category filtering, persistent data storage, dark mode toggle, and responsive design. * **Tech Stack**: Vue 3 (Script Setup) + Vite + Pinia + Vue Router + Element Plus + Tailwind CSS. --- ## Learning Objectives & Practical Value Building this task management system will help you master the following core concepts of the modern Vue ecosystem: | Learning Point | Practical Value in Production | | :--- | :--- | | **Composition API** | Move away from the fragmented Options API and organize code logically by feature. | | **Pinia** | Replace Vuex with a simpler API, better TypeScript support, and zero boilerplate. | | **Composables** | Master Vue 3's core design pattern for extracting and reusing stateful logic. | | **Tailwind CSS** | Utilize the industry-standard utility-first CSS framework to build beautiful, responsive UIs rapidly. | > **Source Code**: (https://static.jyshare.com/download/vue-task-hub-project.zip) --- ## Phase 1: Project Architecture & Environment Setup ### 1. Vite Configuration To ensure clean imports and optimal developer experience, we configure path aliases and auto-import plugins in `vite.config.js`: ```javascript import { defineConfig } from 'vite' import vue from '@vitejs/plugin-vue' import path from 'path' import AutoImport from 'unplugin-auto-import/vite' import Components from 'unplugin-vue-components/vite' import { ElementPlusResolver } from 'unplugin-vue-components/resolvers' export default defineConfig({ plugins: [ vue(), // Auto-import Vue, Vue Router, and Pinia APIs globally AutoImport({ imports: ['vue', 'vue-router', 'pinia'], resolvers: [ElementPlusResolver()], dts: 'src/auto-imports.d.mjs', }), Components({ resolvers: [ElementPlusResolver()], }), ], resolve: { alias: { // Configure '@' to point to the 'src' directory '@': path.resolve(__dirname, './src'), }, }, }) ``` ### 2. Project Standardization To maintain code quality across team environments, integrate ESLint, Prettier, and Husky: * **ESLint**: Enforces code quality rules and catches potential bugs. * **Prettier**: Formats code consistently on save. * **Husky**: Runs pre-commit hooks to ensure only linted, formatted code is committed to Git. ### 3. Styling with Tailwind CSS Tailwind CSS is integrated to enable rapid UI development using utility classes. Add Tailwind to your project styles: ```css /* src/assets/main.css */ @import "tailwindcss"; /* Custom global styles and theme variables */ :root { --el-color-primary: #4f46e5; /* Match Element Plus with Tailwind Indigo */ } ``` --- ## Phase 2: Deep Dive into Composition API ### 1. `ref` vs `reactive` Understanding when to use each reactive API is crucial for clean state management: * Use `ref()` for primitive values (`String`, `Number`, `Boolean`) and when you need to reassign entire arrays or objects. * Use `reactive()` for deeply nested objects or form states where the reference to the object never changes. ```typescript // Best Practice Example const searchKeyword = ref(''); // Use ref for primitives const taskForm = reactive({ // Use reactive for form groups title: '', description: '', priority: 'medium', dueDate: '' }); ``` ### 2. Computed Properties and Watchers * **`computed`**: Used to filter the task list in real-time based on selected categories or search queries. * **`watchEffect`**: Automatically tracks dependencies and synchronizes state (e.g., saving to local storage or fetching data when filters change). ```typescript // Real-time task filtering const filteredTasks = computed(() => { return tasks.value.filter(task => { const matchesSearch = task.title.toLowerCase().includes(searchKeyword.value.toLowerCase()); const matchesCategory = currentCategory.value === 'All' || task.category === currentCategory.value; return matchesSearch && matchesCategory; }); }); // Auto-sync state to localStorage watchEffect(() => { localStorage.setItem('taskhub_tasks', JSON.stringify(tasks.value)); }); ``` ### 3. Lifecycle Hooks Initialize resources when the component mounts and clean them up when it is destroyed to prevent memory leaks. ```typescript onMounted(() => { console.log('Taskhub initialized. Loading tasks...'); // Fetch initial data or set up event listeners }); onUnmounted(() => { console.log('Cleaning up event listeners...'); // Clear timers, cancel API requests, or remove global event listeners }); ``` --- ## Phase 3: Advanced Component Architecture ### 1. Component Communication Modern Vue uses compiler macros to define component interfaces: * `defineProps`: Receives data from parent components. * `defineEmits`: Sends events back to parent components. * `defineExpose`: Explicitly exposes methods or properties to parent components using `ref`. ```vue ``` ### 2. Dependency Injection (`provide` / `inject`) Avoid "prop drilling" in deeply nested component trees by providing state at the root level and injecting it where needed. ```javascript // Parent Component (App.vue) provide('theme', { isDarkMode, toggleTheme: () => { isDarkMode.value = !isDarkMode.value } }); // Deep Child Component (ThemeButton.vue) const { isDarkMode, toggleTheme } = inject('theme'); ``` ### 3. Slots (Named & Scoped Slots) Build highly reusable UI components like Modals and Lists by delegating layout and data rendering to the parent. ```vue ``` ### 4. Async Components Optimize initial page load times by lazy-loading heavy components (like charts or rich text editors) only when they are needed. ```javascript import { defineAsyncComponent } from 'vue'; const AsyncAnalyticsChart = defineAsyncComponent(() => import('@/components/AnalyticsChart.vue') ); ``` --- ## Phase 4: State Management & Routing ### 1. Pinia State Management Pinia acts as the central brain of the application. We split our state into modular stores: `UserStore` and `TaskStore`. ```javascript // src/stores/taskStore.js import { defineStore } from 'pinia'; export const useTaskStore = defineStore('tasks', { state: () => ({ tasks: JSON.parse(localStorage.getItem('tasks')) || [], loading: false }), getters: { completedTasksCount: (state) => state.tasks.filter(t => t.completed).length, }, actions: { addTask(task) { this.tasks.push({ ...task, id: Date.now(), completed: false }); }, deleteTask(id) { this.tasks = this.tasks.filter(t => t.id !== id); } } }); ``` #### ⚠️ The Destructuring Trap (`storeToRefs`) When destructuring state from a Pinia store, direct destructuring breaks reactivity. Always use `storeToRefs` to preserve reactivity. ```javascript // ❌ INCORRECT: Breaks reactivity const { tasks } = useTaskStore(); // CORRECT: Maintains reactivity const taskStore = useTaskStore(); const { tasks } = storeToRefs(taskStore); ``` ### 2. Vue Router & Navigation Guards Secure routes and manage page transitions using dynamic routing and meta fields. ```javascript // src/router/index.js import { createRouter, createWebHistory } from 'vue-router'; const routes = [ { path: '/', component: () => import('@/views/Dashboard.vue'), meta: { requiresAuth: true, title: 'Dashboard - Taskhub' } }, { path: '/login', component: () => import('@/views/Login.vue'), meta: { title: 'Login - Taskhub' } } ]; const router = createRouter({ history: createWebHistory(), routes }); // Navigation Guard (Auth Guard) router.beforeEach((to, from, next) => { const isAuthenticated = !!localStorage.getItem('user_token'); // Update document title dynamically document.title = to.meta.title || 'Taskhub'; if (to.meta.requiresAuth && !isAuthenticated) { next('/login'); } else { next(); } }); export default router; ``` --- ## Phase 5: Logic Reuse & Performance Optimization ### 1. Custom Composables Extract reusable stateful logic into clean, testable functions. Below is a custom composable for managing local storage reactively: ```javascript // src/composables/useLocalStorage.js import { ref, watch } from 'vue'; export function useLocalStorage(key, defaultValue) { const storedValue = localStorage.getItem(key); const data = ref(storedValue ? JSON.parse(storedValue) : defaultValue); watch(data, (newValue) => { localStorage.setItem(key, JSON.stringify(newValue)); }, { deep: true }); return data; } ``` ### 2. Performance Tuning * **`shallowRef` & `markRaw`**: Use these to prevent Vue from deeply tracking large, read-only datasets (e.g., complex third-party chart instances or large API responses), significantly reducing CPU overhead. * **`v-once` & `v-memo`**: Use `v-once` for static content that never updates. Use `v-memo` to conditionally skip re-rendering in long lists unless specific dependencies change. ```vue

{{ item.name }} - {{ item.status }}

``` --- ## Phase 6: Production Deployment & Engineering ### 1. Environment Variables Configure environment variables for different stages of your pipeline: * **`.env.development`**: ```env VITE_API_BASE_URL=http://localhost:3000/api ``` * **`.env.production`**: ```env VITE_API_BASE_URL=https://api.taskhub.com/v1 ``` ### 2. Build Optimization (Vite Manual Chunks) To prevent generating a single massive JavaScript bundle, configure Vite to split vendor libraries into separate chunks for better browser caching: ```javascript // vite.config.js (Partial) build: { rollupOptions: { output: { manualChunks(id) { if (id.includes('node_modules')) { if (id.includes('element-plus')) return 'element-plus'; if (id.includes('vue') || id.includes('pinia')) return 'vue-core'; return 'vendor'; // Other third-party libraries } } } } } ``` ### 3. Automated Deployment (GitHub Actions) Automate your build and deployment process using a CI/CD workflow: ```yaml # .github/workflows/deploy.yml name: Deploy Taskhub on: push: branches: jobs: build-and-deploy: runs-on: ubuntu-latest steps: - name: Checkout Code uses: actions/checkout@v3 - name: Setup Node.js uses: actions/setup-node@v3 with: node-version: 18 - name: Install Dependencies run: npm ci - name: Build Project run: npm run build - name: Deploy to Hosting (e.g., GitHub Pages, Vercel, or VPS) run: | # Add your deployment commands here echo "Deploying build artifacts..." ```
← Claude Code IntroJupyter Notebook Vscode β†’