实现任务截止日期提醒功能

在Vue 3应用中实现任务截止日期提醒功能需要结合前端状态管理和日期处理逻辑。以下是具体实现方法:

安装必要依赖

npm install date-fns @vueuse/core

创建任务模型

interface TodoItem {
  id: string
  title: string
  completed: boolean
  dueDate: Date | null
}

状态管理实现

使用Vue的reactive API创建任务存储:

import { reactive } from 'vue'

const todoStore = reactive({
  items: [] as TodoItem[],
  addItem(title: string, dueDate: Date | null) {
    this.items.push({
      id: Date.now().toString(),
      title,
      completed: false,
      dueDate
    })
  }
})

日期提醒逻辑

实现日期比较和提醒功能:

import { isBefore, differenceInDays, format } from 'date-fns'
import { useIntervalFn } from '@vueuse/core'

const checkDueDates = () => {
  const now = new Date()
  todoStore.items.forEach(item => {
    if (item.dueDate && !item.completed) {
      if (isBefore(item.dueDate, now)) {
        console.warn(`任务"${item.title}"已过期!`)
      } else if (differenceInDays(item.dueDate, now) <= 3) {
        console.log(`任务"${item.title}"即将在3天内到期`)
      }
    }
  })
}

// 每5分钟检查一次
useIntervalFn(checkDueDates, 1000 * 60 * 5)

组件实现

创建任务添加表单组件:

<template>
  <form @submit.prevent="handleSubmit">
    <input v-model="title" placeholder="任务标题" />
    <input 
      type="datetime-local" 
      v-model="dueDateString" 
    />
    <button type="submit">添加</button>
  </form>
</template>

<script setup>
import { ref } from 'vue'

const title = ref('')
const dueDateString = ref('')

const handleSubmit = () => {
  const dueDate = dueDateString.value 
    ? new Date(dueDateString.value) 
    : null
  todoStore.addItem(title.value, dueDate)
  title.value = ''
  dueDateString.value = ''
}
</script>

任务列表显示

实现带日期提醒的任务列表组件:

<template>
  <ul>
    <li v-for="item in sortedItems" :key="item.id" :class="getDueClass(item)">
      {{ item.title }} 
      <span v-if="item.dueDate">
        (截止: {{ formatDate(item.dueDate) }})
      </span>
    </li>
  </ul>
</template>

<script setup>
import { computed } from 'vue'
import { format, isBefore, differenceInDays } from 'date-fns'

const sortedItems = computed(() => {
  return [...todoStore.items].sort((a, b) => {
    if (!a.dueDate) return 1
    if (!b.dueDate) return -1
    return a.dueDate.getTime() - b.dueDate.getTime()
  })
})

const formatDate = (date) => format(date, 'yyyy-MM-dd HH:mm')

const getDueClass = (item) => {
  if (!item.dueDate || item.completed) return ''
  const now = new Date()
  if (isBefore(item.dueDate, now)) return 'overdue'
  if (differenceInDays(item.dueDate, now) <= 3) return 'urgent'
  return ''
}
</script>

<style>
.overdue { color: red; }
.urgent { color: orange; }
</style>

浏览器通知集成

添加更明显的通知功能:

const showNotification = (title: string, options?: NotificationOptions) => {
  if (!('Notification' in window)) return
  
  if (Notification.permission === 'granted') {
    new Notification(title, options)
  } else if (Notification.permission !== 'denied') {
    Notification.requestPermission().then(permission => {
      if (permission === 'granted') {
        new Notification(title, options)
      }
    })
  }
}

// 修改checkDueDates函数
const checkDueDates = () => {
  const now = new Date()
  todoStore.items.forEach(item => {
    if (item.dueDate && !item.completed) {
      if (isBefore(item.dueDate, now)) {
        showNotification(`任务"${item.title}"已过期!`)
      } else if (differenceInDays(item.dueDate, now) <= 3) {
        showNotification(`任务"${item.title}"即将到期`)
      }
    }
  })
}

持久化存储

添加localStorage持久化:

import { watch } from 'vue'

const STORAGE_KEY = 'todo-app-data'

// 加载保存的数据
const savedData = localStorage.getItem(STORAGE_KEY)
if (savedData) {
  try {
    const parsed = JSON.parse(savedData)
    parsed.items.forEach((item: any) => {
      if (item.dueDate) item.dueDate = new Date(item.dueDate)
    })
    todoStore.items = parsed.items
  } catch (e) {
    console.error('加载保存数据失败', e)
  }
}

// 自动保存
watch(() => todoStore.items, (newValue) => {
  localStorage.setItem(STORAGE_KEY, JSON.stringify({
    items: newValue.map(item => ({
      ...item,
      dueDate: item.dueDate ? item.dueDate.toISOString() : null
    }))
  }))
}, { deep: true })

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐