本篇文章起源于我在学习 Vue 过程中遇到的 to-do list 练手项目。当我学习了前端三大件后,就选择了 Vue 作为下一步的学习对象。我目前只读了 Vue 3.0 的官方文档之基础篇,对 Vue 的了解仅限于基础的数据绑定、methods 方法和 v 指令。因此在实现 to-do list 过程中,我所使用的相关技术栈也仅限于上述提到的这些。
阅读本文的前置条件:
- 了解 HTML、CSS、JS 对象和基础函数;
- 了解 Vue 中的数据与组件绑定、methods、v-for、v-on 和 v-bind 指令;
实现目标:
- 用户可输入多项今日待做任务;
- 今日待做任务显示在待做列表中;
- 今日待做任务完成后,待做任务移入已完成列表;
- 用户可重新将待做任务移入待做列表;
- 用户可清空待做列表和已完成列表;
实现路径:
- 目标 1 要求一个输入框和提交按钮,当它提交后,数据进入待做列表;因此,我们需要一个
v-model和 data 数据。 - 目标 2 要求将数据显示在待做列表中,因此我们需要有一个数组(或者对象)、一个监控、当提交按钮点击后,用户所输入的内容能够 push 到数组中。同时我们需要一个
v-for, 将内容进行渲染。 - 目标 3 要求待做任务完成后,可以移入已完成列表。因此我们需要一个监控和未完成数组,当点击完成时,该数据从已完成任务数组中删除,添入未完成数组。同时我们需要一个
v-for, 将内容进行渲染。 - 目标 4 其实是重复了目标 3 ,只不过主次位置进行颠倒。
- 目标 5 只需要将原先的数组、数值全部清空即可。
具体代码:
HTML:
<script src="https://unpkg.com/vue@next"></script>
<div id='todo'>
<input v-model="context">
<button @click="add">add</button>
<button @click="clear">clear</button>
<br>
<br>
<p>待完成</p>
<template v-for="(item,key,i) in list" :key="item.id">
<input value="item" type="checkbox" id="i" @click="change(item)" >
<label for="i" :class="{'del':item.isfalse}">{{item.context}}</label>
<br>
</template>
<p>已完成</p>
<template v-for="(item,key,i) in haslist" :key="item.id">
<input value="item" type="checkbox" id="i" @click="changeagain(item)" checked>
<label for="i" :class="{'del':item.isfalse}">{{item.context}}</label>
<br>
</template>
</div>
CSS:
.list{
float:left;
margin-left:100px;
}
button {
margin-left:10px;
}
.del{
text-decoration:line-through;
}
JS:
const app = Vue.createApp({
data(){
return{
context:"",
list:[],
id:1,
haslist:[]
}
},
methods:{
add(){
this.list.push({context:this.context,id:this.id,isfalse:false});
this.id ++
},
clear(){
this.context = "";
this.list=[];
this.id=1;
this.haslist=[]
},
change(item){
let darray = this.list.splice(this.list.indexOf(item),1);
this.haslist.push(darray[0]);
item.isfalse =!item.isfalse
},
changeagain(item){
let array = this.haslist.splice(this.haslist.indexOf(item),1);
this.list.push(array[0]);
item.isfalse =!item.isfalse
},
}
});
app.mount('#todo');
CodePen:
See the Pen PoWXpzm by 善宝橘 (@liuluffy) on CodePen.
存在难点:
作为一个菜鸟,首先难住我的就是思路,一开始我并未想到直接将数据删除,而是想通过 v-if 来实现单个元素是否渲染。但试了半天(是真的半天)也没有找到解决方案。因为我一直把 v-if 的值设置在 data(){} 里,导致全局的值都改变掉。
后来找网上其他人的解决方案,看到可以直接删除数据来解决该问题。但删除数据对我来说也有问题,即我删除数据是用 splice方法,因此需要一个起始值,我一开始用的是 v-for 中的索引,但是就遇到了 key 值问题。不过我并没有调三方库生成唯一id。
所以我的难点就在于,缺少唯一 id,缺少 false 来添加 class(我想让被删除对象加 line-through)。我还不知道怎么操纵 v-for 的单一 item。
后来还是查资料,才突然发现,其实我因为往数组里推入 obj,对象中可以添加包括 id、isfalse 等判定条件。另外我在 methods 中设置的函数可以传入单个 item 作为参数。
但是后面还是遇到了一个难点,一开始我把 obj 设在了 data(){},结果全局都变了。每一个 item 都一模一样,后来我只在 data(){} 中放最基本的数值,而把 obj 转到了下面的 methods:{} 中,结果发现可行。