Vue TodoList案例组件通信方式webStorage插槽(3种)

Posted YuLong~W

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Vue TodoList案例组件通信方式webStorage插槽(3种)相关的知识,希望对你有一定的参考价值。

TodoList案例(props实现)

案例展示:

实现代码:

main.js文件:

//引入Vue
import Vue from 'vue'
//引入App
import App from './App.vue'
//关闭Vue的生产提示
Vue.config.productionTip = false

//创建vm
new Vue(
	el:'#app',
	render: h => h(App)
)

App.vue文件:

<template>
	<div id="root">
		<div class="todo-container">
			<div class="todo-wrap">
				<MyHeader :addTodo="addTodo"/>
				<MyList :todos="todos" :checkTodo="checkTodo" :deleteTodo="deleteTodo"/>
				<MyFooter :todos="todos" :checkAllTodo="checkAllTodo" :clearAllTodo="clearAllTodo"/>
			</div>
		</div>
	</div>
</template>

<script>
	import MyHeader from './components/MyHeader'
	import MyList from './components/MyList'
	import MyFooter from './components/MyFooter.vue'

	export default 
		name:'App',
		components:MyHeader,MyList,MyFooter,
		data() 
			return 
				//由于todos是MyHeader组件和MyFooter组件都在使用,所以放在App中(状态提升)
				todos:[
					id:'001',title:'抽烟',done:true,
					id:'002',title:'喝酒',done:false,
					id:'003',title:'开车',done:true
				]
			
		,
		methods: 
			//添加一个todo
			addTodo(todoObj)
				this.todos.unshift(todoObj)
			,
			//勾选or取消勾选一个todo
			checkTodo(id)
				this.todos.forEach((todo)=>
					if(todo.id === id) todo.done = !todo.done
				)
			,
			//删除一个todo
			deleteTodo(id)
				this.todos = this.todos.filter( todo => todo.id !== id )
			,
			//全选or取消全选
			checkAllTodo(done)
				this.todos.forEach((todo)=>
					todo.done = done
				)
			,
			//清除所有已经完成的todo
			clearAllTodo()
				this.todos = this.todos.filter((todo)=>
					return !todo.done
				)
			
		
	
</script>

<style>
	/*base*/
	body 
		background: #fff;
	
	.btn 
		display: inline-block;
		padding: 4px 12px;
		margin-bottom: 0;
		font-size: 14px;
		line-height: 20px;
		text-align: center;
		vertical-align: middle;
		cursor: pointer;
		box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
		border-radius: 4px;
	
	.btn-danger 
		color: #fff;
		background-color: #da4f49;
		border: 1px solid #bd362f;
	
	.btn-danger:hover 
		color: #fff;
		background-color: #bd362f;
	
	.btn:focus 
		outline: none;
	
	.todo-container 
		width: 600px;
		margin: 0 auto;
	
	.todo-container .todo-wrap 
		padding: 10px;
		border: 1px solid #ddd;
		border-radius: 5px;
	
</style>

components文件夹:

1、MyHeader.vue文件:
——————————————————————————————————————————————————————————————————————
<template>
	<div class="todo-header">
		<input type="text" placeholder="请输入你的任务名称,按回车键确认" v-model="title" @keyup.enter="add"/>
	</div>
</template>

<script>
	import nanoid from 'nanoid'
	export default 
		name:'MyHeader',
		//接收从App传递过来的addTodo
		props:['addTodo'],
		data() 
			return 
				//收集用户输入的title
				title:''
			
		,
		methods: 
			add()
				//校验数据
				if(!this.title.trim()) return alert('输入不能为空')
				//将用户的输入包装成一个todo对象
				const todoObj = id:nanoid(),title:this.title,done:false
				//通知App组件去添加一个todo对象
				this.addTodo(todoObj)
				//清空输入
				this.title = ''
			
		,
	
</script>

<style scoped>
	/*header*/
	.todo-header input 
		width: 560px;
		height: 28px;
		font-size: 14px;
		border: 1px solid #ccc;
		border-radius: 4px;
		padding: 4px 7px;
	

	.todo-header input:focus 
		outline: none;
		border-color: rgba(82, 168, 236, 0.8);
		box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6);
	
</style>

2、MyList.vue文件:
——————————————————————————————————————————————————————————————————————
<template>
	<ul class="todo-main">
		<MyItem 
			v-for="todoObj in todos"
			:key="todoObj.id" 
			:todo="todoObj" 
			:checkTodo="checkTodo"
			:deleteTodo="deleteTodo"
		/>
	</ul>
</template>

<script>
	import MyItem from './MyItem'

	export default 
		name:'MyList',
		components:MyItem,
		//声明接收App传递过来的数据,其中todos是自己用的,checkTodo和deleteTodo是给子组件MyItem用的
		props:['todos','checkTodo','deleteTodo']
	
</script>

<style scoped>
	/*main*/
	.todo-main 
		margin-left: 0px;
		border: 1px solid #ddd;
		border-radius: 2px;
		padding: 0px;
	

	.todo-empty 
		height: 40px;
		line-height: 40px;
		border: 1px solid #ddd;
		border-radius: 2px;
		padding-left: 5px;
		margin-top: 10px;
	
</style>



3、MyList.vue文件:
——————————————————————————————————————————————————————————————————————
<template>
	<li>
		<label>
			<input type="checkbox" :checked="todo.done" @change="handleCheck(todo.id)"/>
			<!-- 如下代码也能实现功能,但是不太推荐,因为有点违反原则,因为修改了props -->
			<!-- <input type="checkbox" v-model="todo.done"/> -->
			<span>todo.title</span>
		</label>
		<button class="btn btn-danger" @click="handleDelete(todo.id)">删除</button>
	</li>
</template>

<script>
	export default 
		name:'MyItem',
		//声明接收todo、checkTodo、deleteTodo
		props:['todo','checkTodo','deleteTodo'],
		methods: 
			//勾选or取消勾选
			handleCheck(id)
				//通知App组件将对应的todo对象的done值取反
				this.checkTodo(id)
			,
			//删除
			handleDelete(id)
				if(confirm('确定删除吗?'))
					//通知App组件将对应的todo对象删除
					this.deleteTodo(id)
				
			
		,
	
</script>

<style scoped>
	/*item*/
	li 
		list-style: none;
		height: 36px;
		line-height: 36px;
		padding: 0 5px;
		border-bottom: 1px solid #ddd;
	

	li label 
		float: left;
		cursor: pointer;
	

	li label li input 
		vertical-align: middle;
		margin-right: 6px;
		position: relative;
		top: -1px;
	

	li button 
		float: right;
		display: none;
		margin-top: 3px;
	

	li:before 
		content: initial;
	

	li:last-child 
		border-bottom: none;
	

	li:hover
		background-color: #ddd;
	
	
	li:hover button
		display: block;
	
</style>



4、MyFooter.vue文件:
——————————————————————————————————————————————————————————————————————
<template>
	<div class="todo-footer" v-show="total">
		<label>
			<!-- <input type="checkbox" :checked="isAll" @change="checkAll"/> -->
			<input type="checkbox" v-model="isAll"/>
		</label>
		<span>
			<span>已完成doneTotal</span> / 全部total
		</span>
		<button class="btn btn-danger" @click="clearAll">清除已完成任务</button>
	</div>
</template>

<script>
	export default 
		name:'MyFooter',
		props:['todos','checkAllTodo','clearAllTodo'],
		computed: 
			//总数
			total()
				return this.todos.length
			,
			//已完成数
			doneTotal()
				//此处使用reduce方法做条件统计
				/* const x = this.todos.reduce((pre,current)=>
					console.log('@',pre,current)
					return pre + (current.done ? 1 : 0)
				,0) */
				//简写
				return this.todos.reduce((pre,todo)=> pre + (todo.done ? 1 : 0) ,0)
			,
			//控制全选框
			isAll:
				//全选框是否勾选
				get()
					return this.doneTotal === this.total && this.total > 0
				,
				//isAll被修改时set被调用
				set(value)
					this.checkAllTodo(value)
				
			
		,
		methods: 
			/* checkAll(e)
				this.checkAllTodo(e.target.checked)
			 */
			//清空所有已完成
			clearAll()
				this.clearAllTodo()
			
		,
	
</script>

<style scoped>
	/*footer*/
	.todo-footer 
		height: 40px;
		line-height: 40px;
		padding-left: 6px;
		margin-top: 5px;
	

	.todo-footer label 
		display: inline-block;
		margin-right: 20px;
		cursor: pointer;
	

	.todo-footer label input 
		position: relative;
		top: -1px;
		vertical-align: middle;
		margin-right: 5px;
	

	.todo-footer button 
		float: right;
		margin-top: 5px;
	
</style>

案例总结:

组件化编码流程:

  • 拆分静态组件:组件要按照功能点拆分,命名不要与html元素冲突

  • 实现动态组件:考虑好数据的存放位置,数据是一个组件在用,还是一些组件在用:

    • 一个组件在用:放在组件自身即可
    • 一些组件在用:放在他们共同的父组件上(状态提升
  • 实现交互:从绑定事件开始

props适用于:

  • 父组件 ==> 子组件 通信
  • 子组件 ==> 父组件 通信(要求父先给子一个函数)

注意:

  • 使用v-model时要切记:v-model绑定的值不能是props传过来的值,因为props是不可以修改的!
  • props传过来的若是对象类型的值,修改对象中的属性时Vue不会报错,但不推荐这样做。

webStorage

  1. 存储内容大小一般支持5MB左右(不同浏览器可能还不一样)

  2. 浏览器端通过 Window.sessionStorageWindow.localStorage 属性来实现本地存储机制

  3. 相关API:

    1. xxxxxStorage.setItem('key', 'value');
      该方法接受一个键和值作为参数,会把键值对添加到存储中,如果键名存在,则更新其对应的值。

    2. xxxxxStorage.getItem('person');

      ​ 该方法接受一个键名作为参数,返回键名对应的值。

    3. xxxxxStorage.removeItem('key');

      ​ 该方法接受一个键名作为参数,并把该键名从存储中删除。

    4. xxxxxStorage.clear();

      ​ 该方法会清空存储中的所有数据。

  4. 备注:

    1. SessionStorage 存储的内容会随着浏览器窗口关闭而消失
    2. LocalStorage 存储的内容,需要手动清除才会消失
    3. xxxxxStorage.getItem(xxx)如果xxx对应的value获取不到,那么getItem的返回值是null
    4. JSON.parse(null)的结果依然是null

将LocalStorage加入TodoList案例:

其余文件不变,只需要在App.vue文件添加代码
App.vue文件:

<script>
	import MyHeader from './components/MyHeader'
	import MyList from './components/MyList'
	import MyFooter from './components/MyFooter.vue'

	export default 
		name:'App',
		components:MyHeader,MyList,MyFooter,
		data() 
			return 
				//由于todos是MyHeader组件和MyFooter组件都在使用,所以放在App中(状态提升)
				todos:JSON.parse(localStorage.getItem('todos')) || []
			
		,
		methods: 
			//添加一个todo
			addTodo(todoObj)
				this.todos.unshift(todoObj)
			,
			//勾选or取消勾选一个todo
			checkTodo(id)
				this.todos.forEach((todo)=>
					if(todo.id === id) todo.done = !todo.done
				Vue TodoList案例组件通信方式webStorage插槽(3种)

Vue2.0学习—Todolist案例(五十九)

React工程化——webpack构建react工程化——react脚手架解析——函数组件间的通信父—子——函数组件事件绑定——todolist案例

使用Vue父子组件通信实现todolist的功能示例代码

sciter案例 TodoList 带你入门 sciter 组件化编程

sciter案例 TodoList 带你入门 sciter 组件化编程