vue入门

vue入门

本日目标:

理解MVVM设计模式的思路(对比原MVC模式),前后端分离开发架构

掌握vuejs入门操作(掌握常用表达式,记忆特殊表达式的使用场景),为vuejs组件框架(底层基于vuejs实现的新标签)做准备,ElementUI,Ant design(vuejs)

掌握axios(HttpRequest插件)的使用,对比JQuery的ajax操作

MVC设计模式:

问题:

一般开发中(使用的是jsp,底层就是java代码):Model和View存在关联(通信),这违反开发封闭原则,影响代码的扩展性和可维护性

提高扩展和维护性:使用原生视图(html页面),通过在view中编写ajax操作,动态获取后端数据进行前端加载显示(MVP模式,view和Model完全隔离)

如果开发中选择的是第二种方式,那么这也就是MVVM设计模式的前身

MVVM模式:

Model-View-ViewModel:简称MVVM,实际就是MVC改进后的设计模式,将视图和模型完成分开

Model层:请求提供的原始数据
View层:视图展示,由ViewController来控制
ViewModel层:负责业务处理和数据转化

目前在实际开发中,基于前后端分离项目一般都是使用该模式进行开发:

MVVM 的出现促进了 GUI 前端开发与后端业务逻辑的分离,极大地提高了前端开发效率。

MVVM 的核心是 ViewModel 层,它就像是一个中转站(value converter),负责转换 Model 中的数据对象来让数据变得更容易管理和使用,该层向上与视图层进行双向数据绑定,向下与 Model 层通过接口请求进行JSON数据交互,起呈上启下作用。

View 层展现的不是 Model 层的数据,而是 ViewModel 的(data中)数据,由 ViewModel 负责与 Model 层交互,这就完全解耦了 View 层和 Model 层,这个解耦是至关重要的,它是前后端分离方案实施的最重要一环。

技术体现:

前端页面中的数据完全由VM层(vue.js)进行控制

1)要么通过vm层请求后端数据接口返回需要的数据,用于视图展示

2)要么通过vm层收集前端页面数据,请求后端将数据进行持久操作

优点:

1)低耦合

2)高重用

3)利于协作开发

核心操作:

1) 响应式(隐式的有事件关联)

2)动态数据渲染

3)模板解析(在其他vuejs框架中都是基于模板开发)

建议:

下来自行查阅MVC和MVVM的区别:

https://www.pianshen.com/article/3716256399/

vue入门使用:

如果说是JQuery是手工作坊,那么Vue.js就像是一座工厂,虽然Vue.js做的任何事情JQuery都可以做,但无论是代码量还是流程规范性都是前者较优。

Vue.js的官方中文教程其实也是一个不错的教程,不过相比于一次性把所有概念掌握,我更倾向于先会用,之后再在实际应用中把未涉及到的知识点逐步补全。

就像开车,不是非要知道发动机的工作原理才能上路的,甚至你可能一辈子也不用知道。

官方文档:https://cn.vuejs.org/v2/guide/

教程网址:https://www.runoob.com/vue2/vue-tutorial.html

首先,学习前提:

  • 你会用html+css+javascript 写一些网页
  • 你知道什么是DOM和BOM(Browser Object Model)
  • 你知道Vue.js是一个框架而不是一个新语言
  • 你会用百度或者Google其中之一去查找答案

接着,课程会围绕以下几个Vue.js的基本(核心)使用方法逐个做测试和使用说明:

  • 新建vue对象
  • 数据绑定
  • 表单控件绑定
  • 流程结构
  • 事件绑定
  • 自定义组件
  • 计算属性
  • 过滤器和监听器

1. Vue.js 安装

官方文档地址:https://cn.vuejs.org/v2/guide/installation.html

1.1 下载使用(学习中使用)

直接下载并用 <script> 标签引入,Vue 会被注册为一个全局变量。

在开发环境下不要使用压缩版本,不然你就失去了所有常见错误相关的警告!

开发版本:包含完整的警告和调试模式

生产版本:删除了警告


1.2 使用 CDN 方法(学习中使用,前提在网络环境下使用)

对于制作原型或学习,你可以这样使用最新版本:

<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>

对于生产环境,我们推荐链接到一个明确的版本号和构建文件,以避免新版本造成的不可预期的破坏:

<script src="https://cdn.jsdelivr.net/npm/vue@2.6.11"></script>

以下推荐国外比较稳定的两个 CDN,国内还没发现哪一家比较好,目前还是建议下载到本地。

1.3 NPM 方法(实际开发中使用(前提有nodejs环境))

在用 Vue 构建大型应用时推荐使用 NPM 安装。NPM 能很好地和诸如 webpack 或 Browserify 模块打包器配合使用。同时 Vue 也提供配套工具来开发单文件组件。

# 最新稳定版
$ npm install vue

由于 npm 安装速度慢,本教程使用了淘宝的镜像及其命令 cnpm,安装使用介绍参照:使用淘宝 NPM 镜像

npm 版本需要大于 3.0,如果低于此版本需要升级它:

# 查看版本
$ npm -v
2.3.0

#升级 npm
cnpm install npm -g

# 升级或安装 cnpm
npm install cnpm -g

在用 Vue.js 构建大型应用时推荐使用 NPM 安装:

# 最新稳定版
$ cnpm install vue

2. vue的基本结构

完整的vue对象结构:

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8" />
		<title></title>
		<script src="js/vue.js" type="text/javascript" charset="utf-8"></script>
	</head>
	
	<body>
        <!--注意:vue的标识元素,不允许包括html或body,一般应该使用一个自定义的div作为容器-->
        <!--准备一个用于vue操作的容器,在属于vue标识的容器中,可以使用所有vuejs提供的操作-->
		<div id="app">
            <!--基于vuejs开发的标签-->
		</div>
	</body>
</html>

<script>
	var vm = new Vue({
		el:"#app",//标识容器
		data:{
            //定义各种页面元素绑定展示属性
		},
        methods:{
        	//定义各种事件处理或逻辑操作方法
    	}
	});
	
</script>

前端ide:

hbuilderx(本次学习使用,https://www.dcloud.io/hbuilderx.html)

webstorm(专业前端一般使用,和idea是同一家公司产品)

3. 插值-声明式渲染

主要针对普通标签(非表单控件标签)

普通标签设置内容:通过innerHTML(innerText)在标签中间设置内容

表单控件标签设置内容:通过标签的value属性设置内容

参考文档:https://cn.vuejs.org/v2/guide/syntax.html#插值

Vue.js 使用了基于 HTML 的模版语法,允许开发者声明式地将 DOM和底层 Vue 实例的数据进行绑定。

Vue.js 的核心是一个允许你采用简洁模板语法来声明式的将数据渲染进 DOM 的系统。

结合响应系统,在应用状态改变时, Vue 能够智能地计算出重新渲染组件的最小代价并应用到 DOM 操作上。

操作标签内容使用语法:{{data中的属性名}}

​ 该表达式只能用于文本内容输出,类似于innerText,如果想要输出html,那么需要借助v-html指令(指令必须基于html标签使用)

操作标签属性值使用语法: v-bind:标签属性名=“data中的属性名”

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8" />
		<title></title>
		<script src="js/vue.js" type="text/javascript" charset="utf-8"></script>
	</head>
	<body>
		<!-- 在网页的DOM元素中通过指定一个标识,一般使用id,让vue将当前元素识别 -->
		<div id="app">
			<!-- 在DOM中使用vm层中数据 -->
			<!-- 1:使用{{data中的属性名}},类似于EL表达式 -->
            {{ msg }}<br/>
            <p>{{ msg.split('').reverse().join('') }}</p>
            {{ num + 1 }}<br/>
            {{ ok ? 'YES' : 'NO' }}<br/>
            <!-- 类似于innerText -->
			<!-- 等同于输出文本:'<span style="color: red;">span文本</span>' -->
            {{htmltxt}}<br/>
			<!-- 类似于innerHtml -->
			<p v-html="htmltxt">
				<!-- 等同于输出以下标签代码 -->
				<!-- <span style="color: red;">span文本</span> -->
			</p>
            <h3>{{objArray[1].password}}</h3>
			<a href="obj.url">百度一下</a><br/>
			<a v-bind:href="obj.url">百度一下</a><br/>
            <!-- 基于v-bind缩写方式 -->
            <a :href="obj.url">百度一下</a><br/>
		</div>
	</body>
</html>

<script>
	//1:创建vue对象
	var vm = new Vue({
		//标识vue使用范围,在指定范围内就可以使用任意vue语法
		el:"#app",
		//data中是定义用于上面指定的元素中需要使用的各种属性数据,这是vm的作用
		data:{
			//在该代码块中定义了所有用于网页的DOM中进行动态数据加载的属性
			//语法:属性名:值,值的类型:数字值,字符值,对象值,数组值,布尔值
            num:1,
            ok:true,
			msg:'hello vue',
            htmltxt:'<span style="color: red;">span文本</span>',
            val:["one","two"],//数组值
			obj:{//对象值
				username:"zhangsan",
				password:"zs123",
				url:"https://www.baidu.com"
			},
			objArray:[//数组对象值
				{
					username:"zhangsan",
					password:"zs123"
				},
				{
					username:"lisi",
					password:"ls123"
				}
			]
		}
	});
</script>
总结:
  1. 在网页中被标识为Vue容器的元素中进行插入数据使用语法{{data中的属性名}},该语法可以插入标签文本,输出真正的 HTML,那么需要在html标签中借助v-html指令实现输出(该指令底层是基于innerHTML),如果想要给标签属性插入值,需要借助v-bind指令

  2. vue的使用是通过在页面加载时就创建出一个vue对象,在对象存储相关属性,在页面执行后也可以通过动态给当前vue对象赋值的方式,改变属性值

    测试声明式渲染:

补充:Vue.js 为v-bind指令提供了特别的缩写:

v-bind 缩写(实际开发常用缩写方式)

<!-- 完整语法 -->
<a v-bind:href="url"></a>
<!-- 缩写 -->
<a :href="url"></a>

4. 双向绑定

参考文档:https://cn.vuejs.org/v2/guide/forms.html

用于和表单控件标签实现数据双向绑定,也就是给表单标签的value属性双向绑定vue对象的data中的属性值:v-model=“data中的属性名”

双向绑定:

​ 修改表单控件的数据,那么vue的data属性的值也会跟着改变

​ 修改vue的data属性的值,表单控件的数据也会随之改变

这样可以让开发者直接在script代码块中通过获取vue的data中的属性值,就拿到了用户在表单控件上输入的值,而不需要像原开发方式需要:获取表单->获取控件->通过控件元素.value->获取到用户输入值,同时也可以通过在data中给属性设置默认值用于表单控件显示初始值

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8" />
		<title></title>
		<script src="js/vue.js" type="text/javascript" charset="utf-8"></script>
	</head>
	
	<body>
		<div id="app">
			<!-- 双向绑定是针对表单控件控件的 -->
			<!-- 在表单控件标签中通过使用:v-model="data中的属性名",实现数据的双向绑定,就是将控件的value属性值和vue的data属性绑定 -->
			<!-- 1):在控件加载时可以显示默认值 -->
			<!-- 2):改变控件的value属性值,也会改变vue的data中的属性值 -->
			<!-- <input value="通过value属性设置控件默认值,给控件中输入值,也是将值赋值给value属性" /> -->
			<input v-model="msg" /><br/>
			<select v-model="selected">
				<option value="1">one</option>
				<option value="2">two</option>
			</select><br/>
			{{msg}}---{{selected}}
		</div>
	</body>
</html>

<script>
	//1:创建vue对象
	var vm = new Vue({
		el:"#app",
		data:{
			msg:'hello vue',
			selected:2
		}
	});
	
</script>
任务:其他表单控件的代码参考官方进行练习

多行文本:https://cn.vuejs.org/v2/guide/forms.html#多行文本

复选框:https://cn.vuejs.org/v2/guide/forms.html#复选框

单选按钮:https://cn.vuejs.org/v2/guide/forms.html#单选按钮

选择框(下拉列表):https://cn.vuejs.org/v2/guide/forms.html#选择框

5. 条件判断

参考文档:https://cn.vuejs.org/v2/guide/conditional.html

通过条件判断实现元素的动态添加和删除(不是显示隐藏),完成类似于原生开发中针对DOM的节点添加和删除功能

vue完全支持JavaScript中表达式语法:

v-if=“表达式”:类似于java的if结构

v-else:结合v-if语法,完成类似于Java的if...else结构

v-else-if=“表达式”:结合v-if,完成类似于Java的if...else if...结构,和java一样,同时可以结合v-else完成类似 于Java的if...else if......else结构

表达式结果为true就添加元素,为false就删除元素

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8" />
		<title></title>
		<script src="js/vue.js" type="text/javascript" charset="utf-8"></script>
	</head>
	
	<body>
		
		<div id="app">
			<!-- 在标签中使用vue提供的条件判断语法完成标签插入控制 -->
			<!-- 条件表达式为true时,使用语法的标签就被插入到DOM中 -->
			<!-- 条件表达式为false时,使用语法的标签就不添加到DOM中 -->
			<p v-if="username=='zhangsan'">用户:{{username}}</p>
			
			<h4 v-if="age >= 18">成年人</h4>
			<!-- 通过使用v-else给前面的v-if添加了一个类似于java中的else代码块 -->
			<h3 v-else>未成年人</h3>
			
			<p v-if="username=='zhangsan'">用户:张三</p>
			<p v-else-if="username=='lisi'">用户:李四</p>
			<p v-else-if="username=='wangwu'">用户:王五</p>
			<p v-else>未知用户</p>
		</div>
	</body>
</html>

<script>
	//1:创建vue对象
	var vm = new Vue({
		el:"#app",
		data:{
			username:'zhangsan',
			age:19
		}
	});
</script>

v-if和v-show的说明

v-if用于控制网页元素的新增和删除,是基于DOM的节点增加和删除(只有表达式为true的标签存在)

v-show是用于控制网页元素的显示和隐藏,是基于display样式属性控制(标签永远都存在)

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8" />
		<title></title>
		<script src="js/vue.js" type="text/javascript" charset="utf-8"></script>
	</head>
	
	<body>
		
		<div id="app">
			<p v-if="isOk">控制当前元素在网页的DOM中的插入和删除</p>
			<p v-show="isShow">控制当前元素在网页中的display样式属性</p>
		</div>
	</body>
</html>

<script>
	var vm = new Vue({
		el:"#app",
		data:{
			isOk:true,
			isShow:true
		}
	});
	
</script>

如果都为true:那么显示的样子是基本一致的

如果都为false:那么在代码中显示的样子就不一样了

6. 循环操作

参考文档:https://cn.vuejs.org/v2/guide/list.html

通过循环结构完成数组(或对象(看做map结构的数组))遍历的元素添加或普通固定次数的循环元素添加

使用语法:v-for="循环表达式",表达式类似于JavaScript中的for...in

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8" />
		<title></title>
		<script src="js/vue.js" type="text/javascript" charset="utf-8"></script>
	</head>
	
	<body>
		
		<div id="app">
			<!-- 遍历字符串,将字符串看做字符数组 -->
			<p v-for="char in str">{{char}}</p>
			<!-- 普通固定次数循环:v-for="自定义变量名 in 整数值表达式",从1开始循环到指定的整数值表达式结束 -->
			<!-- 使用整数属性表达式 -->
			<p v-for="i in num">{{i}}</p>
			<!-- 使用值表达式 -->
			<p v-for="n in 5">{{n}}</p>
			
			<!-- 数组遍历 -->
			<!-- 使用v-for="(自定义值变量[,自定义数组索引变量]) in 数组属性" -->
			<!-- 自定义值变量:循环存储数组中的值,本次是对象值 -->
			<!-- 自定义数组索引变量(可选):从0开始 -->
			<table>
				<tr>
					<td>编号</td>
					<td>用户名</td>
					<td>密码</td>
				</tr>
				<tr v-for="(user,rowNum) in users">
					<td>{{rowNum+1}}</td>
					<td>{{user.username}}</td>
					<td>{{user.password}}</td>
				</tr>
			</table>
			
			<!-- 对象值循环操作:将对象值看做Map进行操作 -->
			<!-- 1)以对象属性值遍历 -->
			<ul>
				<li v-for="value in student">{{value}}</li>
			</ul>
			<!-- 2)以对象属性值和属性名遍历 -->
			<ul>
				<li v-for="(value,key) in student">{{key}}----{{value}}</li>
			</ul>
			<!-- 3)以属性值,属性名,属性索引遍历 -->
			<ul>
				<li v-for="(value,key,index) in student">{{index}}:{{key}}----{{value}}</li>
			</ul>
		</div>
	</body>
</html>

<script>
	//1:创建vue对象
	var vm = new Vue({
		el:"#app",
		data:{
			str:"hello",
			num:5,
			users:[
				{username:'zhangsan',password:'zs123'},
				{username:'lisi',password:'ls123'}
			],
			student:{username:'zhangsan',password:'zs123'}
		}
	});
</script>

官方API:https://cn.vuejs.org/v2/api/#v-for

数组操作方法Api文档:https://cn.vuejs.org/v2/guide/list.html#数组更新检测,一般在事件处理方法中使用

v-if与 v-for 一起使用

不推荐一个标签同时使用 v-ifv-for(但是可以嵌套使用,如循环生成中需要根据不同结果显示不同内容)

当和 v-if 一起使用时,v-for 的优先级比 v-if 更高

<li v-for="todo in todos" v-if="!todo.isComplete">
  {{ todo }}
</li>

7. 事件绑定

参考文档:https://cn.vuejs.org/v2/guide/events.html

想要使用事件:需要在vue对象中定义了methods属性,在该属性中定义各种用于事件处理的函数

在基本结构中新增结构:

	var vm = new Vue({
		el:"#app",
		data:{
			//定义各种用于被标识的vue元素中的展示属性数据
		},
		methods:{
			//定义各种用于vue标识元素中进行事件操作的函数
			// 函数语法:
            	函数名:function(参数列表){},
            //或(建议使用下面方式)
            	函数名(参数列表){}
		}
	});

通过在DOM元素中使用 v-on:事件名=“methods中定义的事件函数名或需要直接执行的代码逻辑”进行事件绑定

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8" />
		<title></title>
		<script src="js/vue.js" type="text/javascript" charset="utf-8"></script>
	</head>

	<body>

		<div id="app">
			<!-- 直接在事件属性中编写程序逻辑:一般都是编写一些计算逻辑,不能使用其他函数代码 -->
			<!-- 只能用于简单逻辑 -->
			<button v-on:click="num1 += 1">事件按钮1</button><br />
			{{num1}}<br />
			<!-- 如果想要JavaScript中内置函数方法那么必须通过在Methods中定义方式处理 -->
			<!-- 无参事件方法:调用无参函数只需要函数名后面没有() -->
			<button v-on:click="show">事件按钮2</button><br />
			<!-- 有参事件方法 -->
			<button v-on:click="show2('zhangsan')">事件按钮3</button><br />
			<!-- 特殊事件属性,事件发生时传入事件对象本身 -->
			<!-- 在标签上的事件方法引用时使用特殊变量 $event ,代表事件对象本身,可以通过事件对象获取相关属性值,如坐标值-->
			<!-- 在事件方法定义中使用自定义变量接收 -->
			<button v-on:click="show3('lisi',$event)">事件按钮4</button><br />
			必须同时按下ctrl键才能弹窗,通过原生代码实现<br />
			<button v-on:click="show5($event)">事件按钮5</button><br />
			
			<!-- 使用事件修饰符进一步控制事件发生 -->
			<!-- 语法:v-on:事件名.修饰符="事件处理函数名或逻辑代码" -->
			
			<!-- ctrl:限制事件必须满足同时按下指定键才能触发 -->
			必须同时按下ctrl键才能弹窗,通过事件修饰符实现<br />
			<button v-on:click.ctrl="show6">事件按钮6</button><br />
			
			<!-- once:限制事件只能触发一次 -->
			<button v-on:click.once="num += 1">事件按钮1</button><br />
			{{num}}<br />
		</div>
	</body>
</html>

<script>
	//1:创建vue对象
	var vm = new Vue({
		el: "#app",
		data: {
			//定义各种用于被标识的vue元素中的展示属性数据
			num: 1,
			num1: 1
		},
		methods: {
			//定义各种用于vue标识元素中进行事件操作的函数
			// 函数语法:函数名:function(参数列表){}
			show: function() {
				//this.num1,this关键字和java意义是一致,表示当前对象
				//this.num1 等同于 vm.num1
				alert(this.num1);
			},
			// 函数语法:函数名(参数列表){}
			show2(msg) {
				alert(msg);
			},
			//接收事件调用参数和事件对象(事件对象通过标签中调用绑定事件时通过关键字$event传入事件对象本身)
			//在事件处理方法中可以通过事件对象本身获取事件相关属性,如:事件发生时的鼠标坐标等
			//事件属性参考教程https://www.runoob.com/jsref/dom-obj-event.html
			show3(msg, ev) {
				var x;
				if (ev) {
					x = ev.clientX;//获取事件发生的坐标
				}
				alert(msg+"----"+x);
			},
			show5(ev) {
				if (ev.ctrlKey) {
					alert("按下ctrl点击鼠标");
				}
			},
			show6() {
				alert("按下ctrl点击鼠标");
			}
		}
	});
</script>

官方API:https://cn.vuejs.org/v2/api/#v-on

补充:在事件中可以进一步借助事件修饰符进行事件处理限制

https://cn.vuejs.org/v2/guide/events.html#事件修饰符

如:

<!-- 使用修饰符限制事件的使用: once只能调用一次-->
<button v-on:click.once="show">事件按钮4</button><br/>
补充:Vue.js 为v-on指令提供了特别的缩写:

v-on 缩写(事件开发一般都是使用缩写)

<!-- 完整语法 -->
<a v-on:click="doSomething"></a>
<!-- 缩写 -->
<a @click="doSomething"></a>

8. 自定义组件(组件也就是DOM中元素,目前了解)

入门使用参考文档:https://cn.vuejs.org/v2/guide/components.html

使用约定参考文档:https://cn.vuejs.org/v2/style-guide/

vue中允许开发者自定义具有特定功能,特定属性的网页元素,提高代码重用和开发效率

在常见的基于vuejs开发中前端UI框架中都是基于自定义组件开发具有特定功能的标签

如:Iview框架 或ElementUI框架,官方提供的各种组件就是基于自定义组件开发

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8" />
		<title></title>
		<script src="js/vue.js" type="text/javascript" charset="utf-8"></script>
	</head>
	<body>
		<div id="app">
			<!--使用自定义组件都必须成对使用 -->
			<button-counter></button-counter>
			<my-ele></my-ele>
			<my-div txt1="aaaa" txt2="bbbb"></my-div><!--组件显示为:<h4>这是自定义的组件属性txt1的值为aaaa,属性txt2的值为bbbb -->
		</div>
	</body>
</html>
<script>
	// 定义一个名为 button-counter 的新组件
	Vue.component('button-counter', {
		//定义组件中的内置数据
		data: function() {
			return {
				//该属性用于组件模板中使用
				count: 0
			}
		},
		//定义当前组件渲染时的内容(基于网页可识别内容)
		template: '<button v-on:click="count++">You clicked me {{ count }} times.</button>'
	})
	//自定义组件必须定义在创建vue对象前面
	// 如果对象都已经创建了,那么再给vue模板中设置组件是无效
	// 语法:Vue.component("自定义组件名",{data: function() {return {//定义内置数据}},props: [组件属性列表],template: '在网页中使用组件时显示的内容模板'})
	//没有属性的元素组件
	Vue.component("my-ele", {
		template: '<p>这是自定义的组件</p>', //指定显示的元素内容,内容不能是纯文本,需要指定自定义组件显示的HTML元素
	});
	//有属性的元素组件
	Vue.component("my-div", {
		//在使用标签时可以通过以下属性名传入值
		props: ["txt1", "txt2"],//接收标签通过自定义属性传入数据
		template: '<h4>这是自定义的组件属性txt1的值为{{txt1}},属性txt2的值为{{txt2}}</h4>'
	});
	//创建vue对象
	var vm = new Vue({
		el: "#app",
		data: {},
		methods: {

		}
	});
</script>

目前所有的组件都是基于全局注册

注意事项https://cn.vuejs.org/v2/guide/components.html#解析-DOM-模板时的注意事项

开发约定:https://cn.vuejs.org/v2/style-guide/#组件名为多个单词必要

父子组件传值:

1、父组件可以使用 props 把数据传给子组件。
2、子组件可以使用 $emit 触发父组件的自定义事件。

<!--父组件模板-->
<div id="app">
	<!-- 父组件使用(:属性名="数据变量")方式将数据传入子组件 -->
  <temp @item-click="tempClick" :categories="categories"></temp>
</div>

<!--子组件模板-->
<template id="temp">
  <div>
	<!-- 使用子组件私有属性方式 -->
    <button v-for="item in categorieList"
            @click="btnClick(item)">
      {{item.name}}
    </button>
	<br/>
	<!-- 使用父组件传入数据方式 -->
	<!-- <button v-for="item in categories"
	        @click="btnClick(item)">
	  {{item.name}}
	</button> -->
  </div>
</template>

<script src="js/vue.js"></script>
<script>

  // 1.子组件
  const temp = {
	//关联模板
    template: '#temp',
	//注意,组件中的所有 props中的数据,都是通过父组件传递给子组件的
	//只读
	props:['categories'],
	//子组件中的data数据,不是通过父组件传递的是子组件私有的
	//data上的数据,是可读可写的
    data() {
      return {
        categorieList: []
      }
    },
	created(){
		if(this.categories.length == 0){
			this.categorieList = [
				{id: 'aaa', name: '热门推荐'}
			]
		}else{
			this.categorieList = this.categories;
		}
	},
    methods: {
      btnClick(item) {
        // 子组件调用父组件自定义事件
        this.$emit('item-click', item)
      }
    }
  }

  // 2.父组件
  const app = new Vue({
    el: '#app',
    data: {
      message: '你好啊',
	  categories: [
	    {id: 'bbb', name: '手机数码'},
	    {id: 'ccc', name: '家用家电'},
	    {id: 'ddd', name: '电脑办公'},
	  ]
    },
    components: {
      temp
    },
    methods: {
      tempClick(item) {
        console.log(item);
      }
    }
  })
</script>

9. 计算属性的使用(熟悉)

参考文档:https://cn.vuejs.org/v2/guide/computed.html

解决:在模板中放入太多的逻辑会让模板过重且难以维护

通过定义一个方法实现类似于属性的使用,一般用于在需要进行属性计算操作时,建议将计算的逻辑定义为计算属性,这样可以减轻页面代码

定义语法:computed:{//计算属性方法名:function(){}}

	var vm = new Vue({
		el:"#app",
		data:{
			//定义各种普通属性
		},
		//定义计算属性的处理方法,
		computed:{
			//计算属性方法名:function(){}
		}
	});

使用语法:是通过在{{计算属性方法名}}调用方法获取属性值显示

参考代码:

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8" />
		<title></title>
		<script src="js/vue.js" type="text/javascript" charset="utf-8"></script>
	</head>
	<body>
		<div id="app">
			<!-- 非计算属性方式:代码维护不方便 -->
			{{ message.split('').reverse().join('') }}<br/>
			<!-- 计算属性方式实现 -->
			{{ reverseMsg }}<br/>
			{{ upperMsg }}<br/>
		</div>
	</body>
</html>
<script>
	var app = new Vue({
		el: "#app",
		data: {
			message: "hello",
			msg: "hello"
		},
		methods: {

		},
		//定义计算属性的处理方法,页面上是通过在{{计算属性方法名}}调用方法获取属性值
		computed: {
			// 语法:
			// 自定义计算属性方法名: function() {
			// 	计算属性处理逻辑
			// 	return 属性返回值
			// }
			//this关键字是引用当前对象
			reverseMsg: function() {
				//this关键字:表示当前对象本身
				return this.msg.split('').reverse().join("");
			},
			upperMsg: function() {
				return this.msg.charAt(0).toUpperCase() + this.msg.slice(1)
			}
		}
	});
</script>

10. 过滤器的使用(熟悉)

官方文档:https://cn.vuejs.org/v2/guide/filters.html

分为全局和局部过滤器,用于对输出的属性数据进行过滤操作

定义结构:

//在创建vue实例之前,定义全局过滤器,value获取管道符号前的数据
Vue.filter('过滤器名称', function (value) {//value接收过滤的数据
    //....逻辑代码
	return 过滤器后结果
})
var vm = new Vue({
  el: '#demo',
  data: {
      //定义各种属性
  },
  //在vue实例内部,定义局部过滤器
  filters:{
    //定义各种过滤方法
	//语法:
	// 1)无参过滤方法名:function (value) {return 过滤器后显示的文本},value表示被过滤操作的值,也就是管道符号前的数据
	// 2)有参过滤方法名:function (val,param1,param2,....) {return 过滤器后显示的文本},val表示被过滤操作的值,param1表示过滤方法调用显式传入的值
  }
})

使用语法:通过管道符号(|)

{{ 属性 | 过滤器名 | ....}}

<div v-bind:id="属性 | 过滤器名 | ....."></div>
<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8" />
		<title></title>
		<script src="js/vue.js" type="text/javascript" charset="utf-8"></script>
	</head>
	
	<body>
		
		<div id="app">
			{{msg | capitalize}}<br/>
			{{username | show}}<br />
			{{username | show1('111')}}<br />
			{{username | show2('aaa','bbb')}}
		</div>
		
		<div id="app1">
			{{msg1 | capitalize}}<br/>
            <!-- 无效,show是vm中定义的局部过滤器 -->
			{{msg1 | show}}
		</div>
	</body>
</html>

<script>
	//定义全局过滤器,在创建 Vue 实例之前
	Vue.filter('capitalize', function (value) {
	  if (!value) return ''
	  value = value.toString()
	  return value.charAt(0).toUpperCase() + value.slice(1)
	})
	
	var vm = new Vue({
		el:"#app",
		data:{
			msg:"zhangsan",
			username:'abc'
		},
		//定义局部过滤器,只能在el:"#app"中vue元素使用
		filters:{
			//定义各种过滤方法
			//语法:
			// 1)无参过滤方法:function (value) {},value表示被过滤操作的值,也就是管道符号前的属性值
			// 2)有参过滤方法:function (val,param1,param2,....) {},val表示被过滤操作的值,param1表示过滤方法调用传入的值
			show:function(val){
				return '过滤后返回的数据:'+val.charAt(0)
			},
			show1:function(val,parm){
				return '过滤后返回的数据:'+val.charAt(0)+',输入参数为:'+parm;
			},
			show2:function(val,one,two){
				return '过滤后返回的数据:'+val.charAt(0)+',输入参数为:'+one+'----'+two;
			}
		}
	});
	
	var vm1 = new Vue({
		el:"#app1",
		data:{
			msg1:"wangwu"	
		}
	});
	</script>
</script>

11.监听器的使用(熟悉)

参考文档:https://cn.vuejs.org/v2/guide/computed.html)

用于监听属性的值改变,可以获取改变前后的数据

var vm = new Vue({
  el: '#demo',
  data: {
      //定义各种属性
  },
  //定义属性监听器,监听属性改变,事件方法可以获取改变前后的值
  //只要被监听的属性值改变,就会执行监听方法,返回值
  watch: {
	 //语法:
     //data中的属性名:function(属性改变后的值,属性改变前的值){}
  }
})

参考代码:

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8" />
		<title></title>
		<script src="js/vue.js" type="text/javascript" charset="utf-8"></script>
	</head>
	
	<body>
		
		<div id="app">
			<input v-model="msg" /><br/>
			{{rs}}
		</div>
		
	</body>
</html>

<script>
	var vm = new Vue({
		el:"#app",
		data:{
			msg:"zhangsan",
			rs:''
		},
		watch:{
			//主要msg值改变就会执行当前方法,newVal表示的是msg改变后的值,oldVal是msg改变前的值
			msg:function(newVal,oldVal){
				this.rs = '本次监听msg属性改变前的值:'+oldVal+',改变后的值:'+newVal;
			}
		}
	});
	
</script>

12. 生命周期(了解)

vue是具有生命周期,通过特定方法属性控制在不同生命周期可以执行的逻辑

完整的生命周期图示:https://cn.vuejs.org/v2/guide/instance.html#%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F%E5%9B%BE%E7%A4%BA

作为后端开发者:需要掌握的就created和mounted这两个生命周期的内置方法

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8" />
		<title></title>
		<script src="js/vue.js" type="text/javascript" charset="utf-8"></script>
	</head>
	
	<body>
		
		<div id="app">
			
		</div>
	</body>
</html>

<script>
	var vm = new Vue({
		el:"#app",
            data:{

            },
            methods:{

            },
		//用于在页面加载之前执行的方法
		created(){
			//定义一些数据初始化操作(获取页面参数或获取Cookie中的数据)
			//注意:当前方法执行时,网页元素不存在,所以不能对网页元素进行操作(如,给网页表格标签内容赋值)
		},
		//用于在页面加载之后执行的方法
		mounted(){
			//定义网页初始数据的操作展示工作(请求后端获取某些数据用于页面加载时显示)
			//当前方法执行时,网页元素已经加载,所以可以对网页元素进行控制操作
		}
	});
	
</script>

Ajax:(熟悉)

Ajax:

AJAX = 异步 JavaScript 和 XML。

AJAX 是一种用于创建快速动态网页的技术。

通过在后台与服务器进行少量数据交换,AJAX 可以使网页实现异步更新。这意味着可以在不重新加载整个网页的情况下,对网页的某部分进行更新

传统的网页(不使用 AJAX)如果需要更新内容,必需重载整个网页面。

AJAX 是一种在无需重新加载整个网页的情况下,能够更新部分网页的技术。

实现步骤:

1:创建 XMLHttpRequest 对象

var xmlhttp;
if (window.XMLHttpRequest){// code for IE7+, Firefox, Chrome, Opera, Safari
  xmlhttp=new XMLHttpRequest();
}else{// code for IE6, IE5
  xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
}

2:向服务器发送请求

xmlhttp.open("GET","test1.txt",true);
xmlhttp.send();

3:服务器响应+onreadystatechange 事件

如需获得来自服务器的响应内容,请使用 XMLHttpRequest 对象的 responseText 或 responseXML 属性。

当请求被发送到服务器时,我们需要执行一些基于响应的任务。

每当 readyState 改变时,就会触发 onreadystatechange 事件。

readyState 属性存有 XMLHttpRequest 的状态信息。

下面是 XMLHttpRequest 对象的三个重要的属性:

参考代码:

xmlhttp.onreadystatechange=function(){
  if (xmlhttp.readyState==4 && xmlhttp.status==200){
      	//将后端服务器相应的文本赋值给元素元素
    	document.getElementById("myDiv").innerHTML=xmlhttp.responseText;
    }
  }

完整参考代码:

		//创建xhr对象
		var xmlhttp;
		if (window.XMLHttpRequest) { // code for IE7+, Firefox, Chrome, Opera, Safari
			xmlhttp = new XMLHttpRequest();
		} else { // code for IE6, IE5
			xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
		}
		//发送请求
		xmlhttp.open("GET", "txt/my.txt", true);
		xmlhttp.send();
		//定义响应事件
		xmlhttp.onreadystatechange = function() {
			//响应成功的处理
			if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
				//将后端服务器相应的文本赋值给元素元素
				document.getElementById("msg").innerHTML = xmlhttp.responseText;
			}
		}

ajax案例:

注册用户名异步验证

前端代码:
<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
	</head>
	<body>
		用户名:<input id="username" onblur="checkUsername()"/><span id="msg"></span><br/>
		密码:<input /><br/>
</html>
<script>
	function checkUsername() {
		//获取当前输入框数据,使用元素.value
		//获取普通标签<p>innerHTML或innerText内容</p>,使用元素.innerHTML或innerText
		var username = document.getElementById("username").value;
		//创建xhr对象
		var xmlhttp;
		if (window.XMLHttpRequest) { // code for IE7+, Firefox, Chrome, Opera, Safari
			xmlhttp = new XMLHttpRequest();
		} else { // code for IE6, IE5
			xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
		}
		//发送请求
		xmlhttp.open("GET", "http://localhost:8088/ajax/checkUsername?username="+username, true);
		xmlhttp.send();
		//定义响应事件
		xmlhttp.onreadystatechange = function() {
			//响应成功的处理
			if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
				var span = document.getElementById("msg");
				var rs =xmlhttp.responseText;
				if(rs == 'true'){//不可用
					//将后端服务器相应的文本赋值给元素元素
					span.innerHTML = "不可用";
					span.style.color="red";
				}else{
					span.innerHTML = "可用"
					span.style.color="green";
				}
			}
		}

	}
</script>
后端Servlet:
package com.yaorange.web;

import com.yaorange.entity.User;
import com.yaorange.mapper.UserMapper;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;

@WebServlet("/checkUsername")
public class UserServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String username = request.getParameter("username");
        //正常思路:调用业务方法校验用户名
        //本次:直接获取Mapper
        String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        SqlSession session = sqlSessionFactory.openSession();

        UserMapper mapper = session.getMapper(UserMapper.class);
        User user = mapper.selectUserByUsername(username);
        session.commit();
        session.close();
        if(user != null){//用户名存在
            response.getWriter().write("true");
        }else{//不存在
            response.getWriter().write("false");
        }
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws javax.servlet.ServletException, IOException {
        doPost(request,response);
    }
}

JSON:(理解,记忆格式要求)

就是一种前后端交互的文本数据格式

JSON:JavaScript 对象表示法(JavaScript Object Notation)。

JSON 是存储和交换文本信息的语法。类似 XML。

JSON 比 XML 更小、更快,更易解析。

JSON 语法规则

JSON 语法是 JavaScript 对象表示法语法的子集。

  • 数据在名称/值对
  • 数据由逗号分隔
  • 花括号保存对象
  • 方括号保存数组

JSON 名称/值对

JSON 数据的书写格式是:名称/值对。

名称/值对包括字段名称(在双引号中),后面写一个冒号,然后是值:

"firstName" : "John"

这很容易理解,等价于这条 JavaScript 语句:

firstName = "John"

JSON 值

JSON 值可以是:

  • 数字(整数或浮点数)
  • 字符串(在双引号中)
  • 逻辑值(true 或 false)
  • 数组(在方括号中)
  • 对象(在花括号中)
  • null/undefined

JSON 对象

JSON 对象在花括号中书写:

对象可以包含多个名称/值对:

{ "firstName":"John" , "lastName":"Doe" }

这一点也容易理解,与这条 JavaScript 语句等价:

firstName = "John"
lastName = "Doe"

JSON 数组

JSON 数组在方括号中书写:

数组可包含多个对象:

"employees": [
	{ "firstName":"John" , "lastName":"Doe" },
	{ "firstName":"Anna" , "lastName":"Smith" },
	{ "firstName":"Peter" , "lastName":"Jones" }
]
"strs":["aaa","bbb","ccc"]

在上面的例子中,"employees" 是包含三个对象的数组。每个对象代表一条关于某人(有姓和名)的记录。

前端解析JSON字符串

var jsonObj = "{ 'firstName':'John' , 'lastName':'Doe' }"
var obj = eval ("(" + jsonObj + ")");
//obj就是js对象值
obj.firstName//获取对象属性值

JSON 与 JS 对象的关系

很多人搞不清楚 JSON 和 JS 对象的关系,甚至连谁是谁都不清楚。其实,可以这么理解:

JSON 是 JS 对象的字符串表示法,它使用文本表示一个 JS 对象的信息,本质是一个字符串。

var obj = {a: 'Hello', b: 'World'}; //这是一个对象,注意键名也是可以使用引号包裹的`
var jsonObj = "{a: 'Hello', b: 'World'}"//这是一个字符串

类似 XML

  • JSON 是纯文本
  • JSON 具有“自我描述性”(人类可读)
  • JSON 具有层级结构(值中存在值)
  • JSON 可通过 JavaScript 进行解析
  • JSON 数据可使用 AJAX 进行传输

相比 XML 的不同之处

  • 没有结束标签
  • 更短
  • 读写的速度更快
  • 能够使用内建的 JavaScript eval() 方法进行解析
  • 使用数组
  • 不使用保留字

为什么使用 JSON?

对于 AJAX 应用程序来说,JSON 比 XML 更快更易使用:

使用 XML

  • 读取 XML 文档
  • 使用 XML DOM 来循环遍历文档
  • 读取值并存储在变量中

使用 JSON

  • 读取 JSON 字符串
  • 用 eval() 处理 JSON 字符串,转换为js对象

JSON 文件

  • JSON 文件的文件类型是 ".json"
  • JSON 文本的 MIME 类型是 "application/json"

任务:

在create中实现

使用方法eval()练习JSON对象字符串转换展示(结合vuejs的{{对象的属性名}}指令进行页面渲染展示)

'{ "firstName":"John" , "lastName":"Doe" }'

使用方法eval()练习JSON对象数组字符串转换展示(结合vuejs的v-for指令进行页面渲染展示)

'{
	"employees": [
		{ "firstName":"John" , "lastName":"Doe" },
		{ "firstName":"Anna" , "lastName":"Smith" },
		{ "firstName":"Peter" , "lastName":"Jones" }
	]
}'

Axios:(掌握)

vuejs官方推荐用于发送ajax请求的工具,类似于JQuery操作Ajax,比JQuery更加简洁

学习方法:记忆固定结构模板,明白常用属性意义

官方文档(慢慢熟悉):http://www.axios-js.com/zh-cn/docs/

特征

  • 从浏览器中创建 XMLHttpRequests
  • 从 node.js 创建 http 请求
  • 支持 Promise API(一种前端代码风格)
  • 拦截请求和响应(常用)
  • 转换请求数据和响应数据(常用)
  • 取消请求
  • 自动转换 JSON 数据(常用,将前端对象数据转换为json数据发送后端,将后端返回的json数据转换为前端对象)
  • 客户端支持防御 XSRFhttp://en.wikipedia.org/wiki/Cross-site_request_forgery)

安装:

使用 npm:

$ npm install axios

使用 cdn:

<script src="https://unpkg.com/axios/dist/axios.min.js"></script>

或者直接下载离线文件

常用语法结构(掌握,完全记忆):

可以通过向 axios 传递相关配置来创建请求

在事件处理方法中定义axios对象,自动请求后端

语法:axios(config).then(请求成功处理函数).catch(请求失败处理函数)
axios({
  method: '请求方式',//常用值:get,post,put,delete,目前只能使用get和post,在后期基于SpringBoot搭建项目后才能完全使用四种请求
  url: '请求地址',//如果配置给Axios配置了baseUrl就可以使用相对地址,否则使用绝对地址
  //通过请求体发送到后端的JOSN格式参数,对象值,地址中不可见,主要用于post,put  
  data: {
    参数名: 值,
    参数名: 值,
    ......
    参数名: 值
  },
  //通过地址发送到后端的参数,地址中可见,会将数据通过?参数名=值&参数名=值
  //如果前端想要使用基于RestFul风格的地址传值,那么只能通过在url的值直接后面拼接数据  
  params: {
    参数名: 值,
    参数名: 值,
    ......
    参数名: 值
  }
}).then((response) => {//可选结构,请求成功后处理的方法,使用response接收响应数据,自动转换格式
    //then代码是异步执行的,也就是请求发送后就自动执行结构后的代码,不会等待then代码块执行
    //标准写法then(function(error){})
    //参考文档:http://www.axios-js.com/zh-cn/docs/#%E5%93%8D%E5%BA%94%E7%BB%93%E6%9E%84
    //response.data:获取后端响应的数据
    //学习时建议使用console.log(response),查看响应数据内容,明确为什么要使用response.data

}).catch((error) => {//可选结构,请求失败后处理的方法,使用error接收异常对象
    //标准写法catch(function(error){})
    //学习时建议使用console.log(error),查看响应数据错误内容
});
//其他代码逻辑

请求的完整配置内容:(了解,记忆上面结构常用属性)

{
  // `url` 是用于请求的服务器 URL
  url: '/user',

  // `method` 是创建请求时使用的方法
  method: 'get', // 默认是 get

  // `baseURL` 将自动加在 `url` 前面,除非 `url` 是一个绝对 URL。
  // 它可以通过设置一个 `baseURL` 便于为 axios 实例的方法传递相对 URL
  baseURL: 'https://some-domain.com/api/',

  // `transformRequest` 允许在向服务器发送前,修改请求数据
  // 只能用在 'PUT', 'POST' 和 'PATCH' 这几个请求方法
  // 后面数组中的函数必须返回一个字符串,或 ArrayBuffer,或 Stream
  transformRequest: [function (data) {
    // 对 data 进行任意转换处理

    return data;
  }],

  // `transformResponse` 在传递给 then/catch 前,允许修改响应数据
  transformResponse: [function (data) {
    // 对 data 进行任意转换处理

    return data;
  }],

  // `headers` 是即将被发送的自定义请求头
  headers: {'X-Requested-With': 'XMLHttpRequest'},

  // `params` 是即将与请求一起发送的 URL 参数
  // 必须是一个无格式对象(plain object)或 URLSearchParams 对象
  params: {
    ID: 12345
  },

  // `paramsSerializer` 是一个负责 `params` 序列化的函数
  // (e.g. https://www.npmjs.com/package/qs, http://api.jquery.com/jquery.param/)
  paramsSerializer: function(params) {
    return Qs.stringify(params, {arrayFormat: 'brackets'})
  },

  // `data` 是作为请求主体被发送的数据
  // 只适用于这些请求方法 'PUT', 'POST', 和 'PATCH'
  // 在没有设置 `transformRequest` 时,必须是以下类型之一:
  // - string, plain object, ArrayBuffer, ArrayBufferView, URLSearchParams
  // - 浏览器专属:FormData, File, Blob
  // - Node 专属: Stream
  data: {
    firstName: 'Fred'
  },

  // `timeout` 指定请求超时的毫秒数(0 表示无超时时间)
  // 如果请求话费了超过 `timeout` 的时间,请求将被中断
  timeout: 1000,

  // `withCredentials` 表示跨域请求时是否需要使用凭证
  withCredentials: false, // 默认的

  // `adapter` 允许自定义处理请求,以使测试更轻松
  // 返回一个 promise 并应用一个有效的响应 (查阅 [response docs](#response-api)).
  adapter: function (config) {
    /* ... */
  },

  // `auth` 表示应该使用 HTTP 基础验证,并提供凭据
  // 这将设置一个 `Authorization` 头,覆写掉现有的任意使用 `headers` 设置的自定义 `Authorization`头
  auth: {
    username: 'janedoe',
    password: 's00pers3cret'
  },

  // `responseType` 表示服务器响应的数据类型,可以是 'arraybuffer', 'blob', 'document', 'json', 'text', 'stream'
  responseType: 'json', // 默认的

  // `xsrfCookieName` 是用作 xsrf token 的值的cookie的名称
  xsrfCookieName: 'XSRF-TOKEN', // default

  // `xsrfHeaderName` 是承载 xsrf token 的值的 HTTP 头的名称
  xsrfHeaderName: 'X-XSRF-TOKEN', // 默认的

  // `onUploadProgress` 允许为上传处理进度事件
  onUploadProgress: function (progressEvent) {
    // 对原生进度事件的处理
  },

  // `onDownloadProgress` 允许为下载处理进度事件
  onDownloadProgress: function (progressEvent) {
    // 对原生进度事件的处理
  },

  // `maxContentLength` 定义允许的响应内容的最大尺寸
  maxContentLength: 2000,

  // `validateStatus` 定义对于给定的HTTP 响应状态码是 resolve 或 reject  promise 。如果 `validateStatus` 返回 `true` (或者设置为 `null` 或 `undefined`),promise 将被 resolve; 否则,promise 将被 rejecte
  validateStatus: function (status) {
    return status >= 200 && status < 300; // 默认的
  },

  // `maxRedirects` 定义在 node.js 中 follow 的最大重定向数目
  // 如果设置为0,将不会 follow 任何重定向
  maxRedirects: 5, // 默认的

  // `httpAgent` 和 `httpsAgent` 分别在 node.js 中用于定义在执行 http 和 https 时使用的自定义代理。允许像这样配置选项:
  // `keepAlive` 默认没有启用
  httpAgent: new http.Agent({ keepAlive: true }),
  httpsAgent: new https.Agent({ keepAlive: true }),

  // 'proxy' 定义代理服务器的主机名称和端口
  // `auth` 表示 HTTP 基础验证应当用于连接代理,并提供凭据
  // 这将会设置一个 `Proxy-Authorization` 头,覆写掉已有的通过使用 `header` 设置的自定义 `Proxy-Authorization` 头。
  proxy: {
    host: '127.0.0.1',
    port: 9000,
    auth: : {
      username: 'mikeymike',
      password: 'rapunz3l'
    }
  },

  // `cancelToken` 指定用于取消请求的 cancel token
  // (查看后面的 Cancellation 这节了解更多)
  cancelToken: new CancelToken(function (cancel) {
  })
}
补充:

优化请求地址(实际开发中axios请求后端的url不建议使用绝对地址,冗余过多)

通过给axios原型设置 baseURL,让每个axios对象中url可以使用相对地址,baseURL 将自动加在配置的 url 前面

axios.defaults.baseURL = 'http://localhost:8080/';//设置前缀地址

在methods中的事件方法中通过axios请求后端中给url属性设置相对地址

参考前端页面:(因为页面不是放在后端项目的webapp中,所以后端需要配置跨域处理)
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title></title>
    <script src="js/vue.js" type="text/javascript" charset="utf-8"></script>
</head>
<body>
<div id="app">

    <button v-on:click="showGet">axios的Get请求</button><br />
    <p v-for="user in users">
        {{user.id}}--{{user.username}}--{{user.password}}--{{user.name}}
    </p>
    <br />
    <br />
    <button v-on:click="showPost">axios的Post请求</button><br />
    {{msg}}
</div>
</body>
</html>
<!-- 引入axios -->
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script>
    //优化请求
    //设置全局属性
    axios.defaults.baseURL = 'http://localhost:8088/axios'; //设置前缀地址
    axios.defaults.timeout = 5000;
    //响应拦截优化:
    /*
    axios.interceptors.response.use(function (response) {
        // 对响应数据做点什么
        //解析响应数据,让then代码块可以直接拿到后端响应的数据
        return response.data;
      }, function (error) {
        // 对响应错误做点什么
        return Promise.reject(error);
      });
      */
    //创建vue对象
    var vm = new Vue({
        el: "#app",
        data: {
            msg: '',
            users: [],
            user: { //请求体发送JSON参数,后端必须通过JSON数据操作解析,不能使用Request的getParamter接收
                username: 'zhangsan',
                password: 'zs123'
            }
        },
        methods: {
            //发起请求
            showGet() {
                axios({
                    method: 'get', //常用值:get,post,put,delete
                    url: 'axiosGet', //相对地址,完整http://localhost:8088/axios/axiosGet
					//http://localhost:8088/axios/axiosGet?username=zhangsan
                    params: { //通过地址发送到后端的参数,地址中可见,会将数据通过?参数名=值&参数名=值
                        username: 'zhangsan'
                    }
                }).then((resp) => { //可选结构,请求成功后处理的方法,使用resp接收响应数据,自动转换格式
                    console.log(resp);//resp:返回的是一个封装好的响应对象
                	//原生操作中,后端响应的数据在data属性中
                	this.users = resp.data;

                	//通过拦截器处理后then代码块中的resp对象存储的就是后端响应数据
                	//this.users = resp;

				}).catch((err) => { //响应失败时执行的代码块

                });
            },
            //发起请求
            showPost() {
                axios({
                    method: 'post', //常用值:get,post,put,delete
                    url: 'axiosPost',//完整http://localhost:8088/axios/axiosPost
                    //引用对象作为请求参数方式
                    data: this.user, //请求体发送JSON参数,后端必须通过JSON数据操作解析,不能使用Request的getParamter接收
                    // 自定义对象参数方式(一般前端data定义的对象和后端实体对象属性不一致时)
                    // data:{
                    // 	uname:this.user.username,
                    // 	pass:'zs123'
                    // }
                }).then((resp) => { //可选结构,请求成功后处理的方法,使用resp接收响应数据,自动转换格式

                    console.log(resp);
                	//resp:返回的是一个封装好的响应对象
                	//响应的数据在data属性中
                	this.msg = resp.data;

				}).catch((err) => { //响应失败时执行的代码块

                });
            }
        }
    });
</script>

JSON数据操作:

需要在后端添加fastJson的jar

<dependency>
  <groupId>com.alibaba</groupId>
  <artifactId>fastjson</artifactId>
  <version>1.2.58</version>
</dependency>

实体:

package com.yaorange.entity;

public class User {
    private Integer id;
    private String username;
    private String password;
    private String name;

	//省略getter和setter

}

补充:基于原生Servlet处理前端发送JSON字符串和响应JSON给前端

前端发送json(非地址中使用?传入),后端接收:

		//通过io流获取前端发送的json字符串数据
		StringBuffer sb = new StringBuffer() ;
        InputStream is = request.getInputStream();
        InputStreamReader isr = new InputStreamReader(is);
        BufferedReader br = new BufferedReader(isr);
        String s = "" ;
        while((s=br.readLine())!=null){
            sb.append(s) ;
        }
        String jsonStr =sb.toString();

        //将json字符串转为对象
		//添加fastjson的jar
        User user  = JSON.parseObject(jsonStr,User.class);
        /**
         1.对象与字符串之间的互转

         将对象转换成为字符串
         String str = JSON.toJSONString(obj);
         字符串转换成为对象
         InfoDo infoDo = JSON.parseObject(objStr, obj.class);
         2.对象集合与字符串之间的互转

         将对象集合转换成为字符串
         String users = JSON.toJSONString(users);
         将字符串转换成为对象集合
         List<User> userList = JSON.parseArray(userStr, User.class);  
        */

后端返回json:

		ArrayList<User> users = new ArrayList<>();
        User user = new User();
        user.setId(1);
        user.setUsername("zhangsan");
        user.setPassword("zs123");
        user.setName("张三");
        User user1 = new User();
        user1.setId(2);
        user1.setUsername("lisi");
        user1.setPassword("ls123");
        user1.setName("李四");
        users.add(user);
        users.add(user1);

        //将集合数据转换为json响应返回
        String jsonString = JSON.toJSONString(users);
        response.setCharacterEncoding("utf-8");
        response.setContentType("text/html;charset=utf-8");
        response.getWriter().write(jsonString);

基于SpringMMVC开发:

package com.yaorange.controller;

import com.yaorange.entity.User;
import org.springframework.web.bind.annotation.*;

import java.util.ArrayList;
import java.util.List;

@RestController
@RequestMapping("/axios")
//@CrossOrigin//基于注解的跨域处理
public class AxiosController {

    @GetMapping("/axiosGet")
    //使用同名参数直接接收地址?转入的参数值
    public List<User> get(String username){
        System.out.println("前端通过地址?传入参数值:"+username);
        //通过静态模拟请求数据库获取数据
        ArrayList<User> users = new ArrayList<>();
        User user = new User();
        user.setId(1);
        user.setUsername("zhangsan");
        user.setPassword("zs123");
        user.setName("张三");
        User user1 = new User();
        user1.setId(2);
        user1.setUsername("lisi");
        user1.setPassword("ls123");
        user1.setName("李四");
        users.add(user);
        users.add(user1);

        return users;
    }

    @PostMapping("/axiosPost")
    //使用注解接收前端data传入的json对象
    public String add(@RequestBody User user){
        System.out.println("前端通过data传入json对象数据:"+user);
        //省略操作后端数据库存储前端传入数据
        return "add success";
    }
}

任务:

完成前端基于axios发送ajax请求后端,后端接收处理模拟登陆效果

完成后端返回json格式对象数组数据,前端通过表格进行遍历数组对象数据展示

整理前后端登录执行代码流程(画图)

总结

本日主要学习Vue.js的入门使用,通过学习需要明白使用vue.js可以帮助简化的操作功能,理解vue.js在vm层中的意义

在前后端分离开发中:

vue.js作为前端视图(view)和后端数据(model)之间作为一个桥梁的作用

在以后工作中:需要同学们自行加深vue.js的学习

官方教程文档:https://cn.vuejs.org/v2/guide/

官方API:https://cn.vuejs.org/v2/api/,在使用他人开发好的模板时,可以借助文档理解意义

其他教程:https://www.runoob.com/vue2/vue-tutorial.html

面试题:(二升三面试)

1. 说一下Vue的优点

体积小,更高的运行效率,双向数据绑定,生态丰富、学习成本低

2. v-show和v-if的共同点和不同点?

共同点:都能控制元素的显示和隐藏;

不同点:

实现本质方法不同,v-show本质就是通过控制css中的display设置为none,控制隐藏,只会编译一次;

v-if是动态的向DOM树内添加或者删除DOM元素,若初始值为false,就不会编译了。而且v-if不停的销毁和创建比较消耗性能。

总结:如果要频繁切换某节点,使用v-show(切换开销比较小,初始开销较大)。如果不需要频繁切换某节点使用v-if(初始渲染开销较小,切换开销比较大)。

3. 计算属性compoter和侦听属性watch的区别

computed用于处理复杂的逻辑运算,主要和methods储存方法来进行区分;methods储存方法,computed储存需要处理的数据值;methods每次都会调用,computed有缓存机制,只有改变时才执行,性能更佳;

watch顾名思义,用于监听数据变化,其中可以监听的数据来源有三部分:props、data、computed内的数据;watch提供两个参数(newValue,oldValue),第一个参数是新值,第二个参数保存旧值;

区别:

计算属性computed :

支持缓存,只有依赖数据发生改变,才会重新进行计算

不支持异步,当computed内有异步操作时无效,无法监听数据的变化

computed 属性值会默认走缓存,计算属性是基于它们的响应式依赖进行缓存的,也就是基于data中声明过的数据通过计算得到的

如果一个属性是由其他属性计算而来的,这个属性依赖其他属性,是一个多对一或者一对一,一般用computed

如果computed属性属性值是函数,那么默认会走get方法;函数的返回值就是属性的属性值;在computed中的,属性都有一个get和一个set方法,当数据变化时,调用set方法。

侦听属性watch:

不支持缓存,数据变,直接会触发相应的操作;

watch支持异步;

监听的函数接收两个参数,第一个参数是最新的值;第二个参数是输入之前的值;

当一个属性发生变化时,需要执行对应的操作;一对多;

4. 生命周期函数

vue 实例有一个完整的生命周期,也就是从开始创建、初始化数据、编译模板、挂载Dom→渲染、更新→渲染、卸载等一系列过程,我们称这是 Vue 的生命周期。通俗说就是 Vue 实例从创建到销毁的过程,就是生命周期。

钩子函数 描述

beforeCreate 在实例初始化之后,数据观测(data observer)和 event/watch事件配置之前被调用

created 在实例创建完成后立即被调用,在这一步实例已经完成了:数据观测、属性和方法的运算和 event/watch事件的回调,但是$el属性目前不可见,还无法操作dom。

beforeMount 在挂载开始之前被调用

mounted 在挂载成功后被调用,el被新创建的vm.$el替换,已经可以操作dom

beforeUpdate 数据更新之前调用

update 数据更新完成时调用,组件dom已经更新

activated 组件被激活时调用

deactivated 组件被移除时调用

beforeDestory 组件销毁前调用

destoryed 组件销毁后调用

5. 什么是MVVM?

MVVM是Model-View-ViewModel的缩写。MVVM是一种设计思想。Model 层代表数据模型,也可以在Model中定义数据修改和操作的业务逻辑;View 代表UI 组件,它负责将数据模型转化成UI 展现出来,ViewModel 是一个同步View 和 Model的对象。

在MVVM架构下,View 和 Model 之间并没有直接的联系,而是通过ViewModel进行交互,Model 和 ViewModel 之间的交互是双向的, 因此View 数据的变化会同步到Model中,而Model 数据的变化也会立即反应到View 上。

ViewModel 通过双向数据绑定把 View 层和 Model 层连接了起来,而View 和 Model 之间的同步工作完全是自动的,无需人为干涉,因此开发者只需关注业务逻辑,不需要手动操作DOM, 不需要关注数据状态的同步问题,复杂的数据状态维护完全由 MVVM 来统一管理。

6. mvvm和mvc区别?

mvc和mvvm其实区别并不大。都是一种设计思想。主要就是mvc中Controller演变成mvvm中的viewModel。mvvm主要解决了mvc中大量的DOM 操作使页面渲染性能降低,加载速度变慢,影响用户体验。

7. 为什么避免v-if 和 v-for 用在一起

当Vue 处理指令时,v-for 比 v-if 具有更高的优先级,通过v-if 移动到容器元素,不会再重复遍历列表中的每个值。取而代之的是,我们只检查它一次,且不会在 v-if 为否的时候运算 v-for。

8. vue常用的修饰符?

事件修饰符

.prevent: 阻止默认事件(在指定的事件后进行默认事件的阻止);

.stop: 阻止单击事件冒泡(在指定事件后阻止事件冒泡,阻止指定在最内层事件的标签里);

.self: 当事件发生在该元素本身而不是子元素的时候会触发;

.capture: 事件侦听,事件发生的时候会调用

.once:控制元素指定的事件只执行一次

表单元素修饰符

.number:能够强制的指定表单元素的内容数据类型是number

.trim:能够去除输入内容左右两边的空格

.lazy:只有标签的change事件执行后才会执行数据的双向绑定

9. let、var、const之间的区别

1)var定义的变量,没有块的概念,可以跨块访问, 不能跨函数访问。

2)let定义的变量,只能在块作用域里访问,不能跨块访问,也不能跨函数访问。

3)const用来定义常量,使用时必须初始化(即必须赋值),只能在块作用域里访问,而且不能修改。

posted @ 2022-01-04 22:12  恸的池塘  阅读(81)  评论(0编辑  收藏  举报