Vue2-3.笔记

vue-basic

【尚硅谷】2021最新Vue技术全家桶丨vue3.x最新版详细讲解

示例对应 code web

初识vue

DOCTYPE html>
<body>
	
	
	<div id="demo">
		<h1>Hello,{{name.toUpperCase()}},{{address}}h1>
	div>
	<script type="text/javascript" >
		Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
		//创建Vue实例
		new Vue({
			el:'#demo', //el用于指定当前Vue实例为哪个容器服务,值通常为css选择器字符串。
			data:{ //data中用于存储数据,数据供el所指定的容器去使用,值我们暂时先写成一个对象。
				name:'atguigu',
				address:'北京'
			}
		})
	script>
body>

Vue-模板语法

DOCTYPE html>
<body>
	  
	
	<div id="root">
		<h1>插值语法h1>
		<h3>你好,{{name}}h3>
		<hr/>
		<h1>指令语法h1>
		<a v-bind:href="school.url.toUpperCase()" x="hello">点我去{{school.name}}学习1a>
		<a :href="school.url" x="hello">点我去{{school.name}}学习2a>
	div>
body>

<script type="text/javascript">
	Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
	new Vue({
		el:'#root',
		data:{
			name:'jack',
			school:{
				name:'尚硅谷',
				url:'http://www.atguigu.com',
			}
		}
	})
script>

vue-数据绑定

DOCTYPE html>
<body>
	
	
	<div id="root">
		
		

		
		单向数据绑定:<input type="text" :value="name"><br/>
		双向数据绑定:<input type="text" v-model="name"><br/>

		
		
	div>
body>

<script type="text/javascript">
	Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。

	new Vue({
		el:'#root',
		data:{
			name:'尚硅谷'
		}
	})
script>

vue-el与data的两种写法

DOCTYPE html>
<body>
	
	
	<div id="root">
		<h1>你好,{{name}}h1>
	div>
body>

<script type="text/javascript">
	Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。

	//el的两种写法
	/* const v = new Vue({
		//el:'#root', //第一种写法
		data:{
			name:'尚硅谷'
		}
	})
	console.log(v)
	v.$mount('#root') //第二种写法 */

	//data的两种写法
	new Vue({
		el:'#root',
		//data的第一种写法:对象式
		/* data:{
			name:'尚硅谷'
		} */

		//data的第二种写法:函数式
		data(){
			console.log('@@@',this) //此处的this是Vue实例对象
			return{
				name:'尚硅谷'
			}
		}
	})
script>

vue-MVVM

DOCTYPE html>
<body>
	
	
	<div id="root">
		<h1>学校名称:{{name}}h1>
		<h1>学校地址:{{address}}h1>
		
	div>
body>

<script type="text/javascript">
	Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。

	const vm = new Vue({
		el:'#root',
		data:{
			name:'尚硅谷',
			address:'北京',
		}
	})
	console.log(vm)
script>

数据代理

回顾Object.defineProperty方法
<body>
	<script type="text/javascript" >
		let number = 18
		let person = {
			name:'张三',
			sex:'男',
		}

		Object.defineProperty(person,'age',{
			// value:18,
			// enumerable:true, //控制属性是否可以枚举,默认值是false
			// writable:true, //控制属性是否可以被修改,默认值是false
			// configurable:true //控制属性是否可以被删除,默认值是false

			// number 和 person.age 关联上
			//当有人读取person的age属性时,get函数(getter)就会被调用,且返回值就是age的值
			get(){
				console.log('有人读取age属性了')
				return number
			},

			//当有人修改person的age属性时,set函数(setter)就会被调用,且会收到修改的具体值
			set(value){
				console.log('有人修改了age属性,且值是',value)
				number = value
			}

		})
		// console.log(Object.keys(person))
	script>
何为数据代理
DOCTYPE html>
<script type="text/javascript" >
	let obj = {x:100}
	let obj2 = {y:200}

	Object.defineProperty(obj2,'x',{
		get(){
			return obj.x
		},
		set(value){
			obj.x = value
		}
	})
script>
Vue中的数据代理
<body>
	
	
	<div id="root">
		<h2>学校名称:{{name}}h2>
		<h2>学校地址:{{address}}h2>
	div>
body>

<script type="text/javascript">
	Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
	
	const vm = new Vue({
		el:'#root',
		data:{
			name:'尚硅谷',
			address:'宏福科技园'
		}
	})
script>

Vue2-3.笔记_第1张图片
Vue2-3.笔记_第2张图片

事件处理

事件的基本使用
<body>
	
	
	<div id="root">
		<h2>欢迎来到{{name}}学习h2>
		
		<button @click="showInfo1">点我提示信息1(不传参)button>
		<button @click="showInfo2($event,66)">点我提示信息2(传参)button>
	div>
body>
事件修饰符
<body>
	
	
	<div id="root">
		<h2>欢迎来到{{name}}学习h2>
		
		<a href="http://www.atguigu.com" @click.prevent="showInfo">点我提示信息a>

		
		<div class="demo1" @click="showInfo">
			<button @click.stop="showInfo">点我提示信息button>
			
			
		div>

		
		<button @click.once="showInfo">点我提示信息button>

		
		<div class="box1" @click.capture="showMsg(1)">
			div1
			<div class="box2" @click="showMsg(2)">
				div2
			div>
		div>

		
		<div class="demo1" @click.self="showInfo">
			<button @click="showInfo">点我提示信息button>
		div>

		
		<ul @wheel.passive="demo" class="list">
			<li>1li>
			<li>2li>
			<li>3li>
			<li>4li>
		ul>

	div>
body>

键盘事件

<body>
	
	
	<div id="root">
		<h2>欢迎来到{{name}}学习h2>
		<input type="text" placeholder="按下回车提示输入" @keydown.huiche="showInfo">
	div>
body>

<script type="text/javascript">
	Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
	Vue.config.keyCodes.huiche = 13 //定义了一个别名按键

	new Vue({
		el:'#root',
		data:{
			name:'尚硅谷'
		},
		methods: {
			showInfo(e){
				// console.log(e.key,e.keyCode)
				console.log(e.target.value)
			}
		},
	})
script>

计算属性

姓名案例_插值语法实现
<body>
	
	<div id="root">
		姓:<input type="text" v-model="firstName"> <br/><br/>
		名:<input type="text" v-model="lastName"> <br/><br/>
		全名:<span>{{firstName}}-{{lastName}}span>
	div>
body>

<script type="text/javascript">
	Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。

	new Vue({
		el:'#root',
		data:{
			firstName:'张',
			lastName:'三'
		}
	})
script>
姓名案例_methods实现
<body>
	
	<div id="root">
		姓:<input type="text" v-model="firstName"> <br/><br/>
		名:<input type="text" v-model="lastName"> <br/><br/>
		全名:<span>{{fullName()}}span>
	div>
body>

<script type="text/javascript">
	Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。

	// data只要变了,vue模板就会重新刷新
	new Vue({
		el:'#root',
		data:{
			firstName:'张',
			lastName:'三'
		},
		methods: {
			fullName(){
				console.log('@---fullName')
				return this.firstName + '-' + this.lastName
			}
		},
	})
script>
姓名案例_计算属性实现
<body>
	
	
	<div id="root">
		姓:<input type="text" v-model="firstName"> <br/><br/>
		名:<input type="text" v-model="lastName"> <br/><br/>
		全名:<span>{{fullName}}span> <br/><br/>
		全名:<span>{{fullName1}}span> <br/><br/>
	div>
body>
<script type="text/javascript">
	Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
	const vm = new Vue({
		el:'#root',
		data:{
			firstName:'张',
			lastName:'三'
		},
		computed:{
			fullName:{
				//get有什么作用?当有人读取fullName时,get就会被调用,且返回值就作为fullName的值
				//get什么时候调用?1.初次读取fullName时。2.所依赖的数据发生变化时。
				get(){
					// console.log(this) //此处的this是vm
					return this.firstName + '-' + this.lastName;
				},
				//set什么时候调用? 当fullName被修改时。
				set(value){
					const arr = value.split('-');
					this.firstName = arr[0];
					this.lastName = arr[1];
				}
			},
			//简写
			fullName1(){
				return this.firstName + '-' + this.lastName;
			}
		}
	})
script>

监视属性

天气案例_监视属性
<body>
	
	
	<div id="root">
		<h2>今天天气很{{info}}h2>
		<button @click="isHot = !isHot">切换天气button>
	div>
body>

<script type="text/javascript">
	Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
	const vm = new Vue({
		el:'#root',
		data() {
			return {
				isHot:true,
				info: '',
				numbers: { a: { b: 'bb' } }
			}
		},
		watch:{
			isHot:{
				immediate:true, //初始化时让handler调用一下
				deep:true, // 监视多级结构中所有属性的变化
				//handler什么时候调用?当isHot发生改变时。
				handler(newValue,oldValue){
					this.info = this.isHot ? '炎热' : '凉爽';
				}
			},
			//简写
			/* isHot(newValue,oldValue){
				this.info = this.isHot ? '炎热' : '凉爽';
			} */
			// 监视多级结构中某个属性的变化
			'numbers.a.b':{
				handler(){
					console.log('numbers.a.b 被改变了')
				}
			}
		}
	})

	/* vm.$watch('isHot',{
		immediate:true, //初始化时让handler调用一下
		//handler什么时候调用?当isHot发生改变时。
		handler(newValue,oldValue){
			this.info = this.isHot ? '炎热' : '凉爽';
		}
	}) */
script>

绑定样式

<body>
	
	
	<div id="root">
		
		
		<div class="basic" :class="mood" @click="changeMood">{{name}}div> <br/><br/>

		
		
		<div class="basic" :class="classArr">{{name}}div> <br/><br/>

		
		
		<div class="basic" :class="classObj">{{name}}div> <br/><br/>

		
		
		<div class="basic" :style="styleObj">{{name}}div> <br/><br/>
		
		
		<div class="basic" :style="styleArr">{{name}}div>
	div>
body>

条件渲染

<body>
	
	
	<div id="root">
		<h2>当前的n值是:{{n}}h2>
		<button @click="n++">点我n+1button>
		
		
		

		
		
		

		
		

		
		<template v-if="n === 1">
			<h2>你好h2>
			<h2>尚硅谷h2>
			<h2>北京h2>
		template>

	div>
body>

列表渲染

基本列表
<body>
	
	
	<div id="root">
		<h2>(遍历数组)h2>
		<ul>
			<li v-for="(p,index) of persons" :key="index">
				{{p.name}}-{{p.age}}
			li>
		ul>

		<h2>(遍历对象)h2>
		<ul>
			<li v-for="(value,k) of car" :key="k">
				{{k}}-{{value}}
			li>
		ul>

		<h2>遍历字符串(用得少)h2>
		<ul>
			<li v-for="(char,index) of str" :key="index">
				{{char}}-{{index}}
			li>
		ul>
		
		
		<h2>遍历指定次数(用得少)h2>
		<ul>
			<li v-for="(number,index) of 5" :key="index">
				{{index}}-{{number}}
			li>
		ul>
	div>
<body>
key的原理
	
列表过滤 or 列表排序
watch:{
	keyWord:{
		immediate:true,
		handler(val){
			this.filPerons = this.persons.filter((p)=> p.name.indexOf(val) !== -1)
		}
	}
}
or
computed:{
	filPerons(){
		return this.persons.filter((p)=> p.name.indexOf(this.keyWord) !== -1)
	}
}

Vue监视数据的原理

Vue监视数据的原理:
            1. vue会监视data中所有层次的数据。

            2. 如何监测对象中的数据?
                通过setter实现监视,且要在new Vue时就传入要监测的数据。
                    (1).对象中后追加的属性,Vue默认不做响应式处理
                    (2).如需给后添加的属性做响应式,请使用如下API:
                        Vue.set(target,propertyName/index,value) 或 
                        vm.$set(target,propertyName/index,value)

            3. 如何监测数组中的数据?
                通过包裹数组更新元素的方法实现,本质就是做了两件事:
                    (1).调用原生对应的方法对数组进行更新。
                    (2).重新解析模板,进而更新页面。

            4.在Vue修改数组中的某个元素一定要用如下方法:
                1.使用这些API:push()、pop()、shift()、unshift()、splice()、sort()、reverse()
                2.Vue.set() 或 vm.$set()
            
            特别注意:Vue.set() 和 vm.$set() 不能给vm 或 vm的根数据对象 添加属性!!!

收集表单数据

收集表单数据:
            若:,则v-model收集的是value值,用户输入的就是value值。
            若:,则v-model收集的是value值,且要给标签配置value值。
            若:
                1.没有配置input的value属性,那么收集的就是checked(勾选 or 未勾选,是布尔值)
                2.配置input的value属性:
                    (1)v-model的初始值是非数组,那么收集的就是checked(勾选 or 未勾选,是布尔值)
                    (2)v-model的初始值是数组,那么收集的的就是value组成的数组
            备注:v-model的三个修饰符:
                lazy:失去焦点再收集数据
                number:输入字符串转为有效的数字
                trim:输入首尾空格过滤

过滤器

<body>
	
	
	<div id="root">
		
		<h3>现在是:{{time | timeFormater}}h3>
		
		<h3>现在是:{{time | timeFormater('YYYY_MM_DD') | mySlice}}h3>
		<h3 :x="msg | mySlice">尚硅谷h3>
	div>
body>

<script type="text/javascript">
	Vue.config.productionTip = false
	//全局过滤器
	Vue.filter('mySlice',function(value){
		return value.slice(0,4)
	})
	
	new Vue({
		el:'#root',
		data:{
			time:1621561377603, //时间戳
			msg:'你好,尚硅谷'
		},
		//局部过滤器
		filters:{
			timeFormater(value,str='YYYY年MM月DD日 HH:mm:ss'){
				// console.log('@',value)
				return dayjs(value).format(str)
			}
		}
	})
script>

内置指令

学过的指令:
        v-bind	: 单向绑定解析表达式, 可简写为 :xxx
        v-model	: 双向数据绑定
        v-for  	: 遍历数组/对象/字符串
        v-on   	: 绑定事件监听, 可简写为@
        v-if 	 	: 条件渲染(动态控制节点是否存存在)
        v-else 	: 条件渲染(动态控制节点是否存存在)
        v-show 	: 条件渲染 (动态控制节点是否展示)
        v-text指令:
            1.作用:向其所在的节点中渲染文本内容。
            2.与插值语法的区别:v-text会替换掉节点中的内容,{{xx}}则不会。
        v-html指令:
           1.作用:向指定节点中渲染包含html结构的内容。
           2.与插值语法的区别:
               (1).v-html会替换掉节点中所有的内容,{{xx}}则不会。
               (2).v-html可以识别html结构。
           3.严重注意:v-html有安全性问题!!!!
               (1).在网站上动态渲染任意HTML是非常危险的,容易导致XSS攻击。
               (2).一定要在可信的内容上使用v-html,永不要用在用户提交的内容上!
        v-cloak指令(没有值):
           1.本质是一个特殊属性,Vue实例创建完毕并接管容器后,会删掉v-cloak属性。
           2.使用css配合v-cloak可以解决网速慢时页面展示出{{xxx}}的问题。
   	    v-once指令:
           1.v-once所在节点在初次动态渲染后,就视为静态内容了。
           2.以后数据的改变不会引起v-once所在结构的更新,可以用于优化性能。
        v-pre指令:
           1.跳过其所在节点的编译过程。
           2.可利用它跳过:没有使用指令语法、没有使用插值语法的节点,会加快编译。

自定义指令

 		需求1:定义一个v-big指令,和v-text功能类似,但会把绑定的数值放大10倍。
        需求2:定义一个v-fbind指令,和v-bind功能类似,但可以让其所绑定的input元素默认获取焦点。
        自定义指令总结:
            一、定义语法:
                (1).局部指令:
                    new Vue({
                        directives:{指令名:配置对象} 或 directives{指令名:回调函数}
                    }) 
                (2).全局指令:
                    Vue.directive(指令名,配置对象) 或 Vue.directive(指令名,回调函数)

            二、配置对象中常用的3个回调:
                (1).bind:指令与元素成功绑定时调用。
                (2).inserted:指令所在元素被插入页面时调用。
                (3).update:指令所在模板结构被重新解析时调用。

            三、备注:
                1.指令定义时不加v-,但使用时要加v-;
                2.指令名如果是多个单词,要使用kebab-case命名方式,不要用camelCase命名。
        Vue.directive('fbind',{
			//指令与元素成功绑定时(一上来)
			bind(element,binding){
				element.value = binding.value
			},
			//指令所在元素被插入页面时
			inserted(element,binding){
				element.focus()
			},
			//指令所在的模板被重新解析时
			update(element,binding){
				element.value = binding.value
			}

生命周期

生命周期:
	1.又名:生命周期回调函数、生命周期函数、生命周期钩子。
	2.是什么:Vue在关键时刻帮我们调用的一些特殊名称的函数。
	3.生命周期函数的名字不可更改,但函数的具体内容是程序员根据需求编写的。
	4.生命周期函数中的this指向是vm 或 组件实例对象。
常用的生命周期钩子:
	1.mounted: 发送ajax请求、启动定时器、绑定自定义事件、订阅消息等【初始化操作】。
	2.beforeDestroy: 清除定时器、解绑自定义事件、取消订阅消息等【收尾工作】。

关于销毁Vue实例
	1.销毁后借助Vue开发者工具看不到任何信息。
	2.销毁后自定义事件会失效,但原生DOM事件依然有效。
	3.一般不会在beforeDestroy操作数据,因为即便操作数据,也不会再触发更新流程了。

Vue2-3.笔记_第3张图片

非单文件组件

Vue中使用组件的三大步骤:

		一、定义组件(创建组件)
	     使用Vue.extend(options)创建,其中options和new Vue(options)时传入的那个options几乎一样,但也有点区别;
	     区别如下:
	         1.el不要写,为什么? ——— 最终所有的组件都要经过一个vm的管理,由vm中的el决定服务哪个容器。
	         2.data必须写成函数,为什么? ———— 避免组件被复用时,数据存在引用关系。
	     备注:使用template可以配置组件结构。
	     
		二、注册组件
	     1.局部注册:靠new Vue的时候传入components选项
	     2.全局注册:靠Vue.component('组件名',组件)
	     
		三、使用组件(写组件标签):
	     

几个注意点:
		1.关于组件名:
		     一个单词组成:
		         第一种写法(首字母小写):school
		         第二种写法(首字母大写):School
		     多个单词组成:
		         第一种写法(kebab-case命名):my-school
		         第二种写法(CamelCase命名):MySchool (需要Vue脚手架支持)
		     备注:
		         (1).组件名尽可能回避HTML中已有的元素名称,例如:h2、H2都不行。
		         (2).可以使用name配置项指定组件在开发者工具中呈现的名字。
		
		2.关于组件标签:
		     第一种写法:
		     第二种写法:
		     备注:不用使用脚手架时,会导致后续组件不能渲染。
		
		 3.一个简写方式:
		     const school = Vue.extend(options) 可简写为:const school = options

关于VueComponent:
		1.school组件本质是一个名为VueComponent的构造函数,且不是程序员定义的,是Vue.extend生成的。
		
		 2.我们只需要写,Vue解析时会帮我们创建school组件的实例对象,
		     即Vue帮我们执行的:new VueComponent(options)。
		
		 3.特别注意:每次调用Vue.extend,返回的都是一个全新的VueComponent!!!!
		
		 4.关于this指向:
		         (1).组件配置中:
		                     data函数、methods中的函数、watch中的函数、computed中的函数 它们的this均是【VueComponent实例对象】。
		         (2).new Vue(options)配置中:
		                     data函数、methods中的函数、watch中的函数、computed中的函数 它们的this均是【Vue实例对象】。
		
		 5.VueComponent的实例对象,以后简称vc(也可称之为:组件实例对象)。
		     Vue的实例对象,以后简称vm。
		     
内置关系:
		1.一个重要的内置关系:VueComponent.prototype.__proto__ === Vue.prototype
		2.为什么要有这个关系:让组件实例对象(vc)可以访问到 Vue原型上的属性、方法。

Vue - cli

vue-cil 的目录结构

. vue-cil 的目录结构
|-- App.vue
|-- assets
|   `-- logo.png
|-- components
|   |-- School.vue
|   `-- Student.vue
`-- main.js
main.js
/* 该文件是整个项目的入口文件 */
import Vue from 'vue' //引入Vue
import App from './App.vue' //引入App组件,它是所有组件的父组件
Vue.config.productionTip = false; //关闭vue的生产提示

/* 关于不同版本的Vue:
		1.vue.js与vue.runtime.xxx.js的区别:
			(1).vue.js是完整版的Vue,包含:核心功能+模板解析器。
			(2).vue.runtime.xxx.js是运行版的Vue,只包含:核心功能;没有模板解析器。
		2.因为vue.runtime.xxx.js没有模板解析器,所以不能使用template配置项,需要使用
			render函数接收到的createElement函数去指定具体内容。
*/
//创建Vue实例对象---vm
new Vue({
	el:'#app',
	//render函数完成了这个功能:将App组件放入容器中
	render: h => h(App),
	// render:q=> q('h1','你好啊')

	// template:`

你好啊

`,
// components:{App}, })
App.vue
<template>
	<div>
		<img src="./assets/logo.png" alt="logo">
		<School>School>
		<Student>Student>
	div>
template>

<script>
	//引入组件
	import School from './components/School'
	import Student from './components/Student'

	export default {
		name:'App',
		components:{
			School,
			Student
		}
	}
script>

ref属性

<template>
	<div>
		<h1 v-text="msg" ref="title">h1>
		<button ref="btn" @click="showDOM">点我输出上方的DOM元素button>
		<School ref="sch"/>
	div>
template>

<script>
	//引入School组件
	import School from './components/School'

	export default {
		name:'App',
		components:{School},
		data() {
			return {
				msg:'欢迎学习Vue!'
			}
		},
		methods: {
			showDOM(){
				console.log(this.$refs.title) //真实DOM元素
				console.log(this.$refs.btn) //真实DOM元素
				console.log(this.$refs.sch) //School组件的实例对象(vc)
			}
		},
	}
script>

props配

		//简单声明接收
		// props:['name','age','sex'] 

		//接收的同时对数据进行类型限制
		/* props:{
			name:String,
			age:Number,
			sex:String
		} */

		//接收的同时对数据:进行类型限制+默认值的指定+必要性的限制
		props:{
			name:{
				type:String, //name的类型是字符串
				required:true, //name是必要的
			},
			age:{
				type:Number,
				default:99 //默认值
			},
			sex:{
				type:String,
				required:true
			}
		}

mixin混入

// mixin.js
export const hunhe = {
	methods: {
		showName(){
			alert(this.name)
		}
	},
	mounted() {
		console.log('你好啊!')
	},
}
export const hunhe2 = {
	data() {
		return {
			x:100,
			y:200
		}
	},
}
<template>
	<div>
		<h2 @click="showName">学生姓名:{{name}}h2>
		<h2>学生性别:{{sex}}h2>
	div>
template>

<script>
	import {hunhe,hunhe2} from '../mixin'

	export default {
		name:'Student',
		data() {
			return {
				name:'张三',
				sex:'男'
			}
		},
		mixins:[hunhe,hunhe2]
	}
script>

插件

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

//应用(使用)插件
Vue.use(plugins,1,2,3)
//创建vm
new Vue({
	el:'#app',
	render: h => h(App)
})
// plugins.js
export default {
	install(Vue,x,y,z){
		console.log(x,y,z)
		//全局过滤器
		Vue.filter('mySlice',function(value){
			return value.slice(0,4)
		})

		//定义全局指令
		Vue.directive('fbind',{
			//指令与元素成功绑定时(一上来)
			bind(element,binding){
				element.value = binding.value
			},
			//指令所在元素被插入页面时
			inserted(element,binding){
				element.focus()
			},
			//指令所在的模板被重新解析时
			update(element,binding){
				element.value = binding.value
			}
		})

		//定义混入
		Vue.mixin({
			data() {
				return {
					x:100,
					y:200
				}
			},
		})

		//给Vue原型上添加一个方法(vm和vc就都能用了)
		Vue.prototype.hello = ()=>{alert('你好啊')}
	}
}

// 父组件
<template>
	<div class="app">
		<h1>{{msg}},学生姓名是:{{studentName}}h1>
		
		<School :getSchoolName="getSchoolName"/>
		
		
		
		<Student ref="student" @click.native="show"/>
	div>
template>
<script>
	import Student from './components/Student'
	import School from './components/School'

	export default {
		name:'App',
		components:{School,Student},
		data() {
			return {
				msg:'你好啊!',
				studentName:''
			}
		},
		mounted() {
			this.$refs.student.$on('atguigu',this.getStudentName) // 另一种绑定方式,绑定自定义事件
			// this.$refs.student.$once('atguigu',this.getStudentName) //绑定自定义事件(一次性)
		},
	}
script>
// 子组件
<script>
	export default {
		methods: {
			sendStudentlName(){
				//触发Student组件实例身上的atguigu事件
				this.$emit('atguigu',this.name,666,888,900)
				// this.$emit('demo')
				// this.$emit('click')
			},
			unbind(){
				this.$off('atguigu') //解绑一个自定义事件
				// this.$off(['atguigu','demo']) //解绑多个自定义事件
				// this.$off() //解绑所有的自定义事件
			},
			death(){
				this.$destroy() //销毁了当前Student组件的实例,销毁后所有Student实例的自定义事件全都不奏效。
			}
		}
	}
	
script>

全局事件总线 - bus

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

// 总线bus挂载到Vue上,也会挂载到cm上,所以可以用this.$bus.$emit and this.$bus.$on event
/*
	this.$bus.$emit('hello',this.name)
	this.$bus.$on('hello',(data)=>{
		console.log('我是School组件,收到了数据',data)
	})
	也可以引入第三方 'pubsub-js'
*/
new Vue({
	el:'#app',
	render: h => h(App),
	beforeCreate() {
		Vue.prototype.$bus = this //安装全局事件总线
	},
})

过度与动画

<template>
	<div>
		<button @click="isShow = !isShow">显示/隐藏button>
		<transition name="hello" appear>
			<h1 v-show="isShow">你好啊!h1>
		transition>
	div>
template>

<script>
	// transition + name + style(hello-enter-active and hello-leave-active)
	export default {
		name:'Test',
		data() {
			return { isShow:true }
		},
	}
script>

<style scoped>
	h1{ background-color: orange; }
	.hello-enter-active{ animation: atguigu 0.5s linear; }
	.hello-leave-active{ animation: atguigu 0.5s linear reverse; }
	@keyframes atguigu {
		from{ transform: translateX(-100%); }
		to{ transform: translateX(0px); }
	}
style>

配置代理服务器 - axios

// 组件中引入 axios
import axios from 'axios'
export default {
	name:'App',
	methods: {
		getStudents(){
			axios.get('http://localhost:8080/students').then(
				response => {
					console.log('请求成功了',response.data)
				},
				error => {
					console.log('请求失败了',error.message)
				}
			)
		},
		getCars(){
			axios.get('http://localhost:8080/demo/cars').then(
				response => {
					console.log('请求成功了',response.data)
				},
				error => {
					console.log('请求失败了',error.message)
				}
			)
		}
	},
}

插槽 - slot

默认插槽

<template>
	<div class="category">
		<h3>{{title}}分类h3>
		
		<slot>我是一些默认值,当使用者没有传递具体结构时,这句就会出现slot>
	div>
template>

<template>
	<div class="container">
		<Category title="美食" >
			// 塞到默认插槽中
			<img src="https://s3.ax1x.com/2021/01/16/srJlq0.jpg" alt="">
		Category>

		<Category title="游戏" >
			<ul><li v-for="(g,index) in games" :key="index">{{g}}li>ul>
		Category>

		<Category title="电影">
			<video controls src="http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4">video>
		Category>
	div>
template>
具名插槽


<template>
	<div class="category">
		<h3>{{title}}分类h3>
		
		<slot name="center">我是一些默认值,当使用者没有传递具体结构时,我会出现1slot>
		<slot name="footer">我是一些默认值,当使用者没有传递具体结构时,我会出现2slot>
	div>
template>

<template>
	<div class="container">
		<Category title="美食" >
			<img slot="center" src="https://s3.ax1x.com/2021/01/16/srJlq0.jpg" alt="">
			<a slot="footer" href="http://www.atguigu.com">更多美食a>
		Category>

		<Category title="游戏" >
			<ul slot="center">
				<li v-for="(g,index) in games" :key="index">{{g}}li>
			ul>
			<div class="foot" slot="footer">
				<a href="http://www.atguigu.com">单机游戏a>
				<a href="http://www.atguigu.com">网络游戏a>
			div>
		Category>

		// template 会少包裹层
		<Category title="电影">
			<video slot="center" controls src="http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4">video>
			<template v-slot:footer>
				<div class="foot">
					<a href="http://www.atguigu.com">经典a>
					<a href="http://www.atguigu.com">热门a>
					<a href="http://www.atguigu.com">推荐a>
				div>
			template>
		Category>
	div>
template>
作用域插槽

<template>
	<div class="category">
		<h3>{{title}}分类h3>
		<slot :games="games" msg="hello">我是默认的一些内容slot>
	div>
template>

<template>
	<div class="container">

		<Category title="游戏">
			<template scope="atguigu">
				<ul>
					<li v-for="(g,index) in atguigu.games" :key="index">{{g}}li>
				ul>
			template>
		Category>

		<Category title="游戏">
			<template scope="{games}">
				<ol>
					<li style="color:red" v-for="(g,index) in games" :key="index">{{g}}li>
				ol>
			template>
		Category>

		<Category title="游戏">
			<template slot-scope="{games}">
				<h4 v-for="(g,index) in games" :key="index">{{g}}h4>
			template>
		Category>

	div>
template>

Vuex

简版 vuex
// store - index.js
//该文件用于创建Vuex中最为核心的store
import Vue from 'vue'
//引入Vuex
import Vuex from 'vuex'
// 应用Vuex插件
Vue.use(Vuex)

//创建并暴露store
export default new Vuex.Store({
  state:{
    counter:1000
  },
  mutations:{
  	increment(state) {
  		state.counter++;
  	}
  },
  actions:{},
  getters:{},
  modules:{}
})
// main.js
import Vue from 'vue'
import App from './App.vue'
//引入store
import store from './store'

//创建vm
new Vue({
	el:'#app',
	render: h => h(App),
	store
})
// 组件
<script>
	import {mapState, mapGetters, mapMutations, mapActions} from 'vuex'
	export default {
		name:'Count',
		data() {
			return {
				n:1, //用户选择的数字
			}
		},
		computed:{
			...mapState(['sum','school','subject']),
			...mapGetters(['bigSum'])
		},
		methods: {
			//借助mapMutations生成对应的方法,方法中会调用commit去联系mutations(对象写法)
			...mapMutations({increment:'funName1',decrement:'funName2'}),

			//借助mapMutations生成对应的方法,方法中会调用commit去联系mutations(数组写法)
			// ...mapMutations(['funName1','funName2']),
			add() {
				console.log(this.$store.state.counter); // 获取store 的value
				this.$store.commit('increment');
			},
			//借助mapActions生成对应的方法,方法中会调用dispatch去联系actions(对象写法)
			...mapActions({incrementOdd:'funName3',incrementWait:'funName4'})

			//借助mapActions生成对应的方法,方法中会调用dispatch去联系actions(数组写法)
			// ...mapActions(['funName3','funName4'])
		}
	}
script>	

vuex模块化编码
// store - index.js
//该文件用于创建Vuex中最为核心的store
import Vue from 'vue'
//引入Vuex
import Vuex from 'vuex'
// 两个模块的配置文件
import countOptions from './count'
import personOptions from './person'
//应用Vuex插件
Vue.use(Vuex)

//创建并暴露store
export default new Vuex.Store({
	modules:{
		countAbout:countOptions,
		personAbout:personOptions
	}
})

<script>
	export default {
		name:'Person',
		computed:{
			personList(){
				return this.$store.state.personAbout.personList
			},
			sum(){
				return this.$store.state.countAbout.sum
			},
			firstPersonName(){
				return this.$store.getters['personAbout/firstPersonName']
			}
		},
		methods: {
			add(){
				const personObj = { name:this.name };
				this.$store.commit('personAbout/ADD_PERSON',personObj);
			},
			addWang(){
				const personObj = {id:nanoid(),name:this.name};
				this.$store.dispatch('personAbout/addPersonWang',personObj);
			},
			addPersonServer(){
				this.$store.dispatch('personAbout/addPersonServer')
			}
		},
	}
script>

路由

基础路由
// router.js 专门用于创建整个应用的路由器
import VueRouter from 'vue-router'

// 创建并暴露一个路由器
export default new VueRouter({
	routes:[
		{
			name: 'about',
			path:'/about',
			component: () => import('../components/About')
		},
		{
			name: 'home',
			path:'/home',
			component: () => import(/* webpackChunkName: "group-user" */ '../components/Home'),
			children:[
				{
					path:'news',
					component: () => import(/* webpackChunkName: "group-user" */ '../components/News'),
				},
				{
					name: 'message',
					path:'message',
					component: () => import(/* webpackChunkName: "group-user" */ '../components/Message'),
				},
				{
					name:'xiangqing',
					path:'detail/:id/:title',
					component: () => import(/* webpackChunkName: "group-user" */ '../components/Detail'),
				}
			]
		}
	]
})
// main.js
import Vue from 'vue'
import App from './App.vue'
//引入VueRouter
import VueRouter from 'vue-router'
//引入路由器
import router from './router'
//应用插件
Vue.use(VueRouter)

//创建vm
new Vue({
	el:'#app',
	render: h => h(App),
	router:router
})
路由懒加载
前: () => import('../components/About')
后: () => import(/* webpackChunkName: "group-user" */ '../components/Message'),
// 两者的打包方式不同,前者单独一个js文件,后者会将 "group-user" 系列打包到 group-user.xxx,js中	
query参数
<template>
	
	<router-link :to="`/home/message/detail?id=${m.id}&title=${m.title}`">{{m.title}}router-link>

	
	<router-link :to="{
		path:'/home/message/detail',
		query:{
			id:m.id,
			title:m.title
		}
	}">{{m.title}}router-link>

		<router-view>router-view>
	div>
template>

// 目标路由组件
<template>
	<ul>
		<li>消息编号:{{$route.query.id}}li>
		<li>消息标题:{{$route.query.title}}li>
	ul>
template>
命名路由
<template>
	<div>
		
		<router-link :to="{
			name:'message',
			query:{
				id:m.id,
				title:m.title
			}
		}"> {{m.title}} router-link>
		<router-view>router-view>
	div>
template>
params参数
<template>
	<div>
		
		

		
		<router-link :to="{
			name:'xiangqing',
			params:{
				id:m.id,
				title:m.title
			}
		}"> {{m.title}} router-link>
		<hr>
		<router-view>router-view>
	div>
template>
路由的props配置
// main.js 专门用于创建整个应用的路由器
import VueRouter from 'vue-router'

//创建并暴露一个路由器
export default new VueRouter({
	routes:[
		{
			path:'/home',
			component: () => import('../pages/Home'),
			children:[
				{
					path:'message',
					component:Message,
					children:[
						{
							name:'xiangqing',
							path:'detail',
							component:Detail,

							//props的第一种写法,值为对象,该对象中的所有key-value都会以props的形式传给Detail组件。
							// props:{a:1,b:'hello'}

							//props的第二种写法,值为布尔值,若布尔值为真,就会把该路由组件收到的所有params参数,以props的形式传给Detail组件。
							// props:true

							//props的第三种写法,值为函数
							props($route){
								return {
									id:$route.query.id,
									title:$route.query.title,
									a:1,
									b:'hello'
								}
							}

						}
					]
				}
			]
		}
	]
})
<template>
	<ul>
		<li>消息编号:{{id}}li>
		<li>消息标题:{{title}}li>
	ul>
template>

<script>
	export default {
		name:'Detail',
		props:['id','title'],
		computed: {
			// id(){
			// 	return this.$route.query.id
			// },
			// title(){
			// 	return this.$route.query.title
			// },
		},
	}
script>
replace
<router-link replace class="list-group-item" active-class="active" to="/home/news">Newsrouter-link>
<router-link :replace="true" class="list-group-item" active-class="active" to="/home/news">Newsrouter-link>
编程式路由导航
methods: {
	back(){
		this.$router.back()
		// console.log(this.$router)
	},
	forward(){
		this.$router.forward()
	},
	test(){
		this.$router.go(3)
	},
	pushShow(m){
		this.$router.push({
			name:'xiangqing',
			query:{
				id:m.id,
				title:m.title
			}
		})
	},
	replaceShow(m){
		this.$router.replace({
			name:'xiangqing',
			query:{
				id:m.id,
				title:m.title
			}
		})
	}
}
缓存路由组件
<template>
	<div>
		<h2>Home组件内容h2>
		<div>
			<router-link class="list-group-item" active-class="active" to="/home/news">Newsrouter-link>
			<router-link class="list-group-item" active-class="active" to="/home/message">Messagerouter-link>
			
			
				
			
			<keep-alive include="News">
				<router-view>router-view>
			keep-alive>
		div>
	div>
template>
两个新的生命周期钩子

<script>
	export default {
		name:'News',
		activated() {
			console.log('News组件被激活了')
			this.timer = setInterval(() => {
				console.log('@')
				this.opacity -= 0.01
				if(this.opacity <= 0) this.opacity = 1
			},16)
		},
		deactivated() {
			console.log('News组件失活了')
			clearInterval(this.timer)
		},
	}
script>
全局路由守卫 + 独享路由守卫
// main.js 专门用于创建整个应用的路由器
import VueRouter from 'vue-router'

//创建并暴露一个路由器
const router =  new VueRouter({
	routes:[
		{
			name:'guanyu',
			path:'/about',
			component: () => import('../pages/About'),
			meta:{title:'关于'},
			beforeEnter: (to, from, next) => {
				console.log('独享路由守卫',to,from)
				if(to.meta.isAuth){ //判断是否需要鉴权
					if(localStorage.getItem('school')==='atguigu'){
						next()
					}else{
						alert('学校名不对,无权限查看!')
					}
				}else{
					next()
				}
			}
		}
	]
})

//全局前置路由守卫————初始化的时候被调用、每次路由切换之前被调用
router.beforeEach((to,from,next)=>{
	console.log('前置路由守卫',to,from)
	if(to.meta.isAuth){ //判断是否需要鉴权
		if(localStorage.getItem('school')==='atguigu'){
			next()
		}else{
			alert('学校名不对,无权限查看!')
		}
	}else{
		next()
	}
})

//全局后置路由守卫————初始化的时候被调用、每次路由切换之后被调用
router.afterEach((to,from)=>{
	console.log('后置路由守卫',to,from)
	document.title = to.meta.title || '硅谷系统'
})

export default router;
组件内路由守卫
<template>
	<h2>我是About的内容h2>
template>

<script>
	export default {
		name:'About',
		//通过路由规则,进入该组件时被调用
		beforeRouteEnter (to, from, next) {
			console.log('About--beforeRouteEnter',to,from)
			if(to.meta.isAuth){ //判断是否需要鉴权
				if(localStorage.getItem('school')==='atguigu'){
					next()
				}else{
					alert('学校名不对,无权限查看!')
				}
			}else{
				next()
			}
		},

		//通过路由规则,离开该组件时被调用
		beforeRouteLeave (to, from, next) {
			console.log('About--beforeRouteLeave',to,from)
			next()
		}
	}
script>

你可能感兴趣的:(前端,vue.js,前端)