Copy the ToDoList to-do list:
1. Render data
arr:[
{
id:1.content:Content of "1".isShowBorder:true.isFinished:true
},
{
id:2.content:"Content 2".isShowBorder:true.isFinished:true
},
{
id:3.content:"Content 3".isShowBorder:true.isFinished:false}]Copy the code
<div class="tit"><h3>The ongoing</h3> <span>2</span></div>
<ul>
<li v-for="item in arr" v-if=! "" item.isFinished">
<label :for="item.id"><input type="checkbox" :id="item.id" :checked="item.ifCheck"></label>
<div v-if="item.isShowDiv">{{item.content}}</div>
<input v-else type="text" v-model="item.content">
<span>-</span>
</li>
</ul>
<div class="tit"><h3>Has been completed</h3> <span>1</span></div>
<ul>
<li v-for="item in arr" v-if="item.isFinished">
<label :for="item.id"><input type="checkbox" :id="item.id" :checked="item.ifCheck"></label>
<div v-if="item.isShowDiv">{{item.content}}</div>
<input v-else type="text" v-model="item.content">
<span>-</span>
</li>
</ul>
Copy the code
2. Separate the UL into components
<div class="wrap">
<list-comp :arr="arr" title="In progress" type="doing" :counts="counts"></list-comp>
<list-comp :arr="arr" title="已经完成" type="finished" :counts="counts"></list-comp>
</div>.<template id="tmpl">
<div class="con-list">
<div class="hd">
<h3>{{title}}</h3>
<div class="num">{{counts(type)}}</div>
</div>
<ul class="bd">
<li v-for="item in arr" v-show="type=='doing'? ! item.isFinished:item.isFinished">
<div class="check-box"><input type="checkbox"></div>
<input type="text" v-model="item.content">
<div class="btn-box"><div class="del-btn">-</div></div>
</li>
</ul>
</div>
</template>
Copy the code
let listComp = {
template:"#tmpl".props: ["arr"."title"."type"."counts"]}Copy the code
3. Calculate attributes. Calculate the number of data items in the upper right corner
/ / the Vue instances
computed: {counts(){
return type= >{
let ret = this.arr.filter(item= >{
return type=="doing"? ! item.isFinished:item.isFinished })return ret.length
}
}
}
Copy the code
4. Select the check box to move the ongoing tasks to the completed list
<! Parent component passes event function to child component -->
<list-comp :arr="arr" title="In progress" type="doing" :counts="counts" @fn="changeChecked"></list-comp>
<list-comp :arr="arr" title="已经完成" type="finished" :counts="counts" @fn="changeChecked"></list-comp>
<! -->
<div class="check-box"><input type="checkbox" @click="chchecked(key)"></div>
Copy the code
// 4. Call the method passed by the parent
methods: {chchecked(index){
this.$emit("fn",index)
}
}
// 1. Define methods in the parent component
// Click to change the selected state
methods: {changeChecked(index){
// alert(111)
this.arr[index].isFinished = !this.arr[index].isFinished
}
},
Copy the code
5. Click Input to switch the label border color
<! -- Parent component -->
<list-comp
:arr="arr"
title="In progress"
type="doing"
:counts="counts"
@fn="changeChecked"
@fn2="changeBorder"
></list-comp>
<list-comp :arr="arr" title="已经完成" type="finished" :counts="counts" @fn="changeChecked" @fn2="changeBorder"></list-comp>
<! -- -- -- > templates
<input type="text" v-model="item.content" @click="showBorder(key)" :class="item.isShowBorder? 'show-border':''">
Copy the code
/ / child component
showBorder(index){
this.$emit("fn2",index)
}
/ / the parent component
changeBorder(index){
this.arr[index].isShowBorder = !this.arr[index].isShowBorder
}
Copy the code
6. Set out of focus
<! Blur ="showBorder(key)"-->
<input type="text" v-model="item.content" @click="showBorder(key)" @blur="showBorder(key)" :class="item.isShowBorder? 'show-border':''">
Copy the code
7. Delete an item
<! -- Parent template -->
<list-comp
:arr="arr"
title="In progress"
type="doing"
:counts="counts"
@fn="changeChecked"
@fn2="changeBorder"
@fn3="del"
></list-comp>
<list-comp :arr="arr" title="已经完成" type="finished" :counts="counts" @fn="changeChecked" @fn2="changeBorder" @fn3="del"></list-comp>
<! -- Subtemplate -->
<div class="btn-box"><div class="del-btn" @click="del(key)">-</div></div>
Copy the code
// In the child component
del(index){
this.$emit("fn3",index)
}
// Parent component:
del(index){
this.arr.splice(index,1)}Copy the code
8. Enter and press Enter to add an element to “In Progress”
<input class="input-text" type="text" placeholder="Please enter the task" @keyup.enter="add" v-model="txtVal">
Copy the code
// The Vue instance defines num as the id of each data item, and also as a basis for whether the site has been saved locally
methods: {add(){
this.arr.push({
id:this.num,
isFinished:false.content:this.txtVal,
isShowBorder:false
});
this.num++; }}Copy the code
9, record the existing data, so that the next time you open the browser you can still see the current data
// Define methods in the parent component
setToLocalStorage(){
localStorage.setItem('num'.this.num);
localStorage.setItem('arr'.JSON.stringify(this.arr));
}
// Save localStorage for each change
this.setToLocalStorage();
// After each component creation, the two localstorages can be retrieved
created(){
this.num = localStorage.getItem("num")?localStorage.getItem("num") :0;
this.arr=localStorage.getItem("arr")?JSON.parse(localStorage.getItem('arr')) : []; },Copy the code
10. Complete code:
<! DOCTYPEhtml>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="Width = device - width, initial - scale = 1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title></title>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<link rel="stylesheet" href="style/index.css">
</head>
<body>
<div id='app'>
<header>
<div class="wrap">
<h1>ToDoList</h1>
<input type="text" placeholder="Please enter..." v-model='inpTxt' @keyup.enter='add'>
</div>
</header>
<con-comp title='In progress' :arr='arr' type='doing' @fn="changeType" @fn2='borderFa' @fn3='delFa'></con-comp>
<con-comp title='Done' :arr='arr' type='finished' @fn="changeType" @fn2='borderFa' @fn3='delFa'></con-comp>
<div class="footer">
Copyright 2021 todolist.cn clear
</div>
</div>
<template id="tmp">
<div class="wrap">
<div class="hd">
<h3>{{title}}</h3>
<div class="count">{{counts}}</div>
</div>
<ul class="bd">
<! -- Li display or not display is item. IsFinished is for unfinished tasks! Item. isFinished displays unfinished tasks. For completed tasks, item.isFinished displays completed tasks. Item. isFinished or item.isFinished -->
<li v-for='item,key in arr' v-show="type=='doing'? ! item.isFinished:item.isFinished">
<div class="l">
<input type="checkbox" @click="clickCheckbox(key)" :checked='item.isFinished'>
</div>
<input type="text" v-model='item.content' :class="item.isShowBorder? 'showBorder':''"
@focus='borderChil(key)' @blur='borderChil(key)'>
<div class="r">
<div @click='del(key)'>-</div>
</div>
</li>
</ul>
</div>
</template>
<script>
let conComp = {
template: '#tmp'.props: ['title'.'arr'.'type'].computed: {
// doingCounts() {
// Count the number of incomplete entries
// // filters out elements with isFinished as false in the ARR array
// let newArr = this.arr.filter(item => {
// return item.isFinished == false
/ /})
// return newArr.length
// },
// finishedCounts(){
// Count the number of completed entries
// // filters out elements in the ARR array with isFinished as true
// let newArr = this.arr.filter(item => {
// return item.isFinished == true
/ /})
// return newArr.length
// }
counts() {
let newArr = this.arr.filter(item= > {
return this.type == 'doing'? ! item.isFinished : item.isFinished })return newArr.length
}
},
methods: {
clickCheckbox(key) {
// Modify isFinished for the data
this.$emit('fn', key)
},
borderChil(key) {
this.$emit('fn2', key)
},
del(key) {
this.$emit('fn3', key)
}
},
}
new Vue({
el: '#app'.data: {
inpTxt: ' '.num: 3.arr: [
/ / {
// id: 1,
// content: "1",
// isFinished: true
// isShowBorder: false
/ /},
/ / {
// id: 2,
// content: "2",
// isFinished: true
// isShowBorder: false
/ /},
/ / {
// id: 3,
// content: "3",
// isFinished: false, // this is used to tell whether it isFinished
// isShowBorder: false
/ /}]},components: {
conComp
},
created() {
// The lifecycle function that executes the code when the instance/component is first created
// Get num and arr in localstorage
// Assign values to this.num and this.arr
this.num = localStorage.getItem('num')?parseInt(localStorage.getItem('num')) : 0
this.arr =
localStorage.getItem("arr")?JSON.parse(localStorage.getItem("arr":)) []},methods: {
changeType(index) {
this.arr[index].isFinished = !this.arr[index].isFinished
this.setLocalstorage()
},
borderFa(index) {
this.arr[index].isShowBorder = !this.arr[index].isShowBorder
this.setLocalstorage()
},
delFa(index) {
this.arr.splice(index, 1)
this.setLocalstorage()
},
add() {
if (!this.inpTxt) {
return
}
this.arr.push({
id: + +this.num,
content: this.inpTxt,
isFinished: false.// It is used to tell whether or not it is done
isShowBorder: false // To distinguish whether there is a border
})
this.inpTxt = ' '
this.setLocalstorage()
},
setLocalstorage() {
// Save data num and arr
localStorage.setItem("num".this.num)
localStorage.setItem("arr".JSON.stringify(this.arr))
}
},
})
</script>
</body>
</html>
Copy the code
CSS file code:
* {margin: 0;
padding: 0;
list-style: none;
outline: none;
}
body{
background-color: #ccc;
}
header{
height: 50px;
line-height: 50px;
background-color: # 333;
}
h1{
color: #fff;
}
.wrap{
width: 600px;
margin: 0 auto;
}
header .wrap{
display: flex;
justify-content: space-between;
}
header input{
height: 40px;
margin-top: 3px;
width: 300px;
text-indent: 10px;
}
.hd{
display: flex;
justify-content: space-between;
margin-top: 10px;
}
.hd .count{
width: 30px;
height: 30px;
color: #fff;
background-color: # 666;
border-radius: 50%;
text-align: center;
line-height: 30px;
}
.bd{
margin-bottom: 20px;
}
.bd li{
display: flex;
background-color: #fff;
height: 40px;
margin-top: 8px;
}
.l..r{
width: 40px;
height: 40px;
display: flex;
align-items: center;
justify-content: center;
}
.bd input[type=text]{
margin-top: 3px;
flex: 1;
height: 30px;
border-color: #fff;
border-width: 0px;
}
.bd input[type=text].showBorder{
border: 1px solid # 000;
}
.l>input..r>div{
width: 30px;
height: 30px;
}
.r>div{
background-color: pink;
border-radius: 50%;
text-align: center;
line-height: 30px;
}
.footer{
text-align: center;
margin-top: 20px;
}
.bd input[type=checkbox]..r>div{
cursor: pointer;
}
Copy the code