用v3+ts写一个mini版todos(不用pinia)

 可以练习一个基本的增删改查,不用pinia可以更好的练习组件通信

 

以下是基本结构

 

  app.vue

<script setup lang="ts">
import "./styles/base.css"
import "./styles/index.css"  
import TodoHeader from "./components/TodoHeader.vue";
import TodoMain from "./components/TodoMain.vue";
import TodoFooter from "./components/TodoFooter.vue";
import { computed, ref } from "vue";
//定义数据类型
import type { TodoItem, TodoType } from './todo'
// 定义数据
const todos = ref<TodoItem[]>([])
todos.value = JSON.parse(localStorage.getItem('todos')! || '[]')
// todos.value = 
// 当前要显示的类型
const type = ref<TodoType>('all')
//修改type的值
  const setType = (val:TodoType) => {
    type.value = val
  }

const saveTodos = () => {
  localStorage.setItem("todos", JSON.stringify(todos.value))
} 

const hUpdate = (item: TodoItem) => {
  // console.log(item)
  // 修改对应的数据
  const it = todos.value.find(it => it.id === item.id) 
  // it!: 非空断言
  it!.isDone = !(it!.isDone)

  saveTodos()
}

const hAdd = (name: string) => {
  // 向数组中添加
  todos.value.push({
    id: Date.now(),
    name,
    isDone: false
  })
  saveTodos()
}

// 单个删除
const hDel =  (idx:number) => {
  todos.value = todos.value.filter(it => it.id !== idx) 
  saveTodos()
}
// 多个删除
const hDels = () => {
  todos.value = todos.value.filter(it => it.isDone === false)
  saveTodos()
}

const filterTodos = computed(() => {
  if(type.value === 'all'){
    return todos.value
  } else if(type.value === 'yes'){
    return todos.value.filter(it => it.isDone)
  } else {
    return todos.value.filter(it => !it.isDone)
  }
})
</script>
<template>
  <section class="todoapp">
    <TodoHeader @add="hAdd"></TodoHeader>
    <TodoMain @update="hUpdate" :filterTodos="filterTodos" @hDel="hDel"></TodoMain>
    <TodoFooter :filterTodos="filterTodos" :type="type" @setType="setType" @hDels="hDels">
    </TodoFooter>
  </section>
</template>

  头部

<script setup lang="ts">
import { ref } from 'vue';

// 定义数据 - 收集用户输入 - 通过抛出事件把数据传递给父组件
const name = ref('')

const emit = defineEmits<{
  (e: 'add', name: string): void
}>()

const add = () => {
  // 添加
  emit('add', name.value)
  // 清空内容
  name.value = ''
}
</script>

<template >
    <header class="header">
      <h1>todos</h1>
      <input id="toggle-all" class="toggle-all" type="checkbox" >
      <label for="toggle-all"></label>
      <input
        v-model="name"
        @keyup.enter="add"
        class="new-todo"
        placeholder="输入任务名称-回车确认"
        autofocus
      />
    </header>
  </template>

内容区

   
<script setup lang="ts">
import type { TodoItem } from '@/todo';

// 接收
defineProps<{
  // 属性名:类型
  filterTodos:TodoItem[]
}>()

const emit = defineEmits<{
  (e:'update', item: TodoItem): void
  (e:'hDel', idx: number): void
}>()
const hChange = (item: TodoItem) => {
  // 抛出事件
  emit("update", item)
}
const hDel = (idx: number) => {
  // 抛出事件
  emit("hDel", idx)
}                                                    
</script>
<template>
    <ul class="todo-list">
      <!-- completed: 完成的类名 -->
      <li 
        v-for="item in filterTodos"
        :key="item.id"
        :class="{completed: item.isDone}">
        <div class="view">
          <input
            @change="hChange(item)"
            :value="item.isDone"
          class="toggle" type="checkbox" :checked="item.isDone"/>
          <label>{{item.name}}</label>
          <button class="destroy" @click="hDel(item.id)"></button>
        </div>
      </li>
    </ul>

  </template>

底部

<script setup lang="ts">
import type { TodoItem ,TodoType} from '../todo';
// 接收
 const prop = defineProps<{
  // 属性名:类型
  filterTodos: TodoItem[]
  type: TodoType
 }>()
//接收父组件方法
const emit = defineEmits<{
  (e: 'setType', type: TodoType): void
  (e: 'hDels'): void
}>()
//修改type状态值
const setType = (val: TodoType) => {

  emit('setType', val)  
}
// 删除已完成事项
const hDels = () => {
  // 抛出事件
  emit("hDels")
}
</script>
<template>
  <footer class="footer">
    <!-- ?可选链运算符,没有值时不报错 -->
    <span class="todo-count">剩余<strong>{{ filterTodos?.length }}</strong></span>
    <ul class="filters">
      <li>
        <a class="selected" href="javascript:;" @click="setType('all')">全部</a>
      </li>
      <li>
        <a href="javascript:;" @click="setType('no')">未完成</a>
      </li>
      <li>
        <a href="javascript:;" @click="setType('yes')">已完成</a>
      </li>
    </ul>
    <button class="clear-completed" @click="hDels">清除已完成</button>
  </footer>
</template>

 todo.d.ts文件

type TodoItem = {
    id: number
    name: string
    isDone: boolean
}

type TodoType = 'all' | 'no' | 'yes'

export {
    TodoItem,
    TodoType
}

 这些都是 Web 开发中常见的基本技能和概念,通过编写一个待办事项应用程序,可以锻炼这些技能,将它们应用到实际的项目中。编写一个小型应用程序还可以提高你的编码能力、逻辑思维和问题解决能力。

 

  • 5
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值