案例用到的知识点如下:
① vite 创建项目
② 组件的封装与注册
③ props
④ 样式绑定
⑤ 计算属性
⑥ 自定义事件
⑦ 组件上的 v-model
效果如下图;
页面2
项目结构:
初始化项目
在终端运行以下的命令,初始化 vite 项目:
npm init vite-app todos
使用 vscode 打开项目,并安装依赖项:
npm install
安装 less 语法相关的依赖项:
npm i less -D
重置 index.css 中的全局样式如下:
:root {
font-size: 12px;
}
body {
padding: 8px;
}
在终端运行以下的命令,把项目运行起来:
npm run dev
mian.js
import { createApp } from 'vue'
import App from './App.vue'
// 导入bootstrap
import './assets/css/bootstrap.css'
import './index.css'
createApp(App).mount('#app')
app.vue
<template>
<ul class="list-group container">
<li class="list-group-item active" aria-current="true">星月事务管理</li>
</ul>
<div class="container container1">
<todoInput @add="getadd"></todoInput>
<todo-list :list="taskList"></todo-list>
<todoButton :addb="mbstatus" @addb="onsta" v-model:addb="onsta"></todoButton>
</div>
</template>
<script>
import todoList from './components/todolist/todolist.vue'
import todoInput from './components/todoinput/todoinput.vue'
import todoButton from './components/todobutton/todobutton.vue'
export default {
name: 'MyApp',
components:{
todoList,
todoInput,
todoButton
},
data() {
return{
nextid:6,
mbstatus:0,
todoList:[
{ id:1,task:'周一早晨9点开会',done:false },
{ id:2,task:'周二早晨9点开会',done:true },
{ id:3,task:'周三早晨9点开会',done:false },
{ id:4,task:'周四早晨9点开会',done:true },
{ id:5,task:'周五睡觉',done:true },
]
}
},
methods:{
// 把输入框的信息添加到todolist中
getadd(e){
this.todoList.push({
id:this.nextid,
task:e,
done:false
})
this.nextid++
},
// 接收子组件传递的状态,并赋值给按钮的状态,实现按钮的切换
onsta(e){
// console.log(e)
this.mbstatus = e
}
},
computed:{
taskList(){
// if ---else方法
// if(this.mbstatus === 0) {
// return this.todoList
// }else if(this.mbstatus === 1){
// return this.todoList.filter(x=>x.done)
// }else{
// return this.todoList.filter(x=>!x.done)
// }
// switch --- case 方法
switch(this.mbstatus){
case 0: {
return this.todoList
}
case 1:{
return this.todoList.filter(x=>x.done)
}
case 2:{
return this.todoList.filter(x=>!x.done)
}
}
}
}
}
</script>
<style lang="less" scoped>
.list-group{
max-width: 400px;
text-align: center;
}
.container1{
margin-top: 20px;
}
</style>
页面切换状态的按钮组件:todobutton.vue
<template>
<div class="btn-group container" role="group" aria-label="Basic example">
<button type="button" class="btn" :class="addb===0?'btn-primary':'btn-secondary'" @click="onsta(0)">全部</button>
<button type="button" class="btn" :class="addb===1?'btn-primary':'btn-secondary'" @click="onsta(1)">已完成</button>
<button type="button" class="btn" :class="addb===2?'btn-primary':'btn-secondary'" @click="onsta(2)">未完成</button>
</div>
</template>
<script>
export default {
name:'TodoButton',
// 自定义需要绑定的事件addb
emits:['addb'],
props:{
addb:{
type:Number,
required:true,
default:0
}
},
methods:{
// 把当前点击按钮的状态传递给app父组件
// 通过$emit自定义事件子传父,实现双向绑定
onsta(e){
// console.log(e)
if(e === this.addb)return
this.$emit('addb',e)
}
}
}
</script>
<style lang="less" scoped>
.btn-group{
max-width: 400px;
margin-top: 20px;
text-align: center;
}
</style>
渲染事务列表组件: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-switch">
<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 ?'ftdelete':''">{{ 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',
data(){
return{
ftdelete:'ftdelete'
}
},
props:{
list:{
type:Array,
required:true,
default:[]
}
},
// created(){
// this.list.forEach(e=>{
// // console.log(e)
// if( e.done === true ){
// e.done = false
// }else{
// e.done = true
// }
// })
// }
}
</script>
<style lang="less" scoped>
.list-group{
max-width: 400px;
.ftdelete{
text-decoration: line-through;
}
}
</style>