TodoList经典案例

头部

  1. 使用v-model来双向绑定title​​​​​​​
  2. @keydown.enter="show" 绑定键盘回车事件
  3. 下载nanoid之后  引入import {nanoid} from 'nanoid' 
  4. 得要在v-model上面添加 ,trim清除空格 !this.title 代表空的时候弹出 alert
  5. 引入App.vue时要this.函数名()
<template>
    <div>
        <div class="todo-header">
            <!-- 清除空格 .trim -->
          <input type="text" v-model.trim="title" placeholder="请输入你的任务名称,按回车键确认" @keydown.enter="show" />
        </div>
    </div>
</template>
<script>
    // 获取id nanoid生成不同字符串id
    import {nanoid} from 'nanoid'
    export default{
        data(){
            return{
                title:""
            }
        },
        methods:{
            // 1.头部需要添加到相邻兄弟关系 所以需要先在父元素里面设置方法 通过:addTodo='addTodo' 传入到header里面 通过props接收
            // 定义一个添加的数据
            show(){
                if(!this.title){
                    alert("请输入内容")
                    return
                }
                // 添加的数据需要给input框 绑定v-model一个变量
                const todoObj = {id:nanoid(),title:this.title,done:false}
                // console.log(todoObj);
                // alert("sss")
                // 使用addTdo 添加方法
                this.addTodo(todoObj)
                // 填完完成后将文本框里面的title变量清空
                this.title=" "
            }
        },
        // 接收addTodo 方法
        props:['addTodo'],
    }
</script>

内容区域

  1. 使用:props:['todo','deleteTodo','checkTodo'],来接收App.vue传输过来的方法
  2. if(confirm("确定要删除吗?")){ } confirm写一个确定和取消的按钮
<template>
      <li>
          <label>
            <input type="checkbox" :checked="todo.done" @change="changedone(todo.id)"/>
            <span>{{todo.title}}</span>
          </label>
          <button class="btn btn-danger" @click="del(todo.id)">删除</button>
      </li>
</template>
<script>
import { del } from 'vue';

  export default{
    props:['todo','deleteTodo','checkTodo'],
    methods:{
      del(id){
        if(confirm("确定要删除吗?"))
        this.deleteTodo(id)
      },
      changedone(id){
        this.checkTodo(id)
      }

    }
  }
</script>
<style scoped>

</style>

App.vue

  1. 引入子组件 :import TodoHeader from '@/components/TodoHeader'
  2. 注册子组件:components: {TodoHeader} 
  3. 使用子组件:<TodoHeader :addTodo="addTodo"></TodoHeader> 向子元素传输函数需要加 :
  4. 添加功能:this.todos.unshift(todoObj)
  5. 使用filter来过滤实现删除功能: this.todos=this.todos.filter(todo=>todo.id!==id)
  6. 使用forEach来循环全部的todo数据
<template>
    <div id="root">
    <div class="todo-container">
      <div class="todo-wrap">
        <TodoHeader :addTodo="addTodo"></TodoHeader>
        <TodoList :todo="todos" :deleteTodo="deleteTodo" :checkTodo="checkTodo" ></TodoList>
        <TodoFooter :todo="todos" :completeDel="completeDel" :todoArraydone="todoArraydone"></TodoFooter>
      </div>
    </div>
  </div>
    <!-- <img alt="Vue logo" src="./assets/logo.png"> -->
    <!-- <HelloWorld msg="Welcome to Your Vue.js App"/> -->
    
</template>

<script>
// import HelloWorld from './components/HelloWorld.vue'
// 头部
import TodoHeader from '@/components/TodoHeader'
// 中间部分
import TodoList from '@/components/TodoList'
// 尾部
import TodoFooter from '@/components/TodoFooter'
export default {
  name: 'App',
      data(){
        return{
            // 定义数据
            todos:[
                {id:"001",title:"吃饭",done:false},
                {id:"002",title:"睡觉",done:false},
                {id:"003",title:"敲代码",done:false}
            ]
        }
      },
      methods:{
        // 头部: 定义添加功能
        addTodo(todoObj){
          this.todos.unshift(todoObj)
        },
        //中间左边:定义删除功能 
        // 1. 先定义一个删除方法
        // 2. 在父元素通过 :deleteTodo="deleteTodo" 来传入子元素 在通过 :deleteTodo="deleteTodo"传入到子元素
        // 3. 给删除按钮添加点击事件传入 todo.id
        deleteTodo(id){
          this.todos=this.todos.filter(todo=>todo.id!==id)
          // console.log(id);
        },

        // 检测id修改todo设置dome属性
        checkTodo(id){
          this.todos.forEach(todo=>{
            // 当获取到的id和表单的id相同时取反
            if (todo.id===id) {
                todo.done=!todo.done
                return
            }
          })
          // console.log(id); 
        },
        // 删除已完成的
        completeDel(){
          this.todos=this.todos.filter(todo=>!todo.done)
          // alert("ss")
        },
        // 获取到全部的todos里面的 checked的状态
        todoArraydone(checked){
          this.todos.forEach(todo=>{
            todo.done=checked
          })
        }
      },
  // 注册组件
  components: {
    // HelloWorld,
    TodoHeader,
    TodoList,
    TodoFooter,
    
  }
}
</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: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
  border-radius: 4px;
}

.btn-danger {
  border: 1px solid red;  
  color: #fff;
  background-color: #da4f49;
  border: 1px solid #bd362f;
}

.btn-danger:hover {
  color: #fff;
  background-color: #bd362f;
}

.btn:focus {
  outline: none;
}

.todo-container {
  width: 600px;
  margin: 0 auto;
}
.todo-container .todo-wrap {
  padding: 10px;
  border: 1px solid rgb(177, 177, 177);
  border-radius: 5px;
}

/*header*/
.todo-header input {
  width: 560px;
  height: 28px;
  font-size: 14px;
  border: 1px solid #ccc;
  border-radius: 4px;
  padding: 4px 7px;
}

.todo-header input:focus {
  outline: none;
  border-color: rgba(82, 168, 236, 0.8);
  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6);
}

/*main*/
.todo-main {
  margin-left: 0px;
  border: 1px solid #ddd;
  border-radius: 2px;
  padding: 0px;
}

.todo-empty {
  height: 40px;
  line-height: 40px;
  border: 1px solid #ddd;
  border-radius: 2px;
  padding-left: 5px;
  margin-top: 10px;
}
/*item*/
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;
  margin-top: 3px;
  display: none;
}
li:hover{
  background-color: gainsboro;
}
li:hover button{
  
  display: block;
} 
li:before {
  content: initial;
}

li:last-child {
  border-bottom: none;
}

/*footer*/
.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;
  margin-right: 5px;
}

.todo-footer button {
  float: right;
  margin-top: 5px;
}

</style>

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
对于一个Todolist的完整案例,可以包含以下功能: 1. 添加任务:用户可以通过输入框添加新的任务,任务可以包含标题和描述。 2. 删除任务:用户可以点击任务右侧的删除按钮,删除当前任务。 3. 标记任务完成:用户可以点击任务左侧的复选框,标记当前任务为已完成。 4. 修改任务:用户可以双击任务标题或描述,进入编辑状态,修改任务的标题和描述。 5. 过滤任务:用户可以根据任务状态(全部、已完成、未完成)过滤任务。 6. 存储任务:用户可以将添加的任务保存到浏览器本地存储中,以便下次打开页面时可以恢复之前的任务。 下面是一个使用Vue.js实现的Todolist完整案例的代码。 HTML代码: ``` <div id="app"> <h1>Todolist</h1> <div> <input type="text" v-model="newTask" placeholder="添加任务"> <button @click="addTask">添加</button> </div> <div> <button @click="changeFilter('all')">全部</button> <button @click="changeFilter('completed')">已完成</button> <button @click="changeFilter('uncompleted')">未完成</button> </div> <ul> <li v-for="(task, index) in filteredTasks" :key="index"> <input type="checkbox" v-model="task.completed" @change="updateTask(index)"> <span v-show="!task.editing" @dblclick="editTask(index)">{{ task.title }}</span> <input type="text" v-show="task.editing" v-model="task.title" @blur="updateTaskTitle(index)"> <button @click="deleteTask(index)">删除</button> </li> </ul> </div> ``` Vue.js代码: ``` new Vue({ el: '#app', data: { tasks: [], newTask: '', filter: 'all' }, methods: { addTask: function() { if (this.newTask.trim() !== '') { this.tasks.push({ title: this.newTask, completed: false, editing: false }); this.newTask = ''; this.saveTasks(); } }, deleteTask: function(index) { this.tasks.splice(index, 1); this.saveTasks(); }, updateTask: function(index) { this.tasks[index].editing = false; this.saveTasks(); }, editTask: function(index) { this.tasks[index].editing = true; }, updateTaskTitle: function(index) { this.tasks[index].editing = false; this.saveTasks(); }, changeFilter: function(filter) { this.filter = filter; }, saveTasks: function() { localStorage.setItem('tasks', JSON.stringify(this.tasks)); }, loadTasks: function() { var tasks = localStorage.getItem('tasks'); if (tasks !== null) { this.tasks = JSON.parse(tasks); } } }, computed: { filteredTasks: function() { if (this.filter === 'completed') { return this.tasks.filter(function(task) { return task.completed; }); } else if (this.filter === 'uncompleted') { return this.tasks.filter(function(task) { return !task.completed; }); } else { return this.tasks; } } }, mounted: function() { this.loadTasks(); } }); ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值