Vue基础11之TodoList案例第一篇

news/2024/12/12 20:41:12/

Vue基础11

  • TodoList案例
    • 组件拆分
    • 静态组件
      • 代码目录结构
      • App.vue
      • Header.vue
      • List.vue
      • Item.vue
      • Footer.vue
  • 初始化列表
    • List.vue
    • Item.vue
  • 添加功能
    • 使用nanoid作为每项的id值
      • 安装nanoid
      • 使用nanoid
    • 兄弟组件之间的传值
      • App.vue
      • Header.vue
      • List.vue
  • 勾选
    • App.vue
    • List.vue
    • Item.vue
    • 使用v-model也能实现修改功能,不过不推荐使用
      • App.vue
      • List.vue
      • Item.vue

TodoList案例

组件拆分

在这里插入图片描述
样式结构:
在这里插入图片描述

静态组件

代码目录结构

在这里插入图片描述

App.vue

<template><div class="bg"><div class="todoList"><h2 class="title">待办事项</h2><Header /><div class="listItem"><List /><Footer /></div></div></div>
</template><script>import Header from "@/components/Header";
import List from "@/components/List";
import Footer from "@/components/Footer";
export default {name: "App",components:{Footer, Header, List},data(){return{appText:this.text}}
}
</script><style lang="less">
*{padding: 0;margin: 0;
}
.bg{background-color: #333;height: 937px;padding-top: 100px;box-sizing: border-box;.todoList{background-color: #fff;width: 50%;height: 90%;margin: 0 auto;//box-shadow: 5px 5px 10px 3px rgba(147, 221, 255, 0.5),-5px -5px 10px 3px rgba(147, 221, 255, 0.5);  蓝色阴影box-shadow: 5px 5px 10px 3px rgba(0, 0, 0, 0.5),-5px -5px 10px 3px rgba(0, 0, 0, 0.5);padding-top: 20px;box-sizing: border-box;.title{text-align: center;font-size: 30px;font-weight: 300;color: #00a4ff;}.listItem{width: 90%;//height: 200px;margin: auto;/*background-color: pink;*/list-style: none;border-radius: 0 0 5px 5px;box-shadow: 1px 1px 5px 1px rgba(0,0,0,0.1),-1px -1px 5px 1px rgba(0,0,0,0.1);padding: 20px 0;box-sizing: border-box;}}
}
</style>

Header.vue

<template><div><input type="text" class="content" @keyup.enter="enSure" placeholder="请输入你的任务名称,按回车键确认"></div>
</template><script>
export default {name: "Header",data(){return{InputText:''}},methods:{enSure(element){this.InputText=element.target.value;console.log(element.target.value)}}
}
</script><style scoped lang="less">
div{width: 90%;height: 8%;background-color: #ffffff;box-shadow: 1px 1px 5px 1px rgba(0,0,0,0.1),-1px -1px 5px 1px rgba(0,0,0,0.1);margin: 10px auto 2px auto;display: flex;.content{width: 95%;height: 80%;font-size: 25px;outline: none;display: block;margin: auto;justify-content: center;align-self: center;border: none;}
}
</style>

List.vue

<template><div><ul><div class="con"><Item :messages='["打代码","睡觉","吃饭"]'/></div></ul></div>
</template><script>
import Item from "@/components/Item";
export default {name:'List',components:{Item},
}
</script><style scoped lang="less">
ul{.con{//width: 95%;//margin: auto;border-bottom: 1px solid rgba(87, 87, 87, 0.3);border-left: 1px solid rgba(87, 87, 87, 0.3);border-right: 1px solid rgba(87, 87, 87, 0.3);margin: 0px 8px;//background-color: pink;}
}
</style>

Item.vue

<template><div><li v-for="(msg,index) in messages" :key="index"><input type="checkbox" name="matter" id="">&nbsp;{{msg}}<button class="delete">删除</button></li></div>
</template><script>export default {name: "Item",props:{messages:{type:Array,default:['123233','5125656']}}}
</script><style scoped lang="less">
li{//height: 35%;//width: 96%;display: block;//background-color: pink;margin: auto;padding: 12px;border-top: 1px solid rgba(87, 87, 87, 0.3);//border-left: 1px solid rgba(87, 87, 87, 0.3);//border-right: 1px solid rgba(87, 87, 87, 0.3);//box-sizing: border-box;border-collapse: collapse;button{background-color: #d9534f;float: right;padding: 3px 10px;color: white;border: 1px solid #d43f3a;border-radius: 5px;cursor: pointer;&:hover{background-color: #c9302c;border: 1px solid #ac2925;}}&:hover{background-color: rgba(0,0,0,0.1);}
}
</style>

Footer.vue

<template>
<div><input type="checkbox" name="matter" id="">&nbsp;已完成 <span>0</span> / 全部<span>3</span><button>清除已完成任务</button>
</div>
</template><script>export default {name: "Footer"}
</script><style scoped lang="less">
div{width: 95%;margin: auto;margin-top: 10px;//border: 1px solid rgba(87, 87, 87, 0.3);button{background-color: #d9534f;float: right;padding: 3px 10px;color: white;border: 1px solid #d43f3a;border-radius: 5px;cursor: pointer;&:hover{background-color: #c9302c;border: 1px solid #ac2925;}
}
}
</style>

初始化列表

List.vue

<template><div><ul><div class="con"><Item v-for="todoObj in todos" :key="todoObj.id" :todo="todoObj"/></div></ul></div>
</template><script>
import Item from "@/components/Item";
export default {name:'List',components:{Item},data(){return{todos:[{id:'001',title:'上班',done:false},{id:'002',title:'吃饭',done:false},{id:'003',title:'看电影',done:false},]}}
}
</script><style scoped lang="less">
ul{.con{//width: 95%;//margin: auto;border-bottom: 1px solid rgba(87, 87, 87, 0.3);border-left: 1px solid rgba(87, 87, 87, 0.3);border-right: 1px solid rgba(87, 87, 87, 0.3);margin: 0px 8px;//background-color: pink;}
}
</style>

Item.vue

<template><div><li><input type="checkbox" name="matter" id="" :checked="todo.done">&nbsp;{{todo.title}}<button class="delete">删除</button></li></div>
</template><script>export default {name: "Item",props:['todo']}
</script><style scoped lang="less">
li{//height: 35%;//width: 96%;display: block;//background-color: pink;margin: auto;padding: 12px;border-top: 1px solid rgba(87, 87, 87, 0.3);//border-left: 1px solid rgba(87, 87, 87, 0.3);//border-right: 1px solid rgba(87, 87, 87, 0.3);//box-sizing: border-box;border-collapse: collapse;button{background-color: #d9534f;float: right;padding: 3px 10px;color: white;border: 1px solid #d43f3a;border-radius: 5px;cursor: pointer;&:hover{background-color: #c9302c;border: 1px solid #ac2925;}}&:hover{background-color: rgba(0,0,0,0.1);}
}
</style>

在这里插入图片描述

添加功能

使用nanoid作为每项的id值

安装nanoid

npm i nanoid

在这里插入图片描述

使用nanoid

在这里插入图片描述
在这里插入图片描述

兄弟组件之间的传值

在这里插入图片描述

App.vue

<template><div class="bg"><div class="todoList"><h2 class="title">待办事项</h2><Header :addTodo="addTodo"/><div class="listItem"><List :todos="todos"/><Footer /></div></div></div>
</template><script>import Header from "@/components/Header";
import List from "@/components/List";
import Footer from "@/components/Footer";
export default {name: "App",components:{Footer, Header, List},data(){return{todos:[{id:'001',title:'吃饭',done:false},{id:'002',title:'唱歌',done:false},{id:'003',title:'看电影',done:false},]}},methods:{addTodo(addObj){this.todos.unshift(addObj)}}
}
</script><style lang="less">
*{padding: 0;margin: 0;
}
.bg{background-color: #333;height: 937px;padding-top: 100px;box-sizing: border-box;.todoList{background-color: #fff;width: 50%;height: 90%;margin: 0 auto;//box-shadow: 5px 5px 10px 3px rgba(147, 221, 255, 0.5),-5px -5px 10px 3px rgba(147, 221, 255, 0.5);  蓝色阴影box-shadow: 5px 5px 10px 3px rgba(0, 0, 0, 0.5),-5px -5px 10px 3px rgba(0, 0, 0, 0.5);padding-top: 20px;box-sizing: border-box;.title{text-align: center;font-size: 30px;font-weight: 300;color: #00a4ff;}.listItem{width: 90%;//height: 200px;margin: auto;/*background-color: pink;*/list-style: none;border-radius: 0 0 5px 5px;box-shadow: 1px 1px 5px 1px rgba(0,0,0,0.1),-1px -1px 5px 1px rgba(0,0,0,0.1);padding: 20px 0;box-sizing: border-box;}}
}
</style>

Header.vue

<template><div><input type="text" class="content" v-model="title" @keyup.enter="add" placeholder="请输入你的任务名称,按回车键确认"></div>
</template><script>
import {nanoid} from 'nanoid'
export default {name: "Header",data(){return{title:''}},props:['addTodo'],methods:{add(){//校验数据if(!this.title.trim()) return alert("输入的值不得为空");//将用户输入包装成一个todo对象const addObj={id:nanoid(),title:this.title,done:false};//通知App组件去添加一个todo对象this.addTodo(addObj)//清空输入this.title=''}}
}
</script><style scoped lang="less">
div{width: 90%;height: 8%;background-color: #ffffff;box-shadow: 1px 1px 5px 1px rgba(0,0,0,0.1),-1px -1px 5px 1px rgba(0,0,0,0.1);margin: 10px auto 2px auto;display: flex;.content{width: 95%;height: 80%;font-size: 25px;outline: none;display: block;margin: auto;justify-content: center;align-self: center;border: none;}
}
</style>

List.vue

<template><div><ul><div class="con"><Item v-for="todoObj in todos" :key="todoObj.id" :todo="todoObj"/></div></ul></div>
</template><script>
import Item from "@/components/Item";
export default {name:'List',components:{Item},props:['todos']
}
</script><style scoped lang="less">
ul{.con{//width: 95%;//margin: auto;border-bottom: 1px solid rgba(87, 87, 87, 0.3);border-left: 1px solid rgba(87, 87, 87, 0.3);border-right: 1px solid rgba(87, 87, 87, 0.3);margin: 0px 8px;//background-color: pink;}
}
</style>

请添加图片描述

勾选

在这里插入图片描述

App.vue

<template><div class="bg"><div class="todoList"><h2 class="title">待办事项</h2><Header :addTodo="addTodo"/><div class="listItem"><List :todos="todos" :checkTodo="checkTodo"/><Footer /></div></div></div>
</template><script>import Header from "@/components/Header";
import List from "@/components/List";
import Footer from "@/components/Footer";
export default {name: "App",components:{Footer, Header, List},data(){return{todos:[{id:'001',title:'吃饭',done:false},{id:'002',title:'唱歌',done:false},{id:'003',title:'看电影',done:false},]}},methods:{//添加一个todoaddTodo(addObj){this.todos.unshift(addObj)},checkTodo(id){this.todos.forEach((todo)=>{if(todo.id==id) {todo.done=!todo.done}})}}
}
</script><style lang="less">
*{padding: 0;margin: 0;
}
.bg{background-color: #333;height: 937px;padding-top: 100px;box-sizing: border-box;.todoList{background-color: #fff;width: 50%;height: 90%;margin: 0 auto;//box-shadow: 5px 5px 10px 3px rgba(147, 221, 255, 0.5),-5px -5px 10px 3px rgba(147, 221, 255, 0.5);  蓝色阴影box-shadow: 5px 5px 10px 3px rgba(0, 0, 0, 0.5),-5px -5px 10px 3px rgba(0, 0, 0, 0.5);padding-top: 20px;box-sizing: border-box;.title{text-align: center;font-size: 30px;font-weight: 300;color: #00a4ff;}.listItem{width: 90%;//height: 200px;margin: auto;/*background-color: pink;*/list-style: none;border-radius: 0 0 5px 5px;box-shadow: 1px 1px 5px 1px rgba(0,0,0,0.1),-1px -1px 5px 1px rgba(0,0,0,0.1);padding: 20px 0;box-sizing: border-box;}}
}
</style>

List.vue

<template><div><ul><div class="con"><Item v-for="todoObj in todos" :key="todoObj.id" :todo="todoObj" :checkTodo="checkTodo"/></div></ul></div>
</template><script>
import Item from "@/components/Item";
export default {name:'List',components:{Item},props:['todos','checkTodo']
}
</script><style scoped lang="less">
ul{.con{//width: 95%;//margin: auto;border-bottom: 1px solid rgba(87, 87, 87, 0.3);border-left: 1px solid rgba(87, 87, 87, 0.3);border-right: 1px solid rgba(87, 87, 87, 0.3);margin: 0px 8px;//background-color: pink;}
}
</style>

Item.vue

<template><div><li><input type="checkbox" name="matter" id="" :checked="todo.done" @change="handleCheck(todo.id)">&nbsp;{{todo.title}}<button class="delete">删除</button></li></div>
</template><script>export default {name: "Item",//声明接收todo对象props:['todo','checkTodo'],methods:{handleCheck(id){//通知App组件将对应的todo对象的done值取反this.checkTodo(id)}}}
</script><style scoped lang="less">
li{//height: 35%;//width: 96%;display: block;//background-color: pink;margin: auto;padding: 12px;border-top: 1px solid rgba(87, 87, 87, 0.3);//border-left: 1px solid rgba(87, 87, 87, 0.3);//border-right: 1px solid rgba(87, 87, 87, 0.3);//box-sizing: border-box;border-collapse: collapse;button{background-color: #d9534f;float: right;padding: 3px 10px;color: white;border: 1px solid #d43f3a;border-radius: 5px;cursor: pointer;&:hover{background-color: #c9302c;border: 1px solid #ac2925;}}&:hover{background-color: rgba(0,0,0,0.1);}
}
</style>

请添加图片描述

使用v-model也能实现修改功能,不过不推荐使用

在Item.vue中的checkbox使用v-model双向绑定,虽然也能实现功能,但是不推荐,因为有点违反原则,因为修改了props值,Vue的检测是浅度检测,props中是todo对象时,使用todo.done改值后,地址值并没有修改,则Vue检测不到,所以未报错,但是一旦使用变量存储就会报错

App.vue

<template><div class="bg"><div class="todoList"><h2 class="title">待办事项</h2><Header :addTodo="addTodo"/><div class="listItem"><List :todos="todos"/><Footer /></div></div></div>
</template><script>import Header from "@/components/Header";
import List from "@/components/List";
import Footer from "@/components/Footer";
export default {name: "App",components:{Footer, Header, List},data(){return{todos:[{id:'001',title:'吃饭',done:false},{id:'002',title:'唱歌',done:false},{id:'003',title:'看电影',done:false},]}},methods:{//添加一个todoaddTodo(addObj){this.todos.unshift(addObj)}}
}
</script><style lang="less">
*{padding: 0;margin: 0;
}
.bg{background-color: #333;height: 937px;padding-top: 100px;box-sizing: border-box;.todoList{background-color: #fff;width: 50%;height: 90%;margin: 0 auto;//box-shadow: 5px 5px 10px 3px rgba(147, 221, 255, 0.5),-5px -5px 10px 3px rgba(147, 221, 255, 0.5);  蓝色阴影box-shadow: 5px 5px 10px 3px rgba(0, 0, 0, 0.5),-5px -5px 10px 3px rgba(0, 0, 0, 0.5);padding-top: 20px;box-sizing: border-box;.title{text-align: center;font-size: 30px;font-weight: 300;color: #00a4ff;}.listItem{width: 90%;//height: 200px;margin: auto;/*background-color: pink;*/list-style: none;border-radius: 0 0 5px 5px;box-shadow: 1px 1px 5px 1px rgba(0,0,0,0.1),-1px -1px 5px 1px rgba(0,0,0,0.1);padding: 20px 0;box-sizing: border-box;}}
}
</style>

List.vue

<template><div><ul><div class="con"><Item v-for="todoObj in todos" :key="todoObj.id" :todo="todoObj"/></div></ul></div>
</template><script>
import Item from "@/components/Item";
export default {name:'List',components:{Item},props:['todos']
}
</script><style scoped lang="less">
ul{.con{//width: 95%;//margin: auto;border-bottom: 1px solid rgba(87, 87, 87, 0.3);border-left: 1px solid rgba(87, 87, 87, 0.3);border-right: 1px solid rgba(87, 87, 87, 0.3);margin: 0px 8px;//background-color: pink;}
}
</style>

Item.vue

<template><div><li>
<!--      如下代码也能实现功能,但是不太推荐,因为有点违反原则,因为修改了props--><input type="checkbox" name="matter" id="" v-model="todo.done">&nbsp;{{todo.title}}<button class="delete">删除</button></li></div>
</template><script>export default {name: "Item",//声明接收todo对象props:['todo'],}
</script><style scoped lang="less">
li{//height: 35%;//width: 96%;display: block;//background-color: pink;margin: auto;padding: 12px;border-top: 1px solid rgba(87, 87, 87, 0.3);//border-left: 1px solid rgba(87, 87, 87, 0.3);//border-right: 1px solid rgba(87, 87, 87, 0.3);//box-sizing: border-box;border-collapse: collapse;button{background-color: #d9534f;float: right;padding: 3px 10px;color: white;border: 1px solid #d43f3a;border-radius: 5px;cursor: pointer;&:hover{background-color: #c9302c;border: 1px solid #ac2925;}}&:hover{background-color: rgba(0,0,0,0.1);}
}
</style>

http://www.ppmy.cn/news/22734.html

相关文章

Java特性之设计模式【观察者模式】

一、观察者模式 概述 当对象间存在一对多关系时&#xff0c;则使用观察者模式&#xff08;Observer Pattern&#xff09; 观察者模式是一种对象行为模式。它定义对象间的一种一对多的依赖关系&#xff0c;当一个对象的状态发生改变时&#xff0c;所有依赖于它的对象都得到通知…

路由器连接WIFI组网

白驹过隙&#xff0c;逝者如斯。经过断断续续几个月的更新&#xff0c;关于无线路由器和Wi-Fi的介绍终于告一段落。 其实&#xff0c;这个话题下还有很多很多的内容没有涉及到&#xff0c;然生有涯而知无涯&#xff0c;只能在此暂且搁笔&#xff0c;后续缘起再续。 下面&…

第九章(14):STL之常用拷贝和替换算法

文章目录前情回顾常用拷贝算法copy常用替换算法replacereplac_ifswap下一座石碑&#x1f389;welcome&#x1f389; ✒️博主介绍&#xff1a;一名大一的智能制造专业学生&#xff0c;在学习C/C的路上会越走越远&#xff0c;后面不定期更新有关C/C语法&#xff0c;数据结构&…

JVM入门知识总结

在学习虚拟机之前我们要知道为什么要学习虚拟机呢?首先就是增加自己的知识,其次就是面试的需要,其实不懂 JVM 也可以照样写出优质的代码&#xff0c;但是不懂 JVM 有可能别被面试官虐得体无完肤.一.虚拟机的概述虚拟机&#xff08;Virtual Machine&#xff09;&#xff0c;就是…

8 个很棒的 Vue 开发技巧

1.路由参数解耦通常在组件中使用路由参数&#xff0c;大多数人会做以下事情。export default {methods: {getParamsId() {return this.$route.params.id}} }在组件中使用 $route 会导致与其相应路由的高度耦合&#xff0c;通过将其限制为某些 URL 来限制组件的灵活性。正确的做…

MySQl学习(从入门到精通 1.5)

MySQl学习&#xff08;从入门到精通 1.5&#xff09;第 08 章_聚合函数1. 聚合函数介绍1. 1 AVG和SUM函数1. 2 MIN和MAX函数1. 3 COUNT函数2. 1 基本使用2. 2 使用多个列分组2. 3 GROUP BY中使用WITH ROLLUP3. HAVING3. 1 基本使用3. 2 WHERE和HAVING的对比4. SELECT的执行过程…

我的网站上线了!

最近有段时间没有写原创文章了&#xff0c;恰好这两天正在翻阅历史文章的时候&#xff0c;发现文章中的图片竟然裂了&#xff1f;顿时冒了一身冷汗&#xff0c;因为每逢遇到这种情况&#xff0c;动辄需要花费一周的时间迁移图片。。。。。。 当我直接访问图片 url 的时候&#…

一文速学-Pandas数据展示选项设置详解+实例代码操作展示

目录 前言 一、获取数据展示参数 二、可选展示选项 1.describe_option&#xff08;&#xff09; 2.get_option()/set_option() 3.reset_option() 4. option_context&#xff08;&#xff09; 三、 在Python/IPython环境中设置启动选项 四、常用选项 1.display.max_rows…