1. 模块拆分

2.静态页面搭建
2.1.案例目录

2.2.主页 index.html

2.3.main.js

2.4.App.vue

2.5.MyHeader.vue

2.6.MyList.vue

2.7.MyItem.vue


2.8.MyFooter.vue

2.9.静态页面效果展示

3.动态组件
3.1动态显示初始化数据
3.1.1 MyList.vue
定义数据:数组 todos {title, done}数组是存储要做的事的量,对象存储要做的事。
接收数据,v-for遍历数组
<template>
<ul class="todo-main">
<MyItem v-for="todoObj in todos" :key="todoObj.id" :todo="todoObj"/>
</ul>
</template>
<script>
import MyItem from './MyItem.vue'
export default {
name: 'MyList',
components: {MyItem},
data(){
return{
todos:[
{id:'001',title:'drinking',done:true},
{id:'002',title:'smoking',done:true},
{id:'003',title:'driving',done:true}
]
}
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style>
3.1.2 MyItem.vue
得到数据,已完成事项可选
<template>
<li>
<label>
<input type="checkbox" :checked="todo.done"/ <span>{{todo.title}}</span>
</label>
<button class="btn btn-danger" style="display:none">删除</button>
</li>
</template>
<script>
export default {
name: 'MyItem',
//声明接受todo对象
props:['todo']
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style>...
3.1.3 效果展示

3.2动态交互
3.2.1实现子组件向父组件传数据
基本实现方法:在父组件先写一个接受函数,再把这个接受函数传给子组件,子组件利用这个函数接收数据,从而实现传递。
3.2.1.1父组件:App
<template>
<div id="root">
<div class="todo-container">
<div class="todo-wrap">
<MyHeader : addTodo="addTodo"/>
<MyList :todos="todos" />
<MyFooter />
</div>
</div>
</div>
</template>
<script>
import MyHeader from './components/MyHeader.vue'
import MyFooter from './components/MyFooter.vue'
import MyList from './components/MyList.vue'
export default {
name: 'App',
components: {MyHeader,MyFooter,MyList},
data(){
return{
todos:[
{id:'001',title:'drinking',done:true},
{id:'002',title:'smoking',done:true},
{id:'003',title:'driving',done:true}
]
}
},
methods: {
addTodo(todoObj){
this.todos.unshift(todoObj)//要传递的函数
}
}
}
</script>
3.2.1.2子组件:MyHeader
<script>
import {nanoid} from 'nanoid'
export default {
name: 'MyHeader ',
props:['addTodo'],
methods: {
add(){
//包装成todo对像
const todoObj = {id:nanoid(),title: e.target.value,done:false}
this.addTodo(todoObj)
}
}
}
</script>
3.2.1.3效果展示:从输入框中输入数据并增加item。

3.2.2三代组件间传递数据
3.2.2.1App.vue
在APP中写checkTodo方法,先传给MyList,再通过MyList传给MyItem
<template>
<!-- <div id="root"> -->
<div class="todo-container">
<div class="todo-wrap">
<MyHeader :addTodo="addTodo"/>
<MyList :todos="todos" :checkTodo="checkTodo" />
<MyFooter />
</div>
</div>
<!-- </div> -->
</template>
<script>
import MyHeader from './components/MyHeader.vue'
import MyFooter from './components/MyFooter.vue'
import MyList from './components/MyList.vue'
export default {
name: 'App',
components: {MyHeader,MyFooter,MyList},
data(){
return{
todos:[
{id:'001',title:'drinking',done:true},
{id:'002',title:'smoking',done:true},
{id:'003',title:'driving',done:true}
]
}
},
methods: {
//添加todo
addTodo(todoObj){
this.todos.unshift(todoObj)
},
//勾选或者取消勾选
checkTodo(id){
this.todos.forEach(todo => {
if(todo.id === id) todo.done = !todo.done
});
}
}
}
</script>
3.2.2.3MyList
<template>
<ul class="todo-main">
<MyItem v-for="todoObj in todos" :key="todoObj.id" :todo="todoObj" :checkTodo="checkTodo"/>
</ul>
</template>
<script>
import MyItem from './MyItem.vue'
export default {
name: 'MyList',
components: {MyItem},
props:['todos','checkTodo']
}
</script>
3.2.2.3MyItem
<template>
<li>
<label>
<input type="checkbox" :checked="todo.done" @change="handleCheck(todo.id)"/>
<span>{{todo.title}}</span>
</label>
<button class="btn btn-danger" style="display:none">删除</button>
</li>
</template>
<script>
export default {
name: 'MyItem',
//声明接受todo对象
props:['todo','checkTodo'],
methods:{
handleCheck(id){
this.checkTodo(id)
}
}
}
</script>
3.2.2.4效果展示:勾选能够改变item的值


3.2.2.5注意
- v-model也能实现通过勾选使得todo的值改变,但是不推荐,因为props传入的值不可改变,vue只能识别深度的改变,但其实用v-model已经改变props接受的todo的值,所以不推荐。
- props,methods,data,computed都是在一个VC里面,所以函数名不能相同。
3.2.3实现底部全选,删除
3.2.3.1App.vue
<template>
<!-- <div id="root"> -->
<div class="todo-container">
<div class="todo-wrap">
<MyHeader :addTodo="addTodo"/>
<MyList :todos="todos" :checkTodo="checkTodo" :deleteTodo="deleteTodo"/>
<MyFooter :todos="todos" :checkAllTodo="checkAllTodo" :clearAllTodo="clearAllTodo"/>
</div>
</div>
<!-- </div> -->
</template>
<script>
import MyHeader from './components/MyHeader.vue'
import MyFooter from './components/MyFooter.vue'
import MyList from './components/MyList.vue'
export default {
name: 'App',
components: {MyHeader,MyFooter,MyList},
data(){
return{
todos:[
{id:'001',title:'drinking',done:true},
{id:'002',title:'smoking',done:true},
{id:'003',title:'driving',done:true}
]
}
},
methods: {
//添加todo
addTodo(todoObj){
this.todos.unshift(todoObj)
},
//勾选或者取消勾选
checkTodo(id){
this.todos.forEach(todo => {
if(todo.id === id) todo.done = !todo.done
});
},
//删除一个todo
deleteTodo(id){
/* this.todos = this.todos.filter(
(todo)=>{return todo.id !== id}
) */
this.todos = this.todos.filter( todo => todo.id !== id)
},
//取消或全选todo
checkAllTodo(done){
this.todos.forEach((todo)=>{todo.done = done})
},
clearAllTodo(){
this.todos = this.todos.filter( (todo)=>{
return !todo.done
})
}
}
}
</script>
3.2.3.1MyFooter.vue
<template>
<div class="todo-footer" v-show="total" >
<label>
<!-- <input type="checkbox" :checked="isAll" @change="checkAll"/> -->
<input type="checkbox" v-model="isAll"/>
</label>
<span>
<span>已完成{{doneTodo}}</span> / 全部{{total}}
</span>
<button class="btn btn-danger" @click="clearAll" >清除已完成任务</button>
</div>
</template>
<script>
//import { set } from 'vue/types/umd'
export default {
name: 'MyFooter',
props:['todos','checkAllTodo','clearAllTodo'],
computed:{
total(){
return this.todos.length
},
//计算总共完成了多少,使用reduce方法。
doneTodo(){
return this.todos.reduce( (pre,todo)=> pre + (todo.done ? 1:0),0 )
},
isAll:{
get(){
return this.total === this.doneTodo && this.total >0
},
set(value){
this.checkAllTodo(value)
}
}
},
methods:{
clearAll(){
this.clearAllTodo()
}
}
}
</script>
3.2.4利用浏览器存储的版本App.vue
<script>
export default {
data(){
return {
// 从localStorage读取todos
todos: JSON.parse(window.localStorage.getItem('todos_key') || '[]')
watch: { //监视
todos:{
deep: true, // 深度监视
handler: function(value){
// 将todos最新的值的json数据,保存到localStorage
window.localStorage.setItem('todos_key', JSON.stringify(value))
}
}
},
}
</script>
4.案例总结
总的来说本次案例注重细节,基本操作理解。
首先要学会的是组件化编码流程:
(1).拆分静态组件:组件要按照功能点拆分,命名不要与html元素冲突。
(2).实现动态组件:
1).一个组件单独用:放在本组件。
2). 一些组件共用:放在他们共同的父组件上(状态提升)。
(3).实现交互:从绑定事件开始。
这篇博客详细介绍了使用Vue.js开发TodoList应用的过程,包括模块拆分、静态页面搭建、动态组件的实现,如动态显示数据、子组件与父组件间的通信,以及全选删除功能。此外,还强调了组件化编码的重要性,如组件按功能拆分和状态提升。
2937

被折叠的 条评论
为什么被折叠?



