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,国内还没发现哪一家比较好,目前还是建议下载到本地。
- Staticfile CDN(国内) : https://cdn.staticfile.org/vue/2.2.2/vue.min.js
- unpkg:https://unpkg.com/vue/dist/vue.js, 会保持和 npm 发布的最新的版本一致。
- cdnjs : https://cdnjs.cloudflare.com/ajax/libs/vue/2.1.8/vue.min.js
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>
总结:
-
在网页中被标识为Vue容器的元素中进行插入数据使用语法{{data中的属性名}},该语法可以插入标签文本,输出真正的 HTML,那么需要在html标签中借助v-html指令实现输出(该指令底层是基于innerHTML),如果想要给标签属性插入值,需要借助v-bind指令
-
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-if
和 v-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用来定义常量,使用时必须初始化(即必须赋值),只能在块作用域里访问,而且不能修改。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· 终于写完轮子一部分:tcp代理 了,记录一下
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理