基于UniApp与Vue3语法糖的跨平台待办事项应用开发实践

一、项目初始化与基础架构

1.1 环境配置与项目创建

bash 复制代码
# 使用Vite创建UniApp项目(需安装@dcloudio/uni-cli)
npm create vue@latest my-todo-app --template uni-app-vue3
cd my-todo-app
npm install

关键配置说明

  • vite.config.js中启用响应式语法糖:

    javascript 复制代码
    import { defineConfig } from 'vite'
    import uni from '@dcloudio/vite-plugin-uni'
    
    export default defineConfig({
      plugins: [
        uni({
          vueOptions: {
            reactivityTransform: true // 开启响应式语法糖
          }
        })
      ]
    })

    1.2 项目结构规划

    javascript 复制代码
    src/
    ├── components/       # 公共组件
    │   ├── TodoItem.vue # 单个待办项组件
    │   └── AddTodo.vue  # 添加待办组件
    ├── pages/            # 页面目录
    │   └── index/        # 首页
    │       ├── index.vue # 页面容器
    │       └── store.ts  # 状态管理
    ├── App.vue           # 应用入口
    └── main.js           # 应用配置

    二、核心组件开发:Vue3语法糖实战

    2.1 待办项组件(TodoItem.vue)

    html 复制代码
    <template>
      <view class="todo-item" :class="{ completed: todo.completed }">
        <!-- 使用v-model双向绑定复选框 -->
        <checkbox 
          :value="todo.completed" 
          @change="toggleComplete"
        />
        <text class="todo-text">{{ todo.text }}</text>
        <button @click="emitDelete" class="delete-btn">删除</button>
      </view>
    </template>
    
    <script setup>
    // 定义组件props(带类型校验)
    const props = defineProps({
      todo: {
        type: Object,
        required: true,
        validator: (value) => {
          return 'text' in value && 'completed' in value
        }
      }
    })
    
    // 定义组件事件
    const emit = defineEmits(['toggle', 'delete'])
    
    // 切换完成状态
    const toggleComplete = () => {
      emit('toggle', props.todo.id)
    }
    
    // 删除待办项
    const emitDelete = () => {
      emit('delete', props.todo.id)
    }
    </script>
    
    <style scoped>
    .todo-item {
      display: flex;
      align-items: center;
      padding: 12px;
      margin: 8px 0;
      background-color: #f8f8f8;
      border-radius: 8px;
    }
    
    .completed .todo-text {
      text-decoration: line-through;
      color: #999;
    }
    
    .delete-btn {
      margin-left: auto;
      background-color: #ff5252;
      color: white;
      padding: 4px 8px;
      border-radius: 4px;
    }
    </style>

    2.2 添加待办组件(AddTodo.vue)

    html 复制代码
    <template>
      <view class="add-todo">
        <input 
          v-model="inputValue" 
          placeholder="输入待办事项" 
          @keyup.enter="handleSubmit"
          class="todo-input"
        />
        <button @click="handleSubmit" class="submit-btn">添加</button>
      </view>
    </template>
    
    <script setup>
    import { ref } from 'vue'
    
    // 响应式输入值
    const inputValue = ref('')
    
    // 定义组件事件
    const emit = defineEmits(['add'])
    
    // 提交表单
    const handleSubmit = () => {
      if (inputValue.value.trim()) {
        emit('add', inputValue.value.trim())
        inputValue.value = '' // 清空输入框
      }
    }
    </script>
    
    <style scoped>
    .add-todo {
      display: flex;
      gap: 8px;
      margin-bottom: 20px;
    }
    
    .todo-input {
      flex: 1;
      padding: 10px;
      border: 1px solid #ddd;
      border-radius: 4px;
    }
    
    .submit-btn {
      padding: 10px 20px;
      background-color: #007aff;
      color: white;
      border-radius: 4px;
    }
    </style>

    三、状态管理与业务逻辑

    3.1 使用Pinia进行状态管理

    TypeScript 复制代码
    // src/pages/index/store.ts
    import { defineStore } from 'pinia'
    import { ref } from 'vue'
    
    interface TodoItem {
      id: string
      text: string
      completed: boolean
    }
    
    export const useTodoStore = defineStore('todo', () => {
      // 响应式状态
      const todos = ref<TodoItem[]>([])
      
      // 添加待办
      const addTodo = (text: string) => {
        todos.value.push({
          id: Date.now().toString(),
          text,
          completed: false
        })
      }
      
      // 切换完成状态
      const toggleTodo = (id: string) => {
        const todo = todos.value.find(t => t.id === id)
        if (todo) todo.completed = !todo.completed
      }
      
      // 删除待办
      const deleteTodo = (id: string) => {
        todos.value = todos.value.filter(t => t.id !== id)
      }
      
      return { todos, addTodo, toggleTodo, deleteTodo }
    })

    3.2 页面集成与逻辑处理

    html 复制代码
    <template>
      <view class="container">
        <h1>待办事项</h1>
        <AddTodo @add="handleAddTodo" />
        <view v-if="filteredTodos.length === 0" class="empty-tip">
          暂无待办事项
        </view>
        <view v-else>
          <TodoItem 
            v-for="todo in filteredTodos" 
            :key="todo.id"
            :todo="todo"
            @toggle="handleToggleTodo"
            @delete="handleDeleteTodo"
          />
        </view>
      </view>
    </template>
    
    <script setup>
    import { computed } from 'vue'
    import { useTodoStore } from './store'
    import AddTodo from '@/components/AddTodo.vue'
    import TodoItem from '@/components/TodoItem.vue'
    
    // 获取store实例
    const todoStore = useTodoStore()
    
    // 计算属性:过滤未完成事项
    const filteredTodos = computed(() => {
      return todoStore.todos.filter(todo => !todo.completed)
    })
    
    // 事件处理函数
    const handleAddTodo = (text) => {
      todoStore.addTodo(text)
    }
    
    const handleToggleTodo = (id) => {
      todoStore.toggleTodo(id)
    }
    
    const handleDeleteTodo = (id) => {
      todoStore.deleteTodo(id)
    }
    </script>
    
    <style scoped>
    .container {
      padding: 20px;
      max-width: 600px;
      margin: 0 auto;
    }
    
    .empty-tip {
      text-align: center;
      color: #999;
      padding: 20px;
    }
    </style>

    四、跨平台适配与优化

    4.1 平台差异处理

    javascript 复制代码
    // 适配不同平台样式
    const platformStyle = computed(() => {
      const systemInfo = uni.getSystemInfoSync()
      return {
        padding: systemInfo.platform === 'ios' ? '20px' : '10px',
        fontSize: systemInfo.windowWidth < 400 ? '14px' : '16px'
      }
    })

    4.2 性能优化策略

  • 虚拟滚动 :长列表使用scroll-viewscroll-y属性配合uni-list组件

  • 防抖处理 :输入框使用lodash的debounce优化搜索

  • 数据持久化 :通过uni.setStorageSync实现本地存储

    TypeScript 复制代码
    // 持久化存储
    const saveTodos = () => {
      uni.setStorageSync('todos', JSON.stringify(todoStore.todos))
    }
    
    // 初始化加载
    const loadTodos = () => {
      const saved = uni.getStorageSync('todos')
      if (saved) {
        todoStore.todos = JSON.parse(saved)
      }
    }

    4.3 多端发布配置

    TypeScript 复制代码
    // manifest.json配置示例
    {
      "mp-weixin": {
        "appid": "your-appid",
        "setting": {
          "urlCheck": false
        }
      },
      "h5": {
        "title": "待办事项",
        "router": {
          "mode": "hash"
        }
      }
    }
相关推荐
qq_3347347634 分钟前
uniapp uvew2 upload compressorjs 压缩图片
uni-app
ByteCraze35 分钟前
系统性整理组件传参14种方式
前端·javascript·vue.js
大杯咖啡36 分钟前
基于 Vue3 (tsx语法)的动态表单深度实践-只看这一篇就够了
前端·javascript·vue.js
Aniugel37 分钟前
Vue2简单实现一个权限管理
前端·vue.js
爱泡脚的鸡腿39 分钟前
uni-app D8 实战(小兔鲜)
前端·vue.js
izx88840 分钟前
JavaScript 中 `this` 的真相:由调用方式决定的动态指针
javascript
前端缘梦41 分钟前
JavaScript核心机制:执行栈、作用域与this指向完全解析
前端·javascript·面试
春卷同学1 小时前
拼图游戏 - Electron for 鸿蒙PC项目实战案例
javascript·electron·harmonyos
皮蛋瘦肉粥_1211 小时前
pink老师-jsAPIS-day1
javascript·apis