[新手入门]todolist增删改查:vue3+ts版本!

简介: 【10月更文挑战第15天】[新手入门]todolist增删改查:vue3+ts版本!

项目需求

前端的待办事项应用(To-Do List)是一个经典的练习项目,非常适合初学者。这个项目虽然看似简单,但涵盖了许多前端开发的核心概念和技术。那么,本文就实现简单的增删改查功能,实现效果如下图:

image.png

使用脚手架安装相关依赖

使用vueCli 安装预设的vuex+ts+less+router

## 查看@vue/cli版本,确保@vue/cli版本在4.5.0以上
vue --version

## 安装或者升级你的@vue/cli
npm install -g @vue/cli

## 创建
vue create vue3_todo          //create vue3_cli_todo为自定义文件名

按方向键 ↓,选择Manually select features,enter

手动配置:是我们所需要的面向生产的项目,提供可选功能的 npm 包

手动配置,根据你需要用方向键选择(按 “空格键”选择/取消选择,A键全选/取消全选,i反选)对应功能

  1. ? Check the features needed for your project: (Press to select, to toggle all, to invert selection)
  2. ( ) TypeScript // JavaScript的一个超集(添加了可选的静态类型和基于类的面向对象编程:类型批注和编译时类型检查、类、接口、模块、lambda 函数)

  3. ( ) Progressive Web App (PWA) Support // 渐进式Web应用程序
  4. () Router // vue-router(vue路由)
  5. () Vuex // vuex(vue的状态管理模式)
  6. () CSS Pre-processors // CSS 预处理器(如:less、sass)
  7. () Linter / Formatter // 代码风格检查和格式化(如:ESlint)
  8. () Unit Testing // 单元测试(unit tests)
  9. () E2E Testing // e2e(end to end) 测试

我们选择如下

确认enter后,需要选择vue版本,选择3.x的版本然后继续确认

然后如下配置

是否使用class风格的组件语法:Use class-style component syntax?输入N

目录解析

├─ babel.config.js
├─ package-lock.json
├─ package.json
├─ public
│  ├─ favicon.ico
│  └─ index.html
├─ README.md
├─ src
│  ├─ App.vue
│  ├─ assets
│  ├─ components
│  │  ├─ TodoInput               //输入框组件
│  │  │  └─ index.vue  
│  │  └─ TodoList
│  │     ├─ index.vue            //数据组件
│  │     └─ Item.vue
│  ├─ hooks
│  │  └─ index.ts                //公用的hook函数
│  ├─ main.ts                    //入口文件
│  ├─ shims-vue.d.ts             //让Vue识别TS的文件
│  ├─ store
│  │  ├─ actions.ts
│  │  ├─ actionTypes.ts          //派发事件
│  │  ├─ index.ts
│  │  ├─ mutations.ts
│  │  └─ state.ts
│  └─ typings
│     └─ index.ts                //定义vuex中的数据类型,方便使用TS
└─ tsconfig.json

实现路线简析

入口文件

src\main.ts

import {
     createApp } from 'vue' // 引入 Vue 3 中的 createApp 函数
import App from './App.vue' // 引入根组件 App.vue
import store from './store' // 引入 Vuex store
import './assets/style/reset.less' // 引入样式重置文件(使用 Less 预处理器)

// 创建 Vue 应用实例
const app  = createApp(App)

// 使用 Vuex store 插件,并将应用挂载到 id 为 'app' 的 DOM 元素上
app.use(store).mount('#app')

store

store一个基于Vuex的状态管理模块,我们将使用它管理待办事项列表(To-Do List)的状态。通过分离actions、mutations和state,这使代码更加模块化和可维护。

│  ├─ store
│  │  ├─ actions.ts
│  │  ├─ index.ts
│  │  ├─ mutations.ts
│  │  └─ state.ts

src\store\actions.ts

import {
     IState, IList } from "@/typings"
import {
     Commit } from "vuex"
//context对象声明
interface Icontext {
    
    commit: Commit,
    state: IState
}
export default {
    
    //获取数据列表
    // query包含两个参数,context对象,和payload参数
    // context对象包含 commit和state两个参数
    query(context: Icontext,todoList: IList[]): void {
    
        context.commit("query",todoList)
    }, 
}

定义了一个actions对象,用于处理异步操作或复杂的业务逻辑。

query方法接收contexttodoList,使用context.commit调用mutations中的query方法,更新状态。

src\store\mutations.ts

import {
     IState, IList,} from "@/typings"

export default {
    
    query(state: IState, todoList: IList[]): void{
    
        state.list = todoList
    }, 
}

定义了一个mutations对象,用于同步地修改状态。

query方法接收当前状态state和一个新的待办事项列表todoList,并将新的列表赋值给状态中的list

src\store\state.ts

import {
     IState } from "@/typings"
// 这里使用了类型断言的方式对导出的对象进行了声明: <类型>值
export default <IState> {
    
    list: []
}

定义了应用的初始状态。

list初始化为空数组,表示初始状态下没有待办事项。
src\store\index.ts

import {
     createStore } from 'vuex'
import state from './state'
import mutations from './mutations'
import actions from './actions'
export default createStore({
    
  state,
  mutations,
  actions,
})

使用Vuex的createStore方法创建一个新的Store实例。

将定义好的statemutationsactions模块整合在一起,形成一个完整的Vuex Store。

src\typings\index.ts

//接口返回的数据列表类型声明
interface IList {
    
    id: number,
    content: string,
    status:TODO_STATUS,
    createTime: number
}
//state类型定义
interface IState {
    
    list: IList[]
}
enum  TODO_STATUS {
    
    WILLDO = 'willdo',
    DOING = 'doing',
    FINISHED = 'finished'
}
export{
    
    TODO_STATUS,
    IState,
    IList
}

定义了类型接口和枚举,确保在操作状态时有明确的类型约束。

IList接口描述了每个待办事项的结构。

IState接口描述了Vuex状态中list的结构。

TODO_STATUS枚举定义了待办事项的三种状态:WILLDODOINGFINISHED

App.vue

<template>
  <div class="wrapper">
    <TodoInput></TodoInput>
    <TodoList :todoList="todoList"></TodoList>
  </div>
</template>

<script lang="ts">
import {
      computed, defineComponent, onMounted } from 'vue';
import {
      Store, useStore } from 'vuex';
import TodoInput from './components/TodoInput/index.vue';
import TodoList from './components/TodoList/index.vue'
import {
      IUseTodo, useTodo } from './hooks';
//defineComponent是为了帮助Ts语法有更好的类型提示
export default defineComponent({
     
  name: 'App',
  components: {
     
    TodoList,TodoInput
  },
  setup () {
     
    //useTodo是封装了增删改查函数的一个总函数;IUseTodo是函数定义
    const {
      query }: IUseTodo = useTodo();
    //获取vuex的store对象
    const store: Store<any> = useStore()
    onMounted( () => {
     
      //列表初始化
      query();
    })
    return {
     
      todoList : computed(() => store.state.list)
    }
  }

});
</script>

<style lang="less">

</style>

上面的代码是一个Vue 3组件,用于管理和显示一个待办事项列表。其中

  • <TodoInput>组件用于用户输入
  • <TodoList>组件用于列表显示

    hooks

//用于封装组件的公用方法
import {
     Store, useStore } from "vuex"
import axios from "../proxy";
//排序函数
function compare(property : any) {
    
    return function (value1: any, value2: any) {
    
      let v1 = value1[property];
      let v2 = value2[property];
      return v2 - v1
    }
  }
//定义useTodo ()函数接口
export interface IUseTodo {
    
    query: () => void,
    add: (value: string) => void,
    remove: (id: number) => void,
    edit: (item: object) => void,
}
//封装增删改查相关函数
function useTodo (): IUseTodo {
    
    //使用vuex中的store
    const store: Store<any> = useStore(); 
    //1.查询数据 
    function query() {
    
        axios.getList().then((res)=>{
    
            let data = res.data
            data.forEach((res: {
     status: any; }) => {
    
                switch(res.status){
    
                    case 1:
                        res.status = 'willdo'
                        break;
                    case 0:
                        res.status = 'doing'
                        break;
                    case 2:
                        res.status = 'finished'
                        break;
                    default:
                        return
                }
            });
            data = data.sort(compare('createTime'))
            store.dispatch("query", data)
        })
    }
    //2.增加数据   ----->函数输入字符串数据,没有返回值
    function add(value: string): void {
    
        let data = {
    
            content: value,
        }
        axios.addList(data).then(res => {
    
            //数据增加成功后,重新获取数据列表
            query()
        })
    }
    //3.删除数据 
    function remove(id: string | number): void {
    
        axios.deleteList({
     id }).then(res => {
    
            //根据id进行数据删除
            query()
        })   
    }
    //4.更改数据
    function edit(item: any): void {
    
        let data = {
    
            id:item.id,
            content:item.content,
            status:2
        }
        axios.editList(data).then(res => {
    
            query()
        })   
    }
    return {
     query, add,remove, edit }
}
export {
    
    useTodo
}

使用vue3提供的hooks函数将代码逻辑进行了抽象,逻辑更加清晰

proxy

import axios from 'axios';
const baseUrl = 'http://47.97.50.125:8989/todoList/'

const httpUrl = {
    
    getList:baseUrl + 'list/?token=',
    editList:baseUrl + 'editList',
    deleteList:baseUrl + 'deleteList',
    addList:baseUrl + 'addList',
}

//获取列表
function getList(){
    
    return axios.get(httpUrl.getList)
}
//编辑列表
function editList(editData: object) {
    
    return axios.post(httpUrl.editList,editData)
}
//删除列表
function deleteList(deleteData: object) {
    
    return axios.post(httpUrl.deleteList,deleteData)
}
//新增列表
function addList(addData: object) {
    
    return axios.post(httpUrl.addList,addData)
}

export default{
    
    getList,
    editList,
    deleteList,
    addList
}

上述代码片段展示了一个用于与后端待办事项(To-Do List)API进行交互的模块。这个模块使用axios库来发送HTTP请求,并且定义了几个方法来处理不同的操作,包括获取列表、编辑列表、删除列表和新增列表。

TodoInput

src\components\TodoInput\index.vue:

<template>
    <div>
        <div class="wrap" @mouseleave="clearVisible = false">
          <input type="text" v-model="todoValue"  @keyup="setTodoValue" @focus="clearVisible = true" />
          <span class="ensure" @click="ensure"> 确认</span>
          <span class="clerar" v-show="clearVisible || todoValue" @click="todoValue = ''"><img src="../../assets/cleaer.svg" alt=""></span>
        </div> 
    </div>
</template>
<script lang="ts">
import{
      defineComponent ,ref}from 'vue';
import {
      IUseTodo, useTodo } from '../../hooks'
export default defineComponent({
     
    name: "TodoInput",
    setup() {
     

        const todoValue =ref<string>('');
        let clearVisible = ref<Boolean>(false)
        const {
      add }: IUseTodo = useTodo()
        //增  键盘事件
        const setTodoValue = (e: KeyboardEvent): void =>{
     
            if(e.keyCode === 13 && todoValue.value.trim().length){
     
                //设置数据
                add(todoValue.value)
                //清空数据
                todoValue.value = ''
            }
        }
        //增  按钮事件
        const ensure = (): void =>{
     
            if(todoValue.value.trim().length){
     
                //设置数据
                add(todoValue.value)
                //清空数据
                todoValue.value = ''
            }
        }
        return {
     
            todoValue,
            clearVisible,
            setTodoValue,
            ensure
        }
    }
})
</script>
<style lang="less" scoped>
.wrap{
     
    display: flex;
    width: 700px;
    margin: 20px auto;
    justify-content: center;
    position: relative;
    input{
     
        width: 590px;
        height: 40px;
        color: #909399;
        font-size: 16px;
        border: 1px solid rgb(196 199 206);
        border-radius: 10px 0 0 10px;
        padding: 0 10px;
    &:focus{
     
        border: none;
        box-shadow:  0 0 0 1px rgb(78 110 242),0 0 0 1px #BDE7FF;
        outline:none;
        transform: translateY(1px);
         height: 38px;
    }
    &::after{
     
        content: '2222';
        display: block;
        width: 10px;
        height: 10px;
        background-color: aqua;
    }
   }
    .ensure{
     
    cursor: pointer;
        width: 112px;
        display: inline-block;
        height: 40px;
        line-height: 40px;
        background-color: rgb(78 110 242);
        border-radius: 0 10px 10px 0;
        font-size: 17px;
        color:rgb(255 255 255); 
        text-align: center;
    }
    .clerar{
     
        position: absolute;
        height: 40px;
        width: 40px;
        right: 112px;
        display: flex;
        align-items: center;
        justify-content: center;
        line-height: 40px;
        img{
     
            width: 60%;
            height: auto;
        }
    }
}

</style>

TodoList

<template>
    <div>
        <todo-item
            v-for="item in todoList"
            :key = 'item.id'
            :item="item"
            @remove = "remove"
            @edit = "edit"
            @add = "add"
        ></todo-item>   
    </div>
</template>
<script lang="ts">
import {
      IUseTodo, useTodo } from '@/hooks';
import {
      IList } from '@/typings';
import{
      defineComponent, PropType }from 'vue';
import TodoItem from './Item.vue'
export default defineComponent({
     
    name: "TodoList",
    props: {
     
        //类型断言
        todoList: Array as PropType< IList[] >
    },
    components: {
     
        TodoItem
    },
    setup (props) {
     
        const {
      remove, add, edit }: IUseTodo = useTodo();
        return{
     
            remove, 
            add, 
            edit,
        }
    }
})
</script>
<style lang="less" scoped>

</style>
相关文章
|
4天前
|
SQL 人工智能 安全
【灵码助力安全1】——利用通义灵码辅助快速代码审计的最佳实践
本文介绍了作者在数据安全比赛中遇到的一个开源框架的代码审计过程。作者使用了多种工具,特别是“通义灵码”,帮助发现了多个高危漏洞,包括路径遍历、文件上传、目录删除、SQL注入和XSS漏洞。文章详细描述了如何利用这些工具进行漏洞定位和验证,并分享了使用“通义灵码”的心得和体验。最后,作者总结了AI在代码审计中的优势和不足,并展望了未来的发展方向。
|
13天前
|
存储 弹性计算 人工智能
阿里云Alex Chen:普惠计算服务,助力企业创新
本文整理自阿里云弹性计算产品线、存储产品线产品负责人陈起鲲(Alex Chen)在2024云栖大会「弹性计算专场-普惠计算服务,助力企业创新」中的分享。在演讲中,他分享了阿里云弹性计算,如何帮助千行百业的客户在多样化的业务环境和不同的计算能力需求下,实现了成本降低和效率提升的实际案例。同时,基于全面升级的CIPU2.0技术,弹性计算全线产品的性能、稳定性等关键指标得到了全面升级。此外,他还宣布了弹性计算包括:通用计算、加速计算和容器计算的全新产品家族,旨在加速AI与云计算的融合,推动客户的业务创新。
|
11天前
|
编解码 Java 程序员
写代码还有专业的编程显示器?
写代码已经十个年头了, 一直都是习惯直接用一台Mac电脑写代码 偶尔接一个显示器, 但是可能因为公司配的显示器不怎么样, 还要接转接头 搞得桌面杂乱无章,分辨率也低,感觉屏幕还是Mac自带的看着舒服
|
18天前
|
存储 人工智能 缓存
AI助理直击要害,从繁复中提炼精华——使用CDN加速访问OSS存储的图片
本案例介绍如何利用AI助理快速实现OSS存储的图片接入CDN,以加速图片访问。通过AI助理提炼关键操作步骤,避免在复杂文档中寻找解决方案。主要步骤包括开通CDN、添加加速域名、配置CNAME等。实测显示,接入CDN后图片加载时间显著缩短,验证了加速效果。此方法大幅提高了操作效率,降低了学习成本。
2896 10
|
13天前
|
存储 缓存 关系型数据库
MySQL事务日志-Redo Log工作原理分析
事务的隔离性和原子性分别通过锁和事务日志实现,而持久性则依赖于事务日志中的`Redo Log`。在MySQL中,`Redo Log`确保已提交事务的数据能持久保存,即使系统崩溃也能通过重做日志恢复数据。其工作原理是记录数据在内存中的更改,待事务提交时写入磁盘。此外,`Redo Log`采用简单的物理日志格式和高效的顺序IO,确保快速提交。通过不同的落盘策略,可在性能和安全性之间做出权衡。
1578 12
|
5天前
|
人工智能 关系型数据库 Serverless
1024,致开发者们——希望和你一起用技术人独有的方式,庆祝你的主场
阿里云开发者社区推出“1024·云上见”程序员节专题活动,包括云上实操、开发者测评和征文三个分会场,提供14个实操活动、3个解决方案、3 个产品方案的测评及征文比赛,旨在帮助开发者提升技能、分享经验,共筑技术梦想。
730 98
|
1月前
|
弹性计算 人工智能 架构师
阿里云携手Altair共拓云上工业仿真新机遇
2024年9月12日,「2024 Altair 技术大会杭州站」成功召开,阿里云弹性计算产品运营与生态负责人何川,与Altair中国技术总监赵阳在会上联合发布了最新的“云上CAE一体机”。
阿里云携手Altair共拓云上工业仿真新机遇
|
18天前
|
人工智能 Serverless API
AI助理精准匹配,为您推荐方案——如何快速在网站上增加一个AI助手
通过向AI助理提问的方式,生成一个技术方案:在网站上增加一个AI助手,提供7*24的全天候服务,即时回答用户的问题和解决他们可能遇到的问题,无需等待人工客服上班,显著提升用户体验。
1478 9
|
6天前
|
SQL 存储 人工智能
【产品升级】Dataphin V4.3重大升级:AI“弄潮儿”,数据资产智能化
DataAgent如何助理业务和研发成为业务参谋?如何快速低成本的创建行业数据分类标准?如何管控数据源表的访问权限?如何满足企业安全审计需求?
357 0
【产品升级】Dataphin V4.3重大升级:AI“弄潮儿”,数据资产智能化
|
3天前
|
人工智能 自然语言处理 程序员
提交通义灵码创新实践文章,重磅好礼只等你来!
通义灵码创新实践征集赛正式开启,发布征文有机会获得重磅好礼+流量福利,快来参加吧!
203 7