Compositon API 开发之初体验 — TODO DEMO

本文通过一个简单的待办事项项目,介绍如何在Vue2中使用Composition API。从创建项目、安装API、引入到main.js,再到编写存储逻辑、组件UI和方法,展示了Composition API的灵活性和代码可读性,适合敏捷开发。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

概要:VUE2+Compositon API,完成todo list的DEMO。

背景:笔者工作中在大佬的带动下,在VUE2的项目中使用Compositon API进行开发,为了方便学习,笔者这里通过一个简单的待办清单项目,还没有用过 Compositon API 的小伙伴们,请跟我一起一步步地揭开它神秘的面纱;

1、使用 vue-cli 创建项目(过程略)。

2、安装 Compositon API:

npm install @vue/composition-api --save
// 或
yarn install @vue/composition-api --save

3、在 main.js 文件引用 Compositon API

import Vue from 'vue'
import App from './App.vue'

import VueCompositionAPI from '@vue/composition-api'

Vue.use(VueCompositionAPI)

Vue.config.productionTip = false

new Vue({
  render: h => h(App),
}).$mount('#app')

4、新建 untils > storage.ts ,将待办事件的状态存储在 storage 中:

interface TodoItem {
  text: string
  hasDone: boolean
}
export default {
  getItem(key: string) {
    return JSON.parse(localStorage.getItem(key) || '[]')
  },
  setItem(key: string, value: Array<TodoItem>) {
    localStorage.setItem(key, JSON.stringify(value))
  },
  removeItem(key: string) {
    localStorage.removeItem(key)
  },
}

5、编写组件UI代码:

<template>
  <div class="hello">
    <header>
      <section>
        <form @submit.prevent>
          <label for="title">ToDoList</label>
          <input
            type="text"
            name="title"
            placeholder="添加ToDo"
            required="required"
            autocomplete="off"
            v-model="todoItem"
            @keyup.enter="addItem"
          />
        </form>
      </section>
    </header>
    <section>
      <h2>
        正在进行<span>{{ todoCount }}</span>
      </h2>
      <ol class="demo-box">
        <li v-for="item in todoList" :key="item.text">
          <input
            type="checkbox"
            v-model="item.hasDone"
            @change="update(item.text, item.hasDone)"
          />
          <p>{{ item.text }}</p>
          <a href="javascript:" @click.prevent="remove(item.text)">—</a>
        </li>
      </ol>
      <h2>
        已经完成<span>{{ doneCount }}</span>
      </h2>
      <ul>
        <li v-for="item in doneList" :key="item.text">
          <input
            type="checkbox"
            v-model="item.hasDone"
            @change="update(item.text, item.hasDone)"
          />
          <p>{{ item.text }}</p>
          <a href="javascript:" @click.prevent="remove(item.text)">—</a>
        </li>
      </ul>
    </section>
    <footer>
      <a href="javascript:" @click.prevent="clear">清空已完成的任务</a>
    </footer>
  </div>
</template>

<style scoped lang="less">
body{margin: 0; padding: 0; font-size: 16px; background: #cdcdcd;}
header{height: 50px; background: #333; background: rgba(47, 47, 47, 0.98);}
section{width: 600px; margin: 0 auto;}
label{float: left; width: 100px; line-height: 50px; color: #ddd; font-size: 24px; cursor: pointer; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;}
header input{float: right; width: 60%; height: 24px; margin-top: 12px; text-indent: 10px; border-radius: 5px; box-shadow: 0 1px 0 rgba(255, 255, 255, 0.24), 0 1px 6px rgba(0, 0, 0, 0.45) inset; border: none;}
input:focus{outline-width: 0;}
h2{position: relative; text-align: left;}
span{position: absolute; top: 2px; right: 5px; display: inline-block; padding: 0 5px; height: 20px; border-radius: 20px; background: #e6e6fa; line-height: 22px; text-align: center; color: #666; font-size: 14px;}
ol,ul{padding: 0; list-style: none;}
li input{position: absolute; top: 2px; left: 10px; width: 22px; height: 22px; cursor: pointer;}
p{margin: 0; text-align: left;}
li p input{top: 3px; left: 40px; width: 70%; height: 20px; line-height: 14px; text-indent: 5px; font-size: 14px;}
li{height: 32px; line-height: 32px; background: #fff; position: relative; margin-bottom: 10px; padding: 0 45px; border-radius: 3px; border-left: 5px solid #629a9c; box-shadow: 0 1px 2px rgba(0, 0, 0, 0.07);}
ol li{cursor: move;}
ul li{border-left: 5px solid #999; opacity: 0.5;}
li a{position: absolute; top: 2px; right: 5px; display: inline-block; width: 18px; height: 18px; border-radius: 50%; line-height: 18px; text-align: center; color: #fff; font-weight: bold; font-size: 12px; cursor: pointer; background-color: crimson; text-decoration: none;}
footer{padding-top: 50px; text-align: center;}
footer a{text-decoration: none; font-size: 16px; border: 1px solid #ccc; display: inline-block; padding: 4px 12px; border-radius: 3px; color: #333;}
footer a:hover{background-color: #eefbff;}
</style>

6、定义方法:

import { ref, reactive, computed, onMounted } from '@vue/composition-api'
import storage from '../until/storage'

interface TodoItem {
  text: string
  hasDone: boolean
}

export default {
  name: 'ToDoList',
  setup() {
    const todoItem = ref('')
    const todo: {
      list: Array<TodoItem>
    } = reactive({
      list: [],
    })
    // 通过计算获取待办列表内容是列表中尚未完成的项
    const todoList = computed(() => todo.list.filter(item => !item.hasDone))
    // 通过计算获取待办的项的个数    
    const todoCount = computed(
      () => todo.list.filter(item => !item.hasDone).length,
    )
    // 通过计算获取完成列表内容是列表中已完成的项
    const doneList = computed(() => todo.list.filter(item => item.hasDone))
    // 通过计算完成的项的个数
    const doneCount = computed(
      () => todo.list.filter(item => item.hasDone).length,
    )
    // 待办事项添加方法
    const addItem = () => {
      const text = todoItem.value
      for (let i = 0, len = todo.list.length; i < len; i++) {
        if (todo.list[i].text == text) {
          alert('重复了,请换一个~')
          return
        }
      }
      todo.list.push({
        text: text,
        hasDone: false,
      })
      storage.setItem('todolist', todo.list)
      todoItem.value = ''
    }
    // 复选框勾选出发待办事项完成的方法
    const update = (text: string, hasDone: boolean) => {
      todo.list.forEach(item => {
        if (item.text == text) {
          item.hasDone = hasDone
        }
      })
      storage.setItem('todolst', todo.list)
    }
    // 移除一个待办事项的方法
    const remove = (text: string) => {
      todo.list = todo.list.filter(item => item.text == text)
      storage.setItem('todolist', todo.list)
    }
    // 清空已完成列表的方法
    const clear = () => {
      todo.list = todo.list.filter(item => !item.hasDone)
      storage.removeItem('todoList')
    }
    onMounted(() => {
      const list = storage.getItem('todolist')
      if (Array.isArray(list)) {
        todo.list = list
      } else {
        storage.setItem('todolist', todo.list)
      }
    })
    return {
      todoItem,
      todo,
      todoList,
      todoCount,
      doneList,
      doneCount,
      addItem,
      update,
      remove,
      clear,
    }
  },
}

7、查看页面效果:

以上就是利用 Compositon API 完成的一个简单的待办事项功能的DEMO,本文的侧重点在于展示 Compositon API 在使用中,其灵活的组件逻辑、编写的代码易读性好,与敏捷开发更匹配。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值