SOURCE

console 命令行工具 X clear

                    
>
console
const { createApp, ref, computed, onMounted, watch } = Vue;

createApp({
  setup() {
    // 数据
    const tasks = ref([
      { id: 1, text: '学习Vue 3', completed: false },
      { id: 2, text: '完成项目', completed: false },
      { id: 3, text: '提交报告', completed: true },
    ]);
    const newTask = ref('');
    const filter = ref('all');
    const editingTaskIndex = ref(-1);
    const editedTaskText = ref('');
    
    // 计算属性
    const filteredTasks = computed(() => {
      switch(filter.value) {
        case 'active':
          return tasks.value.filter(task => !task.completed);
        case 'completed':
          return tasks.value.filter(task => task.completed);
        default:
          return tasks.value;
      }
    });
    
    const completedTasks = computed(() => {
      return tasks.value.filter(task => task.completed);
    });
    
    // 方法
    const addTask = () => {
      if (newTask.value.trim() === '') return;
      
      tasks.value.push({
        id: Date.now(),
        text: newTask.value,
        completed: false
      });
      
      newTask.value = '';
    };
    
    const toggleTask = (index) => {
      tasks.value[index].completed = !tasks.value[index].completed;
    };
    
    const removeTask = (index) => {
      tasks.value.splice(index, 1);
    };
    
    const clearCompleted = () => {
      tasks.value = tasks.value.filter(task => !task.completed);
    };
    
    const startEditing = (index) => {
      editingTaskIndex.value = index;
      editedTaskText.value = tasks.value[index].text;
    };
    
    const finishEditing = () => {
      if (editedTaskText.value.trim() === '') {
        removeTask(editingTaskIndex.value);
      } else {
        tasks.value[editingTaskIndex.value].text = editedTaskText.value;
      }
      editingTaskIndex.value = -1;
    };
    
    // 生命周期钩子
    onMounted(() => {
      // 从本地存储加载任务
      const savedTasks = localStorage.getItem('vue3-tasks');
      if (savedTasks) {
        tasks.value = JSON.parse(savedTasks);
      }
    });
    
    // 监听任务变化,保存到本地存储
    watch(tasks, (newTasks) => {
      localStorage.setItem('vue3-tasks', JSON.stringify(newTasks));
    }, { deep: true });
    
    return {
      tasks,
      newTask,
      filter,
      filteredTasks,
      completedTasks,
      addTask,
      toggleTask,
      removeTask,
      clearCompleted,
      startEditing,
      finishEditing,
      editingTaskIndex,
      editedTaskText
    };
  }
}).mount('#app');
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Vue 3 待办事项应用</title>
  <script src="https://cdn.tailwindcss.com"></script>
  <link href="https://cdn.jsdelivr.net/npm/font-awesome@4.7.0/css/font-awesome.min.css" rel="stylesheet">
  <script src="https://cdn.jsdelivr.net/npm/vue@3.2.47/dist/vue.global.prod.min.js"></script>
  
  <!-- Tailwind 配置 -->
  <script>
    tailwind.config = {
      theme: {
        extend: {
          colors: {
            primary: '#4CAF50',
            secondary: '#f44336',
            neutral: '#f9f9f9',
          },
          fontFamily: {
            sans: ['Inter', 'system-ui', 'sans-serif'],
          },
        },
      }
    }
  </script>
  
  <!-- 引入外部 CSS -->
  <link rel="stylesheet" href="style.css">
</head>
<body class="bg-gray-50 min-h-screen">
  <div id="app" class="max-w-md mx-auto px-4 py-8">
    <div class="bg-white rounded-xl shadow-lg p-6 transform transition-all duration-300 hover:shadow-xl">
      <h1 class="text-[clamp(1.5rem,3vw,2rem)] font-bold text-gray-800 mb-6 flex items-center">
        <i class="fa fa-tasks text-primary mr-2"></i>
        <span>待办事项</span>
      </h1>
      
      <div class="flex items-center mb-6">
        <input 
          v-model="newTask" 
          @keyup.enter="addTask"
          type="text" 
          placeholder="添加新任务..." 
          class="task-input"
        >
        <button 
          @click="addTask" 
          class="btn btn-primary ml-3"
        >
          <i class="fa fa-plus mr-1"></i> 添加
        </button>
      </div>
      
      <div class="mb-4">
        <div class="flex justify-between items-center mb-2">
          <span class="text-sm text-gray-500">
            共 {{ tasks.length }} 个任务,已完成 {{ completedTasks.length }} 个
          </span>
          <div class="flex space-x-2">
            <button 
              @click="filter = 'all'" 
              :class="['filter-btn', filter === 'all' ? 'active' : '']"
            >
              全部
            </button>
            <button 
              @click="filter = 'active'" 
              :class="['filter-btn', filter === 'active' ? 'active' : '']"
            >
              未完成
            </button>
            <button 
              @click="filter = 'completed'" 
              :class="['filter-btn', filter === 'completed' ? 'active' : '']"
            >
              已完成
            </button>
          </div>
        </div>
        
        <ul class="task-list space-y-2 max-h-[300px] overflow-y-auto pr-1">
          <li 
            v-for="(task, index) in filteredTasks" 
            :key="task.id" 
            class="task-item"
            :class="{ 'completed': task.completed }"
          >
            <div class="flex items-center">
              <input 
                type="checkbox" 
                :checked="task.completed" 
                @change="toggleTask(index)" 
                class="mr-3 h-5 w-5 text-primary focus:ring-primary rounded"
              >
              <span>{{ task.text }}</span>
            </div>
            <button 
              @click="removeTask(index)" 
              class="btn btn-secondary p-1.5"
            >
              <i class="fa fa-trash-o"></i>
            </button>
          </li>
        </ul>
        
        <div v-if="filteredTasks.length === 0" class="empty-state text-center py-8 text-gray-400">
          <i class="fa fa-check-circle text-4xl mb-2 block"></i>
          <p>没有任务了,休息一下吧!</p>
        </div>
      </div>
      
      <button 
        v-if="tasks.length > 0" 
        @click="clearCompleted" 
        class="btn btn-secondary w-full"
      >
        <i class="fa fa-trash mr-1"></i> 清除已完成任务
      </button>
    </div>
    
    <footer class="mt-8 text-center text-gray-400 text-sm">
      <p>双击任务可以编辑内容</p>
    </footer>
  </div>

  <!-- 引入外部 JavaScript -->
  <script src="script.js"></script>
</body>
</html>