Todo-List案例

发布于:2024-05-10 ⋅ 阅读:(24) ⋅ 点赞:(0)

一.Todo-List案例

1.组件化编码流程:

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

 2.props的适用:

(1)父组件===>子组件 通信

(2)子组件===>父组件(要求父先给子一个函数)

3.使用v-model时要切记:v-model绑定的值不能是props传过来的值,因为props是不可修改的

4.props传过来的若是对象的值,修改对象中的属性时Vue不会报错,但不推荐

二.代码案例:

//app.vue
<template>
    <div class="todo-container">
        <Header  :addTodo="addTodo"></Header>
        <List :todos="todos" :checkTodo="checkTodo" :deleteTodo="deleteTodo"></List>
        <Footer :todos="todos" :checkAllTodo="checkAllTodo" :clearAllTodo="clearAllTodo"></Footer>
    </div>
</template>

<script>
    import  Header from './components/testHeader.vue'
    import  Footer from './components/testFooter.vue'
    import List from './components/testList.vue'
    export default {
        name:'app',
        components:{Header,Footer,List},
        data() {
      return {
        todos:[
          {id:'001',title:'吃饭',done:true},
          {id:'002',title:'喝酒',done:false},
          {id:'003',title:'开车',done:false}
        ]
      }
    },
    methods:{
        // 添加一共todo
        addTodo(todoObj){
            this.todos.unshift(todoObj)
        },
        // 勾选或者取消勾选一个todo
        checkTodo(id){
            this.todos.forEach((todo)=>{
                if(todo.id===id)
                todo.done=!todo.done
            })
        },
        // 删除一个todo
        deleteTodo(id){
            console.log(id)
            this.todos=this.todos.filter((todo)=>{
                return todo.id!==id
            })
        },
        // 全选or取消全选
        checkAllTodo(done){
            this.todos.forEach((todo)=>{
                todo.done=done
            })
        },
        // 清除所有已经完成的todo
        clearAllTodo(){
            this.todos=this.todos.filter((todo)=>{
                return !todo.done
            })
        }
    }
    }
</script>
<style >
    body{
        background: #fff;
    }
    .btn{
        display: inline-block;
        padding: 4px 12px;
        margin-bottom: 0;
        font-size: 14px;
        line-height: 20px;
        text-align: center;
        vertical-align: middle;
        cursor: pointer;
        box-shadow: insert 0 1px 0 rgba(255, 255, 255, 0.2),1px 2px rgba(0, 0, 0, 0.2);
        border-radius: 4px;
    }
    .btn-danger{
        color: #fff;
        background-color: rgb(226, 122, 122);
        border: 1px solid pink;
    }
    .btn-danger:hover{
        color: #fff;
        background-color: red;
    }
    .btn:focus{
        outline: none;
    }
    .todo-container{
        width: 600px;
        margin: 0 auto;
        padding: 10px;
        border: 1px solid #ddd;
        border-radius: 5px;
    }
</style>
//header.vue
<template>
  <div class="todo-header">
      <input type="text" placeholder="请输入你的任务,按下回车确定" v-model="title" @keyup.enter="add">
  </div>
</template>

<script>
import {nanoid} from 'nanoid'
export default {
    name:'testHeader',
    props:['addTodo'],
    data() {
      return {
        title:''
      }
    },
    methods:{
      add(event){
        // 校验数据
        if(!this.title.trim())return alert("输入不能为空")
        //将用户输入包装成一个todo对象
        const todoObj ={id:nanoid(),title:event.target.value,done:false}
        // 通知app组件去添加一个todo对象
        this.addTodo(todoObj)
        // 清空输入
        this.title=''
      }
    }
}
</script>

<style scoped>
  .todo-header{
    width: 560px;
    height: 28px;
    font-size: 14px;
    border-radius: 4px;
    padding: 4px 7px;
  }
  .todo-header input:focus{
    outline: none;
    border-color: rgb(96, 139, 219);
    box-shadow: 5px 10px black 0.3;
  }
</style>

 

//item.vue
<template>
   <li>
          <label >
              <!-- 如下代码也可以实现功能,但是不太推荐,因为有点违反原则,因为 修改了props-->
              <!-- <input type="check" v-model="todo.done"> -->
              <input type="checkbox" :checked="todo.done" @change="handCheck(todo.id)">
              <span>{{todo.title}}</span>
          </label>
          <button class="btn btn-danger" @click="handleDelete(todo.id)">删除</button>
      </li>
</template>

<script>
export default {
    name:'MyItem',
    // 声明接收todo对象
    props:['todo',"checkTodo",'deleteTodo'],
    methods: {
        handCheck(id){
            // 通知app组件将对应的todo对象的done值取反
            this.checkTodo(id)
        },
        handleDelete(id){
            if(confirm("确定要删除吗?")){
                this.deleteTodo(id)
            }
        }
    },

}
</script>

<style scoped>
    li{
        list-style: none;
        height: 36px;
        line-height: 36px;
        padding: 0 5px;
        border-bottom: 1px solid #ddd;
    }
    li label{
        float: left;
        cursor: pointer;
    }
    li label li input{
        vertical-align: middle;
        margin-right: 6px;
        position: relative;
        top: -1px;
    }
    li button{
        float: right;
        display: none;
        margin-top: 3px;
    }
    li:before{
        content: initial;
    }
li:last-child{
    border-bottom: none;
}
li:hover{
    background-color: #ddd;
}
li:hover button{
    display: block;
}
</style>

 

//footer.vue
<template>
  <div class="todo-footer" v-show="total">
      <label >
          <input type="checkbox" :checked="isAll" @change="checkAll">
      </label>
      <span>
          <span>已完成{{doneTotal}}</span>/全部{{total}}
      </span>
      <button class="btn btn-danger" @click="clearAll">清除已完成任务</button>
  </div>
</template>

<script>
export default {
    name:'testFooter',
    props:['todos','checkAllTodo','clearAllTodo'],
    computed:{
        total(){
            return this.todos.length
        },
        doneTotal(){
           let i=0
           this.todos.forEach((todo)=>{
               if(todo.done)
               i++
           })
           return i
        },
        isAll(){
            return this.doneTotal==this.total && this.total>0
        },
    },
    methods:{
        checkAll(e){
            this.checkAllTodo(e.target.checked)
        },
        clearAll(){
            this.clearAllTodo()
        }
    }
}
</script>

<style scoped>
    .todo-footer{
        height: 40px;
        line-height: 40px;
        padding-left: 6px;
        margin-top: 5px;
    }
    .todo-footer label{
        display: inline-block;
        margin-right: 20px;
        cursor: pointer;
    }
    .todo-footer label input{
        position: relative;
        top: -1px;
        vertical-align: middle;
    }
    .todo-footer button{
        float: right;
        margin-top: 5px;
    }
</style>

效果图如下:


网站公告

今日签到

点亮在社区的每一天
去签到