前端 框架 Vue

1. 什么是Vue

什么是: 第三方开发的渐进式的基于MVVM设计模式的纯前端js框架
		第三方: 下载
		渐进式: 可逐步在项目中引入Vue的各项功能
				且可与其他技术混用——今后,极力不推荐
		基于MVVM设计模式: ?
		纯前端: 没有后端技术,Vue照样执行!
		js框架: 已经具有核心功能的半成品项目代码。
				开发人员只需要根据具体业务的需求,添加定制自己个性化的那一部分内容即可!
			原生DOM vs 函数库 vs 框架
			原生DOM: 优点: 兼容性各个平台
					  缺点: 繁琐
			函数库: 优点: 简化原生DOM中的每一步操作的代码长度。
					缺点: 没有减少步骤!
			框架: 优点: 彻底简化了开发的步骤!
				  缺点: 不兼容旧浏览器
						需要开发人员彻底转变思路!
	何时: 今后所有以数据为主的项目,都可用Vue框架

2. 如何使用Vue

下载: cn.vuejs.org

2: 
		1. 下载独立的vue.js文件,用<script>引入网页中
			初学者使用,学习单项Vue中的技能
			版本: 2.5
				2个版本: 
					1. 开发版:未压缩,有完备的错误提示
					2. 生产版:压缩,去掉了完备的错误提示
		2. 安装脚手架代码: 3.x
			今后熟练之后,开发项目,都用脚手架

使用vue.js:

准备: 引入vue.js
			<script src="js/vue.js">
		1. 编写界面: 
			1. 所有界面内容必须包裹在一个唯一的父元素内
			2. 找到页面中所有可能变化的位置用{{变量名}}方式临时占位
		2. 编写自定义js程序:
			1. 定义data对象,其中包含所有页面所需的变量及其初始值。页面需要几个变量,data中就要定义几个属性变量
			2. 创建new Vue对象,将界面和保存所有变量的data对象绑定起来: 
				var vm=new Vue({
					el:"#app", //el:element的缩写
							 //el后跟的是要监控的部分的父元素的选择器
							//选择找到那个父元素,哪个父元素下的内容就被new Vue()实时监控
					data, //让new Vue同时监控data中变量的变化
				})
				结果: 
					1. new Vue会自动将data中的初始值替换界面中所有{{变量}}的位置
					2. 只要data中的变量值发生变化,new Vue会自动将新的变量值,更新到页面中{{变量}}位置。
			3. 添加交互行为: 
				DOM 4步: 
				1. 查找触发事件的元素: 不用程序找,用肉眼找到就行
				2. 绑定事件处理函数:
					1. 不用js绑定,而是手动在界面中的要点击的元素上添加: <button @click="处理函数名">2. Vue规定所有事件处理函数需要集中定义在new Vue()中的methods:{}
					new Vue({
						... ...,
						methods:{
							处理函数名(){
								想操作data中的变量,必须加this.变量
							}
						}
					})
				3. 查找要修改的元素:彻底不用自己找
				4. 修改元素: vue中都是通过遥控方式修改元素的: 修改data中的变量值,new Vue可自动更新界面中的元素内容。——绑定

3. MVVM

问题: 传统Web开发重复代码量太大!效率太低!

为什么:

		传统Web开发分为三部分组成: 
		1. HTML:专门编写网页内容的静态语言
		2. CSS:专门编写网页样式的静态语言
		3. JS:专门为网页添加交互行为的程序语言
		问题: HTML和CSS都是静态语言,缺少编程语言必须的要素,比如: 变量,分支,循环...。太弱了!
			导致js必须承担所有查找,修改操作!

解决: MVVM

	现代Web前端开发重新划分了三部分: 
		1. 视图/界面(View): 
			1. HTML+CSS
			2. 增强了HTML和CSS的功能,比如提供了变量,分支,循环等这些程序必备功能
			因为,HTML和CSS功能增强了,所以大大减轻了JS的负担!
		2. 模型数据(Model): 其实就是用一个data对象,统一保存这个界面所需的所有变量。
			因为数据集中保存,所以及其便于维护!
		3. 控制器(ViewModel): 自动实现模型数据data中的内容和界面(View)中的内容,实时同步!
			控制器已经封装了传统的增删改查的功能,所以几乎避免了一切重复操作!
			比如: 今后vue中几乎没有任何查找操作了!
				都是以遥控方式代替手工查找元素
				只要修改data中的变量,界面中的内容自动更新。

Vue是如何实现MVVM的: VUE绑定的原理

		new Vue()中其实包含两大子系统: 
		1. 响应系统:
			什么是: 实时监控data中变量的变化,并能在变量发生变化时,自动发出通知。
			原理: 将data放入new Vue()中后,new Vue()自动为每个变量添加了访问器属性。
			这些访问器属性,直接隶属于new Vue()对象,保护/监控data中的变量。
			而且所有访问器属性中的set方法中,都内置了通知机制。只要试图修改data中的变量,
			只能经过访问器属性,自然就会自动触发通知:xx变量值变了!
		2. 虚拟DOM树: 
			什么是: Vue内存中仅保存可能变化的DOM元素和可能变化的属性的简化版DOM树
			为什么: 真实DOM树,无关的数据太多!遍历和查找速度太慢!
			虚拟DOM树的优点: 
				1. 小,仅包含可能变化的元素和可能变化的属性
				2. 快,遍历快
				3. 自动,虚拟DOM树已经封装了增删改查的操作。
				4. 效率高,仅修改个别可能受影响的元素和可能受影响的属性。多数无关的元素和属性,不收影响。
			原理: 
				形成: 
					首次new Vue()时,传入了el:"#app"参数
					然后new Vue()找到#app这个父元素,扫描其内部的子元素
					变扫描,变创建虚拟DOM树,仅保存可能变化的元素和可能变化的属性
					首次将data中的变量,替换DOM树中的{{}}语法
				当变量变化时: 
					首先触发这个变量的访问器set方法,发出通知,通知虚拟DOM树,哪个变量发生变化
					然后new Vue()遍历虚拟DOM树,找到可能发生变化的元素和属性
					最后,利用已经封装好的DOM的增删改查方法,找到发生变化的元素和属性,修改属性

4. 绑定语法

	什么是: 在页面中使用{{变量}}标记哪里可能发生变化
	学名: 插值语法: Interpolation
	何时: 只要页面中一个位置的内容,可能根据变量的变化而自动变化时,就都用{{变量}}来占位
	结果: 
		1. 所有标有{{变量}}的元素,都被加入虚拟DOM树中
		2. 当变量变化时,根据{{}}中的变量名,判断当前元素内容是否受影响。如果受影响,则自动更新该元素的内容。
	如何: {{}}除了可以写死一个变量外,还可编写任意正确的有返回值的js表达式——用法同模板字符串中的${...}
		比如: {{算术计算}}  {{比较运算}}  {{三目运算}}  {{调用函数}}  {{创建对象/访问对象的属性}}  {{访问数组的元素}}
		不能放程序结构: if else   while    do while  for

5. 指令

什么是: 为HTML添加增强功能的特殊属性
为什么: 传统的HTML缺少程序必须的要素,比如: 变量,函数,分支,循环等,导致js重复操作量巨大。
何时: 今后在vue中,想在HTML里也实现比如分支,循环等功能时
包括: 共13个

(1)v-bind:

		什么是: 专门绑定元素的属性值
			为什么: {{}}只能绑定元素内容,不能绑定元素属性值
			何时: 只要元素的属性值需要根据变量自动变化时,都用v-bind。
			如何: <元素 v-bind:属性="js表达式"
				其实可简写为 ":属性"
			强调: 1. 加了:的属性,值中不用再加{{}}
				2. 加了:的属性,""就是{{}}的作用,""中不但可以写值/变量,而且也可以写js表达式

(2)根据条件控制元素的显示和隐藏: v-show

			1. 控制一个元素的显示隐藏: 
				<元素 v-show="条件表达式"
				结果: 
					1. 如果条件表达式执行结果为true,则当前元素显示——会去掉display:none
					2. 如果条件表达式执行结果为false,则当前元素隐藏——会自动将v-show替换为display:none
			2. 控制两个元素二选一显示隐藏
				问题: v-show如果控制多个元素多选一显示隐藏,必须把判断条件在每个元素上都重复写一遍,代码繁琐!
				解决: v-if   v-else
				如何: 
					<元素1 v-if="判断条件">
					<元素2 v-else>
				结果: 
					如果判断条件返回true,就显示第一个元素,删除第二个元素
					如果判断条件返回false,就显示第二个元素,删除第一个元素
				强调: 
					1. 两个元素之间不能插入其他元素
					2. v-else不需要属性值
			3. 控制多个元素多选一显示隐藏
				用v-else-if
				<元素1 v-if="条件1">
				<元素2 v-else-if="条件2">
				...
				<元素n v-else>
				原理: 
					从上向下一次判断每个v-if或v-else-if后的条件。
					只要条件不满足就删除该元素
					只有满足条件的元素才会保留下来用于显示。
					如果判断走到了下一个元素上,隐含着上一个元素的条件肯定不满足
				强调: 
					1. 多个元素之间不能插入其他元素
					2. v-else不需要属性值
			总结: v-show vs v-if
				v-show采用display:none 隐藏元素 - 效率高,因为未改变DOM树结构
				v-if 采用直接删除元素隐藏元素 - 效率略低

回顾: 三目:

	1. 一个条件,2件事,二选一执行: 
		条件?操作1:操作2
    2. 多个条件,多选一执行:
		条件1?操作1: 
        条件2?操作2: 
        条件3?操作3: 
			  操作4
	其实: ?代替的是if    :代替的是else
		if(条件1)
			操作1 
        else if(条件2)
			操作2 
        else if(条件3)
			操作3
		else
			操作4

回顾: 总结:

1. 只要绑定元素内容: {{}}
2. 只要绑定元素属性值:  :
3. 只要控制一个元素的显示隐藏: v-show
4. 只要控制两个元素,二选一显示隐藏: v-if   v-else
5. 只要控制多个元素,多选一显示隐藏: v-if  v-else-if  v-else


(3)反复生成多个相同结构的元素v-for

		1. 前提: 一定有一个数组或一个数值,让你可参照着反复生成元素内容
		2. 如何: 
		 <要反复生成的元素 v-for="(item,i) of 数组或数值"><子元素>中可以将item和i用于绑定值
			...
		</要反复生成的元素>
		3. 原理: 
			数组中有几个元素,vue在扫描时,就会重复创建几个相同结果的元素。
			每遍历数组中一个元素,就可以获得两个值: 第一个变量item获得数组中当前元素的值,第二个变量i获得当前正在遍历的数组元素的下标位置。
			每创建一个元素,就会将重复结构中的绑定语法,替换为本次遍历获得的item或index值
 

前端 框架 Vue_第1张图片

		4. 强调: 
			1. 想重复生成哪个元素,v-for就放在哪个元素的开始标签中!
			2. v-for="  of   "原理和js中的for of完全一样,只不过js中的for of只能获得元素的内容,无法获得元素的下标。而vue中的v-for of即可获得元素内容,又可获得下标。
		5.: vue中要修改数组中某个元素,让页面自动更新,决不能用下标修改。必须用API修改。因为vue不监控下标,只监控API调用。
			比如: this.tasks[1]="吃饭" 界面上不会变,因为vue不知道1位置的值被修改了。
				换成用替换API: this.tasks.splice(1,1,"吃饭"),界面就会自动跟着变化,因为vue始终监控着数组API的调用(其实是因为Vue用一批自己定义的数组API,把原数组API给替换了。而Vue偷梁换柱的数组API中,都带通知机制。所以,调用数组API,vue会发出通知。而下标,vue是换不了的,所以通过下标修改元素值,vue无法发出通知)
		6. :key : 每个v-for的元素中,都强烈绑定一个key属性,值为当前元素的下标位置index。
		<要反复生成的元素 v-for="(item,i) of 数组或数值" :key="i"><子元素>中可以将item和i用于绑定值
			...
		</要反复生成的元素>
			不加:key,每个<li>最终除了内容,在属性上是毫无差别的,当数组中某个位置的元素发生更改时,vue只能用最笨的方法,遍历所有li,把所有li的内容重新更新一遍。

前端 框架 Vue_第2张图片

:key, 每个<li>就变成: <li key="0"><li key="1">...,
就都有了一个唯一的标识。当数组中某个元素发生改变时,
vue就可根据修改元素的下标位置,对应找到相同key值的元素,
只更新这个位置相同的元素,别的元素保持不变。

前端 框架 Vue_第3张图片

		7. 问题: 没有数组,只有数量,也想反复生成多个相同结构的元素
			解决: vue中的v-for of后不但可以写数组,而且可以写数字!——js的for of肯定不行!
			如何: <li v-for="i of 整数" :key="i">
				结果: <li>1</li><li>2</li>...
			何时: 分页按钮

(4)绑定事件:v-on

		<元素 v-on:事件名="处理函数"
		可简写为@事件名="处理函数"
		四种情况: 
			1. 如果处理函数不需要参数,可省略()
			2. 如果处理函数需要参数,也可加(实参值, ...)
			3. 如果处理函数需要获得事件对象
				1. 不需要在绑定时传参
				2. 只在methods中定义函数时添加第一个形参e即可。
				3. e获得的对象和DOM中事件对象e,完全一样。
			4. 如果处理函数即需要获得参数,又需要获得事件对象时:
				问题: 
					如果在绑定时传入实参值,就会顶替事件对象参数的位置。所以,如果想获得事件对象e,又不能添加其它实参值。
				解决: 就要在绑定时,即提供实参值,又提供$event。
					其中$event是vue中独有的关键词,代表DOM中的事件对象。

(5)绑定HTML片段内容:v-html

		问题: {{}}不能用于绑定html片段。如果{{}}绑定的是HTML片段,不会解析其中的内嵌标签和特殊符号,而是尽量保持原样显示
		解决: 今后,凡是绑定HTML片段,都用v-html
		强调: v-html是指令,应该放在开始标签内!

(6)防止用户短暂看到{{}} v-cloak

		问题: 如果vue加载慢,可能导致用户短暂看到{{}}语法
		解决: 
			1. v-cloak指令: 专门用于在new Vue加载完之前,临时隐藏个别元素
				如何: 2: 
					1. 问题: 因为v-cloak自己不带隐藏样式,所以,要先在<style>中用属性选择器为有v-cloak属性的元素,添加隐藏样式。让标有v-cloak的元素先隐藏。等vue在加载完之后,会自动移除所有元素上的v-cloak属性。这些元素就自动恢复显示
					2. 在要隐藏的元素上,添加v-cloak属性,不要给属性值。
				适用于暂时隐藏大片内容结构复杂的元素
				问题: v-cloak是彻底隐藏,连结构和样式也看不见,用户体验不好。
			2. 如果希望保持其它样式和结构,仅内容文本暂时隐藏: 
				<元素 v-text="表达式"></元素>
				原理: 
					如果vue没有加载完,v-text=""属性,反正浏览器也不认识,自然元素中就没有任何显示。
					当Vue加载完,解析到v-text时,才为当前元素填充文本内容。
		总结: 今后,尽量用v-text代替{{}},绑定普通文本内容
			如果字符串需要动态生成,且拼接逻辑比较复杂,首选{{}}+v-cloak隐藏
			如果父元素中子元素内容结构复杂,想全部隐藏这部分元素及其子元素时,首选v-cloak;


(7)只在页面加载时,自动绑定一次,之后,即使变量变化,也不自动更新页面。 v-once

		原理: 只在首次扫描真实DOM树时,替换一次内容,且并没有将这个元素添加到虚拟DOM树。所以,今后变量变化,不会再扫描到这个元素。

(8)保持内容中的{{}}不被编译:v-pre

		何时: 刚巧内容正文中有不希望被替换的{{}}
		v-pre

在这里插入图片描述

6. 双向绑定

	单向绑定: 只能从模型到界面的绑定(M->V)
	双向绑定: 即能从模型到界面的绑定(M->V),又能将界面的修改,自动更新回模型中(V->M)
	何时: 只要绑定表单元素的值时,都用双向绑定。因为只有表单元素才让用户手动修改内容。
	如何: 

(1)文本框和文本域:

<input v-model:value="变量">

(2)单选按钮:

			1. value是提前写死的! 选中不选中,这个value值都是固定不变的,所以v-model不能写在value上
			2. 因为选中不选中时修改的是checked属性,所以v-mode绑定的就是checked属性
			<input type="radio" value="1" v-model:checked="变量"><input type="radio" value="0" v-model:checked="变量" >女
			M->V绑定时: 用变量的值和每个value做比较
				如果变量的值等于当前radio的value值,则当前radio选中!
				如果变量的值不等于当前radio的value值,则当前radio不选中!
			V-M绑定时: 当选中项改变时,会用当前选中的radio的value值,更新到data中变量中。

(3)复选框单用:

			因为复选框在选中或取消选中时,改的是checked属性,所以v-model也要绑定在checked属性上
			因为复选框单用,没有value的,所以选中时,会自动将true,更新到变量中。如果没选中,会将false更新到变量
			M->V绑定时,也是绑定的bool<input type="checkbox" v-model:checked="变量">同意

(4)单选列表:

1. 每一项的value都是写死在每个option上的,所以v-model一定不会写在每个option上
2. 选中项切换时,改的是value属性,所以v-model应该写在select的value上
			<select v-mode:value="变量">
				<option value="写死的value">
				<option value="写死的value">
				<option value="写死的value">
			当M->V绑定时,用变量的值和每个option的值做比较,如果变量的值等于哪个option的值,那么这个option就被选中。
			当选中项改变时,将当前选中的option的value值,更新回变量中

		简写: 其实,之前所有v-model:属性名="变量"中的":属性名"都可省略。v-model可自动根据所在元素的不同,自动决定绑定哪个属性。
			比如: v-model="变量"
				如果出现在文本框中: 
					<input v-model="变量">
					自动绑定的就是value属性
				如果出现在checkbox中: 
					<input type="checkbox" v-model="变量">
					自动绑定的就是checked属性
				... ...

	原理:
		凡是带有v-model:的元素,都自动添加事件处理函数: oninput或onchange。在自动绑定的事件处理函数中,内置了自动修改data中变量的方法。——信任

3. 

	监视函数: 
		什么是: 当一个变量值发生改变时,自动触发的函数
		何时: 如果希望当一个变量值改变时,立刻自动执行一个操作。
		如何: 
			new Vue({
				el:"选择器",
				data:{ 变量 },
				methods:{ 函数 },
				watch:{
					变量名(){ ... }
				}
			})
		强调: 要监视哪个变量的变化,就要将监视函数的名字起的和那个要监视的变量名一样!
		触发: watch中的函数,会在data中同名变量的值发生改变时,自动触发。

7. 绑定样式

(1)绑定style属性:

		何时: 如果程序需要频繁单独调整一个元素的单个css属性时,才绑定style属性。
			比如: 游戏中,控制一个元素的上下左右位置
		如何: 2: 
		1. 将元素的style属性当做一个字符串值来绑定
			<元素 :style="变量">
			data:{
				变量:"left:100px; top:200px;"
			}
			问题: css属性都混在一个字符串中,不便于操作单个css属性
		2. 将style作为一个对象来绑定: 
			<元素 :style="变量">
			data:{
				变量:{ left:"100px",  top:"200px" }
			}
			结果: vue会自动将变量中的对象翻译为style所需的字符串: "left:100px; top:200px;"
			强调: 数值属性必须带单位
			另一种写法: 
			<元素 :style="{ left: popLeft, top: popTop}">
			data:{
				popLeft:"100px",  
				popTop:"200px"
			}
			结果,也是自动将变量的值放入对象中,并翻译为一个字符串整体,赋值给style属性。
			问题: 增多了data中的变量,不便于维护,强烈不推荐。
		说明: 如果元素中包含部分不需要变化的内联样式,:style和style其实可并存。不变的css属性放在style中,变化的css属性放在:style中
			比如: <div style="position:fixed" :style="popStyle">
			结果: 两个style合为一处
				<div style="position:fixed; left:100px; top:200px;"

(2)绑定class:

		何时: 如果批量应用一批样式时,首选绑定class
		如何: 
			1. 将整个class作为一个大的字符串绑定
				问题: 不便于操作其中一个class
			2.class属性看做一个对象结构来绑定: 
				<元素 :class="变量">
				data:{
					变量:{
						class1: true/false
						class2: true/false
						class3: true/false
					}
				}
				结果: 所有值为true的class,最后会拼成一个完整的字符串,赋值给class属性
		说明: 如果元素中包含部分不需要变化的class:classclass其实可并存。不变的class放在普通的class属性中,变化的class放在:class中绑定。
			比如: <a class="btn" :class="aClass">
				data:{
					aClass:{
						"btn-success":false,
						"btn-danger":true
					}
				}
			结果: 两个class合为一处
				<div class="btn btn-danger"

总结:

1. 元素内容变化: {{}}
2. 元素属性值变化: v-bind 或 :
3. 一个元素显示隐藏: v-show
4. 两个元素显示隐藏: v-if  v-else
5. 多个元素显示隐藏: v-if  v-else-if  v-else
6. 根据数组或整数,反复生成多个相同结构的元素: v-for :key
7. 绑定事件: v-on 或 @
8. 只要绑定html片段: v-html
9. 暂时隐藏一部分元素,避免用户短暂看到{{}}: v-cloak
10. 暂时隐藏一个元素的内容,但保留结构和样式时: v-text

做vue效果的基本步骤:

1. 先做静态页面:元素内容和需要切换的class先写死
2. 定义或获取数据保存在data中:
	1. 如果ajax请求来的数据,就直接放在data中
	2. 如果除了ajax请求来的数据,界面还需要其他数据,就在data中补充个别变量。
3. 修改静态页面:
	1. 内容可能变化,就用{{}}
	2. 属性那可能变化就用:
	3. 为写死的class或显示隐藏效果添加绑定条件。比如:class="三目"或v-show="条件"或v-if="条件"4. 先不要绑定事件,现在控制台,手工修改data中变量的值,测试界面动态效果是否正常
/***************************************************/
5. 如果第4步页面效果切换正常,才开始:
	查找触发事件的元素,添加事件绑定
	也可以利用事件委托,原理和DOM中利用冒泡一样。
	在事件处理函数中,不需要查找要修改的元素,都是通过只修改data中的变量,来自动更新页面的。

8. 自定义指令

	何时: 当一个常用的DOM操作,Vue没有提供对应的指令时
	如何: 
		1. 向vue中添加自定义指令
			Vue.directive("指令名",{
				inserted(domElem){
					对domElem执行常用的DOM操作
				}
			})
			强调: 定义指令时,指令名不要加v-前缀
			结果: 
				1. 在vue类型中就多出一种新的指令
				2. 将来运行时,当vue扫描到哪个DOM元素上带有这个自定义指令,就自动触发内部的inserted函数,自动获得当前dom元素对象,然后在inserted函数内,对当前dom元素执行想要的操作。
		2. 使用自定义指令: 和使用官方指令是一样的,只不过,不用带参数。
			<元素  v-指令名>
		强调: 使用指令时,必须加v-前缀

9. 计算属性

	什么是: 不实际保存属性值,仅通过其他属性计算获得属性值
	何时: 只要一个属性的值不是现成的,而需要通过其他属性计算,才能获得!
	如何: 2: 

(1) 定义计算属性,根据其他属性的值,动态计算获得自己的属性值

			new Vue({
				el:"选择器",
				data:{ 变量 },
				methods:{ 函数 },
				watch:{ 监视函数 },
				computed:{ 
					属性名(){ //计算属性本质是一个函数,但是,函数名却是名词!
						通过data中其它变量,计算获得统计结果。
						return 计算结果
					}
				}
			})

(2)使用计算属性进行绑定:

			计算属性的用法,和data中普通变量完全一样!
			强调: 不要加()

		vs methods
			methods中的函数,反复调用几次,就需要重复计算几次,如果反复使用效率低
			computed中的计算属性,只在首次使用时,计算一次。之后,即使重复使用计算属性,也不会重复计算,效率高!Vue会缓存计算属性的结算结果。只有计算属性依赖的变量值发生变化,才重新一次,并重新缓存计算结果,反复使用。
		总结: 
			1. 如果你仅希望使用计算结果这个值时,首选计算属性
			2. 更希望执行一系列操作流程时,首先函数

10. 过滤器

	什么是: 专门对原始类型的值进行加工后再显示的函数
	为什么: 因为有些数据库中保存的原始值,人看不懂,所以需要加工后,再给人看。
		比如: 性别! 日期和时间!  状态!
	何时: 只要原始属性,必须经过加工后,才能给人看时
	如何: 
		1. 添加过滤器
			Vue.filter("过滤器名",function(oldVal){
				return 处理后的新值
			})
		2. 使用过滤器: 
			在绑定语法中: {{变量 | 过滤器}}

	过滤器还可以加参数:
		1. 添加过滤器时,就要额外多写几个形参
			Vue.filter("过滤器名",function(oldVal, 其它形参...){
				return 根据不同的实参值返回不同的结果
			})
		2. 使用过滤器时,可加()传入实参值: 
			在绑定语法中: {{变量 | 过滤器(实参值, )}}
		强调: 第一个实参值,就写在实参列表的第一个位置,也不会覆盖过滤器函数定义时的第一个形参oldVal。而是自动传给过滤器函数定义时的第二个形参变量。过滤器第一个形参,永远接到的是变量的原始值。
	多个过滤器可以连用: 
		使用过滤器时,多个过滤器可用|连接
		强调: 后一个过滤器收到的不一定是原始值,而是前一个过滤器处理后的中间产物


11. axios

	什么是: 专门发送ajax请求的js函数库
	为什么: 发送ajax请求: 
		1. 编写原生ajax四步: 繁琐!
		2. 自己封装ajax函数: 功能弱!
		3. jQuery中有ajax函数: $.ajax()
			在Vue通常不会用到jQuery库,所以,仅仅为了一个ajax函数,将整个jQuery库引入项目,小题大做!
		4. Vue官方提供了vue-resource模块: 已不再更新
		5. Vue官方推荐使用第三方函数库: axios
	何时: 今后只要在vue中发送ajax请求,都可用axios
	说明: axios其实是第三方独立的函数库,并不仅仅局限于vue中!
	如何: 
		1. 发get请求: 
			axios.get(
				"服务端接口地址",
				{
					params:{
						参数:, 
						... : ...
					}
				}
			).then(result=>{
				result.data 才是服务器端返回的结果!
			})
		2. 发post请求:: 如果服务端给出的接口是post类型,可用postman软件先测试一下。
			axios.post(
				"服务端接口地址",
				//本来需要"查询字符串"
				//比如:"uname=dingding&upwd=123456"
				//不推荐
				//推荐: 对象语法
				//但是必须借助一个工具叫qs.min.js
				//<script src="js/qs.min.js">
				//Qs的stringify函数可将对象转为查询字符串格式
				Qs.stringify({
					变量1:1, 
					变量2:2
				})
				//转换之后: "变量1=值1&变量2=值2"
			).then(result=>{
				result.data 才是服务器端返回的结果!
			})

12. 组件

	什么是: 拥有专属的HTML,CSS,JS和数据的可重用页面独立区域
	为什么: 重用!
	何时: 只要发现一个功能区域需要反复使用,都要先封装为组件。
	如何: 
		1. 创建一个组件: 
			Vue.component("组件名",{
				//每个组件内都是一个完整的小社会
				//new Vue中能写什么,组件中就能写什么!
				el:"选择器",
				template:`HTML片段, 必须包在一个唯一的父元素内`,——因为组件的HTML片段不是只用一次,而是会被反复复制到页面上,用了几次,就复制几次。所以,这最初的一次HTML片段定义,就称为今后的模板
				data:{ 变量 },
				data(){
					return { //=new Vue中的data
						变量:,
						... : ...
					}
				},——因为每重用一次组件,都需要一个新创建的专属的数据,而不能和之前创建的混用!所以,每使用一次组件时,都自动调用data()函数,返回一个为本次组件专门创建的专属的新对象
				//其它和new Vue()完全一样!
				methods:{ 函数 },
				watch:{ 监视函数 },
				computed:{ 计算属性 }
			})
		2. 反复使用组件:
			组件其实就是一个可重复使用的自定义的HTML标签而已 。<组件名></组件名>  尽量用双标记
		强调: 如果组件名由多个单词组成:
			不要用驼峰命名: 因为组件名就是标签名,而HTML不区分大小写,所以拼写相同,但是大小写不同,是不能区分不同标签的。
			所以,如果组件名由多个单词组成,可用-分割多个单词: <my-header>     <my-counter>
	原理: 
		1. new Vue()在扫描真实DOM树时,发现组件标签
		2. 在Vue家里找到组件标签同名的组件类型
		3. 用组件类型中的template HTML片段,代替界面中组件标签的位置
		4. 为这个位置的组件标签,创建一个专属的data{}对象
		5. new Vue()发现几处组件标签,就用组件中的HTML模板片段代替几处组件标签,就反复调用几次data()重复创建几个相同的data对象给每处组件,专属使用,互不干扰。


13. 组件化开发

	什么是组件化开发: 将来所有的页面,都是由组件组成的。拿到页面后,第一件事是划分组件
	为什么: 1. 便于分工和协作
		   2. 松耦合
	何时: 今后几乎所有前端项目都是组件化开发
	如何: 
		1. 将一个页面划分成多个组件,并创建多个组件类型
		2. 在一个html中,将分头编写的多个组件,再组合起来!
	原理:
		1. new Vue()会扫描主页面,只要碰到组件标签,就会用组件的模板片段代替标签所在的位置
		2. 替换后,为防止有更子一级组件,还会重复扫描更替换上来的组件模板的内容,如果发现更子一级组件标签,则继续替换。
	问题: Vue.component()创建的是全局组件!没有使用限制
	解决:组件的分类: 
		1. 根组件: new Vue()
		2. 全局组件: 可以用在任何页面的任何位置,没有限制
		3. 子组件: 仅能在一个指定的父组件内使用的组件
			如何: 2: 
				1. 创建子组件: 
					1. 内部结构和全局组件是完全一样的
					2. 但是要将全局组件降级为普通js对象
						且子组件的对象名必须用驼峰命名
				2. 为父组件添加components:
					父组件{
						template:`...`,
						data(){ return {} },
						...
        				components:{
							子组件对象名,比如: todoAdd, todoList, todoItem
						}
						Vue会自动将todoAdd -> <todo-add>
									todoList -> <todo-list>
									todoItem -> <todo-item>
										自动翻译
					}

组件间传参: 3种:

父->子:

		1.->: 
			问题: 父组件中的成员,子组件默认不允许随意访问!因为,每个组件中的数据,归当前组件专属独有!
			解决: 
				1. 父组件中:
				<子组件标签  :自定义属性名="父的变量"
				2. 子组件中: 
					子组件={
						template:`html片段`,
						data(){ return { } },
						props:[ "要接收的自定义属性名" ],
						...
					}
				结果:
				  

结果:
前端 框架 Vue_第4张图片
前端 框架 Vue_第5张图片

子->父: 笔试题库

	父组件中用到了一个子组件:
	Vue.component("parent",{
  		template:`<div>
    			<h1>父组件</h1>
    			<child v-for="(item,i) of arr" 
				:key="i" ></child>
  		</div>`,
  		data(){
    			return { arr:[1,2,3] }
  		},
  		methods:{
    			handlerTest(item,e){
      			console.log(item);
      			console.log(e);
    			}
  		},
  		components:{
    			child
  		}
	})
	子组件中通过触发自定义事件向父组件传递一个数据: 
	var child={
  		template:`<div>
    			<h2>子组件</h2>
    			<button @click="handler">click</button>
  		</div>`,
  		methods:{
    			handler(){
      			this.$emit("test","something");
    			}
  		}
	}
	要求: 父组件的函数handlerTest中如何即输出item,又输出子组件传入的"something"字符串?
	答: <child ...  @test="handlerTest(item, $event)">
		首先,子组件给父组件传参,需要用到自定义事件
			2: 
			1. 父元素在自己的<template>中的子元素标签<child>上用@自定义事件名="父组件处理函数"方式,将父组件的处理函数绑定在子组件的自定义事件上。
			2. 子组件在单击按钮时,通过this.$emit("自定义事件名",参数值)方式,触发父组件绑在自己身上的自定义事件,并将参数值沿着事件触发的路线,顺便传递给父组件提前绑定的事件处理函数。
			结果: 即使父组件中为子组件绑定自定义事件的处理函数后没有加(),子组件传的参数值,也会默认放在VUE框架自动生成的$event关键字中,作为事件处理函数的第一个参数默认传入父组件处理函数内。
			父组件处理函数只需要在定义时,添加一个形参等着接就行了。
			比如: 子组件中: 触发名为test的自定义事件,自动传递数据"something"到父组件处理函数
				this.$emit("test", "something")
			父组件中: 
				<child @test="handlerTest">
				methods:{
					handlerTest(val){
						console.log(val)
					}
				}
			结果: handlerTest中的形参val自动接到的就是VUE在事件发生时自动创建的$event关键字,其中保存的就是子组件传来的"something"字符串。
		问题: 这个题: 事件处理函数需要两个参数,第一个参数是来自于v-for的item变量,第二个参数才是子组件传来的事件参数值。
		解决: 因为默认$event是作为第一个参数传入的。如果第一个参数不是$event,就不能用默认方式传值。而应该在绑定自定义事件时,显式写明每个参数的来源,比如:
			@test="handlerTest(item,$event)"
			这就是说,当事件发生时,处理函数的两个参数分别来自于item变量和VUE内置对象$event,而$event会自动收到子组件触发事件时,传来的参数值。


前端 框架 Vue_第6张图片

兄弟间: 笔试题库

前端 框架 Vue_第7张图片

14.SPA: Single Page Application

什么是: 一个应用程序中,只有一个完整的HTML页面,其它所谓的页面,
其实都是一些较大的组件而已。所谓的页面跳转,其实是更换不同的组件加载而已。

前端 框架 Vue_第8张图片

为什么: SPA vs 多页面

		1. 请求次数: 
			多页面应用,每更换一次页面都需要重新请求服务器,重新下载网页文件——增加了请求次数,增大了服务器的负担,同时也增加了用户等待
			单页面应用,在首次请求页面时,就把所有的组件一起下载下来。今后,切换页面其实就是在客户端本地切换不同组件显示而已,不需要反复请求服务器——减少了请求次数,减轻了服务器的负担,避免了切换页面等待的事件,提高了用户体验。
		2. 加载效率: 
			多页面应用,每更换一次页面都需要重建整棵DOM树,效率低!
			单页面应用,因为只替换页面中部分内容,不需要重建整棵DOM树,所以效率高!
		3. 公共资源: bootstrap.css  bootstrap.js  jquery.js
			多页面应用,因为每个页面都包含<link><script>,所以,每更换一次页面都重新请求这些公共资源——也增加了请求次数,增大了服务器的负担,也增加了用户等待的时间
			单页面应用,因为唯一完整的index.html文件只在首次记载时,下载一次,<link><script>也仅在首次加载时下载一次。之后更换页面组件,不会重新加载<link><script>——减少了请求次数,减轻了服务器的负担,避免了切换页面等待的时间,提高了用户体验。
		4. 页面过渡效果: 
			多页面应用不可能实现页面过渡效果,因为两个.html文件不可能并存在一个浏览器窗口内!
			单页面应用,因为所有组件都是以元素方式,保存在客户端,所以,完全可以通过定位,CSS3变换的方式,实现页面组件之间的切换效果。
		5. 首屏加载效率: ——SPA的缺点
			多页面应用,首屏只需要下载第一个页面的内容,其它页面内容暂时不需要下载,所以,首屏加载快!
			单页面应用,首屏就要把所有组件内容都下载下载,所以首屏加载慢——已解决: 配合打包工具webpack,让组件的js文件异步延迟加载: 先加载首屏组件用着,其它组件js在后台异步下载,不影响首屏下载速度。

如何实现: 4步

		1. 创建一个唯一完整的HTML页面,应该包含new Vue()
			引入: <script src="js/vue.js">
				<script src="js/vue-router.js"><div id="app">: 添加占位符
				<router-view/>
		2. 创建多个组件: 
			需求中有几个页面,就创建几个子组件来包含页面的内容。
			多个页面共用的组件,才创建为全局组件,并在各个页面中需要的位置引入全局组件标签。
		3. 创建路由字典和路由器对象: 
			路由字典: 保存一组相对路径和组件名对应关系的数组: 
				var routes=[
					{path:"/", component: index}, //默认路径
					{path:"/index", component: index}, 
					{path:"/details", component: details},
					{path:"/login", component: login},
					{path:"/*", component:{
						template:`<h2>404:Not Found</h2>`
					}}
				]
				问题: routes只是一个字典,无法完成替换组件的动作: 
			路由器对象: 
				创建路由器对象,将路由字典装入路由器对象中。
				var router=new VueRouter({ routes });
				原理: 
					路由器对象始终监视地址栏中的url地址后的#锚点地址变化。(Vue客户端路由采用的是锚点地址)
					只要锚点地址变化,立刻从路由字典中找到对应的组件,替换唯一完整的HTML中的<router-view>区域
		4. 将所有页面组件、路由器都引入唯一完整的HTML中,还要将路由器对象,装入new Vue()//<script src="全局组件.js">
			//<script src="2_index.js">
			//相当于引入了var index={}
			//<script src="2_details.js">
			//相当于引入了var details={}
			//<script src="2_router.js">
			//相当于引入了var router=new VueRouter({routes})

			new Vue({
				... , 
				router
			})

路由跳转: 2种:

		1. 在HTML中: 
			不要再用a
			<router-link to="/相对路径">文本</router-link>
			自动翻译成
			<a href="#/相对路径">文本</router-link>
		2. js中: 
			this.$router.push("/相对路径")
				路由器

路由传参: 3步:

		1. 接收参数的页面的路由字典中就要配置参数: 
			{path:"/details/:lid", component:details, props:true}
                          变量名
			其中: props:true,让url中参数自动成为props中的自定义属性
		2. 在要接收参数的目标组件中,添加与路由参数同名的自定义属性变量: 
			var details={
				... 
				props:["lid"], 这个lid就可自动接到url中的值,在details页面内,像普通变量一样使用
			}
		3. 跳转时: 应该在相对路径之后加"/参数值"
			强调: 
				1. 不要有?
				2. 不要写参数名=
				3. /直接跟参数值

15.脚手架

	什么是脚手架: 已经包含标准项目文件夹结构和核心功能代码的半成品项目
	为什么: 
		1. 简化开发: 
		2. 标准化开发: 
	何时: 今后几乎所有项目的创建,都是用脚手架代码,比如: nodejs express, vue, 微信小程序 , ng, react。所以今后,每学一项新技术,首先要找脚手架代码!

如何: 2步:

		1. 全局安装生成脚手架代码的工具: 
			npm i -g @vue/cli
		2. 用脚手架生成工具为本次项目生成一套脚手架结构代码: 
			vue create 项目名
		结果: 
			1. 当前目录下多出一个项目名文件夹
			2. 进入文件夹: cd 项目名, 
			3. 运行脚手架半成品项目: npm run serve

在vscode中调试脚手架代码:

		1. 打开vscode->文件->打开文件夹->选项目文件夹
		2. 右键单击package.json文件,选在终端中打开
		3. 在终端中输入npm run serve
		4. 按住ctrl点链接:http://localhost:8080
		结果自动打开浏览器,显示正在调试的页面

脚手架的项目结构:

		public文件夹: 
			不需要编译和打包的文件,都要放在public文件夹下。
			包括: 
				1. 唯一的index.html页面
				2. 图片文件夹
				3. 从第三方下载的已经压缩过的通用的库: 
					bootstrap.min.css
					jquery-1.11.3.min.js
					bootstrap.min.js
				4. 在唯一完整的index.html开头,引入公共的css或js库
		src文件夹: 
			一切我们自己编写的内容都要放在src文件夹下
			包括: 
				页面组件都要放在views文件夹下
				全局组件/子组件都要放在components文件夹下
				自己编写的公共的css和js库都要放在assets下。比如: base.css
				App.vue相当于之前的<div id="app">
				main.js相当于之前的new Vue({})
					很多配置,都需要在main.js中的new Vue()之前定义好,才能new Vue()
					比如: 
						1. 全局组件的创建
						2. axios的配置和引用
				router.js相当于之前的路由字典和路由器
					当添加了新页面组件,或删除旧的页面组件,都要在router.js中配置路由字典

一个.vue文件的内容:

				1. 一个.vue文件就是一个组件,要创建几个组件,就要添加几个.vue文件
				2. 每个vue文件中,都包含3样东西: 
					1. HTML:
						每个组件的HTML片段,必须写在一个<template></template>内——相当于之前组件对象中的template:`HTML片段`属性,且不再放在字符串中,有了提示和颜色显示。
					2. 组件对象的js:
						export default {
							除了没有template外,其余和之前完全一样!
						}
						但是,vue脚手架采用的是模块化开发!
						回顾: node中的模块: 
							1. 亮哥封装了一个pool模块,其中包含一个query函数。如果亮哥想让别人使用这个模块的内容,必须使用module.exports将内容以对象形式抛出
							function query(...){...}
							module.exports={ query }
							2. 别人想用亮哥的pool模块中的query,就要用require()引入亮哥抛出的模块,然后才能调用模块对象中的方法
							var pool=require("../pool.js")
							pool.query()
						Vue脚手架里的模块化开发要求: 
							1. 每个组件其实都是一个模块对象,组件对象定义好后,都要用 export default { ... } 抛出。
								export default代替了module.exports=
							2. 任何想使用这个组件对象的地方,都要用import 变量 from "路径/组件.vue" 先引入组件对象,并起别名,才能使用。
								import 变量 from 代替了const 变量=require("...")

前端 框架 Vue_第9张图片

					3. CSS: 写在专门的<style></style>标签内。
						1. 可直接将css代码写在<style scoped></style>内部
							scoped 可自动为每个选择器加一个统一的随机的前缀!与其他组件的即使同名的class自动区分。比如: .fade{ ... } 会被scoped翻译为: .fade[随机父组件名]{ ... }
							问题: css和HTML,js混搭不便于维护。
						2. 在assets/css文件夹中独立编写css文件,再在<style></style>标签内,用@import url(... )引入!
							问题: scoped失效,只能靠自己的书写习惯来避免组件间样式冲突。

16.生命周期

每个组件(根组件, 全局组件, 子组件)都有自己的一套加载过程——称为组件的生命周期

包括: 4个阶段

		1. 创建create:仅创建了new Vue()或组件对象,同时创建了组件对象中的data对象。
		2. 挂载mount:开始扫描真实DOM树,形成虚拟DOM树,并首次替换绑定内容为data中的变量值。
		3. 更新update:在任何位置修改了data中的变量值,都会触发更新阶段
		4. 销毁destroy:只在调用$destroy()函数,销毁组件时,才触发销毁阶段

前端 框架 Vue_第10张图片

	为什么: 有些事儿,必须在指定的阶段,自动被调用执行
		比如: 当组件对象创建后,自动发送ajax请求,加载数据
	如何: 
		vue中每个生命周期的执行阶段前后,都各有一个钩子函数。
		包括:

前端 框架 Vue_第11张图片

16. $router 和 $route

	问题: 一个带参数的路由地址,仅修改参数值,不修改相对路径名,整个页面不刷新的,无法加载新参数值对应的内容。
		因为是单页面应用!
	解决方案一: 地址栏中参数值变化,说明props中的变量值跟着变了!可以在watch中,监视变量,只要props变量变化,就重新ajax请求数据,修改data中的变量,引发更新页面。
	解决方案二: 监视地址栏对象$route
		DOM中有location对象代表地址栏,可获得地址栏中的信息。
		Vue中有$route代表地址栏!
			比如: 不用props获得参数lid
				也可以this.$route.params.lid
	$route vs $router
		$router 是路由器对象,专门执行跳转动作的对象			$route 是封装地址栏信息的对象,是保存数据的,不执行操作。

17. 配置axios的基本url地址

	问题: 服务器端部署位置的地址,经常发生变化。如果客户端每个.vue文件中都要写完整的域名/相对地址,那么每次服务端地址修改,都要修改所有.vue中的请求地址——相当麻烦!
	解决: main.js中
		axios.defaults.baseURL="http://服务器地址"
		其它.vue中: 
		this.axios.get("/相对地址",参数).then(...)

前端 框架 Vue_第12张图片

	结果: 将来运行时,会将baseURL+/相对地址,形成完整地址
		而如果服务端地址变化,则只需要修改main.js中baseURL一处,就可切换不同服务端!


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