1 案例效果
2 用到的知识点
- 1 使用vite创建项目
- 2 组件的封装和组册
- 3 props
- 4 样式的绑定
- 5 计算属性
- 6 自定义事件
- 7 组件的v-model
3 实现步骤
4 实现功能
- 1 实现添加新任务功能
- 2 输入内容不能为空
- 3 区分完成与未完成任务
- 4 对任务进行区分
5案例展示
6程序结构
初始化项目
- x npm init vite-app todos
- npm install
- npm i less -D
7 代码展示
App.vue
<template>
<h1>app根组件</h1>
<!-- 使用组件 -->
<!-- 监听TodoInput的自定义add事件 -->
<todo-input @add="onAddNewTask"></todo-input>
<todo-list :list="tasklist" class="mt-2"></todo-list>
<todo-button v-model:active="activeBtnIndex"></todo-button>
</template>
<script>
import TodoList from './components/TodoList.vue'
import TodoInput from './components/TodoInput.vue'
import TodoButton from './components/TodoButton.vue'
export default {
name: 'RootApp',
components:{
TodoList,
TodoInput,
TodoButton
},
data(){
return{
todoList:[
{ id:1,task:'周一早晨九点开会',done:false},
{ id:2,task:'周一晚上八点半聚餐',done:false},
{ id:3,task:'准备周三上午发布会',done:true},
],
//下一个可用的id值
nextId:4,
//激活按钮的索引
activeBtnIndex:0
}
},
computed:{
tasklist(){
switch(this.activeBtnIndex){
case 0: // 全部
return this.todoList;
case 1: // 已完成
return this.todoList.filter(todo=>todo.done)
case 2: //未完成
return this.todoList.filter(todo=>!todo.done)
}
}
},
methods:{
onAddNewTask(taskname){
// 向任务列表新增任务
this.todoList.push({
id : this.nextId,
task:taskname,
done:false
})
this.nextId++
}
},
}
</script>
TodoList.vue
<template>
<ul class="list-group ">
<li class="list-group-item d-flex justify-content-between align-items-center" v-for="item in list" :key="item.id">
<!-- 复选框 -->
<div class="custom-control custom-checkbox">
<input type="checkbox" class="custom-control-input" :id="item.id" v-model="item.done">
<label class="custom-control-label" :for="item.id" :class="item.done? 'delete':''">{{item.task}}</label>
</div>
<span class="badge badge-success badge-pill" v-if="item.done">完成</span>
<span class="badge badge-warning badge-pill" v-else>未完成</span>
</li>
</ul>
</template>
<script>
export default{
name:'TodoList',
props:{
//列表数据
list:{
type:Array,
required:true,
default:[]
}
},
data(){
return{
taskname:''//新任务的名称
}
}
}
</script>
<style lang='less' scoped>
.list-group{
width:600px
}
.delete{
text-decoration: line-through;
}
</style>
TodoInput.vue
<template>
<form class="form-inline" @submit.prevent="onFormSubmit">
<div class="input-group md-2 mr-sm-2">
<div class="input-group-prepend">
<div class="input-group-text">任务</div>
</div>
<input type="text" class="form-control" v-model.trim="taskname" placeholder="请填写任务信息" style="width:355px">
</div>
<!-- 添加按钮 -->
<button type="submit" class="btn btn-primary md-2">添加新任务</button>
</form>
</template>
<script>
export default{
name:'TodoInput',
//声明自定义事件
emits:['add'],
data(){
return{
taskname:''
}
},
methods:{
onFormSubmit(){
//判断任务名称是否为空
if(!this.taskname){
alert('任务不能为空')
return
}
//触发自定义事件 并向外传递数据
this.$emit('add',this.taskname)
//清空文本
this.taskname=''
}
}
}
</script>
<style class="less" scoped>
</style>
TodoButton.vue
<template>
<div class="button-container mt-3">
<div class="btn-group">
<div class="btn-group">
<button type="button" class="btn" :class="active===0?'btn-primary':'btn-secondary'" @click='onBtnClick(0)'>全部</button>
<button type="button" class="btn" :class="active===1?'btn-primary':'btn-secondary'" @click='onBtnClick(1)'>已完成</button>
<button type="button" class="btn" :class="active===2?'btn-primary':'btn-secondary'" @click='onBtnClick(2)'>未完成</button>
</div>
</div>
</div>
</template>
<script>
export default{
name:'TodoButton',
props:{
active:{//激活项的索引值
type:Number,
required:true,
// 默认激活索引值为0(0 全部 1 已完成 2 未完成)
default:0
}
},
emits:['update:active'],
methods:{
onBtnClick(index){
console.log(index +"---"+this.active)
if(index === this.active){
return
}else{
this.$emit('update:active',index)
}
}
}
}
</script>
<style class="less" scoped>
.button-container{
width: 400px;
text-align: center;
}
</style>
index.css
:root{
font-size: 12px;
}
body{
padding: 8px;
}