VUE小案例---todolist

这篇博客详细介绍了使用Vue.js开发TodoList应用的过程,包括模块拆分、静态页面搭建、动态组件的实现,如动态显示数据、子组件与父组件间的通信,以及全选删除功能。此外,还强调了组件化编码的重要性,如组件按功能拆分和状态提升。

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).实现交互:从绑定事件开始。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值