• Free download project download link

Create a Vue project

There are many ways to create a project, so let’s briefly say two ways: 1, command line to create win+r enter CMD enter CD to enter the directory you want to create, enter the following command, when you need to confirm the place press Enter, generally no problem

vue init webpack todolist // Todolist is the project name
Copy the code

After successful creation, enter the project to install the dependency run

cd todolist
npm install // yarn 或  cnpm install
npm run dev
Copy the code

2, if you use the HBuilder development tool, you can directly create a project in the tool click on the upper left corner of the file -> New -> project input name, select a folder, click create it1) Install NPM I router. 2) Create router folder in SRC and create an index.js file to configure routes

import Vue from "vue"
import Router from "vue-router"
Vue.use(Router)

import Index from '@/pages/todoist'

const router = new Router({
	mode: 'history'.routes: [{path: '/'.name: 'index'.component: Index
		},
	]
})

export default router

Copy the code

3) Import routes in main.js

import Vue from 'vue'
import App from './App.vue'
import router from './router'
import VueRouter from 'vue-router'

Vue.config.productionTip = false
Vue.use(VueRouter)

new Vue({
	router,
	render: h= > h(App)
}).$mount('#app')

Copy the code

The final project files are as follows:

Second, the component

Todolist can be divided into three sections: 1, header (add input field), 2, list (add column list), 3, bottom (button, etc.) We can split these three sections into three components:

Add todoHeader, todoItem and todoFooter to the components folder

import todoHeader from './components/todoHeader.vue'
import todoItem from './components/todoItem.vue'
import todoFooter from './components/todoFooter.vue'
export default {
	components: {
		todoHeader,
		todoItem,
		todoFooter
	},
	data() {
		return{}},methods: {}}Copy the code

Component code

index.vue

<template>
	<div class="page flex">
		<div class="card">
			<h1>Todo List</h1>
			<todoHeader @confirm="confirm" />
			<todoItem :list="list" @change="changeList" />
			<todoFooter :list="list" @change="allChange" @delete="show_confirm" />
		</div>
	</div>
</template>

<script>
	import todoHeader from './components/todoHeader.vue'
	import todoItem from './components/todoItem.vue'
	import todoFooter from './components/todoFooter.vue'
	export default {
		components: {
			todoHeader,
			todoItem,
			todoFooter
		},
		data() {
			return {
				list: [
					/ / {
					// value: 'eat ',
					// checked: false
					// },
					/ / {
					// value: 'sleep ',
					// checked: false
					// }]}},methods: {
			changeList({checked, index}) {
				this.list[index].checked = checked
			},
			confirm(value) {
				this.list.push({
					value,
					checked: false})},allChange(checked) {
				this.list.map(item= > {
					item.checked = checked
				})
			},
			show_confirm() {
				if (this.list.length > 0) {
					let flag = false
					this.list.map(item= > {
						if (item.checked) {
							flag = true}})if (flag) {
						let modal = confirm("Are you sure you want to delete completed tasks?");
						if (modal) {
							this.del()
						}
					} else {
						alert('Only completed tasks can be deleted! ')}}else {
					alert('No task to delete! ')}},del() {
				let arr = []
				this.list.map((item, index) = > {
					if(! item.checked) { arr.push(item) } })this.list = arr
			}
		}
	}
</script>

<style>
	.page{
		width: 100%;
		margin-top: 50px;
		justify-content: center;
	}
	
	.flex{
		display: flex;
		align-items: center;
	}
	
	.flex-1{
		flex: 1;
	}
	
	.card{
		width: 500px;
		padding: 15px 16px;
		border-radius: 4px;
		border: 1px solid #DCDFE6;
	}
	
	.card:hover{
		box-shadow: 0 2px 12px 0 rgba(0.0.0.0.1)}h1{
		text-align: center;
		margin-bottom: 20px;
	}
</style>

Copy the code

todoHeader.vue

<template>
	<div class="header flex">
		<div class="inputs flex-1" :class="isfocus ? 'focus' :''">
			<input placeholder="Please enter your task name and press Enter to confirm." class="input" type="text" v-model="value" @focus="focus" @blur="blur" @keyup.enter="confirm" />
		</div>
		<button v-show="isfocus" class="btn" type="button">Add</button>
	</div>
</template>

<script>
	export default {
		data() {
			return {
				isfocus: false.value: ' '}},methods: {
			focus() {
				this.isfocus = true
			},
			blur() {
				this.isfocus = false
			},
			confirm() {
				this.$emit('confirm'.this.value)
				this.value = ' '}}}</script>

<style>
	.header{
		width: 100%;
		margin-bottom: 20px;
		justify-content: space-between;
	}
	
	.inputs{
		border-radius: 4px;
		border: 1px solid #DCDFE6;
		padding: 6px 10px;
	}
	
	.inputs.focus{
		border: 1px solid #409EFF;
		box-shadow: 0 1px 8px 0 rgba(64.158.255.0.4)}.input{
		width: 100%;
		height: 20px;
	}
	
	.btn{
		padding: 6px 10px;
		background-color: red;
		color: #FFFFFF;
		border-radius: 4px;
		cursor: pointer;
		margin-left: 20px;
	}
	
	.btn:hover{
		background-color: #F56C6C;
	}
</style>

Copy the code

todoItem.vue

<template>
	<div class="list">
		<ul v-if="list.length">
			<li class="flex" v-for="(item, index) in list" :key="index">
				<div class="flex-1" @click="change(! item.checked, index)">
					<input class="checkbox" type="checkbox" :value="item.value" v-model="item.checked" @change.stop="change(item.checked, index)" />
					<label class="label">{{ item.value }}</label>
				</div>
				<div v-if="item.checked" style="color: #C0C4CC;">Has been completed</div>
			</li>
		</ul>
		<div class="empty flex" v-else>
			<span>No task</span>
		</div>
	</div>
</template>

<script>
	export default {
		props: {
			list: {
				type: Array.default: []}},data() {
			return{}},methods: {
			change(checked, index) {
				this.$emit('change', {checked, index})
			}
		}
	}
</script>

<style>
	.list{
		width: 100%;
		margin-bottom: 20px;
	}
	
	ul{
		width: 100%;
		border-radius: 4px;
		border: 1px solid #DCDFE6;
	}
	
	li{
		padding: 0 10px;
		border-bottom: 1px solid #DCDFE6;
		justify-content: space-between;
		cursor: pointer;
	}
	
	li > div{
		padding: 8px 0;
	}
	
	li > div >  .label{
		margin-left: 8px;
		font-size: 14px;
		line-height: 14px;
	}
	
	li:last-child{
		border-bottom: none;
	}
	
	li:hover{
		color: #409eff;
		background-color: #ecf5ff;
	}
	
	.empty{
		justify-content: center;
		width: 100%;
		height: 50px;
	}
	
	.empty span{
		color: #C0C4CC;
		font-size: 20px;
	}
</style>

Copy the code

todoFooter.vue

<template>
	<div class="footer flex">
		<div class="flex">
			<input class="checkbox" type="checkbox" value="all" v-model="checked" @change="change(checked)" />
			<label class="label">Complete ({{count}})/all ({{total}})</label>
		</div>
		<div>
			<button class="btn" type="button" @click="del">Delete</button>
		</div>
	</div>
</template>

<script>
	export default {
		props: {
			list: {
				type: Array.default: []}},data() {
			return {
				checked: false}},computed: {
			total() {
				return this.list.length
			},
			count() {
				let count = 0
				this.list.map(item= > {
					if (item.checked) {
						count += 1}})return count
			}
		},
		methods: {
			change(checked) {
				this.$emit('change', checked)
			},
			del() {
				this.$emit('delete')}}}</script>

<style>
	.footer{
		width: 100%;
		justify-content: space-between;
	}
	
	.btn{
		padding: 6px 10px;
		background-color: red;
		color: #FFFFFF;
		border-radius: 4px;
		cursor: pointer;
	}
	
	.btn:hover{
		background-color: #F56C6C;
	}
	
	.label{
		margin-left: 15px;
		line-height: 14px;
		font-size: 14px;
	}
</style>

Copy the code

Component communication

1. Parent and child components often need to interact with each other, and there are many methods for data transfer between them. Here, the props method is used

props: {
	list: {  // The name of the data to pass
		type: Array.// Data type
		default: []  / / the default value}}Copy the code

$emit = $emit; $emit = $emit

// In the child component
change(checked, index) {
	this.$emit('change', {checked, index})  // The first argument is the name of the method to be passed, and the second argument is the argument to be passed out of the item
}  

// In the parent component
// Receive the execution method through change defined in the child component
<todoItem :list="list" @change="changeList" />
Copy the code

Images demonstrate