1.需求说明
-
拆分基础组件
-
渲染待办任务
-
添加任务
-
删除任务
-
底部合计 和 清空功能
-
持久化存储
2.拆分基础组件
咱们可以把小黑记事本原有的结构拆成三部分内容:头部(TodoHeader)、列表(TodoMain)、底部(TodoFooter)
3、综合案例-列表渲染
思路分析:
-
提供数据:提供在公共的父组件 App.vue
-
通过父传子,将数据传递给TodoMain
-
利用v-for进行渲染
<template>
<div class="App">
<TodoHeader @handleContent="handleAdd"></TodoHeader>
<TodoBoy :list="list" @id="delById"></TodoBoy>
<TodoFooter :list="list" @removeAll="removeAll"></TodoFooter>
</div>
</template>
<script>
import TodoHeader from "@/components/TodoHeader.vue";
import TodoBoy from "@/components/TodoBoy.vue";
import TodoFooter from "@/components/TodoFooter.vue";
export default {
name: 'App',
components: {
TodoHeader,
TodoBoy,
TodoFooter
},
data() {
return {
list: JSON.parse(localStorage.getItem('list')) || [
{id: 1, name: '打篮球'},
{id: 2, name: '看电影'},
{id: 3, name: '逛街'}
]
}
},
methods:{
handleAdd(value){
this.list.unshift({
id:+new Date(),
name:value
})
},
delById(id){
this.list=this.list.filter(item=>id!==item.id)
},
removeAll(){
this.list.splice(0,this.list.length)
}
},
watch:{
list:{
deep:true,
handler(newValue){
localStorage.setItem('list',JSON.stringify(newValue))
}
}
}
}
</script>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>
TodoMain.vue
<template>
<section class="main">
<ul class="todo-list">
<li class="todo" v-for="(item,index) in list" :key="item.id">
<div class="view">
<span class="index">{{index+1}}</span> <label>{{item.name}}</label>
<button class="destroy" @click="del(item.id)"></button>
</div>
</li>
</ul>
</section>
</template>
<script>
export default {
name: "TodoBoy",
props:{
list:Array
},
methods:{
del(id){
this.$emit('id',id)
}
}
}
</script>
<style scoped>
</style>
4、综合案例-添加功能
思路分析:
-
收集表单数据 v-model
-
监听时间 (回车+点击 都要进行添加)
-
子传父,将任务名称传递给父组件App.vue
-
父组件接受到数据后 进行添加 unshift(自己的数据自己负责)
TodoHeader.Vue
<template>
<!-- 输入框 -->
<header class="header">
<h1>小黑记事本</h1>
<input @keyup.enter="handleAdd" v-model="todoName" placeholder="请输入任务" class="new-todo"/>
<button class="add" @click="handleAdd">添加任务</button>
</header>
</template>
<script>
export default {
name: "TodoHeader",
data() {
return {
todoName: ''
}
},
methods: {
handleAdd() {
if(this.todoName==''){
confirm("任务名不能为空")
return
}
this.$emit('handleContent',this.todoName)
this.todoName=''
}
}
}
</script>
<style scoped>
</style>
App.Vue
<template>
<div class="App">
<TodoHeader @handleContent="handleAdd"></TodoHeader>
<TodoBoy :list="list" @id="delById"></TodoBoy>
<TodoFooter :list="list" @removeAll="removeAll"></TodoFooter>
</div>
</template>
<script>
import TodoHeader from "@/components/TodoHeader.vue";
import TodoBoy from "@/components/TodoBoy.vue";
import TodoFooter from "@/components/TodoFooter.vue";
export default {
name: 'App',
components: {
TodoHeader,
TodoBoy,
TodoFooter
},
data() {
return {
list: JSON.parse(localStorage.getItem('list')) || [
{id: 1, name: '打篮球'},
{id: 2, name: '看电影'},
{id: 3, name: '逛街'}
]
}
},
methods:{
handleAdd(value){
this.list.unshift({
id:+new Date(),
name:value
})
},
delById(id){
this.list=this.list.filter(item=>id!==item.id)
},
removeAll(){
this.list.splice(0,this.list.length)
}
},
watch:{
list:{
deep:true,
handler(newValue){
localStorage.setItem('list',JSON.stringify(newValue))
}
}
}
}
</script>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>
5、综合案例-删除功能
思路分析:
-
监听时间(监听删除的点击)携带id
-
子传父,将删除的id传递给父组件App.vue
-
进行删除 filter (自己的数据自己负责)
TodoBoy.vue
<template>
<section class="main">
<ul class="todo-list">
<li class="todo" v-for="(item,index) in list" :key="item.id">
<div class="view">
<span class="index">{{index+1}}</span> <label>{{item.name}}</label>
<button class="destroy" @click="del(item.id)"></button>
</div>
</li>
</ul>
</section>
</template>
<script>
export default {
name: "TodoBoy",
props:{
list:Array
},
methods:{
del(id){
this.$emit('id',id)
}
}
}
</script>
<style scoped>
</style>
App.Vue
<template>
<div class="App">
<TodoHeader @handleContent="handleAdd"></TodoHeader>
<TodoBoy :list="list" @id="delById"></TodoBoy>
<TodoFooter :list="list" @removeAll="removeAll"></TodoFooter>
</div>
</template>
<script>
import TodoHeader from "@/components/TodoHeader.vue";
import TodoBoy from "@/components/TodoBoy.vue";
import TodoFooter from "@/components/TodoFooter.vue";
export default {
name: 'App',
components: {
TodoHeader,
TodoBoy,
TodoFooter
},
data() {
return {
list: JSON.parse(localStorage.getItem('list')) || [
{id: 1, name: '打篮球'},
{id: 2, name: '看电影'},
{id: 3, name: '逛街'}
]
}
},
methods:{
handleAdd(value){
this.list.unshift({
id:+new Date(),
name:value
})
},
delById(id){
this.list=this.list.filter(item=>id!==item.id)
},
removeAll(){
this.list.splice(0,this.list.length)
}
},
watch:{
list:{
deep:true,
handler(newValue){
localStorage.setItem('list',JSON.stringify(newValue))
}
}
}
}
</script>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>
6、综合案例-底部功能及持久化存储
思路分析:
-
底部合计:父组件传递list到底部组件 —>展示合计
-
清空功能:监听事件 —> 子组件通知父组件 —>父组件清空
-
持久化存储:watch监听数据变化,持久化到本地
TodoFooter.vue
<template>
<footer class="footer">
<!-- 统计 -->
<span class="todo-count">合 计:<strong>{{ list.length }}</strong></span>
<!-- 清空 -->
<button class="clear-completed" @click="removeAll">
清空任务
</button>
</footer>
</template>
<script>
export default {
name: "TodoFooter",
props: {
list: Array
},
methods: {
removeAll(){
this.$emit('removeAll')
}
}
}
</script>
<style scoped>
</style>
App.vue
<template>
<div class="App">
<TodoHeader @handleContent="handleAdd"></TodoHeader>
<TodoBoy :list="list" @id="delById"></TodoBoy>
<TodoFooter :list="list" @removeAll="removeAll"></TodoFooter>
</div>
</template>
<script>
import TodoHeader from "@/components/TodoHeader.vue";
import TodoBoy from "@/components/TodoBoy.vue";
import TodoFooter from "@/components/TodoFooter.vue";
export default {
name: 'App',
components: {
TodoHeader,
TodoBoy,
TodoFooter
},
data() {
return {
list: JSON.parse(localStorage.getItem('list')) || [
{id: 1, name: '打篮球'},
{id: 2, name: '看电影'},
{id: 3, name: '逛街'}
]
}
},
methods:{
handleAdd(value){
this.list.unshift({
id:+new Date(),
name:value
})
},
delById(id){
this.list=this.list.filter(item=>id!==item.id)
},
removeAll(){
this.list.splice(0,this.list.length)
}
},
watch:{
list:{
deep:true,
handler(newValue){
localStorage.setItem('list',JSON.stringify(newValue))
}
}
}
}
</script>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>