Vue学习笔记 第 1 章:Vue 核心(下)

学习资料来自尚硅谷VUE教学视频

csdn:课程代码、vue3笔记、课件

gitee:课件、代码、资料

其他:vscode插件推荐、第三方库网站、npmjs库

工具库推荐:
moment.js 时间处理工具,很强很大。还有个轻量的叫dayjs
生成全球唯一id工具:uuid,但是很大,有个精简版:nanoid

章节导航:

第 1 章:Vue 核心(上)

第 1 章:Vue 核心(下)

第 2 章:Vue 组件化编程

第 3 章:使用 Vue 脚手架

第 4 章:Vue 中的 ajax

第 5 章:vuex

第 6 章:vue-router(Vue路由)

第 7 章:Vue UI 组件库

第 1 章:Vue 核心 下

  • 1.7. 计算属性与监视
    • 1.7.1. 计算属性
      • 1.7.1.1 姓名案例_插值语法实现
      • 1.7.1.2. 姓名案例_methods实现
      • 1.7.1.3. 姓名案例_计算属性实现
      • 1.7.1.4. 姓名案例_计算属性简写
    • 1.7.2. 监视(侦听)
      • 1.7.2.1 天气案例_监视属性
      • 1.7.2.2 天气案例_深度监视
      • 1.7.2.3 天气案例_监视属性_简写
      • 1.7.2.4 姓名案例_watch实现
  • 1.8. 绑定样式
  • 1.9. 条件渲染
  • 1.10. 列表渲染
    • 1.10.1. 基本列表
    • 1.10.2. key的原理
    • 1.10.3. 列表过滤
    • 1.10.4. 列表排序
  • Vue监视数据的原理
  • 1.11. 收集表单数据
  • 1.12. 过滤器
  • 1.13. 内置指令与自定义指令
    • 1.13.1. 常用内置指令
    • 1.13.2. 自定义指令
  • 1.14. Vue 实例生命周期

1.7. 计算属性与监视

在表达式中,调用方法时,不加小括号表示方法体本身,加小括号表示运行方法拿方法的返回值。
只要data里数据发生改变,Vue就会重新解析模板,插值语法里的方法都会重新执行一遍。

1.7.1. 计算属性

1.7.1.1 姓名案例_插值语法实现

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

1.7.1.2. 姓名案例_methods实现

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

1.7.1.3. 姓名案例_计算属性实现

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

1.7.1.4. 姓名案例_计算属性简写

注意,插值语法中不能写{fullName()} ,computed:{}中的fullName()只是简写,实际是读取fullName这个计算属性,属性值调用了get()方法,所以插值语法中不能加()

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

绑定事件的时候:@xxx=“yyy” yyy可以写一些简单的语句(例如:),但是不能写vm身上没有东西。vue会先从实例对象上找方法和属性,如果没有再从原型上找,都没有就报错。所以不能写alert(),因为这事Window上的东西

1.7.2. 监视(侦听)

1.7.2.1 天气案例_监视属性

			监视属性watch:
				1.当被监视的属性变化时, 回调函数自动调用, 进行相关操作
				2.监视的属性必须存在,才能进行监视!!
				3.监视的两种写法:
						(1).new Vue时传入watch配置
						(2).通过vm.$watch监视
					(3)可以通过handler(newValue,oldValue),传2值来获取新值和旧值
<!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调用一下
					//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>

1.7.2.2 天气案例_深度监视

			深度监视:
					(1).Vue中的watch默认不监测对象内部值的改变(一层)。
					(2).配置deep:true可以监测对象内部值改变(多层)。
					(3).immediate:true, //初始化时让handler调用一下
			备注:
					(1).Vue自身可以监测对象内部值的改变,但Vue提供的watch默认不可以!
					(2).使用watch时根据数据的具体结构,决定是否采用深度监视。
					(3).监视多级结构中某个属性的变化  'numbers.a'要加''引号
<!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>
			<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>

1.7.2.3 天气案例_监视属性_简写

<!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', function(newValue, oldValue) {
        console.log('isHot被修改了', newValue, oldValue, this)
    })
</script>

</html>

1.7.2.4 姓名案例_watch实现

			computed和watch之间的区别:
					1.computed能完成的功能,watch都可以完成。
					2.watch能完成的功能,computed不一定能完成,例如:watch可以进行异步操作。
			两个重要的小原则:
						1.所被Vue管理的函数,最好写成普通函数,这样this的指向才是vm 或 组件实例对象。
						2.所有不被Vue所管理的函数(定时器的回调函数、ajax的回调函数等、Promise的回调函数),最好写成箭头函数,
							这样this的指向才是vm 或 组件实例对象。
<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>姓名案例_watch实现</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:'三',
				fullName:'张-三'
			},
			watch:{
				firstName(val){
					setTimeout(()=>{
						console.log(this)
						this.fullName = val + '-' + this.lastName
					},1000);
				},
				lastName(val){
					this.fullName = this.firstName + '-' + val
				}
			}
		})
	</script>
</html>

1.8. 绑定样式

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

1.9. 条件渲染

			条件渲染:
						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一定可以获取到。

补充知识:template 包裹的内容最终渲染在页面上会去掉template,不会影响.class选择器,可配合v-if使用