App.vue组件
<template>
<div class="app">
<MyHeader @handleAddTodo="handleAddTodo" />
<MyMain :list="showList" @handleDeleteTodo="handleDeleteTodo" />
<MyFooter
:list="list"
:type="type"
@handleSelectType="handleSelectType"
@handleChangeIsAll="handleChangeIsAll"
@handleClear="handleClear"
/>
</div>
</template>
<script>
import MyHeader from './components/MyHeader.vue';
import MyFooter from './components/MyFooter.vue';
import MyMain from './components/MyMain.vue';
export default {
name:'App',
components: { MyHeader, MyFooter, MyMain },
data() {
return {
list: [
{ id: 1, todo: '做饭', done: false, isHide: false },
{ id: 2, todo: '散步', done: false, isHide: false },
{ id: 3, todo: '买菜', done: false, isHide: false },
{ id: 4, todo: '洗澡', done: false, isHide: false },
],
type: 0,
};
},
computed: {
showList() {
if (this.type === 0) {
return this.list;
} else if (this.type === 1) {
return this.list.filter((todo) => !todo.done);
} else if (this.type === 2) {
return this.list.filter((todo) => todo.done);
}
},
},
methods: {
handleAddTodo(todo) {
this.list.push(todo);
const isAll =
this.list.length && this.list.some((todo) => todo.done);
this.type = isAll ? 0 : 1;
},
handleChangeIsAll(value) {
this.type = value ? 2 : 1;
this.list.forEach((todo) => (todo.done = value));
},
handleDeleteTodo(id) {
this.list = this.list.filter((todo) => todo.id !== id);
},
handleSelectType(type) {
this.type = type;
},
handleClear() {
this.list = this.list.filter((todo) => !todo.done);
},
},
};
</script>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
</style>
<style scoped>
.app {
width: 450px;
margin: 20px auto;
}
</style>
MyHeader.vue组件
<template>
<div class="header">
<input
type="text"
v-model="todo"
placeholder="请输入任务"
@keydown="handleAddTodo"
/>
</div>
</template>
<script>
export default {
name: 'MyHeader',
data() {
return {
todo: '',
};
},
methods: {
handleAddTodo(e) {
if (e.key !== 'Enter') return false;
if (!this.todo) {
alert('todo 信息不能为空');
return false;
}
this.$emit('handleAddTodo', {
id: +new Date(),
todo: this.todo,
done: false,
});
this.todo = '';
},
},
};
</script>
<style scoped>
.header {
height: 40px;
width: 100%;
}
input {
width: 100%;
height: 100%;
}
input:focus {
border: 1px solid #000;
}
</style>
MyMain.vue组件
<template>
<div class="todo-list">
<div class="todo-item" v-for="item in list" :key="item.id">
<label :for="item.id">
<input type="checkbox" :id="item.id" v-model="item.done" />
<span :class="item.done && 'todo-font'">{{ item.todo }}</span>
</label>
<div class="delete" @click="handleDeleteTodo(item.id)">+</div>
</div>
</div>
</template>
<script>
export default {
name: 'MyMain',
props: ['list'],
methods: {
handleDeleteTodo(id) {
this.$emit('handleDeleteTodo', id);
},
},
};
</script>
<style scoped>
.todo-item {
position: relative;
line-height: 44px;
border: 1px solid #999;
border-top: none;
}
.delete {
position: absolute;
display: none;
top: 50%;
right: 5px;
transform: translateY(-50%) rotate(45deg);
}
.todo-item:hover > .delete {
display: block;
cursor: pointer;
}
input[type='checkbox'] {
width: 24px;
height: 24px;
margin: 0 10px 0 5px;
vertical-align: middle;
}
.todo-font {
color: #cdcdcd;
text-decoration: line-through;
}
</style>
MyFooter.vue组件
<template>
<div class="footer">
<label for="is-all">
<input type="checkbox" id="is-all" v-model="isAll" />
{{ msg }}
</label>
<div class="select-model">
<div
v-for="t in typeList"
:key="t.type"
:style="t.type === type && style"
@click="handleSelectType(t.type)"
>
{{ t.name }}
</div>
</div>
<div
class="clear"
:style="isDone && 'visibility: visible;'"
@click="handleClear"
>
清除已完成
</div>
</div>
</template>
<script>
export default {
name:'MyFooter',
props: ['list', 'type'],
data() {
return {
msg: '全选',
style: { borderColor: 'red' },
typeList: [
{ type: 0, name: '全部' },
{ type: 1, name: '未完成' },
{ type: 2, name: '已完成' },
],
};
},
computed: {
isAll: {
get() {
const isAll =
this.list.length && this.list.every((todo) => todo.done);
this.msg = isAll ? '全不选' : '全选';
return isAll;
},
set(value) {
this.$emit('handleChangeIsAll', value);
},
},
isDone() {
return this.list.length && this.list.some((todo) => todo.done);
},
},
methods: {
handleSelectType(type) {
this.$emit('handleSelectType', type);
},
handleClear() {
this.$emit('handleClear');
},
},
};
</script>
<style scoped>
.footer {
display: flex;
width: 100%;
height: 34px;
padding: 0 5px;
border: 1px #999 solid;
border-top: none;
align-items: center;
justify-content: space-between;
}
#is-all {
width: 20px;
height: 20px;
vertical-align: bottom;
}
.select-model {
display: flex;
}
.select-model > div {
padding: 2px 5px;
margin: 0 5px;
border: 1px #ccc solid;
}
.clear {
cursor: pointer;
visibility: hidden;
}
</style>