vue todolist_多选框

父组件todo.vue

<template>
<section class="real-app">
<headers></headers>
<input
type="text"
class="add-input"
autofocus="autofocus"
placeholder="接下来做什么"
@keyup.enter="addTodo"
>
<Item
v-for="todo in filterTodos"
:todo="todo"
:key="todo.id"
@del="deleteTodo"
/>
<Tabs
:filter="filter"
:todos="todos"
@toggle="toggleFilter"
@clearAll="clearAllCompletedTodo"
/>
</section>
</template>

<script>
import Item from './item.vue';
import Tabs from './tabs.vue';
import headers from './header.vue';
// import { constants } from 'crypto';

let id = 0;

export default {
data() {
return {
todos: [], //list
filter: '全部'
}
},
components: {
Item,
Tabs,
headers
},
computed: {
filterTodos() {
if(this.filter === '全部') {
return this.todos;
}
const filterCompleted = this.filter === '已完成';
return this.todos.filter(todo=> todo.completed===filterCompleted);
}
},
methods: {
//input 按下enter事件 给todo中添加条目
addTodo(e) {
this.todos.unshift({
id: id++,
content: e.target.value,
completed: false
});

e.target.value = '';
},
//点击当前todo删除
deleteTodo(id) {
this.todos.splice(this.todos.findIndex(todo => id === todo.id), 1);
},
//点击状态按钮
toggleFilter(state) {
console.log('我是state',state);
this.filter = state;
},
//清除所有已完成 todo.completed设为false
clearAllCompletedTodo() {
this.todos = this.todos.filter(todo=> todo.completed===false);
}
}
}
</script>

<style lang='less' scoped>
.real-app{
width:600px;
margin:0 auto;
box-shadow:0 0 5px #666;
}
.add-input{
position:relative;
margin:0;
width:100%;
font-size:24px;
font-family:inherit;
font-weight:inherit ;
line-height:1.4em;
border:none;
outline:none;
color:inherit;
box-sizing:border-box;
// font-smoothing:antialiased;
padding:16px 16px 16px 36px;
border:none;
box-shadow:inset 0 -2px 1px rgba(0, 0, 0, 0.03);
}
</style>

子组件header.vue

<template>
<header class="main-header">
<h1>Todo</h1>
</header>
</template>

<style lang="less" scoped>
.main-header{
text-align:center;
h1{
font-size:100px;
color:rgba(175,47,47,0.4);
font-weight:400;
margin:20px;
}
}
</style>

子组件item.vue

<template>
<div :class="['todo-item', todo.completed? 'completed': '']">
<!-- 多选框 -->
<input
type="checkbox"
class="toggle"
v-model="todo.completed"
>
<!-- item -->
<label for="">{{todo.content}}</label>
<!-- 删除键 -->
<button class="destory" @click="deleteTodo"></button>
</div>
</template>

<script>
export default {
props: {
todo: {
type: Object,
required: true
}
},
methods: {
//把要删除的id传递给父元素
deleteTodo() {
this.$emit('del', this.todo.id);
}
}
}
</script>

<style lang='less' scoped>
.todo-item{
position:relative;
background-color :#fff;
font-size :24px;
border-bottom :1px solid rgba(0,0,0,0.06);
&:hover{
.destory:after{
content:'x';
}
}
label{
white-space:pre-line;
word-break:break-all;
padding:15px 60px 15px 15px;
margin-left:45px;
display:block;
line-height:1.2;
transition :color 0.4s;
&.completed{
label{
color:#d9d9d9;
text-decoration:line-through;
}
}
}
}
.toggle{
text-align:center;
width:50px;
height:30px;
position:absolute;
top:0;
bottom:0;
margin:auto 0;
border:none;
appearance:none;
outline:none;
&:after{
content:url('../assets/img/unChecked.svg');
}
&:checked:after{
content:url('../assets/img/checked.svg');
}
}
.destory{
position:absolute;
top:0;
right:10px;
bottom:0;
width:40px;
height:40px;
margin:auto 0;
font-size:30px;
color:#cc9a9a;
margin-bottom:11px;
transition:color 0.2s ease-out;
background-color:transparent;
appearance:none;
border-width :0;
cursor:pointer;
outline:none;
}
</style>

子组件tabs.vue

<template>
<div class="helper">
<span class="left">{{this.unfinishedTodo.length}} items left</span>
<span class="tabs">
<span v-for="state in states" :key="state" :class="[state, filter === state ? 'actived': '']" @click="toggleFilter(state)">
{{state}}
</span>
</span>
<span class="clear" @click="clearAllCompleted">清除已完成</span>
</div>
</template>

<script>
export default {
props: {
filter: {
type: String,
required: true //必传
},
todos: {
type: Array,
required: true
}
},
data() {
return {
states: ['全部', '未做', '已完成']
}
},
computed: {
//页面初始过滤未完成数据 监听展示
unfinishedTodo: function() {
return this.todos.filter(todo => todo.completed===false);
}
},
methods: {
//清除所有已完成
clearAllCompleted() {
this.$emit('clearAll'); //未传值 只是通知父组件发生了点击 逻辑在父组件里面判断
},
//点击状态按钮
toggleFilter(state) {
this.$emit('toggle', state); //传值
}
},
mounted(){

}
}
</script>

<style lang='less' scoped>
.helper{
font-weight:100;
display:flex;
justify-content:space-between;
padding: 5px 0;
line-height:30px;
background-color :#ffffff;
font-size:14px;
// font-smoothing:antialiased;
}

.left, .clear, .tabs{
padding:0 10px;
}
.left .clear{
width:150px;
}
.left{
text-align:center;
}
.clear{
text-align:right;
cursor:pointer;
}
.tabs{
width:200px;
display:flex;
justify-content:space-between;
*{
display:inline-block;
padding:0 10px;
cursor:pointer;
border:1px solid rgba(175,47,47,0);
&.actived{
border-color:rgba(175,47,47,0.4);
border-radius:5px;
}
}
}
</style>