认识Vue
Vue.js是一套用于构建用户界面的渐进式javascript框架。
渐进式框架:说明vue.js的轻量,是指一个前端项目可以使用vue.js一两个特性也可以整个项目都用vue.js。
Vue 不支持 IE8 及以下版本,因为 Vue 使用了 IE8 无法模拟的 ECMAScript 5 特性。在使用vue之前,先将IDEA中JavaScript语法的版本指定为ECMAScript5以上。
Vue功能的认识
- 声明式渲染
Vue.js 的核心是一个允许采用简洁的模板语法来声明式地将数据渲染进 DOM 的系统。
比如:使用vue.js的插值表达式放在Dom的任意地方,差值表达式的值将被渲染在Dom中。
- 条件与循环
dom中可以使用vue.js提供的v-if、v-for等标签,方便对数据进行判断、循环。 - 双向数据绑定
Vue 提供v-model指令,它可以轻松实现Dom元素和数据对象之间双向绑定,即修改Dom元素中的值自动修改绑定的数据对象,修改数据对象的值自动修改Dom元素中的值。 - 处理用户输入
为了让用户和你的应用进行交互,我们可以用 v-on 指令添加一个事件监听器,通过它调用在 Vue 实例中定义的方法
Vue的优点
- 体积小
- 更高的运行效率
基于虚拟的dom,一种可以预先通过JavaScript进行各种计算,把最终的DOM操作计算出来并优化的技术,由于这个DOM操作属于预处理操作,并没有真实的操作DOM,所以叫做虚拟DOM - 双向数据绑定
让开发者不用再去操作dom对象,把更多的精力投入到业务逻辑上 - 生态丰富、学习成本低
市场上拥有大量成熟、稳定的基于vue.js的ui框架、常用组件!拿来即用实现快速开发!
了解两种模式
- MVVM框架
MVVM拆分解释为:将视图 UI 和业务逻辑分开
Model:负责数据模型和业务模型 (开发人员要进行相关的代码开发)
View:负责页面展示数据 (view负责页面数据的渲染
View Model: 模型和视图之间的双向操作(无需开发人员进行代码开发)
MVVM要解决的问题是将业务逻辑代码与视图代码进行完全分离,使各自的职责更加清晰,后期代码维护更加简单。
- MVC框架
模型-视图-控制器
MVC开始是存在于桌面程序中的,M是指业务模型,V是指用户界面,C则是控制器,使用MVC的目的是将M和V的实现代码分离,从而使同一个程序可以使用不同的表现形式。比如一批统计数据可以分别用柱状图、饼图来表示。C存在的目的则是确保M和V的同步,一旦M改变,V应该同步更新。
Vue的入门开发程序
编写HTML文件必须要引入vue脚本
编写vue入门:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>hello-vue</title>
</head>
<body>
<div id="app">
标签获取数据模型绑定数据<br>
{{name}}
<p>
{{sex}}
</p>
</div>
<script src="vue/vue-v2.6.10.js"></script>
<!--js vue 数据模型层 -->
<script>
// 获取 vue 对象 json
var vue = new Vue({
el:"#app", // el 绑定页面标签
// 数据模型声明
data:{
name:'你好 ',
age:12,
sex:'male'
}
})
</script>
</body>
</html>
Vue() 对象 里面两个参数 : el和 data
el : 需要获取的页面标签名
data: 展示的数据 格式: {} js对象形式
el
每个Vue实例都需要关联一段Html模板,Vue会基于此模板进行视图渲染。我们可以通过el属性来指定。
例如一段html模板:
然后创建Vue实例,关联这个div
这样,Vue就可以基于id为app的div元素作为模板进行渲染了。在这个div范围以外的部分是无法使用vue特性的。
数据data
当Vue实例被创建时,它会尝试获取在data中定义的所有属性,用于视图的渲染,并且**监视**data中的属性变化,当data发生改变,所有相关的视图都将重新渲染,这就是“响应式“系统。html:
js:
name的变化会影响到div标签内{ {} }的值
方法methods
Vue实例中除了可以定义data属性,也可以定义方法,并且在Vue的作用范围内使用。
一般方法都会和对应的事件绑定:
语法格式: v-on:click="函数名称"
效果:点击事件触发对应的函数
Vue指令----单向绑定
- 插值表达式
一般用来获取vue数据模型中定义的数据
语法:{ {} }
- 该表达式支持JS语法,可以调用js内置函数(必须有返回值)如:new Date()
- 表达式必须有返回结果,例如 1 + 1。没有结果的表达式不允许使用,如:var a = 1 + 1。
- 可以直接获取Vue实例中定义的数据或函数
- 插值表达式 不可以使用在标签内的属性值上 一定注意!
<!DOCTYPE html>
<html lang="en" xmlns:v-on="http://www.w3.org/1999/xhtml">
<head>
<meta charset="UTF-8">
<title>test</title>
</head>
<body>
<div id="app" >
<!--插值表达式 可以支持数学和逻辑运算-->
{{1+1}}
{{1==1?'true':'false'}}
<br>
<!--插值表达式可以支持js内置函数-->
{{new Date()}}
<br>
<!--获取数据模型中数据-->
{{name}}
</div>
<script src="../js/vue.js"></script>
<!--js vue 数据模型层 -->
<script>
var vue = new Vue({
el:"#app",
data:{name:'黑马程序员'}
})
</script>
</body>
</html>
测试效果:
小结: 插值表达式一般用来获取数据模型中对应的数据,要求书写在标签体中 ,不可以出现在标签的属性中!
举例: 在上面的题目中: div 标签 添加一个属性 aa=’’{{name}}"
- v-text和v-html
标签显示文本数据, 我们也可以使用v-text和v-html指令来替代{ {} }
v-text=“数据模型定义的数据”
v-html=“数据模型定义的数据”
说明:
- v-text: 将数据输出到元素内部,如果输出的数据有HTML代码,会作为**普通文本输出
- v-html:将数据输出到元素内部,如果输出的数据有HTML代码,会**被渲染
<html lang="en" xmlns:v-on="http://www.w3.org/1999/xhtml">
<head>
<meta charset="UTF-8">
<title>test</title>
</head>
<body>
<div id="app" >
v-html:<span v-html="hello"></span>
<br>
v-text:<span v-text="hello"></span>
</div>
<script src="../js/vue.js"></script>
<!--js vue 数据模型层 -->
<script>
var vue = new Vue({
el:"#app",
data:{hello:'<h1>大家好,我是刘德华</h1>'}
})
</script>
</body>
</html>
小结: v-text 或者 v-html 一般都使用在页面标签,用于显示标签文本或html片段!
v-bind:属性名或:属性名
v-bind 用于将vue的值绑定给对应dom的属性值 主要用于对标签的元素属性赋值语法:
v-bind:元素属性名="数据模型定义的初始数据"
// 简化语法
:元素属性名="数据模型定义的初试数据"
实例:
<!DOCTYPE html>
<html lang="en" xmlns:v-on="http://www.w3.org/1999/xhtml" xmlns:v-bind="http://www.w3.org/1999/xhtml">
<head>
<meta charset="UTF-8">
<title>test</title>
</head>
<body>
<div id="app" >
固定跳转
<a href="http://www.baidu.com">百度</a><br>
动态跳转
<a v-bind:href="forwardUrl">{{forwardTitle}}</a><br>
<br>
原始语法如下:
<div v-bind:hidden="hiddenValue">v-bind test</div><br>
简化写法
<div :hidden="hiddenValue">v-bind test</div>
</div>
<script src="../js/vue.js"></script>
<!--js vue 数据模型层 -->
<script>
var vue = new Vue({
el:"#app",
data: {
hiddenValue:false, // 页面元素不影藏 , 如果是true表示隐藏页面元素
forwardUrl:"http://www.baidu.com",
forwardTitle:"百度"
}
})
</script>
</body>
</html>
双向绑定
v-text和v-html可以看做是单向绑定,数据影响了视图渲染,但是反过来就不行。接下来学习的v-model是双向绑定,视图(View)和模型(Model)之间会互相影响。
语法:
v-model=“vue中data的属性”
目前v-model的可使用元素有: 作用范围
- input
- select
- textarea
- checkbox
- radio
- components(Vue中的自定义组件)
基本上除了最后一项,其它都是表单的输入项。
<!DOCTYPE html>
<html lang="en" xmlns:v-on="http://www.w3.org/1999/xhtml">
<head>
<meta charset="UTF-8">
<title>test</title>
</head>
<body>
<div id="app" >
<input v-model="name"/>
<div>
你输入了{{name}}
</div>
<hr>
<input type="radio" name="sex" value="male" v-model="sex"> 男性
<input type="radio" name="sex" value="female" v-model="sex"> 女性
<div>
你选择了{{sex}}
</div>
<hr>
<div>
<select name="xueli" v-model="xueli">
<option value="chuzhong">初中</option>
<option value="gaozhong">高中</option>
<option value="daxue">大学</option>
<option value="boshi">博士</option>
</select>
</div>
<div>
你选择了{{xueli}}
</div>
<hr>
<input type="checkbox" v-model="ischecked" />是否选中<br/>
单选框:{{ischecked}}
<hr>
<input type="checkbox" v-model="language" value="Java" />Java<br/>
<input type="checkbox" v-model="language" value="PHP" />PHP<br/>
<input type="checkbox" v-model="language" value="GO" />GO<br/>
<div>
多选框:{{language}}
</div>
</div>
<script src="../js/vue.js"></script>
<!--js vue 数据模型层 -->
<script>
var vue = new Vue({
el:"#app",
data:{
name:"xiaoli",
sex:"male",
xueli:"boshi",
language: [],// 对于多选框 我们用数组array来接受多个选项值!
ischecked: true // 对于一个选项框: boolean 来定义
}
})
</script>
</body>
</html>
小结:
- 页面展示的数据,来源于我们的数据模型 data定义
- 多个checkbox对应一个model时,model的类型是一个数组,单个checkbox值是boolean类型
- radio对应的值是input的value值
- input 和textarea 默认对应的model是字符串
- select单选对应字符串,多选对应也是数组
事件绑定(v-on或@)
v-on指令用于给页面元素绑定事件 语法:格式
v-on:事件名="js片段或函数名"
缩写:
@事件名="js片段或函数名"
例如:v-on:click=‘add’ 可以简写为 @click=‘add’
<!DOCTYPE html>
<html lang="en" xmlns:v-on="http://www.w3.org/1999/xhtml">
<head>
<meta charset="UTF-8">
<title>test</title>
</head>
<body>
<div id="app" >
<!--事件中,简单js片段可以直接写-->
<button @click="crement">增加</button>
<!--事件中复制逻辑可以调用函数-->
<button @click="decrement">减少</button>
<h1>{{num}}</h1>
</div>
<script src="../js/vue.js"></script>
<!--js vue 数据模型层 -->
<script>
var vue = new Vue({
el:"#app",
data:{
num:0
},
methods:{
decrement:function () {
num--;
},
crement:function () {
num++;
}
}
})
</script>
</body>
</html>
运行效果:
遍历数组---(v-for)
语法:v-for="item in items"- items:要遍历的数组需要在vue的data中定义好
- item:迭代得到的数组元素别名
<!DOCTYPE html>
<html lang="en" xmlns:v-on="http://www.w3.org/1999/xhtml">
<head>
<meta charset="UTF-8">
<title>v-for</title>
</head>
<body>
<div id="app">
<!--遍历数组 -->
<table width="100%" border="1px">
v-for位置:在需要遍历的元素父元素中书写
<tr v-for="user in users">
<td >{{user.name}}</td>
<td v-text="user.gender"></td>
<td v-text="user.age"></td>
</tr>
</table>
</div>
<script src="../js/vue.js"></script>
<!--js vue 数据模型层 -->
<script>
var app = new Vue({
el: "#app",
data:{
// 定义数组对象 遍历的数据源
users:[
{name:'柳岩', gender:'女', age: 20},
{name:'有哥', gender:'男', age: 30},
{name:'范冰冰', gender:'女', age: 24},
{name:'刘亦菲', gender:'女', age: 18},
{name:'古力娜扎', gender:'女', age: 25}
]
}
});
</script>
</body>
</html>
运行测试:
遍历数组---(v-for)
语法: v-for="(item,index) in items"- items:要迭代的数组
- item:迭代得到的数组元素别名
- index:迭代到的当前元素索引,从0开始。
<!DOCTYPE html>
<html lang="en" xmlns:v-on="http://www.w3.org/1999/xhtml">
<head>
<meta charset="UTF-8">
<title>test</title>
</head>
<body>
<div id="app" >
<table width="100%" border="1px">
<tr v-for="(user,index) in users">
<!--<td >{{index+1}}</td> 或者下面写法 -->
<td v-text="index+1"></td>
<td v-text="user.name"></td>
<td v-text="user.age"></td>
<td v-text="user.gender"></td>
</tr>
</table>
</div>
<script src="../js/vue.js"></script>
<!--js vue 数据模型层 -->
<script>
var vue = new Vue({
el:"#app",
data:{
// 定义数组对象 遍历的数据源
users:[
{name:'柳岩', gender:'女', age: 20},
{name:'有哥', gender:'男', age: 30},
{name:'范冰冰', gender:'女', age: 24},
{name:'刘亦菲', gender:'女', age: 18},
{name:'古力娜扎', gender:'女', age: 25}
]
}
})
</script>
</body>
</html>
运行测试:
.v-if &v-else 使用
v-if,顾名思义,条件判断。当得到结果为true时,所在的元素才会被渲染。语法:
v-if="布尔表达式"
v-else
<!DOCTYPE html>
<html lang="en" xmlns:v-on="http://www.w3.org/1999/xhtml">
<head>
<meta charset="UTF-8">
<title>test</title>
</head>
<body>
<div id="app" >
<div @click="flag=!flag">
点击我试试
</div>
<p v-if="flag">你好 黑马程序员</p>
<p v-else>你好 传智播客</p>
</div>
<script src="../js/vue.js"></script>
<!--js vue 数据模型层 -->
<script>
var vue = new Vue({
el:"#app",
data:{
flag: true
}
})
</script>
</body>
</html>
运行结果:
v-else-if嵌套(了解)
v-else-if,顾名思义,充当v-if 的“else-if 块”,可以连续使用:
<div id="app" >
<div v-if="type=='A'">
A
</div>
<div v-else-if="type=='B'">
B
</div>
<div v-else-if="type=='C'">
C
</div>
<div v-else>
Not A/B/C
</div>
</div>
<script>
var vue = new Vue({
el:"#app",
data:{
type:"D"
}
})
</script>
类似于 v-else,v-else-if 也必须紧跟在带 v-if 或者v-else-if 的元素之后。
Vue生命周期
-
每个 Vue 实例在被创建时都要经过一系列的初始化过程 :创建实例,装载模板,渲染模板等等。
-
Vue为生命周期中的每个状态都设置了监听函数。
-
每当Vue实例处于不同的生命周期时,对应的函数就会被触发调用。
-
vue的生命周期中具体做了什么事情我们通常不需要关心,我们只要关注生命周期的8个监听函数。
生命周期流程图:
上图描述了详细的Vue对象的整个生命周期,这里我们提取出里面重点的地方,简化为下面这个流程图:
监听函数
vue的整个生命周期中,提供了8个监听函数,以便我们可以在某个生命周期段根据需要做相应的操作: -
beforeCreate:在vue实例创建前调用
-
created:在vue实例创建后调用,这个监听函数是最常用的,这个时候会初始化data数据,通常去后端取数据;
-
beforeMount:在挂载开始之前被调用 。 什么是挂载?可以将vue对象和视图模板进行关联的过程看作是挂载
-
mounted:挂载到实例上去之后调用
-
beforeUpdate:数据更新时调用,发生在虚拟 DOM 重新渲染和打补丁之前
-
updated:由于数据更改导致的虚拟 DOM 重新渲染和打补丁,在这之后会调用该钩子
-
beforeDestroy:实例销毁之前调用。在这一步,vue实例仍然完全可用。
-
destroyed:Vue 实例销毁后调用。调用后,Vue 实例指示的所有东西都会解绑定,所有的事件监听器会被移除,所有的子实例也会被销毁。
简单的案例演示:
<!DOCTYPE html>
<html lang="en" xmlns:v-on="http://www.w3.org/1999/xhtml">
<head>
<meta charset="UTF-8">
<title>test</title>
</head>
<body>
<div id="app">
<h1>{{message}}</h1>
</div>
<script src="js/vue.js"></script>
<!--js vue 数据模型层 -->
<script type="text/javascript">
var vue = new Vue({
el: '#app',
data: {
message: "we are 伐木累!"
},
beforeCreate: function () {
console.group('beforeCreate 创建前状态===============》');
console.log("%c%s", "color:red", "el : " + this.$el); //undefined
console.log("%c%s", "color:red", "data : " + this.$data); //undefined
console.log("%c%s", "color:red", "message: " + this.message)
},
created: function () {
console.group('created 创建完毕状态===============》');
console.log("%c%s", "color:red", "el : " + this.$el); //undefined
console.log("%c%s", "color:red", "data : " + this.$data); //已被初始化
console.log("%c%s", "color:red", "message: " + this.message); //已被初始化
},
beforeMount: function () {
console.group('beforeMount 挂载前状态===============》el');
console.log(this.$el);
console.log("%c%s", "color:red", "data : " + this.$data); //已被初始化
console.log("%c%s", "color:red", "message: " + this.message); //已被初始化
},
mounted: function () {
console.group('mounted 挂载结束状态===============》');
console.log(this.$el); //已被挂载,就是当前指向的el元素
console.log("%c%s", "color:red", "data : " + this.$data); //已被初始化
console.log("%c%s", "color:red", "message: " + this.message); //已被初始化
},
beforeUpdate: function () {
console.log('beforeUpdate 即将更新渲染=');
console.log("%c%s", "color:red", "el : " + this.$el);
console.log(this.$el);
console.log("%c%s", "color:red", "data : " + this.$data);
console.log(this.$data);
console.log("%c%s", "color:red", "message: " + this.message);
},
updated: function () {
console.group('updated 更新完成状态===============》');
console.log("%c%s", "color:red", "el : " + this.$el);
console.log(this.$el);
console.log("%c%s", "color:red", "data : " + this.$data);
console.log(this.$data);
console.log("%c%s", "color:red", "message: " + this.message);
},
beforeDestroy: function () {
console.group('beforeDestroy 销毁前状态===============》');
console.log("%c%s", "color:red", "el : " + this.$el);
console.log(this.$el);
console.log("%c%s", "color:red", "data : " + this.$data);
console.log("%c%s", "color:red", "message: " + this.message);
},
destroyed: function () {
console.group('destroyed 销毁完成状态===============》');
console.log("%c%s", "color:red", "el : " + this.$el);
console.log(this.$el);
console.log("%c%s", "color:red", "data : " + this.$data);
console.log("%c%s", "color:red", "message: " + this.message)
}
})
</script>
</body>
</html>
运行效果:
当在控制台输入一个data数据 更改message 值是,此事 beforeUpdate 和 update 钩子方法触发
回车 此时的$el 是虚拟的dom 对象 会立刻更新为 hello heima ! 页面view还未更新最新的数据。
等到update 方法执行 会实现页面view 的数据更新
小结: 了解生命周期,掌握常用的 created方法! 可以理解 页面标签数据初始化之前执行的方法!
通常在此方法中,我们发起后台数据请求,在渲染页面标签数据之前,先获取后台数据,进行data 数据的模型赋值!
this对象的说明
我们可以看下在vue内部的this变量是谁,我们在created的时候,打印thisvar vue = new Vue({
el:"#app",
data:{
hello: '' // hello初始化为空
},
created(){
thishello = "hello, world! 我出生了!";
console.log(this);
}
})
控制台的输出:
总结:
this就是当前的Vue实例,在Vue对象内部,必须使用this才能访问到Vue中定义的data内属性、方法等
HTTP请求与HTTP报文
使用浏览器查看HTTP请求
HTTP请求传参方式:
一个完整的HTTP报文分为请求报文(Request)和返回报文(Response),这里我们主要讲解请求报文。请求报文又都分为请求头(header)和请求体(body),如下图所示。
HTTP请求的传参方式很多,做网站的主要传参方式有:URL传参和请求体传参
Url传参
URL传参就是将请求拼接在URL后面,传送到服务器。- 格式:
http://xxx.xxx.com?param1=xxx¶m2=xxx - 缺点:
http协议对url长度是没有限制的,但是无论浏览器还是后端服务器(nginx、tomcat等)都会限制url的长度,所以URL传参会有参数长度限制问题。
请求体传参
请求体可以用于传输任何可以二进制表示的数据。 服务端如何区分Http body里存的是什么内容?- http请求头Content-type用来指定body中的数据格式
- 例如:
application/json:json数据格式
application/x-www-form-urlencoded :表单默认的提交数据的格式
multipart/form-data : 需要在表单中进行文件上传时,可以使用该格式
GET与POST
- 什么是幂等操作?
- 可以简单理解为,可以重复多次操作,不会影响服务器状态(主要是数据),一般都是查询操作。
- 如何判断应该使用POST还是GET?
- 一般查询操作使用GET请求
- 其他操作(创建、删除、更新)使用POST,在RESTFul风格,删除用DELETE、更新用PUT
axios使用
axios是对ajax技术的一种封装,就像jQuery实现ajax封装一样。简单来说: ajax技术实现了网页的局部数据刷新,axios实现了对ajax的封装。
axios各种传参方式
- GET请求(URL传参)
两种使用方法: - axios.get(url).then((response)=>{}) ;
- axios.get(url,{ params:实际参数}).then((response)=>{}) ;
以用户登录请求为例,我们可以通过两种方式传参,如下:
// 方式一
axios.get("/vuedemo/user?username=admin&password=123").then((response) => {
//处理返回结果
});
// 方式二,axios会自动将第二个参数里的username和password拼接到URL后面,效果等同于方式一
axios.get("/vuedemo/user",{ params: {"username":"admin","password":"123"}}).then((response) => {
//操作返回结果
});
后端Controller的参数接收方式也有两种,效果相同:
String username = request.getParameter(“username”);
String password = request.getParameter(“password”);
- POST请求(URL传参|Body传参)
三种使用方法:
- axios.post(url).then((response)=>{}) ; //请求体为空
- axios.post(url,body).then((response)=>{}) ; //携带请求体,默认是JSON请求
- axios.post(url,body,config).then((response)=>{}) ; //可以通过config进行更多的配置,例如设置请求头
场景一:URL传参
前端:
axios.post("/vuedemo/user?username=admin&password=123").then((response) => {
//处理返回结果
});
后端Controller的参数接收方式与GET请求的URL传参方式相同,如下:
String username = request.getParameter("username");
String password = request.getParameter("password");
场景二:表单提交(Body传参)
axios默认发送的请求是JSON请求,如果使用axios进行进行一个表单请求要怎么处理呢?这里还是举一个登录的例子:
// axios默认发送请求的content-type为application/json
//所以发送表单请求,则需要指定content-type为application/x-www-form-urlencoded
axios.post("/vuedemo/user", "username=admin&password=123", {
headers: {'content-type': 'application/x-www-form-urlencoded'},
}).then((response) => {
//处理返回结果
});
这种情况下,后端Controller的参数接收方式,和URL传参的后端接收方式相同,不再赘述。
场景三:JSON提交(Body传参)
前端代码:
axios.post("/vuedemo/user", {"username":"xxx","password":"xxx"}).then((response) => {
//处理返回结果
});
后端Controller的参数接收方式:
```html
public class LoginParam {
private String username;
private String password;
// setter
// getter
// 构造方法
}
LoginParam loginParam = JSON.parseObject(request.getInputStream(),LoginParam.class);
System.out.println(loginParam);
结论:只要确定前端传递的是JSON时,后端肯定要用流来接收,其他都是正常接收。
axios返回值
这里以get请求为例,axios的返回值获取方式如下所示:axios.get("http://xxxxxxxxx").then((response)=>{
//response.data就是服务器端返回的内容(例如json)
console.log(response.data);
}).catch((error)=>{
console.log(error);
this.$message.error("网络异常");
});