Vue2.x-基础梳理(一)

76 阅读9分钟

本系列文章是对vue2.x的知识进行系统梳理,也算是一个回顾。

本系列只针对基础知识,难度较浅,如有错误,欢迎大佬指正,不胜感激!!!

第一个vue例子
  • 想让Vue工作,首先要创建一个Vue实例,并且传入一个配置对象;
  • root容器里的代码叫做Vue模版,包含一些特殊的Vue语法;
  • Vue实例和容器是一一对应的;
  • {{xx}}中的xxx要写js表达式,且xxx可以自动读取到data中的所有属性;
  • 一旦data中的数据发生改变,那么页面中用到该数据的地方也会自动更新;
<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>第一个vue例子</title>
		<!-- 引入Vue -->
		<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
	</head>
	<body>
		<!-- 准备好一个容器 -->
		<div id="root">
			<h1>{{msg1}}</h1>
      <h1>{{msg2}}</h1>
		</div>

		<script type="text/javascript" >
			//创建Vue实例
			new Vue({
        // el用于指定当前Vue实例为哪个容器服务,值通常为css选择器字符串。
				el:'#root', 
        // data中用于存储数据,数据供el所指定的容器去使用,值暂时先写成一个对象。
				data (){ 
          return {
            msg1: 'Hello Vue!!!',
          	msg2: 'This is my first Vue Demo'
          }
				}
			})
		</script>
	</body>
</html>
模版语法
  • 插值语法:
    • 功能:用于解析标签体内容。
    • 写法:{{xxx}},xxx是js表达式,可以直接读取到data中的所有属性。
  • 指令语法:
    • 功能:用于解析标签(包括:标签属性、标签体内容、绑定事件.....)。
    • 举例:v-bind:href="xxx" 或 简写为 :href="xxx",xxx同样要写js表达式,同样可以直接读取到data中的所有属性。
    • 备注:Vue中有很多的指令,且形式都是:v-??
<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>模板语法</title>
		<!-- 引入Vue -->
		<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
	</head>
	<body>
		<!-- 准备好一个容器-->
		<div id="root">
			<h1>插值语法</h1>
			<h3>姓名:{{name}}</h3>
      <h3>职业:{{job}}</h3>
			<hr/>
			<h1>指令语法</h1>
			<a v-bind:href="address" x="hello">点我去{{target}}冒险</a>
			<a :href="address" x="hello">点我去{{address}}冒险</a>
		</div>
	</body>

	<script type="text/javascript">
		new Vue({
			el:'#root',
			data:{
				name:'伍六七',
        job: '理发师',
        target: '玄武国',
        address: 'https://movie.douban.com/subject/35161255/'
			}
		})
	</script>
</html>
数据绑定

Vue中有2种数据绑定的方式:

  • 单向绑定(v-bind):数据只能从data流向页面。
  • 双向绑定(v-model):数据能从data流向页面,也可以从页面流向data。
    • 双向绑定一般都应用在表单类元素上(如:input、select等)。
    • v-model:value 可以简写为 v-model,因为v-model默认收集的就是value值。
<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>数据绑定</title>
		<!-- 引入Vue -->
		<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
	</head>
	<body>
		<!-- 准备好一个容器-->
		<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">
		new Vue({
			el:'#root',
			data:{
				name:'伍六七'
			}
		})
	</script>
</html>
data与el

data与el的2种写法

  • el的2种写法
    • new Vue时候配置el属性。
    • 先创建Vue实例,随后再通过vm.$mount('#root')指定el的值
  • data的2种写法
    • 对象式(目前这种写法可以用对象式,后面用到组件就必须用函数式)
    • 函数式
  • 注意:由Vue管理的函数,一定不要写箭头函数,一旦写了箭头函数,this就不再是Vue实例了。
<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>data与el的两种写法</title>
		<!-- 引入Vue -->
		<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
	</head>
	<body>
		<!-- 准备好一个容器-->
		<div id="root">
			<h1>姓名:{{name}}</h1>
		</div>
	</body>

	<script type="text/javascript">
		// el的两种写法
    // 第一种写法
		/* const v = new Vue({
				el:'#root', 
				data:{
					name:'伍六七'
				}
			})
		*/
    // 第二种写法 
    /* const v = new Vue({
        data:{
          name:'伍六七'
        }
			})
			v.$mount('#root') 
		*/

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

			// 第二种写法:函数式
			data(){
				console.log('this:',this) //此处的this是Vue实例对象
				return{
					name:'伍六七'
				}
			}
		})
	</script>
</html>
数据代理
  • 实现:通过vm对象来代理data对象中属性的读写操作。
  • 原理:通过Object.defineProperty()把data对象中所有属性添加到vm上。同时为每一个添加到vm上的属性,都指定一个getter/setter方法,并在getter/setter内部去操作data中对应的属性(比如页面渲染等伴随操作)。
数据监听

Vue监视数据的原理:

  • vue会监视data中所有层次的数据。
  • 如何监测对象中的数据?通过setter实现监视,且要在new Vue时就传入要监测的数据。
    • 对象中后追加的属性,Vue默认不做响应式处理
    • 如需给后添加的属性做响应式,请使用如下API:
      • Vue.set(target,propertyName/index,value)
      • vm.$set(target,propertyName/index,value)
  • 如何监测数组中的数据?通过包裹数组更新元素的方法实现,本质就是做了两件事:
    • (1)调用原生对应的方法对数组进行更新。
    • (2)重新解析模板,进而更新页面。
    • 注意,在Vue修改数组中的某个元素一定要用如下方法:
      • 使用这些API:push()、pop()、shift()、unshift()、splice()、sort()、reverse()
      • Vue.set()vm.$set()
  • 特别注意:Vue.set() vm.$set() 不能给 vm 或 vm的根数据对象 添加属性!!!
事件处理
基本使用
  • 使用v-on:xxx@xxx 绑定事件,其中xxx是事件名;
  • 事件的回调需要配置在methods对象中,最终会在vm上;
  • methods中配置的函数,不要用箭头函数!否则this就不是vm了;
  • methods中配置的函数,都是被Vue所管理的函数,this的指向是 vm组件实例对象
  • @click="demo"@click="demo($event)" 效果一致,但后者可以传参;
事件描述符
  • prevent:阻止默认事件(常用);
  • stop:阻止事件冒泡(常用);
  • once:事件只触发一次(常用);
  • capture:使用事件的捕获模式;
    • 冒泡是从里往外冒,捕获是从外往里捕。
    • 当捕获存在时,先从外到里的捕获,剩下的从里到外的冒泡输出。
  • self:只有event.target是当前操作的元素时才触发事件;
  • passive:事件的默认行为立即执行,无需等待事件回调执行完毕;
计算属性
  • 定义:要用的属性不存在,要通过已有属性计算得来。
  • 原理:底层借助了Objcet.defineproperty方法提供的getter和setter。
  • get函数什么时候执行?
    • 初次读取时会执行一次。
    • 当依赖的数据发生改变时会被再次调用。
  • 优势:与methods实现相比,内部有缓存机制(复用),效率更高,调试方便。
  • 备注:
    • 计算属性最终会出现在vm上,直接读取使用即可。
    • 如果计算属性要被修改,那必须写set函数去响应修改,且set中要引起计算时依赖的数据发生改变。
<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>计算属性</title>
		<!-- 引入Vue -->
		<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/vue@2/dist/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">
		const vm = new Vue({
			el:'#root',
			data(){
        return {
          firstName:'伍',
          lastName:'六七',
        }
      },
			computed:{
        // 完整写法
				fullName:{
					// get有什么作用?当有人读取fullName时,get就会被调用,且返回值就作为fullName的值
					// get什么时候调用?1.初次读取fullName时。2.所依赖的数据发生变化时。
					get(){
						console.log('get被调用了')
						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]
					}
				}
        
        //简写
        /*
				fullName(){
					console.log('get被调用了')
					return this.firstName + '-' + this.lastName
				}
				*/
			}
		})
	</script>
</html>
监视属性
基本使用
  • 当被监视的属性变化时, 回调函数自动调用, 进行相关操作
  • 监视的属性必须存在,才能进行监视
  • 监视的两种写法:
    • new Vue时传入watch配置
    • 通过vm.$watch监视
<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>监视属性</title>
		<!-- 引入Vue -->
		<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
	</head>
	<body>
		<!-- 准备好一个容器-->
		<div id="root">
			<h2>小鸡岛的天气真:{{info}}</h2>
			<button @click="changeInfo">变天</button>
		</div>
	</body>

	<script type="text/javascript">
		
		const vm = new Vue({
			el:'#root',
			data:{
				isHot: true,
			},
			computed:{
				info(){
					return this.isHot ? '热啊' : '凉快'
				}
			},
			methods: {
				changeInfo(){
					this.isHot = !this.isHot
				}
			},
      // 第一种写法
			/*
			watch:{
				isHot:{
					// 初始化时让handler调用一下
					immediate: true, 
					// 当isHot发生改变时调用。
					handler(newValue,oldValue){
						console.log('isHot被修改了',newValue,oldValue)
					}
				}
			} 
			*/
      
      // 第一种写法:简写
      /* 
      isHot(newValue,oldValue){
				console.log('isHot被修改了',newValue,oldValue,this)
			} 
			*/
		})

    // 第二种写法
		vm.$watch('isHot',{
      // 初始化时让handler调用一下
			immediate:true, 
			// 当isHot发生改变时调用。
			handler(newValue,oldValue){
				console.log('isHot被修改了',newValue,oldValue)
			}
		})
    
    // 第二种写法:简写
		/* 
		vm.$watch('isHot',(newValue,oldValue)=>{
			console.log('isHot被修改了',newValue,oldValue,this)
		}) 
		*/
	</script>
</html>
深度监视
  • Vue中的watch默认不监测对象内部值的改变。
  • 配置deep:true可以监测对象内部值改变。
样式绑定

class样式,写法:class="xxx" xxx可以是字符串、对象、数组。

  • 字符串写法适用于:类名不确定,要动态获取。
  • 对象写法适用于:要绑定多个样式,个数不确定,名字也不确定。
  • 数组写法适用于:要绑定多个样式,个数确定,名字也确定,但不确定用不用。 style样式,写法:style="{fontSize: xxx}",其中xxx是动态值。:style="[a,b]"其中a、b是样式对象。
条件渲染
v-if
  • 写法:v-if="表达式" v-else-if="表达式"v-else="表达式"
  • 适用于切换频率较低的场景。
  • 特点:不展示的DOM元素直接被移除
v-show
  • 写法:v-show="表达式"
  • 适用于切换频率较高的场景。
  • 特点:不展示的DOM元素未被移除,仅仅是使用display样式隐藏掉 使用v-if时,元素可能无法获取到,而使用v-show一定可以获取到。
列表渲染
  • 用于展示列表数据
  • 语法:v-for="(item, index) in list" :key="id"
key的原理
  • key的作用:key是虚拟DOM对象的标识,当数据发生变化时,Vue会根据【新数据】生成【新的虚拟DOM】, 随后Vue进行【新虚拟DOM】与【旧虚拟DOM】的差异比较,比较规则如下:
    • 旧虚拟DOM中找到了与新虚拟DOM相同的key:
      • ①.若虚拟DOM中内容没变, 直接使用之前的真实DOM!
      • ②.若虚拟DOM中内容变了, 则生成新的真实DOM,随后替换掉页面中之前的真实DOM。
    • 旧虚拟DOM中未找到与新虚拟DOM相同的key
      • 创建新的真实DOM,随后渲染到到页面。
  • 用index作为key可能会引发的问题:
    • 若对数据进行:逆序添加、逆序删除等破坏顺序操作:会产生没有必要的真实DOM更新 ==> 界面效果没问题, 但效率低。
    • 如果结构中还包含输入类的DOM:会产生错误DOM更新 ==> 界面有问题。
  • 开发中如何选择key:
    • 1.最好使用每条数据的唯一标识作为key, 比如id、手机号等唯一值。
    • 2.如果不存在对数据的逆序添加、逆序删除等破坏顺序操作,仅用于渲染列表用于展示,使用index作为key是没有问题的。
收集表单数据
  • 若:<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属性:
      • v-model的初始值是非数组,那么收集的就是checked(勾选 or 未勾选,是布尔值)
      • v-model的初始值是数组,那么收集的的就是value组成的数组
  • v-model的三个修饰符:
    • lazy:失去焦点再收集数据
    • number:输入字符串转为有效的数字
    • trim:输入首尾空格过滤
<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>收集表单数据</title>
		<script type="text/javascript" src="../js/vue.js"></script>
	</head>
	<body>
		<!-- 准备好一个容器-->
		<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>
过滤器

定义:对要显示的数据进行特定格式化后再显示(适用于一些简单逻辑的处理)。 语法:

  • 注册过滤器:Vue.filter(name,callback)new Vue{filters:{}}
  • 使用过滤器:{{ xxx | 过滤器名}}v-bind:属性 = "xxx | 过滤器名" 注意:
  • 过滤器也可以接收额外参数、多个过滤器也可以串联
  • 并没有改变原本的数据, 是产生新的对应的数据
内置指令
常用指令
  • v-bind : 单向绑定解析表达式, 可简写为 :xxx
  • v-model : 双向数据绑定
  • v-for : 遍历数组/对象/字符串
  • v-on : 绑定事件监听, 可简写为@
  • v-if v-else: 条件渲染
  • v-show : 条件渲染
v-text指令:
  • 作用是向其所在的节点中渲染文本内容,相当于原生js中的innerText。
  • 与插值语法的区别:v-text会替换掉节点中的内容,{{xx}}则不会。
v-html指令:
  • 作用是向指定节点中渲染包含html结构的内容,相当于原生js中的innerHTML。
  • 与插值语法的区别:
    • (1).v-html会替换掉节点中所有的内容,{{xx}}则不会。
    • (2).v-html可以识别html结构。
  • 注意:v-html有安全性问题
    • 在网站上动态渲染任意HTML是非常危险的,容易导致XSS攻击。
    • 一定要在可信的内容上使用v-html,永不要用在用户提交的内容上
v-cloak指令(没有值):
  • 本质是一个特殊属性,Vue实例创建完毕并接管容器后,会删掉v-cloak属性。
  • 使用css配合v-cloak可以解决网速慢时页面展示出{{xxx}}的问题。
v-once指令:
  • v-once所在节点在初次动态渲染后,就视为静态内容了。
  • 以后数据的改变不会引起v-once所在结构的更新,可以用于优化性能。
v-pre指令:
  • 跳过其所在节点的编译过程。
  • 可利用它跳过:没有使用指令语法、没有使用插值语法的节点,会加快编译。
自定义指令
  • 定义语法:
    • 局部指令:new Vue({directives:{指令名:配置对象}})new Vue({directives{指令名:回调函数}})
    • 全局指令:Vue.directive(指令名,配置对象) Vue.directive(指令名,回调函数)
  • 配置对象中常用的3个回调:
    • (1).bind:指令与元素成功绑定时调用。
    • (2).inserted:指令所在元素被插入页面时调用。
    • (3).update:指令所在模板结构被重新解析时调用。
  • 备注:
    • 指令定义时不加v-,但使用时要加v-;
    • 指令名如果是多个单词,要使用kebab-case命名方式,不要用camelCase命名。