【无标题】

TodoList案例

添加

在输入框输入,anenter键添加到MyList组件中
MyHeader.vue:

<template>
    <div class="todo-header">
        <input type="text" placeholder="请输入你的任务名称,按回车键确认" @keyup.enter="add" v-model="content">
        <!-- 1.@keyup.enter="add"绑定一个键盘事件,按enter键添加一个元素,事件名字add -->
        <!-- 2.v-model="content",这里是为了下面获得表单元素,先把content定义为空。也可以用另一种方法:add(event){console.log(event.target.value) -->
    </div>
</template>

<script>
import {nanoid} from "nanoid"   //nanoid引入使用分别引入
// 引入nanoid,nanoid是用来生成唯一id的小型库
export default {
    name:"MyHeader",
    data(){
        return {
            content:""
        }
    },
    methods:{
        add(){
            if(!this.content.trim()){       //空字符串布尔值是false,取反则为true;trim()是去掉前面的空格,这样写更完整。
            return alert("输入不能为空")
        }
        // step1:获取表单元素
        // console.log(this.content)
        // step2:由于todoobj是由id,title,done组成的,所以要将用户输入的内容包装成todoobj
        const todoobj={id:nanoid(),title:this.content,done:false}
        // id:nanoid()的使用方法
        // step3:实现将表单中输入的内容添加到列表中。
            // 这时要将MyList和MyHeader两个组件建立联系,则需要用到他们共同的父亲App组件。
            // todos是共用的,将其放在App组件
            // 将在MyList组件中的todos数据给父亲App,然后App传送数据给MyList组件;(用props,父传子)
            // MyHeader里的todoobj给App,(子传父),父亲先给儿子一个函数,儿子调用这个函数。
        this.addTodoObj(todoobj)   //调用
        //step4:细节进行修改
            // 当添加完元素之后,输入框为空
        this.content=""
            // 写判断语句判断输入框是否为空,空的话按enter键无效(要写在上方才可以)
        }

    },
    props:["addTodoObj"]  //接收数据
}
</script>

MyItem.vue

<template>
    <li>
        <label>
            <input type="checkbox" :checked="todo.done">
            <!--1. :checked="todo.done"根据done是true还是false确定是否默认勾选 -->
            <span>{{todo.title}}</span>
            <!-- 2.插值语法,对应需要的值 -->
        </label>
        <button class="btn btn-danger" style="display:none">删除</button>
    </li>
</template>

<script>
export default {
    name:"MyItem",
    // 1.接收来自MyList组件传来的信息
    props:["todo"]
}
</script>

MyList.vue

<template>
    <ul class="todo.main">
        <!-- 遍历todos数组,要用多少次MyItem;并且要将每一条todoobj对应属性传给MyItem(用props) -->
        <MyItem v-for="todoobj in todos" :key="todoobj.id" :todo="todoobj"/>
    </ul>
</template>

<script>
import MyItem from './MyItem'   //注意路径和前边的不一样
export default {
    name:"MyList",
    components:{
        MyItem
    },
    props:["todos"]
}
</script>

App.vue

<template>
  <div class="root">
        <div class="todo-container">
            <div class="todo-wrap">
                <MyHeader :addTodoObj="addTodoObj"/>   <!-- 将addTodoObj传给MyHeader组件 -->
                <MyList :todos="todos"/>   <!-- 将todos传给MyList组件 -->
                <MyFooter/>
            </div>
        </div>
    </div>
</template>

<script>
import MyHeader from './components/MyHeader.vue'
import MyList from './components/MyList.vue'
import MyFooter from './components/MyFooter.vue'
export default {
    name: 'App',
    data(){
        return {
            todos:[
                {id:"001",title:"打代码",done:"true"},  //id一般用字符串,done表示完成
                {id:"002",title:"睡觉",done:"false"},
                {id:"003",title:"吃饭",done:"true"}
            ]
        }
    },
    methods:{
        addTodoObj(todoobj){
            this.todos.unshift(todoobj)
        }
    },
    components: {
      MyHeader,
      MyList,
      MyFooter
  }  
}
</script>

勾选

MyList.vue

<template>
    <ul class="todo.main">
        <!-- 遍历todos数组,要用多少次MyItem;并且要将每一条todoobj对应属性传给MyItem(用props) -->
        <MyItem v-for="todoobj in todos" :key="todoobj.id" :todo="todoobj" :checkTodo="checkTodo"/>
    </ul>
</template>

<script>
import MyItem from './MyItem'   //注意路径和前边的不一样
export default {
    name:"MyList",
    components:{
        MyItem
    },
    props:["todos","checkTodo"]
}
</script>

MyItem.vue

<template>
    <li>
        <label>
            <input type="checkbox" :checked="todo.done" @click="handleCheck">
            <!--1. :checked="todo.done"根据done是true还是false确定是否默认勾选 -->
            <!-- @click="handleCheck"注册点击事件确认是否勾选 -->
            <!-- <input type="checkbox" :checked="todo.done" v-model="todo.done">
            这样写可以直接实现,但是不推荐,因为props里的数据最好不要修改,这样的话虽然不会报错,但是修改了props里todo的数据。 -->
            <span>{{todo.title}}</span>
            <!-- 2.插值语法,对应需要的值 -->
        </label>
        <button class="btn btn-danger" style="display:none">删除</button>
    </li>
</template>

<script>
export default {
    name:"MyItem",
    // 1.接收来自MyList组件传来的信息
    props:["todo","checkTodo"],
    methods:{
        handleCheck(){
            // 找到勾选项对应的id
            // 在todos找到对应的id
            // 给对应id的done值取反
                // 调用App中的函数
            this.checkTodo()
        }
    }
}

</script>

App.vue

<template>
  <div class="root">
        <div class="todo-container">
            <div class="todo-wrap">
                <MyHeader :addTodoObj="addTodoObj"/>   <!-- 将addTodoObj传给MyHeader组件 -->
                <MyList :todos="todos" :checkTodo="checkTodo"/>   <!-- 将todos传给MyList组件 -->
                <MyFooter/>
            </div>
        </div>
    </div>
</template>

<script>
import MyHeader from './components/MyHeader.vue'
import MyList from './components/MyList.vue'
import MyFooter from './components/MyFooter.vue'
export default {
    name: 'App',
    data(){
        return {
            todos:[
                {id:"001",title:"打代码",done:"true"},  //id一般用字符串,done表示完成
                {id:"002",title:"睡觉",done:"false"},
                {id:"003",title:"吃饭",done:"true"}
            ]
        }
    },
    methods:{
        addTodoObj(todoobj){
            this.todos.unshift(todoobj)
        },
        checkTodo(id){
            this.todos.forEach((todoobj)=>{
                if(todoobj.id===id) {
                    todoobj.done!==todoobj.done
                }
            })
        }
    },
    components: {
      MyHeader,
      MyList,
      MyFooter
  }
  
}
</script>

删除

MyItem.vue:

<button class="btn btn-danger" @click="handleDelete(todo.id)">删除</button>
handleDelete(id){
            if (confirm("确定删除吗")) {
                this.deleteTodo(id)
            }
        }

App.vue

// 删除
        deleteTodo(id){
            this.todos.forEach((todoobj,index) =>{
                if(todoobj.id===id){
                    this.todos.splice(index,1,id)
                }
            })
        }
        // 或者:
        // deleteTodo(id){
        //     this.todos=this.todos.filter(todo=>todo.id!==id
        // })
    },

底部计算

MyFooter.vue

<span>
    <span>已完成{{doneTotal}}</span>/全部{{todos.length}}
</span>
props:["todos"],
    computed:{
        doneTotal(){
          return  this.todos.reduce((pre,current)=>pre+(current.done?1:0),0)
        }
    }
}

底部交互

App.vue

// 清除所有已经完成的todo
        clearAllTodo(){
            this.todos=this.todos.filter((todo)=>!todo.done)
        }

Myfooter.vue

computed:{
        doneTotal(){
          return  this.todos.reduce((pre,current)=>pre+(current.done?1:0),0)
        },
        total(){
            return this.todos.length
        },
        isAll(){
            //满足下面两个条件直接返回布尔值
            return this.doneTotal===this.todos.length && this.total>0  
        }
// 或者:整合在一起
// isAll:{
//     get(){
//         return this.doneTotal===this.todos.length && this.total>0  
//     },
//     set(value){
//         checkAll(e){
//             this.checkAllTodo(e.target.checked)  
//         }
//     }
// }

    },
    methods:{
        checkAll(e){
            this.checkAllTodo(e.target.checked)  //全选或全不选
        },
        // 清除所有已经完成的todo
        clearAll(){
            this.clearAllTodo()
        }
    },
    
}

</script>

总结TodoList案例

1.组件化编码流程

(1)拆分静态组件:组件要按照功能点拆分,命名不要与html元素冲突。
(2)实现动态组件:考虑好数据的存放位置,数据是一个组件再用,还是一些组件在用。
(1)一个组件在用:放在组件自身即可
(2)一些组件在用:放在他们共同组件上(状态提升)
(3)实现交互:从绑定事件开始

2.props适用于:

(1)父组件==>子组件 通信
(2)子组件==>父组件 通信(要求父亲先给儿子一个函数,儿子自己调用这个函数)

3.使用v-model要切记:

v-model绑定的值不能是props传过来的值,因为props是不可以修改的!!

4.props传过来的若是对象类型的值,修改对象中的属性时vue不会报错,但不推荐这样做。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值