ToDoList待办事件(Vue实现)详解

组件化的编码流程(通用)

  1. 实现静态组件:抽取组件,使用组件实现静态页面效果
  2. 展示动态数据
    数据的类型名称
    数据保存的组件位置
  3. 交互-从绑定事件监听开始

实现静态页面

组件按照功能划分

也可以按照其他的划分,我是按照功能划分的

制作过程

创建文件夹,终端进入目录下创建项目

vue create todolist

在这里插入图片描述

在组件文件夹下创建四个文件,分别是MyTop.vue;List.vue;Item.vue;MyFooter.vue;
并将四个组件引入App.vue
注意:Top.vue不要写Header.vue,容易和html的标签冲突
后来我的Top.vue也报错了,我改长一点,MyTop,就正常了
注册组件

export default {
  name: 'App',
  components: { MyTop,MyList,MyFooter}
}

因为item是list的子组件所以item注册在list里面就好啦
ToDoList待办事件(Vue实现)详解_第1张图片

完整代码

MyTop.vue







MyList.vue







MyItem.vue







MyFooter.vue







App.vue






展示动态数据

待办事件的数据需要数组来进行存储,id标识,数组保存在List.
在MyList中的MyItem子组件中遍历todos数组,给MyItem传数据。
在MyItem中设置props设置传值

   //声明接收todo对象
    props:['todo'],

checkbox添加checked就会在页面中显示勾选,动态的拥有某个属性,

:checked="true"

在表达式通过改变true来实现是否勾选
使其=todo.done即可

完整代码

MyItem.vue




MyList.vue




添加待办事件

在Top中将用户的输入包装成一个todo对象,将用户的输入todoObj添加到list当中
两个兄弟组件之间传递数据的思路:父组件App中有todos数组(将list中的数据复制到app中),将top中的todoObj传给todos,再通过props将todos中的数据传给list。

App.vue

 
  

  

MyTop

 props:['addTodo'],

子组件给父组件传数据的思路

父组件传给子组件一个函数,子组件合适的时候调用。

top传给list数据的整个过程

App中操作todos中的数据unshift可以捕获到数组的修改,todos改变,vue重新解析模板,此时todos增加一个数据,todo数组传给mylist,mylist会重新解析模板,myitem出现四个虚拟dom,dom比较,旧的复用,新的添加。

完善细节

回车键后输入框为空

  e.target.value=''

但是这个语句直接操作DOM了,违背了Vue的原则。


input框添加v-model可以避免这个问题
ToDoList待办事件(Vue实现)详解_第2张图片

//在methods里面添加

this.title=''

输入空格回车也会成功添加

  if (!this.title.trim()) return alert('输入不能为空')

勾选

勾选与否引起数据的变化,才可以显示完成率,产生交互.

通过勾选找到数据的id,在todo里面找到,然后通知app组件将对应的todo对象的done值取反。

首先需要input框显示勾选的todo(初始化交互)

:checked="todo.done"

绑定事件响应是否勾选(click/change都可以)

@click="handleCheck(todo.id)

可以通过点击输出勾选事件的id

console.log(id)

app组件中,通知app组件将对应的todo对象的done值取反

    checkTodo(id) {
      // 遍历list中的item
      this.todos.forEach((todo) => {
        if (todo.id === id) todo.done=!todo.done
      })
    }

组件间通信
本次采用逐次传递。
在App中将checkTodo传递给MyList组件,在MyList组件中使用props接收checkTodo

      
  props:['todos','checkTodo'],

因为是Myitem使用,所以在MyList组件中的MyItem中单项数据绑定

:checkTodo="checkTodo"

在MyItem中使用props接收checkTodo。

MyItem中input框使用v-model双向数据绑定v-model=“todo.done”,通过布尔值决定input的checkbox是否勾选
props传值todo,todo的属性值修改,vue监测的就是todo属性
但是props的值不允许修改
看一下下面的例子

let a=3;
a=8;

修改了

let obj={a:2,b:3}
obj.=666
obj={x:100,y:200}

vue只能监测到obj={x:100,y:200}。

在本项目中myItem中添加

 

props接收a
但是这种方法并不推荐,因为有点违反原则,修改了props,vue监测不到。

删除

在item中给按钮button添加点击事件handleDelete,注意接受todo的id

 
 handleDelete(id) {
      // 删除
      if (confirm('确定删除吗?')) {
        // console.log(id)
        
      }
      
    }
    deleteTodo(id) {
      this.todos = this.todos.filter((todo) => {
        return todo.id!==id
      })
    }

再次经历爷孙传值

先App传给MyList,MyList中props接收deleteTodo,MyItem标签中单项数据绑定deleteTodo。之后MyList传给MyItem,item的props接收即可。

   

myitem中的操作
  props: ['todo', 'checkTodo','deleteTodo'],
    handleDelete(id) {
      // 删除
      if (confirm('确定删除吗?')) {
        // console.log(id)
          this.deleteTodo(id)
      }
    }

底部统计

完成事件统计

首先将todos传给myitem

//App.vue
 
//MyFooter.vue
 props:['todos']

使用计算属性computed实现底部统计

     已完成{{doneTotal}}/全部{{ todos.length }}
computed: {
        doneTotal() {
            let i = 0
           this.todos.forEach((todo) => {
            if(todo.done)i++
           });
           return i
        }
}

底部统计也可以使用ES6的reduce方法完成一种更为高级的写法

     const x= this.todos.reduce((pre,cur) => {
                console.log('@', pre, cur)
                return pre + (cur.done?1:0)
            }, 0)
            console.log('###', x)
            return x

精简为一句代码

return this.todos.reduce((pre,cur)=>pre+(cur.done?1:0),0)

pre上一个值,cur当前的值,数组的长度就是函数的调用次数.
打印pre,0,undefined,undefined。统计的初始值是0,所以第一次调用是0,再调用的时候,pre是第一次调回的函数的返回值,第一次调用没有返回值,所以第二次和第三次都是undefined。如果有return 3,那么第二次和第三次pre都是3.所以返回值应该是return pre+1.这样第一次返回值是1,第二次是2,第三次是3。所以最后3就是reduce的返回值。

底部交互-无任务时显示为空

全部{{ total}}
computed: {
        total() {
            return this.todos.length
        },
}

当任务为0时,不显示底部




checkAllTodo(done) {
      this.todos.forEach((todo) => {
         todo.done=done
      })
     
    }

Myfooter.vue中props接收传值,然后方法调用

 props: ['todos','checkAllTodo'],

 methods: {
        checkAll(e) {
            console.log(e.target.checked)//借助属性拿到Dom没有操作DOM
            this.checkAllTodo(e.target.checked)
        }
    }

优化方案

v-model替换
在这里插入图片描述

点击勾选框,[Vue warn]: Write operation failed: computed property “isAll” is readonly.
将isAll改为计算属性

isAll(){}改成isAll: {}

清空已完成任务

思路:给清空已完成的按钮设置click事件clearAll
methods设置方法clearAll,clearAll调用App入口文件的clearAllTodo方法,给myfooterclearAllTodo传给MyFooter组件

    clearAllTodo() {
        this.todos=this.todos.filter((todo) => {
        return !todo.done
      })
    }

MyFooter文件使用props接收文件。

总结

  1. 组件化编程流程:
    (1)拆分静态组件:组件按照功能点拆分,命名不与html元素冲突。
    (2)实现动态组件:考虑好数据的存放位置,数据是一个组件在用(放在组件自身),还是一些组件在用(放在共同的父组件上面)。
    (3)实现交互:从绑定事件开始。
  2. props适用于:
    (1).父组件=>子组件 通信
    (2).子组件==>父组件通信(父组件先给子组件一个函数)
  3. 使用v-model时要切记:v-model绑定的值不能使props传过来的,因为props是不可以修改的
  4. props传过来的若是对象类型的值,修改对象中的属性Vue不会报错,但不推荐这样做
    {}
## 清空已完成任务
> 思路:给清空已完成的按钮设置click事件clearAll
methods设置方法clearAll,clearAll调用App入口文件的clearAllTodo方法,给myfooterclearAllTodo传给MyFooter组件
clearAllTodo() {
    this.todos=this.todos.filter((todo) => {
    return !todo.done
  })
}

MyFooter文件使用props接收文件。

总结

  1. 组件化编程流程:
    (1)拆分静态组件:组件按照功能点拆分,命名不与html元素冲突。
    (2)实现动态组件:考虑好数据的存放位置,数据是一个组件在用(放在组件自身),还是一些组件在用(放在共同的父组件上面)。
    (3)实现交互:从绑定事件开始。
  2. props适用于:
    (1).父组件=>子组件 通信
    (2).子组件==>父组件通信(父组件先给子组件一个函数)
  3. 使用v-model时要切记:v-model绑定的值不能使props传过来的,因为props是不可以修改的
  4. props传过来的若是对象类型的值,修改对象中的属性Vue不会报错,但不推荐这样做

你可能感兴趣的:(vue.js,javascript,前端)