TodoList
学习笔记:
总结TodoList案例
1.组件化编码流程:
(1).拆分静态组件:组件要按照功能点拆分,命名不要与htm|元素冲突。
(2).实现动态组件:考虑好数据的存放位置,数据是一个组件在用, 还是一些组件在用: .
1).-个组件在用:放在组件自身即可。
2). -些组件在用:放在他们共同的父组件上(状态提升)。(3).实现交互:从绑定事件开始。
- props适用于:
(1).父组件==>子组件通信
(2).子组件==>父组件通信(要求父先给子-一个函数)
3.使用v-model时要切记: v-model绑定的值不能是props传过来的值,因为props是不可以修改的!
- props传过来的若是对象类型的值,修改对象中的属性时Vue不会报错,但不推荐这样做。
运行截图:
全选和取消全选,相应的全选或取消全选后全选按钮作出相应的反应:
增加
删除
清除已经完成的,全部清除后底部消失:
组件结构:
本项目是在vue-cil5,vue2,nanoid环境下运行
源码:
main.js
import Vue from 'vue'
import App from './App.vue'
Vue.config.productionTip = false
new Vue({
render: h => h(App),
}).$mount('#app')
app.vue
<template>
<div id="app">
<div class="todo-container">
<div class="todo-wrap">
<myHeader :addTodo="addTodo"/>
<myList :todos="todos" :checkTodo="checkTodo" :deleteTodo="deleteTodo"/>
<myFoot :datas="todos" :checkAll="checkAll" :clearAlldone="clearAlldone"/>
</div>
</div>
</div>
</template>
<script>
import myHeader from "./components/myHeader.vue"
import myList from "./components/myList.vue"
import myFoot from "./components/myFoot.vue"
export default {
name: 'App',
data(){
return{
todos:
[{id:"001",title:"睡觉",done:true},
{id:"002",title:"开车",done:false},
{id:"003",title:"吹牛",done:true}]
}
},
methods:{
addTodo(todoObj){
const obj=todoObj;
this.todos.unshift(obj);
},
checkTodo(id){
this.todos.forEach((todo)=>{
if(todo.id==id)
todo.done=!todo.done
})
},
deleteTodo(id){
this.todos=this.todos.filter((todo)=>{
return todo.id!=id
})
},
checkAll(done){
this.todos.forEach((to)=>{
to.done=done
})
},
clearAlldone(){
this.todos=this.todos.filter((a)=>{
return !a.done
})
}
},
components: {
myHeader,
myList,
myFoot
}
}
</script>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
color: #2c3e50;
margin-top: 60px;
}
body{
background: #fff;
}
.btn{
display: inline-block;
margin-bottom: 0;
padding: 4px 12px;
font-size: 14px;
line-height: 20px;
text-align: center;
vertical-align: middle;
cursor: pointer;
box-shadow: inset 0 1px 0 rgba(0, 0, 0, 0.2), 0 1px 2px rgba(0,0,0,0.3);
}
.btn-danger{
color: #fff;
background-color:#da4f49;
border:1px solid #ba362f;
}
.btn-danger:hover{
color: #fff;
background-color: #bd362f;
}
.btn:focus{
outline:none;
}
.todo-container{
width: 600px;
margin: 0 auto;
}
.todo-container .todo-wrap{
padding: 10px;
border:1px solid #ddd;
border-radius: 5px;
}
</style>
myHeader.vue
<template>
<div class="todo-header">
<input type="text" placeholder="请输入你的任务名称,按回车生成" @keyup.enter="add" v-model="title"/>
</div>
</template>
<script>
import {nanoid} from "nanoid"
export default{
name:"myHead",
props:["addTodo"],
data(){
return{
title:""
}
},
methods:{
add(){
if(this.title.trim()!=""){
const todoobj={id:nanoid(),title:this.title,done:false}
this.addTodo(todoobj)
this.title=""
}
else{
alert("不能为空啊")
}
}
},
}
</script>
<style scoped>
.todo-header input{
width: 560px;
height: 28px;
font-size: 14px;
border:1px solid #ccc;
border-radius: 4px;
padding: 4px 7px;
}
.todo-header input:focus{
outline: none;
border-color: rgba(80,160,231,0.7);
box-shadow: inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(80,160,231,0.7);
}
</style>
myList
<template>
<ul class="todo-main">
<myItem
v-for="t in todos"
:key="t.id"
:todo="t"
:checkTodo="checkTodo"
:deleteTodo="deleteTodo"/>
</ul>
</template>
<script>
import myItem from "./myItem.vue"
export default {
name:"myList",
components:{
myItem,
},
props:["todos","checkTodo","deleteTodo"]
}
</script>
<style>
.todo-main{
border:1px #bbb solid;
}
</style>
myFoot
<template>
<div class="todo-footer" v-if="total">
<label ><input type="checkbox" v-model="istotal"/>
</label>
<span>
<span>已完成{{donetotal}}</span>/全部{{total}}
</span>
<button class="btn btn-dabger" @click="cleardone">清除已完成任务</button>
</div>
</template>
<script>
export default {
name:"myFoot",
props:["datas","checkAll","clearAlldone"],
computed:{
total(){
return this.datas.length
},
donetotal(){
let total=this.datas.filter((t)=>{
return t.done
}).length
return total
},
istotal:{
get(){
return this.total==this.donetotal&&this.total>0 ? true:false;
},
set(value){
this.checkAll(value)
}
}
},
methods:{
cleardone(){
this.clearAlldone()
}
}
}
</script>
<style scoped>
.todo-footer{
position: relative;
}
.todo-footer .btn{
position: absolute;
right: 10px;
top: -5px;
border-radius: 3px;
background-color: #e7064d;
border: 1px #d8235a solid;
color: white;
}
.todo-footer .btn:hover{
transform: scale(1.01);
}
.todo-footer span{
margin-left: 10px;
}
</style>
myItem
<template>
<div class="todo-footer" v-if="total">
<label ><input type="checkbox" v-model="istotal"/>
</label>
<span>
<span>已完成{{donetotal}}</span>/全部{{total}}
</span>
<button class="btn btn-dabger" @click="cleardone">清除已完成任务</button>
</div>
</template>
<script>
export default {
name:"myFoot",
props:["datas","checkAll","clearAlldone"],
computed:{
total(){
return this.datas.length
},
donetotal(){
let total=this.datas.filter((t)=>{
return t.done
}).length
return total
},
istotal:{
get(){
return this.total==this.donetotal&&this.total>0 ? true:false;
},
set(value){
this.checkAll(value)
}
}
},
methods:{
cleardone(){
this.clearAlldone()
}
}
}
</script>
<style scoped>
.todo-footer{
position: relative;
}
.todo-footer .btn{
position: absolute;
right: 10px;
top: -5px;
border-radius: 3px;
background-color: #e7064d;
border: 1px #d8235a solid;
color: white;
}
.todo-footer .btn:hover{
transform: scale(1.01);
}
.todo-footer span{
margin-left: 10px;
}
</style>
这给小项目作为vue新手练手组件化开发还是很不错的,这个项目b站上面有尚硅谷的课可以免费看(我只是一名普通的网友啊)
https://www.bilibili.com/video/BV1Zy4y1K7SH?p=70