Vue.js基本语法:声明式渲染
概念
声明式
『声明式』是相对于『编程式』而言的。
- 声明式:告诉框架做什么,具体操作由框架完成
- 编程式:自己编写代码完成具体操作
demo
HTML代码
<!-- 使用{{}}格式,指定要被渲染的数据 -->
<div id="app">{{message}}</div>
vue代码
// 1.创建一个JSON对象,作为new Vue时要使用的参数
var argumentJson = {
// el用于指定Vue对象要关联的HTML元素。el就是element的缩写
// 通过id属性值指定HTML元素时,语法格式是:#id
"el":"#app",
// data属性设置了Vue对象中保存的数据
"data":{
"message":"Hello Vue!"
}
};
// 2.创建Vue对象,传入上面准备好的参数
var app = new Vue(argumentJson);
查看声明式渲染的响应式效果
通过验证Vue对象的『响应式』效果,看到Vue对象和页面上的HTML标签确实是始终保持着关联的关系,同时看到Vue在背后确实是做了大量的工作。
Vue.js基本语法:绑定元素属性
1、基本语法
v-bind:HTML标签的原始属性名
2、demo
①HTML代码
<div id="app">
<!-- v-bind:value表示将value属性交给Vue来进行管理,也就是绑定到Vue对象 -->
<!-- vueValue是一个用来渲染属性值的表达式,相当于标签体中加{{}}的表达式 -->
<input type="text" v-bind:value="vueValue" />
<!-- 同样的表达式,在标签体内通过{{}}告诉Vue这里需要渲染; -->
<!-- 在HTML标签的属性中,通过v-bind:属性名="表达式"的方式告诉Vue这里要渲染 -->
<p>{{vueValue}}</p>
</div>
②Vue代码
// 创建Vue对象,挂载#app这个div标签
var app = new Vue({
"el":"#app",
"data":{
"vueValue":"太阳当空照"
}
});
3、小结
本质上,v-bind:属性名=”表达式”它们都是用Vue对象来渲染页面。只不过:
- 文本标签体:使用形式
- 属性:使用v-bind:属性名=”表达式”形式
Vue.js基本语法:双向数据绑定
提出问题
而使用了双向绑定后,就可以实现:页面上数据被修改后,Vue对象中的数据属性也跟着被修改。
demo
HTML代码
<div id="app">
<!-- v-bind:属性名 效果是从Vue对象渲染到页面 -->
<!-- v-model:属性名 效果不仅是从Vue对象渲染到页面,而且能够在页面上数据修改后反向修改Vue对象中的数据属性 -->
<input type="text" v-model:value="vueValue" />
<p>{{vueValue}}</p>
</div>
Vue代码
// 创建Vue对象,挂载#app这个div标签
var app = new Vue({
"el":"#app",
"data":{
"vueValue":"太阳当空照"
}
});
效果:
去除前后空格
:value可以省略
<input type="text" v-model="vueValue" />
.trim修饰符
实际开发中,要考虑到用户在输入数据时,有可能会包含前后空格。而这些前后的空格对我们程序运行来说都是干扰因素,要去掉。在v-model后面加上.trim修饰符即可实现。
<input type="text" v-model.trim="vueValue" />
Vue会帮助我们在文本框失去焦点时自动去除前后空格。
Vue.js基本语法:条件渲染
v-if
HTML代码
<div id="app">
<h3>if</h3>
<img v-if="flag" src="/pro03-vue/./images/one.jpg" />
<img v-if="!flag" src="/pro03-vue/./images/two.jpg" />
</div>
Vue代码
var app = new Vue({
"el":"#app",
"data":{
"flag":true
}
});
v-if和v-else
<div id="app02">
<h3>if/else</h3>
<img v-if="flag" src="/pro03-vue/./images/one.jpg" />
<img v-else="flag" src="/pro03-vue/./images/two.jpg" />
</div>
Vue代码
var app02 = new Vue({
"el":"#app02",
"data":{
"flag":true
}
});
v-show
HTML代码
<div id="app03">
<h3>v-show</h3>
<img v-show="flag" src="/pro03-vue/./images/mi.jpg" />
</div>
Vue代码
var app03 = new Vue({
"el":"#app03",
"data":{
"flag":true
}
});
Vue.js基本语法:列表渲染
HTML代码
<div id="app01">
<ul>
<!-- 使用v-for语法遍历数组 -->
<!-- v-for的值是语法格式是:引用数组元素的变量名 in Vue对象中的数组属性名 -->
<!-- 在文本标签体中使用{{引用数组元素的变量名}}渲染每一个数组元素 -->
<li v-for="fruit in fruitList">{{fruit}}</li>
</ul>
</div>
Vue代码
var app01 = new Vue({
"el":"#app01",
"data":{
"fruitList": [
"apple",
"banana",
"orange",
"grape",
"dragonfruit"
]
}
});
迭代一个对象数组
HTML代码
<div id="app">
<table>
<tr>
<th>编号</th>
<th>姓名</th>
<th>年龄</th>
<th>专业</th>
</tr>
<tr v-for="employee in employeeList">
<td>{{employee.empId}}</td>
<td>{{employee.empName}}</td>
<td>{{employee.empAge}}</td>
<td>{{employee.empSubject}}</td>
</tr>
</table>
</div>
Vue代码
var app = new Vue({
"el":"#app",
"data":{
"employeeList":[
{
"empId":11,
"empName":"tom",
"empAge":111,
"empSubject":"java"
},
{
"empId":22,
"empName":"jerry",
"empAge":222,
"empSubject":"php"
},
{
"empId":33,
"empName":"bob",
"empAge":333,
"empSubject":"python"
}
]
}
});
Vue.js基本语法:事件驱动
demo:字符串顺序反转
HTML代码
<div id="app">
<p>{{message}}</p>
<!-- v-on:事件类型="事件响应函数的函数名" -->
<button v-on:click="reverseMessage">Click me,reverse message</button>
</div>
Vue代码
var app = new Vue({
"el":"#app",
"data":{
"message":"Hello Vue!"
},
"methods":{
"reverseMessage":function(){
this.message = this.message.split("").reverse().join("");
}
}
});
demo:获取鼠标移动时的坐标信息
HTML代码
<div id="app">
<div id="area" v-on:mousemove="recordPosition"></div>
<p id="showPosition">{{position}}</p>
</div>
Vue代码
var app = new Vue({
"el":"#app",
"data":{
"position":"暂时没有获取到鼠标的位置信息"
},
"methods":{
"recordPosition":function(event){
this.position = event.clientX + " " + event.clientY;
}
}
});
Vue.js基本语法:侦听属性
提出需求
<div id="app">
<p>尊姓:{{firstName}}</p>
<p>大名:{{lastName}}</p>
尊姓:<input type="text" v-model="firstName" /><br/>
大名:<input type="text" v-model="lastName" /><br/>
<p>全名:{{fullName}}</p>
</div>
在上面代码的基础上,我们希望firstName或lastName属性发生变化时,修改fullName属性。此时需要对firstName或lastName属性进行『侦听』。
具体来说,所谓『侦听』就是对message属性进行监控,当firstName或lastName属性的值发生变化时,调用我们准备好的函数。
Vue代码
在watch属性中声明对firstName和lastName属性进行『侦听』的函数:
var app = new Vue({
"el":"#app",
"data":{
"firstName":"jim",
"lastName":"green",
"fullName":"jim green"
},
"watch":{
"firstName":function(inputValue){
this.fullName = inputValue + " " + this.lastName;
},
"lastName":function(inputValue){
this.fullName = this.firstName + " " + inputValue;
}
}
});
Vue.js基本语法:简化写法
v-bind的简化写法
正常写法:
<input type="text" v-bind:value="message" />
简化以后:
<input type="text" :value="message" />
v-on的简化写法
正常写法:
<button v-on:click="sayHello">SayHello</button>
简化以后:
<button @click="sayHello">SayHello</button>
练习
功能效果演示
任务解析
- 第一步:显示表格
- 第二步:显示四个文本框
- 第三步:创建一个p标签用来显示用户在文本框中实时输入的内容
- 第四步:点击添加记录按钮实现记录的添加
第一步:显示表格
HTML标签
<table id="appTable">
<tr>
<th>编号</th>
<th>姓名</th>
<th>年龄</th>
<th>专业</th>
</tr>
<tr v-for="employee in employeeList">
<td>{{employee.empId}}</td>
<td>{{employee.empName}}</td>
<td>{{employee.empAge}}</td>
<td>{{employee.empSubject}}</td>
</tr>
</table>
Vue代码
var appTable = new Vue({
"el": "#appTable",
"data": {
"employeeList": [{
"empId": 1,
"empName": "tom",
"empAge": 11,
"empSubject": "java"
},
{
"empId": 2,
"empName": "jerry",
"empAge": 22,
"empSubject": "php"
},
{
"empId": 3,
"empName": "peter",
"empAge": 33,
"empSubject": "python"
}
]
}
});
第二步:显示四个文本框
HTML标签
<!-- 四个文本框、显示收集到的文本框数据的p标签、按钮这三个部分需要共享数据,所以要放在同一个app中 -->
<div id="appDiv">
<!-- 第一部分:四个文本框 -->
编号:<input type="text" v-model="empId" /><br/>
姓名:<input type="text" v-model="empName" /><br/>
年龄:<input type="text" v-model="empAge" /><br/>
专业:<input type="text" v-model="empSubject" /><br/>
<!-- 第二部分:显示收集到的文本框数据的p标签 -->
<!-- 第三部分:按钮 -->
</div>
Vue代码
var appDiv = new Vue({
"el":"#appDiv",
"data":{
// 初始值设置空字符串即可
"empId":"",
"empName":"",
"empAge":"",
"empSubject":""
}
});
第三步:创建一个p标签
HTML标签:
<!-- 四个文本框、显示收集到的文本框数据的p标签、按钮这三个部分需要共享数据,所以要放在同一个app中 -->
<div id="appDiv">
<!-- 第一部分:四个文本框 -->
编号:<input type="text" v-model="empId" placeholder="请输入编号" /><br/>
姓名:<input type="text" v-model="empName" placeholder="请输入姓名" /><br/>
年龄:<input type="text" v-model="empAge" placeholder="请输入年龄" /><br/>
专业:<input type="text" v-model="empSubject" placeholder="请输入专业" /><br/>
<!-- 第二部分:显示收集到的文本框数据的p标签 -->
<p>{{empId}} {{empName}} {{empAge}} {{empSubject}}</p>
<!-- 第三部分:按钮 -->
</div>
第四步:点击添加记录按钮
第一小步:给按钮设置事件驱动
HTML标签
<!-- 四个文本框、显示收集到的文本框数据的p标签、按钮这三个部分需要共享数据,所以要放在同一个app中 -->
<div id="appDiv">
<!-- 第一部分:四个文本框 -->
编号:<input type="text" v-model="empId" placeholder="请输入编号" /><br/>
姓名:<input type="text" v-model="empName" placeholder="请输入姓名" /><br/>
年龄:<input type="text" v-model="empAge" placeholder="请输入年龄" /><br/>
专业:<input type="text" v-model="empSubject" placeholder="请输入专业" /><br/>
<!-- 第二部分:显示收集到的文本框数据的p标签 -->
<p>{{empId}} {{empName}} {{empAge}} {{empSubject}}</p>
<!-- 第三部分:按钮 -->
<button type="button" v-on:click="addRecord">添加记录</button>
</div>
Vue代码
var appDiv = new Vue({
"el":"#appDiv",
"data":{
// 初始值设置空字符串即可
"empId":"",
"empName":"",
"empAge":"",
"empSubject":""
},
"methods":{
"addRecord":function(){
console.log("我点击了那个按钮……");
}
}
});
第二小步:打印一下文本框输入的数据
var appDiv = new Vue({
"el":"#appDiv",
"data":{
// 初始值设置空字符串即可
"empId":"",
"empName":"",
"empAge":"",
"empSubject":""
},
"methods":{
"addRecord":function(){
console.log("我点击了那个按钮……");
console.log(this.empId);
console.log(this.empName);
console.log(this.empAge);
console.log(this.empSubject);
}
}
});
第三小步:将收集到的数据添加到表格中
"addRecord":function(){
// 确认单击事件是否绑定成功
console.log("我点击了那个按钮……");
// 确认是否能够正确收集到文本框数据
console.log(this.empId);
console.log(this.empName);
console.log(this.empAge);
console.log(this.empSubject);
// 将收集到的文本框数据封装为一个对象
var employee = {
"empId":this.empId,
"empName":this.empName,
"empAge":this.empAge,
"empSubject":this.empSubject
};
// 将上面的对象压入表格数据的employeeList数组
appTable.employeeList.push(employee);
}
Vue对象生命周期
概念
在各种语言的编程领域中,『生命周期』都是一个非常常见的概念。一个对象从创建、初始化、工作再到释放、清理和销毁,会经历很多环节的演变。
Vue对象的生命周期
生命周期钩子函数
Vue允许我们在特定的生命周期环节中通过钩子函数来加入我们的代码。
<div id="app">
<p id="content">{{message}}</p>
<button @click="changeValue">点我</button>
</div>
new Vue({
"el":"#app",
"data":{
"message":"hello"
},
"methods":{
"changeValue":function(){
this.message = "new hello";
}
},
// 1.实例创建之前
"beforeCreate":function(){
console.log("beforeCreate:"+this.message);
},
// 2.实例创建完成
"created":function(){
console.log("created:"+this.message);
},
// 3.数据挂载前
"beforeMount":function(){
console.log("beforeMount:"+document.getElementById("content").innerText);
},
// 4.数据已经挂载
"mounted":function(){
console.log("mounted:"+document.getElementById("content").innerText);
},
// 5.数据更新前
"beforeUpdate":function(){
console.log("beforeUpdate:"+document.getElementById("content").innerText);
},
// 6.数据更新之后
"updated":function(){
console.log("updated:"+document.getElementById("content").innerText);
}
});
Ajax概述
服务器端渲染
Ajax渲染(局部更新)
前后端分离
彻底舍弃服务器端渲染,数据全部通过Ajax方式以JSON格式来传递。
同步与异步
Ajax本身就是Asynchronous JavaScript And XML的缩写,直译为:异步的JavaScript和XML。在实际应用中Ajax指的是:不刷新浏览器窗口,不做页面跳转,局部更新页面内容的技术。
『同步』和『异步』是一对相对的概念,那么什么是同步,什么是异步呢?
同步
多个操作按顺序执行,前面的操作没有完成,后面的操作就必须等待。所以同步操作通常是串行的。
异步
多个操作相继开始并发执行,即使开始的先后顺序不同,但是由于它们各自是在自己独立的进程或线程中完成,所以互不干扰,**谁也**不用等**谁**。
Axios简介
使用原生的JavaScript程序执行Ajax极其繁琐,所以一定要使用框架来完成。而Axios就是目前最流行的前端Ajax框架。Axios官网
使用Axios和使用Vue一样,导入对应的*.js文件即可。官方提供的script标签引入方式为:
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
Axios基本用法
在前端页面引入开发环境
<script type="text/javascript" src="/demo/static/vue.js"></script>
<script type="text/javascript" src="/demo/static/axios.min.js"></script>
发送普通请求参数
前端代码
HTML标签:
<div id="app">
<button @click="commonParam">普通请求参数</button>
</div>
Vue+axios代码:
new Vue({
"el":"#app",
"data":{},
"methods":{
"commonParam":function () {
axios({
"method":"post",
"url":"/demo/AjaxServlet?method=commonParam",
"params":{
"userName":"tom",
"userPwd":"123456"
}
}).then(function (response) {
console.log(response);
}).catch(function (error) {
console.log(error);
});
}
}
});
效果:所有请求参数都被放到URL地址后面了,哪怕我们现在用的是POST请求方式。
后端代码
public class AjaxServlet extends ModelBaseServlet {
protected void commonParam(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String userName = request.getParameter("userName");
String userPwd = request.getParameter("userPwd");
System.out.println("userName = " + userName);
System.out.println("userPwd = " + userPwd);
response.setContentType("text/html;charset=UTF-8");
response.getWriter().write("服务器端返回普通文本字符串作为响应");
}
}
axios程序接收到的响应对象结构
属性名 | 作用 |
---|---|
config | 调用axios(config对象)方法时传入的JSON对象 |
data | 服务器端返回的响应体数据 |
headers | 响应消息头 |
request | 原生JavaScript执行Ajax操作时使用的XMLHttpRequest |
status | 响应状态码 |
statusText | 响应状态码的说明文本 |
服务器端处理请求失败后
catch(function (error) { // catch()服务器端处理请求出错后,会调用
console.log(error); // error就是出错时服务器端返回的响应数据
console.log(error.response); // 在服务器端处理请求失败后,获取axios封装的JSON格式的响应数据对象
console.log(error.response.status); // 在服务器端处理请求失败后,获取响应状态码
console.log(error.response.statusText); // 在服务器端处理请求失败后,获取响应状态说明文本
console.log(error.response.data); // 在服务器端处理请求失败后,获取响应体数据
});
在给catch()函数传入的回调函数中,error对象封装了服务器端处理请求失败后相应的错误信息。其中,axios封装的响应数据对象,是error对象的response属性。response属性对象的结构如下图所示:
可以看到,response对象的结构还是和then()函数传入的回调函数中的response是一样的:
回调函数
开发人员声明,但是调用时交给系统来调用。像单击响应函数、then()、catch()里面传入的都是回调函数。回调函数是相对于普通函数来说的,普通函数就是开发人员自己声明,自己调用:
function sum(a, b) {
return a+b;
}
var result = sum(3, 2);
console.log("result="+result);
发送请求体JSON
前端代码
HTML代码:
<button @click="requestBodyJSON">请求体JSON</button>
Vue+axios代码:
"methods":{
"requestBodyJSON":function () {
axios({
"method":"post",
"url":"/demo/AjaxServlet?method=requestBodyJSON",
"data":{
"stuId": 55,
"stuName": "tom",
"subjectList": [
{
"subjectName": "java",
"subjectScore": 50.55
},
{
"subjectName": "php",
"subjectScore": 30.26
}
],
"teacherMap": {
"one": {
"teacherName":"tom",
"tearcherAge":23
},
"two": {
"teacherName":"jerry",
"tearcherAge":31
},
},
"school": {
"schoolId": 23,
"schoolName": "atguigu"
}
}
}).then(function (response) {
console.log(response);
}).catch(function (error) {
console.log(error);
});
}
}
效果:
后端代码
加入Gson包
Gson是Google研发的一款非常优秀的JSON数据解析和生成工具,它可以帮助我们将数据在JSON字符串和Java对象之间互相转换.
Servlet代码
protected void requestBodyJSON(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 1.由于请求体数据有可能很大,所以Servlet标准在设计API的时候要求我们通过输入流来读取
BufferedReader reader = request.getReader();
// 2.创建StringBuilder对象来累加存储从请求体中读取到的每一行
StringBuilder builder = new StringBuilder();
// 3.声明临时变量
String bufferStr = null;
// 4.循环读取
while((bufferStr = reader.readLine()) != null) {
builder.append(bufferStr);
}
// 5.关闭流
reader.close();
// 6.累加的结果就是整个请求体
String requestBody = builder.toString();
// 7.创建Gson对象用于解析JSON字符串
Gson gson = new Gson();
// 8.将JSON字符串还原为Java对象
Student student = gson.fromJson(requestBody, Student.class);
System.out.println("student = " + student);
System.out.println("requestBody = " + requestBody);
response.setContentType("text/html;charset=UTF-8");
response.getWriter().write("服务器端返回普通文本字符串作为响应");
}
P.S.:看着很麻烦是吧?但是,在SpringMVC之后,一个**@RequestBody**注解就能够搞定,非常方便!
服务器端返回JSON数据
前端代码
axios({
"method":"post",
"url":"/demo/AjaxServlet?method=responseBodyJSON"
}).then(function (response) {
console.log(response);
}).catch(function (error) {
console.log(error);
});
then()中获取到的response在控制台打印效果如下:我们需要通过data属性获取响应体数据
后端代码
Servlet代码
protected void responseBodyJSON(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 1.准备数据对象
Student student = new Student();
student.setStuId(10);
student.setStuName("tom");
student.setSchool(new School(11,"atguigu"));
student.setSubjectList(Arrays.asList(new Subject("java", 95.5), new Subject("php", 93.3)));
Map<String, Teacher> teacherMap = new HashMap<>();
teacherMap.put("t1", new Teacher("lili", 25));
teacherMap.put("t2", new Teacher("mary", 26));
teacherMap.put("t3", new Teacher("katty", 27));
student.setTeacherMap(teacherMap);
// 2.创建Gson对象
Gson gson = new Gson();
// 3.将Java对象转换为JSON对象
String json = gson.toJson(student);
// 4.设置响应体的内容类型
response.setContentType("application/json;charset=UTF-8");
response.getWriter().write(json);
}