前端-vue学习-组件、路由、脚手架、Vuex

本文深入探讨Vue.js中的组件使用、数据管理及状态管理,包括组件的基本使用、全局与局部组件、父子组件通信、插槽、路由配置、Vuex状态管理等核心概念。文章详细解析了组件注册、数据传递、事件监听、插槽使用、路由懒加载、动态路由、导航守卫等功能,并通过案例TabBar展示了组件的实际应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

2、组件

2.1 组件的基本使用

组件使用的基本步骤:(可直接看2.4 组件注册写法简化)

  • 创建组件构造器

  • 注册组件

  • 使用组件
    在这里插入图片描述

    <!DOCTYPE html>
    <html>
    	<head>
    		<meta charset="utf-8">
    		<title></title>
    		<script src="../js/vue.js"></script>
    	</head>
    	<body>
    		<div id="app">
    			{{message}}
    			<!-- 3、使用组件 -->
    			 <my-con></my-con>
    		</div>
    	<script>
    		//1、创建组件构造器
    		let cpnContruction = Vue.extend({
    			template:'<div><h2>我是标题</h2></div>'
    		});
    		
    		//2、注册组件
    		Vue.component('my-con',cpnContruction);
    		
    		let vue = new Vue({
    			el:'#app',
    			data:{
    				message:'haooo'
    			},
    			methods:{},
    		});
    	</script>
    	
    	</body>
    </html>
    

2.2 全局组件和局部组件

  • 全局组件:可以在多个vue实例中使用。

    <script>
    		//1、创建组件构造器
    		let cpnContruction = Vue.extend({
    			template:'<div><h2>我是标题</h2></div>'
    		});
    		
    		//2、注册全局组件
    		Vue.component('my-con',cpnContruction);
    		
    		let vue = new Vue({
    			el:'#app',
    			data:{
    				message:'haooo'
    			},
    			methods:{},
    		});
    </script>
    
  • 局部组件

    	<script>
    		//1、创建组件构造器
    		let cpnContruction = Vue.extend({
    			template:'<div><h2>我是标题</h2></div>'
    		});
    		
    		//2、注册全局组件
    		// Vue.component('my-con',cpnContruction);
    		
    		let vue = new Vue({
    			el:'#app',
    			data:{
    				message:'haooo'
    			},
    			//2、注册局部组件
    			components:{
    				mycon:cpnContruction
    			},
    			methods:{},
    		});
    	</script>
    

2.3 父组件和子组件

let cpnc2 = Vue.extend({
			template:'<div><h2>我是标题2</h2><cpn1></cpn1></div>',
			//组件中注册组件
			components:{
				cpn1:cpnc1
			}
		});
<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
		<script src="../js/vue.js"></script>
	</head>
	<body>
		<div id="app">
			{{message}}
			<!-- 3、使用组件 -->
			 <cpn2></cpn2>
		</div>
	<script>
		//1、创建组件构造器
		let cpnc1 = Vue.extend({
			template:'<div><h2>我是标题1</h2></div>'
		});
		let cpnc2 = Vue.extend({
			template:'<div><h2>我是标题2</h2><cpn1></cpn1></div>',
			//组件中注册组件
			components:{
				cpn1:cpnc1
			}
		});
		
		let vue = new Vue({
			el:'#app',
			data:{
				message:'haooo'
			},
			//注册局部组件
			components:{
				cpn2:cpnc2
			},
			methods:{},
		});
	</script>
	
	</body>
</html>

2.4 组件注册写法简化(组件注册语法糖)

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
		<script src="../js/vue.js"></script>
	</head>
	<body>
		<div id="app">
			<cpn1></cpn1>
			<cpn2></cpn2>
		</div>
		
	</body>
	<script>
		// 全局注册
		Vue.component('cpn1',{
			template:'<div>1111111111</div>'
		});
		
		var vue = new Vue({
			el:'#app',
			//局部注册
			components:{
				cpn2:{
					template:'<div>2222222</div>',
				},
			},
		});
	</script>
</html>

2.5 组件模板抽离的方法

  • 方式一:使用script标签<script type="text/x-template" id="component">(不常用)

    <!DOCTYPE html>
    <html>
    	<head>
    		<meta charset="utf-8">
    		<title></title>
    		<script src="../js/vue.js"></script>
    	</head>
    	<body>
    		<div id="app">
    			<cpn1></cpn1>
    		</div>
    	</body>
    	
    	<!--模板抽离方式1:不常用 -->
    	<script type="text/x-template" id="component">
    		<div>
    			<h2>1111111</h2>
    		</div>
    	</script>
    	
    	<script>
    		let vue = new Vue({
    			el:'#app',
    			components:{
    				cpn1:{
    					template:'#component'
    				},
    			}
    		});
    	</script>
    </html>
    
  • 方式二:使用tempalte标签<template id="component">

    <!DOCTYPE html>
    <html>
    	<head>
    		<meta charset="utf-8">
    		<title></title>
    		<script src="../js/vue.js"></script>
    	</head>
    	<body>
    		<div id="app">
    			<cpn1></cpn1>
    		</div>
    	</body>
    
    	<!-- 方式二:使用template标签 -->
    	<template id="component">
    		<div>
    			<h2>2222222222</h2>
    		</div>
    	</template>
    	<script>
    		let vue = new Vue({
    			el: '#app',
    			components: {
    				cpn1: {
    					template: '#component'
    				},
    			}
    		});
    	</script>
    </html>
    

2.6 组件内部的data域

​ 组件内部不可以访问Vue实例中的data,组件有自己的数据data,也有methods等属性。

data:function(){
		return{
				msg:'组件的数据'
		}
},
<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
		<script src="../js/vue.js"></script>
	</head>
	<body>
		<div id="app">
			<cpn1></cpn1>
		</div>
	</body>

	<template id="component">
		<div>
			<h2>222222</h2>
			<h3>{{msg}}</h3>
		</div>
	</template>
	
	<script>
		let vue = new Vue({
			el:'#app',
			components:{
				cpn1:{
					template:'#component',
					data:function(){
						return{
							msg:'组件的数据'
						}
					},
				},
			}
		});
	</script>
</html>

2.7 父子组件的通信

在这里插入图片描述

2.7.1 父组件通过props向子组件传递数据

(1)父组件的data

el:'#app',
data:{
		movies:['海贼王','蜡笔小新','小猪佩奇','海尔兄弟'],
		msg:'vue实例的数据传递给组件'
},

(2)子组件使用props定义子组件中需要的属性。props:['cmovies','cmsg']

           //局部组件
			components:{
				cpn1:{
					template:'#component',
					props:['cmovies','cmsg'],
					data:function(){
						return{
						}
					},
				},
			} 

(3)在组件(template)中使用props中的属性。

	<template id="component">
		<div>
			<h2>{{cmsg}}</h2>
			<ul>
				<li v-for="(item) in cmovies">{{item}}</li>
			</ul>
		</div>
	</template>

(4)在使用组件时向组件props中的属性传递数据

        <div id="app">
			<cpn1 v-bind:cmovies="movies" :cmsg="msg"></cpn1>
		</div>
<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
		<script src="../js/vue.js"></script>
	</head>
	<body>
		<div id="app">
			<cpn1 v-bind:cmovies="movies" :cmsg="msg"></cpn1>
		</div>
	</body>

	<template id="component">
		<div>
			<h2>{{cmsg}}</h2>
			<ul>
				<li v-for="(item) in cmovies">{{item}}</li>
			</ul>
		</div>
	</template>
	
	<script>
		let vue = new Vue({
			el:'#app',
			data:{
				movies:['海贼王','蜡笔小新','小猪佩奇','海尔兄弟'],
				msg:'vue实例的数据传递给组件'
			},
			//局部组件
			components:{
				cpn1:{
					template:'#component',
					props:['cmovies','cmsg'],
					data:function(){
						return{
						}
					},
				},
			}
		});
	</script>
</html>
props的定义方式
                    //1、数组
					 props:['cmovies','cmsg'],
					//2、对象
					props:{
						//2.1、类型限制
						// cmovies:Array,
						// cmsg:String,
						
						//2.2、提供默认值
						cmsg:{
							type:String,
							default:'默认值',
							required:true,
						},
						//类型是一个数组或者对象时,默认值必须是一个函数
						cmovies:{
							type:Array,
							default:function(){
								return ['111','222']
							},
						},
					},
	             props:{
						//1、基础的类型检查(null:匹配任何类型)
						propA:Number,
						//2、多个可能的类型
						propB:[String,Number],
						//3、必填的字符串
						propC:{
							type:String,
							required:true,
						},
						//4、带有默认值的数字
						propD:{
							type:Number,
							default:100,
						},
						//5、带有默认值的对象
						propE:{
							type:Object,
							default:function(){
								return {message:'helle'}
							}
						},
						//6、自定义验证函数
						propF:{
							validator:function(value){
								//这个值必须匹配下列字符串中的一个
								return ['success','warning'].indexOf(value) !== -1
							}
						}
					}
props驼峰命名

如果props中的属性是驼峰命名cMovies,在传递数据的时候应该写成:c-movies="movies"

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
		<script src="../js/vue.js"></script>
	</head>
	<body>
		<div id="app">
			<cpn1 :c-msg="msg" :c-movies="movies"></cpn1>
		</div>
	</body>

	<template id="component">
		<div>
			<h2>{{cMsg}}</h2>
			<ul>
				<li v-for="(item) in cMovies">{{item}}</li>
			</ul>
		</div>
	</template>
	
	<script>
		let vue = new Vue({
			el:'#app',
			data:{
				movies:['海贼王','蜡笔小新','小猪佩奇','海尔兄弟'],
				msg:'vue实例的数据传递给组件'
			},
			//局部组件
			components:{
				cpn1:{
					template:'#component',
					//1、数组
					props:['cMovies','cMsg'],
					data:function(){
						return{
						}
					},
				},
			}
		});
	</script>
</html>

2.7.2 子组件通过事件向父组件发送消息

(1)子组件发射自定义事件

            methods:{
						btnClick:function(item){
							console.log("子组件发射:" + item);
							//1、子组件发射事件
							this.$emit("item-click",item);
						},
					}

(2)子组件绑定点击事件

	<template id="component">
		<div>
			<!-- 2、子组件绑定点击事件 -->
			<button v-for="item in categories" @click="btnClick(item)">{{item}}           			</button>
		</div>
	</template>

(3)父组件接收事件

		methods:{
				//3、 父组件接收事件
				cnpClick:function(item){
					console.log("父组件接收:" + item);
				}
			},

(4)组件使用时绑定事件

			<!--4、 绑定事件 -->
			<cpn1 v-on:item-click="cnpClick"></cpn1>		
<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
		<script src="../js/vue.js"></script>
	</head>
	<body>
		<div id="app">
			<!--4、 绑定事件 -->
			<cpn1 v-on:item-click="cnpClick"></cpn1>
		</div>
	</body>
	
	<template id="component">
		<div>
			<!-- 2、子组件绑定点击事件 -->
			<button v-for="item in categories" @click="btnClick(item)">{{item}}</button>
		</div>
		
	</template>

	<script>
		let vue = new Vue({
			el:'#app',
			//局部组件
			components:{
				cpn1:{
					template:'#component',
					data:function(){
						return{
							categories:['海贼王','蜡笔小新','小猪佩奇','海尔兄弟']
						}
					},
					methods:{
						btnClick:function(item){
							console.log("子组件发射:" + item);
							//1、子组件发射事件
							this.$emit("item-click",item);
						},
					}
				},
			},
			
			methods:{
				//3、 父组件接收事件
				cnpClick:function(item){
					console.log("父组件接收:" + item);
				}
			}
		});
	</script>
</html>

2.8 父子组件的访问方式

2.8.1 父组件访问子组件( c h i l d r e n 、 children、 childrenrefs)

$children

$children:结果是一个数组,通过遍历数组来获取子组件。
在这里插入图片描述

         methods:{
				getSubCpn:function(){
					// 访问子组件的属性和方法
					console.log(this.$children);
					for (let var1 of this.$children) {
						//访问子组件的属性
						console.log(var1.subMsg);
						//访问子组件的方法
						var1.subMethod();
					}
				}
			}, 
<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
		<script src="../js/vue.js"></script>
	</head>
	<body>
		<div id="app">
			<cpn></cpn>
			<button @click="getSubCpn">通过$children访问子组件</button>
		</div>
	</body>
	
	<template id="component">
		<div>
			<h2>子组件</h2>
		</div>
	</template>

	<script>
		let vue = new Vue({
			el:'#app',
			methods:{
				getSubCpn:function(){
					// 访问子组件的属性和方法
					console.log(this.$children);
					for (let var1 of this.$children) {
						//访问子组件的属性
						console.log(var1.subMsg);
						//访问子组件的方法
						var1.subMethod();
					}
				}
			},
			components:{
				cpn:{
					template:'#component',
					data:function(){
						return {
							subMsg:'子组件属性'
						}
					},
					methods:{
						subMethod:function(){
							console.log("子组件的方法");
						}
					}
				}
			}
		});
	</script>
</html>
$refs

$refs:获取的是一个对象,需要在使用组件时添加属性:ref=“cpn1”

在这里插入图片描述

        <div id="app">
			<cpn ref="cpn1"></cpn>
			<cpn ref="cpn2"></cpn>
			<button @click="getSubCpn">通过$children访问子组件</button>
		</div> 
	      methods:{
				getSubCpn:function(){	
					//2、$refs:获取的是一个对象,需要在使用组件时添加属性:ref="cpn1"
					console.log(this.$refs.cpn2.subMsg);
				}
			},
<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
		<script src="../js/vue.js"></script>
	</head>
	<body>
		<div id="app">
			<cpn ref="cpn1"></cpn>
			<cpn ref="cpn2"></cpn>
			<button @click="getSubCpn">通过$children访问子组件</button>
		</div>
	</body>
	
	<template id="component">
		<div>
			<h2>子组件</h2>
		</div>
	</template>

	<script>
		let vue = new Vue({
			el:'#app',
			methods:{
				getSubCpn:function(){
					// // 1、$children:访问子组件的属性和方法
					// console.log(this.$children);
					// for (let var1 of this.$children) {
					// 	//访问子组件的属性
					// 	console.log(var1.subMsg);
					// 	//访问子组件的方法
					// 	var1.subMethod();
					// }
					
					//2、$refs:获取的是一个对象,需要在使用组件时添加属性:ref="cpn1"
					console.log(this.$refs.cpn2.subMsg);
				}
			},
			components:{
				cpn:{
					template:'#component',
					data:function(){
						return {
							subMsg:'子组件属性'
						}
					},
					methods:{
						subMethod:function(){
							console.log("子组件的方法");
						}
					}
				}
			}
		});
	</script>
</html>

2.8.2 子组件访问父组件( p a r e n t 、 parent、 parentroot)

$parent

​ 子组件访问父组件。

	components:{
				cpn:{
					template:'#component',
					methods:{
						btnClick:function(){
                            //访问父组件的数据
							console.log(this.$parent.message);
						}
					}
				}
			}
<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
		<script src="../js/vue.js"></script>
	</head>
	<body>
		<div id="app">
			<cpn></cpn>
		</div>
	</body>
	
	<template id="component">
		<button @click="btnClick">访问父组件的数据</button>
	</template>

	<script>
		let vue = new Vue({
			el:'#app',
			data:{
				message:'父组件的数据'
			},
			components:{
				cpn:{
					template:'#component',
					methods:{
						btnClick:function(){
                            //访问父组件的数据
							console.log(this.$parent.message);
						}
					}
				}
			}
		});
	</script>
</html>
$root

​ 子组件访问根组件(Vue实例)。

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
		<script src="../js/vue.js"></script>
	</head>
	<body>
		<div id="app">
			<cpn></cpn>
		</div>
	</body>
	
	<template id="component">
		<cpn1></cpn1>
	</template>
	<template id="component1">
		<button @click="btnClick">访问根组件的信息</button>
	</template>
	
	<script>
		let vue = new Vue({
			el:'#app',
			data:{
				message:'根组件信息'
			},
			components:{
				cpn:{
					template:'#component',
					components:{
						cpn1:{
							template:'#component1',
							methods:{
								btnClick:function(){
									console.log(this.$root);
								}
							}
						}
					}
				}
			}
		});
	</script>
</html>

2.9 插槽

2.9.1 插槽的基本使用

​ 组件的插槽是为了让封装的组件更有扩展性。

插槽的基本使用:

​ 1、在模板中使用slot标签,可设置name属性,在使用插槽时用v-slot:×××来标识向哪个插槽中添加内容。

<slot name="slot2"></slot>

​ 2、可以在slot中添加标签提供默认值

​ 3、在使用组件标签时,在组件标签中添加标签,替换或者添加插槽中的内容。非默认插槽必须

<template v-slot:slot1><h3>具名插槽slot1</h3></template>

(1)v-slot:×××必须使用在template上。特殊情况

(2)具名插槽的缩写:#插槽名

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
		<script src="../../js/vue.js"></script>
	</head>
	<body>
		<div id="app">
			<cpn>
			<!-- 	<template v-slot:slot1>
					<h3>具名插槽slot1</h3>
				</template> -->
				
				<template #slot1>
					<h3>具名插槽slot1缩写</h3>
				</template>
				
				<!-- <h3>替换默认插槽</h3> -->
				<template v-slot:default>
					<h3>具名插槽default</h3>
				</template>
				
				<template v-slot:slot2>
					<h3>具名插槽slot2</h3>
				</template>
				
				<!-- 此方式已弃用 -->
				<!-- <h3 slot="slot1">替换插槽1中的默认值</h3>
				<button slot="slot2">向插槽2中添加内容</button> -->
			</cpn>
		</div>
	</body>
	
	<template id="component">
		<div>
			<h2>插槽的基本使用:</h2>
			<h3>1、在模板中使用slot标签,可设置name属性,在使用插槽时用v-slot:××来标识向哪个插槽中添加内容</h3>
			<h3>2、可以在slot中添加标签提供默认值</h3>
			<h3>3、在组件标签中添加标签,替换或者添加插槽中的内容</h3>
			
			<slot name="slot1"><h3>插槽1</h3></slot>
			<slot>默认插槽</slot>
			<slot name="slot2"></slot>
		</div>
	</template>
	
	<script>
		let vue = new Vue({
			el:'#app',
			components:{
				cpn:{
					template:'#component'
				}
			}
			
		});
	</script>
</html>

2.9.2 作用域插槽

作用:父组件替换插槽中的标签,并且数据由子组件来提供。

(1)在slot中使用v-bind:user="user"定义插槽prop。也就是向上传递子组件的user数据。

	<!-- v-bind:user="user":向上传递user数据 -->
	<slot name="slot1" v-bind:user="user"></slot>

(2)使用插槽时用v-slot:slot1="userProp",这里的userProp就是slot向上传递的子组件的user数据。

	<template v-slot:slot1="userProp">
		<h3>{{userProp.user.firstname}}</h3>
	</template>
<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
		<script src="../../js/vue.js"></script>
	</head>
	<body>
		<div id="app">
			<cpn>
				<template v-slot:slot1="userProp">
					<h3>{{userProp.user.firstname}}</h3>
				</template>
				
				<template v-slot:slot2="languageProp">
					<ul>
						<li v-for="item in languageProp.language">{{item}}</li>
					</ul>
				</template>
			</cpn>
		</div>
	</body>
	
	<template id="component">
		<div>
			<!-- v-bind:user="user":向上传递user数据 -->
			<slot name="slot1" v-bind:user="user"></slot>
			<!-- v-bind:language="language":向上传递language数据 -->
			<slot name="slot2" v-bind:language="language"></slot>
		</div>
	</template>
	
	<script>
		let vue = new Vue({
			el:'#app',
			components:{
				cpn:{
					template:'#component',
					data:function(){
						return{
							user:{
								username:'zhaowendi',
								firstname:'zhao',
								lastname:'wendi'
							},
							language:['C++','Java','C#']
						}
					}
				}
			}
		});
		
	</script>
</html>

3、ES6模块化的导入导出

(1)在html中引入js文件时,type必须是module。

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
	</head>
	<body>
		<script src="./aaa.js" type="module"></script>
		<script src="./bbb.js" type="module"></script>
	</body>
</html>

(2)导出方式:导出aaa.js中的变量、类或者方法。使用export或者export default导出。

export可以在需要导出的对象定义后使用

var flag = true;

function sum(sum1,sum2){
	return sum1+sum2;
}

if(flag){
	console.log(name + ": " + sum(20,30));
}
// 导出方式一:
export{
	flag,
	sum,
}

export也可以在定义变量、函数或者类的时候使用

//导出方式二-变量
export var height = 180;
//导出方式二-函数
export function mul(num1,num2){
	return num1 * num2;
}
//导出方式二-类
export class Person{
	run(){
		console.log("类中的方法")
	}
}

export default导出方式:export default在同一模块中不允许同时存在多个。

//导出方式三:export default
// var dft = 'export default';
// export default dft;

// function dft(){
// 	console.log('export default');
// }
// export default dft;

export default function(){
	console.log('export default');
}
var name = '小明';
var age = 18;
var flag = true;

function sum(sum1,sum2){
	return sum1+sum2;
}

if(flag){
	console.log(name + ": " + sum(20,30));
}
// 导出方式一:
export{
	flag,
	sum,
}
//导出方式二-变量
export var height = 180;
//导出方式二-函数
export function mul(num1,num2){
	return num1 * num2;
}
//导出方式二-类
export class Person{
	run(){
		console.log("类中的方法")
	}
}
//导出方式三:export default
// var dft = 'export default';
// export default dft;

export default function(){
	console.log('export default');
}

(3)导入方式:使用import…from 导入。

//1、导出方式为export的导入方式
import{flag, sum} from "./aaa.js";
import * as aa from "./aaa.js";
//2、导出方式为export default的导入方式,接收参数可自己命名
import dftVar from "./aaa.js";
//1、导出使用export的导入方式。{}中是导出时的命名
import{flag, sum} from "./aaa.js";

var name = '小红';
if(flag){
	console.log(name + ": " + sum(100,300));
}

import{Person} from "./aaa.js";
var prsn = new Person();
prsn.run();

//2、统一全部导入
import * as aa from "./aaa.js";
console.log(aa.height);
console.log("sum: " + aa.sum(1,2));

//3、导出方式为 export default,的导入方式,接收参数可自己命名
import dftVar from "./aaa.js";
// console.log(dftVar);//变量
dftVar();//方法

4、webpack(未学完,直接脚手架)

4.1 webpack安装

  • webpack安装首先需要安装Node.js,Node.js自带了软件包管理工具npm

  • 查看自己的node版本

    node -v
    
  • 全局安装webpack(这里指定安装的版本号是3.6.0,vue cli2依赖该版本)

    npm install webpack@3.6.0 -g
    
  • 局部安装webpack(暂时不安装)

    cd 对应目录
    npm install webpack@3.6.0 --save-dev
    
  • 为什么全局安装后,还需要局部安装呢?

    • 在终端直接执行webpack命令,使用的全局安装的webpack
    • 当在package.json中定义了scripts时,其中包含了webpack命令,那么使用的是局部webpack。

5、Vue CLI

​ CLI是Command-Line-Interfave,翻译为命令行界面,但是俗称脚手架。

​ Vue CLI是一个官方发布vue.js项目脚手架。

​ 使用vue-cli可以快速搭建Vue开发环境以及对应的webpack配置。

脚手架使用的前提:安装node.js。vue脚手架安装

5.1 render

在这里插入图片描述

//以App作为template替换挂载#app中的内容。效果等同于下方的写法。运行周期为 render->vdom->ui;此性能更高
new Vue({
  render: h => h(App),
}).$mount('#app')

// //效果等同于上面写法:运行周期为template->ast->render->vdom->ui
// new Vue({
// 	el:'#app',
// 	template:'<App/>',//替换#app
// 	components:{App}
// })

6、Vue-Router

vue-router官方文档

6.1、什么是路由

​ vue-router是基于路由和组件的:

  • 路由用于设定访问路径,将路径和组件映射起来。
  • 在vue-router的单页面应用中,页面的路劲的改变就是组件的切换。

6.2、vue-router的安装和使用

​ (1)导入路由对象,并且调用Vue.user(VueRouter)

​ (2)创建路由实例,并且传入路由映射配置。

​ (3)在Vue实例中挂载创建的路由实例。

首先安装好插件,然后在src/router/下生成index.js文件。内容如下:

import Vue from 'vue'
import VueRouter from 'vue-router'
import Home from '../views/Home.vue'

//1、通过Vue.use安装插件
Vue.use(VueRouter)

  const routes = [
  {
    path: '/',
    name: 'Home',
    component: Home
  },
  {
    path: '/about',
    name: 'About',
    // route level code-splitting
    // this generates a separate chunk (about.[hash].js) for this route
    // which is lazy-loaded when the route is visited.
    component: () => import(/* webpackChunkName: "about" */ '../views/About.vue')
  }
]
//2、配置路由和组件之间的映射关系:一个url对应一个组件
const router = new VueRouter({
  routes
})

//3、将router对象导出,并使用到Vue的实例中。
export default router

​ 在main.js中挂载路由

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

Vue.config.productionTip = false

//以App作为template替换挂载#app中的内容。效果等同于下方的写法。运行周期为 render->vdom->ui;此性能更高
new Vue({
  router,//使用路由
  render: h => h(App)
}).$mount('#app')

// //效果等同于上面写法:运行周期为template->ast->render->vdom->ui
// new Vue({
// 	el:'#app',
// 	template:'<App/>',//替换#app
// 	components:{App}
// })

6.3、vue-router的使用步骤

  • 第一步:创建路由组件。在components目录下创建Home.vue和About.vue两个文件

    <template>
    	<div>
    		<h3>我是首页</h3>
    	</div>
    </template>
    
    <script>
    	export default{
    		name:"Home"
    	}
    </script>
    
    <style>
    </style>
    
    <template>
    	<h3>我是相关页面</h3>
    </template>
    
    <script>
    	export default{
    		name: "About"
    	}
    </script>
    
    <style>
    </style>
    
  • 第二步:配置路由映射:组件和路劲映射关系。在router/index.js 下添加映射

    import Vue from 'vue'
    import VueRouter from 'vue-router'
    import Home from '../components/Home.vue'
    import About from '../components/About.vue'
    
    //1、通过Vue.use安装插件
    Vue.use(VueRouter)
    
      const routes = [
      {
        path: '/home',
        component: Home
      },
      {
        path: '/about',
    	component: About
        // component: () => import(/* webpackChunkName: "about" */ '../views/About.vue')
      }
    ]
    //2、配置路由和组件之间的映射关系:一个url对应一个组件
    const router = new VueRouter({
      routes
    })
    
    //3、将router对象导出,并使用到Vue的实例中。
    export default router
    
  • 第三步:使用路由:通过和。在App.vue中使用路由。

    <template>
      <div id="app">
    	  <router-link to="/home">首页   </router-link>
    	  <router-link to="/about">关于</router-link>
    	  <router-view></router-view>
      </div>
    </template>
    <script>
    	export default{
    		name:'App'
    	}
    </script>
    <style>
    </style>
    

    运行:npm run serve

配置默认路由

  {
	  //默认路由
	  path:'',
	  // component:Home,//问题:显示首页的时候路径并不是首页的路径
	  redirect:'/home'
  },

使用html5 的history

​ 改变路径的方式有两种:url的hash、html5的history。

​ 默认情况下,改变路径使用的是hash。

//2、配置路由和组件之间的映射关系:一个url对应一个组件
const router = new VueRouter({
  routes,
  mode:'history'//默认为hash,在路径前面会有#号
})

router-link的补充

  • to:用于指定跳转的路径。

  • tag:可以指定之后渲染成什么标签,默认渲染为标签。

     <router-link to="/home" tag="button" replace>首页   </router-link>
     <router-link to="/about" tag="li" replace>关于</router-link>
    
  • active-class(没什么用):对应路由匹配成功后,自动给当前元素设置一个router-link-active的class。

    <template>
      <div id="app">
    	  <router-link to="/home" tag="button" replace >首页   </router-link>
    	  <router-link to="/about" tag="button" replace>关于</router-link>
    	  <router-view></router-view>
      </div>
    </template>
    <script>
    	export default{
    		name:'App'
    	}
    </script>
    <style>
    	.router-link-active{
    		color: #42B983;
    	}
    </style>
    

    使用active-class给classrouter-link-active重新命名。

    <template>
      <div id="app">
    	  <router-link to="/home" tag="button" replace active-class="active">首页   </router-link>
    	  <router-link to="/about" tag="button" replace>关于</router-link>
    	  <router-view></router-view>
      </div>
    </template>
    <script>
    	export default{
    		name:'App'
    	}
    </script>
    <style>
    	.active{
    		color: #42B983;
    	}
    </style>
    

通过代码跳转路由$router

<template>
  <div id="app">
	 <!-- <router-link to="/home" tag="button" replace active-class="active">首页   </router-link>
	  <router-link to="/about" tag="button" replace>关于</router-link> -->
	  <button @click="btnIndex">首页</button>
	  <button @click="btnAbout">关于</button>
	  <router-view></router-view>
  </div>
</template>
<script>
	export default{
		name:'App',
		methods:{
			  btnIndex:function(){
				  console.log("首页按钮");
				  // this.$router.push('/home');
				  this.$router.replace('/home');
			  },
			  btnAbout:function(){
				  console.log("关于按钮");
				  // this.$router.push('/about');
				  this.$router.replace('/about');
				  
			  }
		}
	}
</script>
<style>
	.active{
		color: #42B983;
	}
</style>

6.4、动态路由this.$route

动态路由

案例:在首页点击用户,跳转到用户组件,并且携带参数,在用户组件中再获取参数。

  • 首先添加一个User.vue组件:this.$route获取当前活跃的路由。

    <template>
    	<h3>我是用户页面: {{getUserId}}</h3>
    </template>
    
    <script>
    	export default{
    		name: "User",
    		computed:{
    			getUserId:function(){
    				console.log(this.$route.params.userId);
    				return this.$route.params.userId;//获取跳转时携带的参数
    			}
    		}
    	}
    </script>
    
    <style>
    </style>
    
  • 将组件添加到路由:path: '/user/:userId',在路由地址中添加动态参数

    import User from '../components/User.vue'
    
      {
        path: '/user/:userId',
        component: User
      },
    
    import Vue from 'vue'
    import VueRouter from 'vue-router'
    import Home from '../components/Home.vue'
    import About from '../components/About.vue'
    import User from '../components/User.vue'
    
    //1、通过Vue.use安装插件
    Vue.use(VueRouter)
    
      const routes = [
      {
    	  //默认路由
    	  path:'',
    	  // component:Home,//问题:显示首页的时候路径并不是首页的路径
    	  redirect:'/home'
      },
      {
        path: '/home',
        component: Home
      },
      {
        path: '/about',
    	component: About
        // component: () => import(/* webpackChunkName: "about" */ '../views/About.vue')
      },
      {
        path: '/user/:userId',
        component: User
      },
    ]
    //2、配置路由和组件之间的映射关系:一个url对应一个组件
    const router = new VueRouter({
      routes,
      mode:'history',//默认为hash,在路径前面会有#号
      linkActiveClass:'active'
    })
    
    //3、将router对象导出,并使用到Vue的实例中。
    export default router
    
  • 在App.vue中进行路由跳转

     <router-link v-bind:to="'/user/' + userId">用户  </router-link>
    
    	data:function(){
    			return {
    				userId:'zhaowendi'
    			}
    		},
    
    <template>
      <div id="app">	  
    	  <router-link to="/home">首页  </router-link>
    	  <router-link to="/about">关于  </router-link>
    	  <router-link v-bind:to="'/user/' + userId">用户  </router-link>
    	  <router-view></router-view>
      </div>
    </template>
    <script>
    	export default{
    		name:'App',
    		data:function(){
    			return {
    				userId:'zhaowendi'
    			}
    		}
    	}
    </script>
    <style>
    </style>
    
  • 在User.vue中使用:this.$route.params.userId获取传递过来的参数。

6.5、路由懒加载

路由懒加载

​ 首先路由中通常会定义很多不同的页面。这些页面最后被打包到哪里呢?一般情况下,是放在一个js文件中。但是这么多页面放到一个js文件中,必然会造成这个页面非常的大。

​ 如果我们 一次性从服务器请求这个页面,可能会花费一定的时间,甚至用户的电脑上还会出现短暂空白的情况。如何避免这种情况呢?使用路由懒加载就可以了。

路由懒加载做了什么:路由懒加载的主要作用就是将路由对应的组件打包成一个个的js代码块,只有在这个路由被访问的时候,才加载对应的组件。

//使用路由懒加载
const Home = () => import('../components/Home.vue')
const About = () => import('../components/About.vue')
const User = () => import('../components/User.vue')
import Vue from 'vue'
import VueRouter from 'vue-router'
// import Home from '../components/Home.vue'
// import About from '../components/About.vue'
// import User from '../components/User.vue'

//使用路由懒加载
const Home = () => import('../components/Home.vue')
const About = () => import('../components/About.vue')
const User = () => import('../components/User.vue')

//1、通过Vue.use安装插件
Vue.use(VueRouter)

  const routes = [
  {
	  //默认路由
	  path:'',
	  // component:Home,//问题:显示首页的时候路径并不是首页的路径
	  redirect:'/home'
  },
  {
    path: '/home',
    component: Home
  },
  {
    path: '/about',
	component: About
    // component: () => import(/* webpackChunkName: "about" */ '../views/About.vue')
  },
  {
    path: '/user/:userId',
    component: User
  },
]
//2、配置路由和组件之间的映射关系:一个url对应一个组件
const router = new VueRouter({
  routes,
  mode:'history',//默认为hash,在路径前面会有#号
  linkActiveClass:'active'
})

//3、将router对象导出,并使用到Vue的实例中。
export default router

6.6、路由嵌套

嵌套路由

实现嵌套路由有两个步骤:

​ (1)创建对应的子组件,并且再路由映射中配置对应的子路由。

​ (2)在组件内部使用

在.vue文件中,template中的标签用div包裹。

  • 创建两个组件HomeMessage.vue、HomeNews.vue。

    <template>
    	<div>
    		<h3>首页消息</h3>
    		<ul>
    			<li>消息1</li>
    			<li>消息2</li>
    			<li>消息3</li>
    			<li>消息4</li>
    		</ul>
    	</div>
    </template>
    
    <script>
    	export default{
    		name:'HomeMessage'
    	}
    </script>
    
    <style>
    </style>
    
    <template>
    	<div>
    		<h3>首页新闻</h3>
    		<ul>
    			<li>新闻1</li>
    			<li>新闻2</li>
    			<li>新闻3</li>
    			<li>新闻4</li>
    		</ul>
    	</div>
    </template>
    
    <script>
    	export default{
    		name:'HomeNews'
    	}
    </script>
    
    <style>
    </style>
    
  • 配置路由。将HomeNews和HomeMessage嵌套在Home路由下。

    注意children:下的path写法,前面不用加斜杠

    //使用路由懒加载
    const Home = () => import('../components/Home.vue')
    const HomeMessage = () => import('../components/HomeMessage.vue')
    const HomeNews = () => import('../components/HomeNews.vue')
    
    {
        path: '/home',
        component: Home,
    	//路由嵌套
    	children:[
    		{
    			path:'',
    			redirect:'message'
    		},
    		{
    			//不能写成 `/message`
    			path:'message',
    			component:HomeMessage
    		},
    		{
    			path:'news',
    			component:HomeNews
    		}
    	]
      },
          
    
  • 在Home.vue组件中使用HomeMessage和HomeNews。

    <template>
    	<div>
    		<h3>我是首页</h3>
    		<div>
    			<router-link to="/home/message">消息</router-link>
    			<router-link to="/home/news">新闻</router-link>
    			<router-view></router-view>
    		</div>
    	</div>
    </template>
    
    <script>
    	export default{
    		name:"Home"
    	}
    </script>
    
    <style>
    </style>
    

6.7、vue-router参数传递

params

该参数传递见6-6.4动态路由

query

参数传递方式:

<router-link :to="{path:'/profile',query:{name:'kobo',age:12,height:188}}">档案 </router-link>

参数接收方式:$route.query

<h4>{{$route.query.name}}</h4>
<h4>{{$route.query.age}}</h4>
<h4>{{$route.query.height}}</h4>
  • Profile.vue组件
<template>
	<div>
		<h3>档案页面</h3>
		<h4>{{$route.query.name}}</h4>
		<h4>{{$route.query.age}}</h4>
		<h4>{{$route.query.height}}</h4>
	</div>
</template>

<script>
	export default{
		name:'Profile'
	}
</script>

<style>
</style>
  • 配置Profile路由:

    const Profile = () => import('../components/Profile.vue')
    
      {
    	  path:'/profile',
    	  component:Profile
      }
    
  • 在App.vue中访问路由

    <router-link :to="{path:'/profile',query:{name:'kobo',age:12,height:188}}">档案 </router-link>
    <router-view></router-view>
    
写代码的方式跳转

路由配置不变(path: '/user/:userId',path:'/profile'),接收方式不变($route.params$route.query)。

	 <button @click="btnUser">用户</button>
	 <button @click="btnProfile">档案</button>
             btnUser:function(){
				  this.$router.replace('/user/' + this.userId);
			  },
			  btnProfile:function(){
				  this.$router.replace({path:'/profile',
				  query:{name:'kobo',age:18,height:198}
				  })
			  }

6.8、vue-router导航守卫

导航守卫

​ 生命周期函数:

​ create:创建组件实例时回调

​ mounted:组件创建后,将template挂载到dom中时回调

​ updated:页面每刷新一次就会回调。

全局守卫-前置守卫、后置钩子

​ 在页面跳转之前修改页面的title属性。

  • 首先在路由中添加meta元数据。路由元信息

     const routes = [
      {
        path: '/about',
    	component: About,
    	meta:{
    		title:'关于'
    	}
        // component: () => import(/* webpackChunkName: "about" */ '../views/About.vue')
      },
      {
        path: '/user/:userId',
        component: User,
    	meta:{
    		title:'用户'
    	}
      },
      {
    	  path:'/profile',
    	  component:Profile,
    	  meta:{
    		  title:'档案'
    	  }
      }
    ]
    
  • 添加前置守卫

    //前置守卫:在跳转之前调用
    router.beforeEach((to,from,next) => {
    	// console.log(to)
    	console.log("++++++++++++")
    	//从from跳转到to
    	document.title = to.meta.title;
    	
    	//必须调用next
    	next();
    })
    //后置钩子(hook):在跳转后调用
    router.afterEach((to,from) => {
    	console.log("------------")
    })
    
局部守卫

路由独享守卫 组件内的守卫

6.9、keep alive

keep-alive

keep-alive是Vue内置的一个组件,可以使被包含的组件保留状态,或避免重新渲染。

属性:

​ include:字符串或正则表达式,只有匹配的组件会被缓存。

​ exclude:字符串或正则表达式,任何匹配的组件都不会被缓存。

方法:activated、deactivated。在获得状态和失去状态时触发。

7、案例TabBar

环境:Vue CLI4

在这里插入图片描述

  • 1、在assets下创建 img/tabbar,然后存放需要用到的图标(8个)

  • 2、在components下创建tabbar目录,并创建TabBarItem.vue以及TabBar.vue两个组件。

    TabBarItem.vue

    <template>
    	<div id="tabBarItem" @click="itemClick">
    		<!-- 图标 -->
    		<div v-if="!isActive">
    			<slot  name="item-icon"></slot>
    		</div>
    		<!-- 活跃状态的图标 -->
    		<div  v-else>
    			<slot name="item-icon-active"></slot>
    		</div>
    		<!-- 图标下面的文字,字体颜色可以动态设置 -->
    		<div :style="activeStyle">
    			<slot name="item-text"></slot>
    		</div>
    	</div>
    </template>
    
    <script>
    	export default {
    		name: 'TabBarItem',
    		props:{
    			//需要跳转的路径
    			path:String,
    			//动态绑定style的值
    			activeColor:{
    				type:String,
    				default:"#1296db"
    			}
    		},
    		computed:{
    			// 当父组件传递过来的path和当前活跃状态的path一致时为true
    			isActive:function(){
    				return (this.$route.path.indexOf(this.path) !== -1);
    			},
    			activeStyle:function(){
    				return this.isActive ? {color:this.activeColor}:{} ;
    			}
    		},
    		methods:{
    			itemClick:function(){
    				console.log("跳转:" + this.path);
    				if(this.$route.path != this.path){
    					this.$router.push(this.path);
    				}
    			}
    		}
    
    	}
    </script>
    
    <style>
    	#tabBarItem {
    		flex: 1;
    		text-align: center;
    		height: 49px;
    		font-size: 14px;
    		cursor: pointer;
    	}
    
    	#tabBarItem img {
    		height: 24px;
    		width: 24px;
    		margin-top: 3px;
    		vertical-align: middle;
    		margin-bottom: 2px;
    	}
    
    	.active {
    		color: #1296db;
    	}
    </style>
    

    TabBar.vue

    <template>
    	<div id="tab-bar">
    		<slot></slot>
    	</div>
    </template>
    
    <script>
    	export default{
    		name:'TabBar',
    	}
    </script>
    
    <style>
    	#tab-bar{
    		display: flex;
    		background-color: #f6f6f6;
    		position: fixed;
    		left: 0;
    		right: 0;
    		bottom: 0;
    		box-shadow: 0 -1px 1px rgba(100,100,100,.2);
    	}
    </style>
    
  • 3、创建router-view中需要显示的页面。

在这里插入图片描述

内容如下:

<template>
	<h3>首页</h3>
</template>

<script>
</script>

<style>
</style>
  • 4、配置上述4个页面的路由

    import Vue from 'vue'
    import VueRouter from 'vue-router'
    
    const Home = () => import('../views/home/Home.vue')
    const Category = () => import('../views/category/Category.vue')
    const Cart = () => import('../views/cart/Cart.vue')
    const Profile = () => import('../views/profile/Profile.vue')
    
    //1、通过Vue.use安装插件
    Vue.use(VueRouter)
    
    const routes = [{
    		path: '',
    		redirect: '/home'
    	},
    	{
    		path: '/home',
    		component: Home
    	},
    	{
    		path: '/category',
    		component: Category
    	},
    	{
    		path: '/cart',
    		component: Cart
    	},
    	{
    		path: '/profile',
    		component: Profile
    	}
    ]
    //2、配置路由和组件之间的映射关系
    const router = new VueRouter({
    	mode: 'history',
    	// base: process.env.BASE_URL,
    	routes
    })
    //3、导出路由
    export default router
    
  • 在App.vue中使用TabBar、TabBarItem组件,以及使用进行路由之间的跳转和显示。

    <template>
    	<div id="app">
    		<router-view></router-view>
    		<tab-bar>
    			<!-- 首页:需要向子组件传递path和activeColor(可选)参数-->
    			<tab-bar-item path="/home" activeColor="#1296db">
    				<template v-slot:item-icon>	
    				<img src="./assets/img/tabbar/home.svg"/>
    				</template>
    				
    				<template v-slot:item-icon-active>
    				<img src="./assets/img/tabbar/homeActive.svg"/>
    				</template>
    				
    				<template v-slot:item-text>
    					<div >首页</div>
    				</template>
    			</tab-bar-item>
    			
    			<!-- 分类 -->
    			<tab-bar-item path="/category">
    				<template v-slot:item-icon>	
    				<img src="./assets/img/tabbar/category.svg"/>
    				</template>
    				<template v-slot:item-icon-active>
    				<img src="./assets/img/tabbar/categoryActive.svg"/>
    				</template>
    				<template v-slot:item-text>
    					<div >分类</div>
    				</template>
    			</tab-bar-item>
    			
    			<!-- 购物车 -->
    			<tab-bar-item path="/cart">
    				<template v-slot:item-icon>	
    				<img src="./assets/img/tabbar/shopCart.svg"/>
    				</template>
    				<template v-slot:item-icon-active>
    				<img src="./assets/img/tabbar/shopCartActive.svg"/>
    				</template>
    				<template v-slot:item-text>
    					<div>购物车</div>
    				</template>
    			</tab-bar-item>
    			
    			<!-- 我的 -->
    			<tab-bar-item path="/profile">
    				<template v-slot:item-icon>	
    				<img src="./assets/img/tabbar/mine.svg"/>
    				</template>
    				<template v-slot:item-icon-active>
    				<img src="./assets/img/tabbar/mineActive.svg"/>
    				</template>
    				<template v-slot:item-text>
    					<div>我的</div>
    				</template>
    			</tab-bar-item>
    			
    		</tab-bar>
    	</div>
    </template>
    
    <script>
    	import TabBar from './components/tabbar/TabBar.vue'
    	import TabBarItem from './components/tabbar/TabBarItem.vue'
    	export default {
    		name: 'App',
    		components:{
    			TabBar,
    			TabBarItem
    		}
    	}
    </script>
    
    <style>
    	/* @import url("./assets/css/base.css"); */
    </style>
    

补充:还可以将App.vue中的内容抽取出来作为一个组件。

8、Promise

见另一篇:https://blog.youkuaiyun.com/qq_38332722/article/details/109000648

9、Vuex

Vuex

​ 官方解释:Vuex是一个专为Vue.js应用程序开发的状态管理模式。

它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。

Vuex也集成到Vue的官方调试工具devtools extension,提供了诸如零配置的time-travel调试,状态快照导入导出等高级调试功能。

状态管理是什么? 可以简单的将其看成把需要多个组件共享的变量全部存储在一个对象里面。然后将这个对象放在顶层的Vue实例中,让其它组件可以使用。

​ 哪些状态需要在多个组件之间共享呢?比如用户的登录状态、用户名称、头像、地理位置等等。这些状态信息都可以放在统一的地方,对它进行保存和管理,而且它们还是响应式的。

使用环境:创建项目时安装Vuex插件、在浏览器中安装devTools插件(可以跟踪Vuex中的属性)

9.1、简单案例( s t o r e . s t a t e . c o u n t 、 store.state.count、 store.state.countstore.commit(‘increment’))

在这里插入图片描述

  • 创建项目时安装Vuex插件,会在src下创建store/index.js文件来管理Vuex。在创建Vuex对象store时,添加了state、mutations等属性。
import Vue from 'vue'
import Vuex from 'vuex'

//1、安装Vuex
Vue.use(Vuex)

//2、创建Vuex对象store
const store = new Vuex.Store({
	//共享变量
	state:{
		count:1000
	},
	//同步操作的方法
	mutations:{
		increment:function(state){
			state.count++;
		},
		decrement:function(state){
			state.count--;
		}
	},
	//异步操作的方法
	actions:{},
	
	// getters:{},
	// modules:{}
});

//3、导出store
export default store;
  • 在components下创建HelloVuex.vue组件。

    <template>
    	<div>
    		<h3>HelloVuex内容</h3>
    		{{$store.state.count}}
    	</div>
    </template>
    
    <script>
    </script>
    
    <style>
    </style>
    
  • App.vue

    访问Vuex中的state属性$store.state.count

    调用Vuex中的mutations方法$store.commit('increment');

    <template>
    	<div id="app">
    		<h3>App的内容</h3>
    		{{$store.state.count}}
    		<button @click="add">+</button>
    		<button @click="sub">-</button>
    		<hello-vuex></hello-vuex>
    	</div>
    </template>
    
    <script>
    	import HelloVuex from './components/HelloVuex.vue'
    
    	export default {
    		name: 'App',
    		data: function() {
    			return {
    				message: '消息',
    			}
    		},
    		components: {
    			HelloVuex
    		},
    		methods:{
    			add:function(){
    				this.$store.commit('increment');
    			},
    			sub:function(){
    				this.$store.commit('decrement');
    			}
    		}
    	}
    </script>
    
    <style>
    </style>
    

9.2 Vuex的核心概念

state、getters

​ 类似于组件中的计算属性computed。将state中的数据经过处理后再使用。

   //相当于组件的computed
	getters: {
		powerCount: function(state) {
			return state.count * state.count;
		},
		//1、默认参数state
		more20Stu: function(state) {
			return state.students.filter(stu => stu.age > 20);
		},
		//2、默认参数getters
		more20Length:function(state,getters){
			return getters.more20Stu.length;
		},
		//3、调用getters时传入参数;通过返回一个函数来实现
		moreStu:function(state){
			return function(age){
				return state.students.filter( stu => stu.age >= age);
			}
		}
	},
        <h3>getters的使用:</h3>
		<h4>1、默认参数state,getters</h4>
		<div>{{$store.getters.more20Stu}}</div>
		<div>{{$store.getters.more20Length}}</div>
		<h4>2、向getters中传入自定义参数,通过在getters中返回一个函数来实现</h4>
		<div>{{$store.getters.moreStu(28)}}</div>

全部代码:

import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

export default new Vuex.Store({
	state: {
		count: 100,
		students: [
			{
				id: 100,name: 'cobo',age: 28
			},
			{
				id: 101,name: 'curry',age: 10
			},
			{
				id: 102,name: 'windy',age: 23
			},
		]
	},
	mutations: {
		increment: function(state) {
			state.count++;
		},
		decrement: function(state) {
			state.count--;
		}
	},
	actions: {},

	//相当于组件的computed
	getters: {
		powerCount: function(state) {
			return state.count * state.count;
		},
		//默认参数state
		more20Stu: function(state) {
			return state.students.filter(stu => stu.age > 20);
		},
		//默认参数getters
		more20Length:function(state,getters){
			return getters.more20Stu.length;
		},
		//调用getters时传入参数;通过返回一个函数来实现
		moreStu:function(state){
			return function(age){
				return state.students.filter( stu => stu.age >= age);
			}
		}
	},
	modules: {}
})
<template>
	<div id="app">
		<h3>App中的内容</h3>
		<div>
			<div>{{$store.state.count}}</div>
			<button @click="add">+</button>
			<button @click="sub">-</button>
		</div>
		<h3>getters的使用:</h3>
		<h4>1、默认参数state,getters</h4>
		<div>{{$store.getters.more20Stu}}</div>
		<div>{{$store.getters.more20Length}}</div>
		<h4>2、向getters中传入自定义参数,通过在getters中返回一个函数来实现</h4>
		<div>{{$store.getters.moreStu(28)}}</div>
		<hello-vuex></hello-vuex>
	</div>
</template>

<script>
	import HelloVuex from './components/HelloVuex.vue'
	export default {
		name: 'App',
		components:{
			HelloVuex
		},
		methods: {
			add: function() {
				this.$store.commit('increment');
			},
			sub: function() {
				this.$store.commit('decrement');
			}
		}
	}
</script>

<style>
</style>
mutations(必须同步方法)

​ Vuex的store状态(state)的更新的唯一方式:提交mutation

  • mutations方法定义:
mutations: {
		increment: function(state) {
			state.count++;
		},
		decrement: function(state) {
			state.count--;
		},
		//携带参数
		incrementCount:function(state,cnt){
			state.count += cnt;
		}
	},
  • 使用mustations中的方法:
            <h3>mutations的使用:</h3>
			<h4>1、不传参数,使用默认的state参数</h4>
			<button @click="add">+</button>
			<button @click="sub">-</button>
			<h4>2、携带参数</h4>
			<button @click="addCount(5)">+5</button>
			<button @click="addCount(10)">+10</button>
	 methods: {
			add: function() {
				this.$store.commit('increment');
			},
			sub: function() {
				this.$store.commit('decrement');
			},
			//携带参数的写法
			addCount: function(cnt) {
				this.$store.commit('incrementCount', cnt);
			}
		}
  • mustations的提交风格:提交形式有两种,如下
				//1、普通提交形式
				// this.$store.commit('incrementCount', cnt);
				
				//2、特殊的提交形式
				this.$store.commit({
					type:'incrementCount',
					cnt:cnt,
					age:18
				});
//携带参数
incrementCount:function(state,cnt){
//1、普通提交的接收参数的方式
// state.count += cnt;
			
//2、特殊形式提交 接收参数的方式,cnt是一个对象:{ type: "incrementCount", cnt: 5, age: 18 }
	console.log(cnt);
	state.count += cnt.cnt;
}
info:{
		name:'cobo',
		age:19
	}

add:function(state){
		// state.info['address'] = "遵义";//该方式做不到响应式
		//响应式的增加元素
		Vue.set(state.info,'address','遵义');
			
		//响应式的删除元素
		Vue.delete(state.info,'name');
		console.log(state.info);
	}
  • mutations的类型常量:将mutations的方法名定义为常量,在使用时使用常量来减少错误。

    • 首先在store下创建 mutation-types.js文件,在里面定义常量并导出

      export const INCREMENT = 'increment'
      
    • 在store的mutations中使用常量

      import {INCREMENT} from './mutation-types.js'
      
      mutations: {
      		[INCREMENT]: function(state) {
      			state.count++;
      		},
      }
      
    • 在App.vue中调用该mutations方法。

      methods: {
      	add: function() {
      		this.$store.commit(INCREMENT);
      	},
      }
      
actions(可以包含异步操作)

actions

modules

modules

10、网络请求的封装 Axios

安装:npm install axios --save

10.1、axios的基本使用

在这里插入图片描述

1、get请求的参数拼接:也可以直接拼接在地址中。如果是post,则是data

axios({
	url:'',
	method:'get'
	params:{
		userid:'123'
	}
}).then({
	res => {
		console.log(res);
	}
})

2、发送并发请求:

//2、axios发送并发请求
axios.all([axios(), axios()])
	.then(results => {
		//并发请求的请求结果:数组results[0],results[1]
	})

axios.all([axios(), axios()])
	.then(axios.spread((res1, res2) => {
		//已将结果进行分割成两个变量
	}))

3、全局配置:
在这里插入图片描述

在这里插入图片描述

4、上述的配置都是全局的,对于每一请求都有用。创建Axios实例

//4、axios实例
const instance1 = axios.create({
	baseURI:'localhost:8080',
	timeout:5000,
    headers:{}
});

instance1({
	url:'/home'
}).then({
	res => {
		console.log(res);
	}
});

5、axios的封装:首先在src下创建:network/request

  • 方式一:request.js,需要传递三个参数。一个config,其他两个是函数。

    import axios from 'axios'
    
    export function request(config,success,failure){
    	//1、创建axios的实例
    	const instance = axios.create({
    		baseURL:'http://123.207.32.32:8000',
    		timeout:5000
    	});
    	
    	//2、发送请求
    	instance(config)
    		.then(res => {
    			// console.log(res);
    			success(res);
    		})
    		.catch(err => {
    			// console.log(err);
    			failure(err);
    		})
    }
    
    
    //其他不同配置的请求的封装
    export function instance2(){
    	
    }
    

    调用方式:

    //请求axios的封装
    import {request} from './network/request.js'
    
    request({
    	url: '/home/multidata'
    }, res => {
    	console.log(res);
    }, err => {
    	console.log(err);
    })
    
  • 方式二:只用传递一个config参数,直接将请求结果返回。

    import axios from 'axios'
    
    // export function request(config,success,failure){
    // 	//1、创建axios的实例
    // 	const instance = axios.create({
    // 		baseURL:'http://123.207.32.32:8000',
    // 		timeout:5000
    // 	});
    	
    // 	//2、发送请求
    // 	instance(config)
    // 		.then(res => {
    // 			// console.log(res);
    // 			success(res);
    // 		})
    // 		.catch(err => {
    // 			// console.log(err);
    // 			failure(err);
    // 		})
    // }
    
    export function request(config){
    	//1、创建axios的实例
    	const instance = axios.create({
    		baseURL:'http://123.207.32.32:8000',
    		timeout:5000
    	});
    	
    	//2、发送请求
    	return instance(config);
    }
    
    //其他不同配置的请求的封装
    export function instance2(){
    	
    }
    

    调用方式:

    request({
    	url: '/home/multidata'
    }).then( res => {
    	console.log(res);
    }).catch( err => {
    	console.log(err);
    })
    

6、axios拦截器:请求成功,请求失败,响应成功,响应失败

//2、axios的拦截器
	//2.1请求拦截
	instance.interceptors.request.use( config => {
		//请求成功
		console.log(config);
		return config;
	}, err => {
		//请求失败
		console.log(err);
		
	});
	
	//2.2响应拦截
	instance.interceptors.response.use( res =>{
		//响应成功
		//可以对结果进行处理后再返回
		return res;
	}, err => {
		//响应失败
		console.log(err);
	})
import axios from 'axios'

export function request(config){
	//1、创建axios的实例
	const instance = axios.create({
		baseURL:'http://123.207.32.32:8000',
		timeout:5000
	});
	
	//2、axios的拦截器
	//2.1请求拦截
	instance.interceptors.request.use( config => {
		//请求成功
		console.log(config);
		return config;
	}, err => {
		//请求失败
		console.log(err);
		
	});
	
	//2.2响应拦截
	instance.interceptors.response.use( res =>{
		//响应成功
		//可以对结果进行处理后再返回
		return res;
	}, err => {
		//响应失败
		console.log(err);
	})
	
	//3、发送请求
	return instance(config);
}

//其他不同配置的请求的封装
export function instance2(){
	
}

ce1 = axios.create({
baseURI:‘localhost:8080’,
timeout:5000,
headers:{}
});

instance1({
url:’/home’
}).then({
res => {
console.log(res);
}
});


### 5、axios的封装:首先在src下创建:network/request

+ 方式一:request.js,需要传递三个参数。一个config,其他两个是函数。

  ```js
  import axios from 'axios'
  
  export function request(config,success,failure){
  	//1、创建axios的实例
  	const instance = axios.create({
  		baseURL:'http://123.207.32.32:8000',
  		timeout:5000
  	});
  	
  	//2、发送请求
  	instance(config)
  		.then(res => {
  			// console.log(res);
  			success(res);
  		})
  		.catch(err => {
  			// console.log(err);
  			failure(err);
  		})
  }
  
  
  //其他不同配置的请求的封装
  export function instance2(){
  	
  }

调用方式:

//请求axios的封装
import {request} from './network/request.js'

request({
	url: '/home/multidata'
}, res => {
	console.log(res);
}, err => {
	console.log(err);
})
  • 方式二:只用传递一个config参数,直接将请求结果返回。

    import axios from 'axios'
    
    // export function request(config,success,failure){
    // 	//1、创建axios的实例
    // 	const instance = axios.create({
    // 		baseURL:'http://123.207.32.32:8000',
    // 		timeout:5000
    // 	});
    	
    // 	//2、发送请求
    // 	instance(config)
    // 		.then(res => {
    // 			// console.log(res);
    // 			success(res);
    // 		})
    // 		.catch(err => {
    // 			// console.log(err);
    // 			failure(err);
    // 		})
    // }
    
    export function request(config){
    	//1、创建axios的实例
    	const instance = axios.create({
    		baseURL:'http://123.207.32.32:8000',
    		timeout:5000
    	});
    	
    	//2、发送请求
    	return instance(config);
    }
    
    //其他不同配置的请求的封装
    export function instance2(){
    	
    }
    

    调用方式:

    request({
    	url: '/home/multidata'
    }).then( res => {
    	console.log(res);
    }).catch( err => {
    	console.log(err);
    })
    

6、axios拦截器:请求成功,请求失败,响应成功,响应失败

//2、axios的拦截器
	//2.1请求拦截
	instance.interceptors.request.use( config => {
		//请求成功
		console.log(config);
		return config;
	}, err => {
		//请求失败
		console.log(err);
		
	});
	
	//2.2响应拦截
	instance.interceptors.response.use( res =>{
		//响应成功
		//可以对结果进行处理后再返回
		return res;
	}, err => {
		//响应失败
		console.log(err);
	})
import axios from 'axios'

export function request(config){
	//1、创建axios的实例
	const instance = axios.create({
		baseURL:'http://123.207.32.32:8000',
		timeout:5000
	});
	
	//2、axios的拦截器
	//2.1请求拦截
	instance.interceptors.request.use( config => {
		//请求成功
		console.log(config);
		return config;
	}, err => {
		//请求失败
		console.log(err);
		
	});
	
	//2.2响应拦截
	instance.interceptors.response.use( res =>{
		//响应成功
		//可以对结果进行处理后再返回
		return res;
	}, err => {
		//响应失败
		console.log(err);
	})
	
	//3、发送请求
	return instance(config);
}

//其他不同配置的请求的封装
export function instance2(){
	
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值