todoList案例----vue组件拆分

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: {
		/* 计算出不同类型的todo任务 */
		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: {
		/* 添加todo */
		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));
		},
		/* 删除todo */
		handleDeleteTodo(id) {
			this.list = this.list.filter((todo) => todo.id !== id);
		},
		/* 选择todo类型 */
		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;
	/* background-color: aqua; */
}
</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: {
		/* 添加todo */
		handleAddTodo(e) {
			// 判断按键是否为回车Enter键
			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: {
		/* todo选择全部、未完成、已完成 */
		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>

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值