目录
一.准备工作
二.编写各个组件的页面结构
三.实现初始任务列表的渲染
四.新增任务
五.删除任务
六.展示未完成条数
七.切换状态-筛选数据
八.待办事项(全)代码
一.准备工作
在开发“ToDoList”案例之前,需要先完成一些准备工作,包括创建项目、引入 BootStrap 样式文件和搭建基本项目结构,下面分别进行实现。
(1)创建项目 创建项目包含新建项目、安装依赖项和运行项目,具体步骤如下。
① 创建项目。使用HbuliderX软件创建todolist项目 在src的目录下创建style.css 文件中的样式,具体代码如下。
style.css样式如下:
:root { font-size: 16px; } body { margin: 0; }
复制
② 新建并封装组件。在D:\vue\chapter03\todolist\src\components 目录下新建文件 ToDoHeader.vue、ToDoMain.vue 和 ToDoFooter.vue,分别表示 ToDoHeader、ToDoMain 和ToDoFooter 组件。
③ 各个组件中的<style>节点的样式代码。
二.编写各个组件的页面结构
准备工作完成之后,接下来编写各个组件的页面结构,实现“ToDoList”案例静态页 面的渲染,具体步骤如下。
①在App组件中以局部注册的方式引入ToDoHeader、ToDoMain、ToDoFooter组 件
②在ToDoHeader组件中编写输入区域的页面结构
③ 在ToDoMain组件中编写列表区域的页面结构
④ 在ToDoFooter组件中编写切换状态区域的页面结构
三.实现初始任务列表的渲染
App 组件为根组件,数据在App组件中,现在需要将App根组件中的初始数据传递 到列表区域,ToDoMain组件中。即通过props(自定义属性)从父组件(App组件)向 子组件(ToDoMain组件)中传递数据。实现初始任务列表具体步骤如下。
① 在ToDoMain组件中定义可以从父组件中接收的数据
② 在App组件中定义页面的初始数据
③ 通过自定义属性进行传递数据
④ 修改ToDoMain组件中的代码,将接收到的list数据进行展示。
四.新增任务
“ToDoList”案例中在文本框中输入内容,按下回车后添加任务到任务列表,将用户 输入的任务名称通过自定义事件从ToDoHeader组件传递到App组件,具体步骤如下代码省略。、
① 修改ToDoHeader组件中的代码,添加页面的初始数据
② 获取input输入框的值,修改ToDoHeader组件中的代码
③ 修改ToDoHeader组件中的代码,为input输入框绑定回车事件,事件处理函数 名称为enterName
④ 修改ToDoHeader组件中的代码,通过调用defineEmits()方法来声明自定义事 件
⑤ 在ToDoHeader组件中添加enterName()方法,通过调用emit()方法触发自定义事 件
⑥ 在App组件中监听addTodo自定义事件,当enterName事件触发时,调用 addToDo()方法
⑦ 添加addToDo方法,实现数据的处理
五.删除任务
当鼠标指针滑到任务列表中每一项时,在右侧会出现“×”图标,单击该图标即可 进行删除当条任务操作。首先在ToDoMain组件中声明并触发自定义事件,传递参数 6 id,接着在App组件中监听自定义事件,当自定义事件被触发时,执行对应的方法,进 行删除操作,删除任务的具体实现步骤如下。
① 在ToDoMain组件中,声明自定义事件delTodo,用于表示删除任务
② 在ToDoMain组件中定义delToDo()方法,触发自定义事件
③ 修改删除按钮的代码,添加点击事件,传入需要删除的id
④ 在App组件中监听
⑤ 在App组件中添加delToDo方法,进行列表中对应任务的删除操作
六.展示未完成条数
在任务状态区域的左侧会显示未完成任务的条数,接下来计算未完成任务的条数并 将其在页面中渲染出来,具体步骤如下代码省略。
① 在App组件中定义计算属性,计算未完成的任务条数
② 将自定义属性传给ToDoFooter组件
③ 在ToDoFooter组件中接收lastLength
④ 在ToDoFooter组件中将条数展示出来
七.切换状态-筛选数据
单击切换状态区域时,默认状态为all,即显示全部任务,当状态切换为active时, 显示未完成的任务,当状态切换为completed时,显示已完成的任务,实现切换数据筛选 状态具体步骤如下代码省略。
① 首先在App组件中定义页面的使用一个任务状态状态属性status
② 在App组件中通过不同的status展示不同的任务,实现任务数据的切换
③ 修改App组件,将showList传递给ToDoMain组件
④ 设置自定义事件名称
⑤ 在ToDoFooter组件中定义props属性,表示从父组件中接收该数据
⑥ 在App组件中定义props,即从App组件中传递status到ToDoFooter组件中
⑦ 在ToDoFooter组件中单击链接按钮时更改状态
⑧ 在App组件中监听updateStatus自定义事件,通过自定义事件将status属性的值 从ToDoFooter组件传递到App组件中,具体代码如下
⑨ 定义updateStatus()方法,用来更新状态,具体代码如下。
八.待办事项(全)代码
ToDoFooter.vue代码:
<template> <div class="footer"> <span class="todo-count">共<strong>{{ lastLength }}</strong>条未完成任务 </span> <ul class="filters"> <ul class="filters"> <li> <a @click.prevent="emit('updateStatus', 'all')" :class="{ selected: status === 'all' }" href="#/">All</a> </li> <li> <a @click.prevent="emit('updateStatus', 'active')" :class="{ selected: status === 'active' }" href="#/active">Active</a> </li> <li> <a @click.prevent="emit('updateStatus', 'completed')" :class="{ selected: status === 'completed' }" href="#/completed">Completed</a> </li> </ul> </ul> </div> </template> <script setup> const props = defineProps(['lastLength', 'status']) const emit = defineEmits(['updateStatus']) </script> <style> .footer { padding: 10px 15px; height: 20px; text-align: center; font-size: 15px; border-top: 1px solid #e6e6e6; } .footer:before { content: ""; position: absolute; right: 0; bottom: 0; left: 0; height: 50px; overflow: hidden; box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2), 0 8px 0 -3px #f6f6f6, 0 9px 1px -3px rgba(0, 0, 0, 0.2), 0 16px 0 -6px #f6f6f6, 0 17px 2px -6px rgba(0, 0, 0, 0.2); } .todo-count { float: left; text-align: left; } .todo-count strong { font-weight: 300; } .filters { float: right; margin: 0; padding: 0; list-style: none; } .filters li { display: inline; } .filters li a { color: inherit; margin: 3px; padding: 3px 7px; text-decoration: none; border: 1px solid transparent; border-radius: 3px; border-color: #767676; } .filters li a:hover { border-color: #db7676; } .selected { border-color: #db7676; } </style>
复制
ToDoHeader.vue代码:
<template> <div> <div class="header"> <p class="title">待办事项</p> <input class="new-todo" type="text" placeholder="请填写任务" v-model.trim="name" @keyup.enter="enterName" /> </div> </div> </template> <script setup> import { ref } from 'vue' const name = ref('') const enterName = () => { emit('addTodo', name.value) name.value = '' } const emit = defineEmits(['addTodo']) </script> <style> .title{ border-bottom:1px solid grey; text-align:center; font-size:36px; color:brown; } .header{ border:1px solid grey; } .new-todo{ position: relative; top:-20px; left: 50px; border: none; font-size: 20px; } </style>
复制
ToDoMain.vue代码:
<template> <div class="main"> <ul class="todo-list"> <li v-for="item in list" :key="item.id" :class="{ completed: item.done }"> <div class="view"> <input class="toggle" type="radio" v-model="item.done" /> <label class="zi">{{ item.name }}</label> <button class="destroy" @click="delTodo(item.id)"></button> </div> </li> </ul> </div> </template> <script setup> const props = defineProps({ list: { type: Array, required: true }, }) const emit = defineEmits(['delTodo']) const delTodo = id => { id && emit('delToDo', id) // 触发事件 } </script> <style> .toggle{ width: 30px; height: 30px; } .view{ margin-left: -40px; } .zi{ font-size: 18px; padding-left: 20px; } .destroy{ border: none; margin-left: 10px; } </style>
复制
App.vue代码:
<template> <ToDoHeader @addTodo="addTodo" /> <ToDoMain :list="showList" @delToDo="delToDo" /> <ToDoFooter :lastLength="lastLength" :status="status" @updateStatus="updateStatus" /> </template> <script setup> import ToDoHeader from './components/ToDoHeader.vue' import ToDoMain from './components/ToDoMain.vue' import ToDoFooter from './components/ToDoFooter.vue' import { ref, computed } from 'vue' const status = ref('all') const list = ref([ { id: 1, name: '晨练', done: false, }, { id: 2, name: '练书法', done: true, }, ]) const addTodo = name => { list.value.push({ name, done: false, id: ~~(Math.random() * 1000) }) } const delToDo = id => { list.value = list.value.filter(item => item.id !== id) } // 计算剩下没有完成任务的条数 const lastLength = computed(() => { return list.value.filter(item => !item.done).length }) const showList = computed(() => { if (status.value === 'all') { return list.value; } if (status.value === 'active') { return list.value.filter(item => !item.done) } if (status.value === 'completed') { return list.value.filter(item => item.done) } }) const updateStatus = (status1) => { status.value = status1 // 将子组件的状态赋值给父组件 } </script>
复制
main.js代码:
import { createApp } from 'vue' import App from './App.vue' createApp(App).mount('#app')
复制
最终效果图如下:
功能展示:
今天就分享到此,感谢预览~