1、简介
Vue.js是一套构建用户界面的渐进式框架。Vue只关注视图层,采用自底向上增量开发的设计。Vue的目标是通过尽可能简单的API实现响应的数据绑定和组合的视图组件。Vue能最大程度上解放DOM操作,应用在单页web项目开发和传统网站开发等。
2、Vue核心特征
遵循MVVM模式
1、解耦视图与数据
2、M-V-VM模型
M:即Model,模型,包括数据和一些基本操作
V:即View, 视图,页面渲染结果
VM:即View-Model,模型和视图的双向操作
3、双向数据绑定
(一)MVVM之前
开发人员从后端获取需要的数据,然后要通过DOM操作Model渲染到View中。而后当用户操作视图,我们还需要通过DOM获取View中的数据,然后同步到Model中。
(二)MVVM之后
而MVVM中的VM要做的事情就是把DOM操作完全封装起来,开发人员不用再关心Model和View之间是如何相互影响的:
——只要我们Model发生了改变,View上自然就会表现出来。
——当用户修改了View,Model中的数据也会跟着改变
把开发人员从繁琐的DOM操作中解放出来,把关注点放在如何操作Model上。
3、Vue入门
(一)下载安装
vue是一个前端框架,也就是一个js文件,下载vue.js文件并在页面中引入
vue.js的下载方式:
1、可以引入在线的vue.js(公共的CDN服务)
<!-- 开发环境版本,包含了用帮助的命令行警告 -->
<script src="http://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
或
<!-- 生产环境版本,优化了尺寸和速度 -->
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
2、可以离线下载vue.js:
https://plugins.jetbrains.com/plugin/9442-vue-js/versions
(二)第一个Vue
vue参数详解:
1、body中设置vue管理的视图<div id="app"></div>
2、引入vue.js
3、实例化Vue对象 new Vue();
4、设置Vue实例的选项:如el、data...
5、在<div id='app'></div>中通过{{ }}使用data中的数据
6、vue实化可以挂载到大多数的标签,不要挂载到body和html标签上,一般建议挂在给div标签
7、vue实例作用域就在当前的挂载的标签中,出了这个标签就不能使用了。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<!-- 引入vue.js -->
<script src="js/vue.js"></script>
</head>
<body >
<!--
1、下载和引用vue.js
-->
<!-- 1、只能通过id挂载吗?
也可以通过class挂载 官方建议通过id去挂载
2、vue只能挂载到div上吗?
绝大数标签都是可以挂载,但是不能挂载到body、html标签上,官方建议使用div
-->
<div id="app">
<!-- {{}} 插值表达式 使用插值表达式显示data中的数据 -->
{{ message }}
<div>
{{ message }}
</div>
{{list}}
</div>
<!-- 没有效果 -->
{{ message }}
</body>
</html>
<script>
//创建一个vue对象
new Vue({
//el代表的是挂载的元素 #app id为app的元素
el:"#app",
//vue中定义的数据
data:{
message:"hello vue1"
}
})
</script>
4、Vue常见指令
指令(Directives)是带有 v- 前缀的特殊attribute。是vue框架提供的语法,扩展了html标签的功能,大部分的指令的值是js的表达式。用于取代DOM操作。
(一)显示数据(v-text和v-html)
类似innerText和innerHTML
v-text:更新标签中的内容
v-html:更新标签中的内容/标签
案例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="js/vue.js"></script>
</head>
<body>
<!--
v-text js innerText
v-html js innerHTML
v-text不能识别标签和样式
v-html可以识别标签和样式
-->
<div id="app">
<!-- 插值表达式 -->
<span>{{ msg }}</span>
<span v-text="msg"></span>
<span v-html="msg"></span>
<!-- msg常量 加上单引号就是常量-->
<span v-text="'msg'"></span>
<!-- msg 代表的是字符串常量 -->
<span v-html=`msg`></span>
<span v-text=`${msg}`></span>
<!-- 变量+常量 -->
<span v-text="msg + '你很帅'"></span>
<span v-text=`${msg}你很帅`></span>
<div v-text="msg1"></div>
<div v-html="msg1"></div>
</div>
</body>
</html>
<script>
new Vue({
el:"#app",
data:{
msg:"张三",
msg1:"<span style='color:red'>李四</span>"
}
})
</script>
(二)条件渲染(v-if和v-show)
根据表达式的boolean值进行判断是否渲染该元素
案例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="js/vue.js"></script>
</head>
<body>
<!--
v-if和v-show
根据表达式的boolean来判断是否渲染该元素
v-if和v-show 设置为true 渲染该元素
设置为false
v-if 直接不渲染该标签
v-show 设置display样式为none 让标签隐藏
-->
<div id="app">
<div v-if="bo">王五</div>
<div v-show="bo">赵六</div>
</div>
</body>
</html>
<script>
new Vue({
el:"#app",
data:{
bo:false
}
})
</script>
(三)绑定事件监听(v-on)
作用:使用 v-on 指令绑定DOM事件并在事件被触发时执行一些JavaScript代码
语法:v-on:事件名 = “methods中的方法名”;
v-on的简写方法:@事件名 = “methods中的方法名”;
案例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="js/vue.js"></script>
</head>
<body>
<!--
v-on 用来绑定js中的事件
1、v-on:事件名 = methods中的方法
2、简写: @事件名 = methods中的方法
事件名跟jQuery的事件名一致 将js的事件名前面的on去掉即可
-->
<div id="app">
<button v-on:click="fun1()">点我1</button>
<button @click="fun2()">点我2</button>
{{ n }} <br>
<button @click="fun3()">点我n++</button>
<!-- n代表的是data中的n -->
<button @click="fun4(n)">点我3</button>
<!-- 常量n -->
<button @click="fun4('n')">点我4</button>
</div>
</body>
</html>
<script>
var app = new Vue({
el:"#app",
//定义数据
data:{
n:1
},
//定义方法
methods:{
fun1:function() {
console.log("fun1方法执行了");
},
fun2() {
console.log("fun2执行了");
},
fun3() {
//在methods中要想获取data中的数据 前面加上一个this
this.n++;
},
fun4(n) {
console.log(n);
}
}
})
</script>
(四)列表渲染(v-for)
作用:列表渲染,当遇到相似的标签结构时,就用v-for去渲染
格式:1、(item,index)in 数组或集合
参数item:数组中的每个元素
参数index:数组中元素的下标
2、(value,key,index)in 对象
参数index:对象中每对key-value的索引 从0开始
参数key:键 参数value:值
案例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="js/vue.js"></script>
</head>
<body>
<!--
v-for 用来遍历对象或者数组
1、遍历数组
(item,index) in lists
lists代表要遍历的数组
item代表当前遍历的元素
index 代表的是索引 从0开始
2、遍历对象
(value,key,index) in obj
obj代表的是遍历的对象
value代表的属性值
key代表的是属性名
index代表的索引 从0开始
-->
<div id="app">
<table border="1" width="500px">
<tr>
<th>序号</th>
<th>姓名</th>
<th>年龄</th>
<th>性别</th>
<th>爱好</th>
</tr>
<!-- v-for遍历数组 -->
<tr v-for="(item,index) in userList">
<td>{{ index + 1 }}</td>
<td v-text="item.name"></td>
<td>{{ item.age }}</td>
<td v-html="item.sex"></td>
<td v-html="item.hobby"></td>
</tr>
</table>
<!-- 遍历对象 -->
<p v-for="(value,key,index) in student">
索引:<span>{{ index }}</span>
value值:<span>{{ value }}</span>
key值:<span v-text="key"></span>
</p>
</div>
</body>
</html>
<script>
new Vue({
el: "#app",
data: {
//userList就是从后台查询出来的所有用户信息
userList: [
{
name: "张三1",
age: 17,
sex: "男",
hobby: "吃饭"
},
{
name: "张三2",
age: 17,
sex: "男",
hobby: "吃饭"
},
{
name: "张三3",
age: 17,
sex: "男",
hobby: "吃饭"
},
{
name: "张三4",
age: 17,
sex: "男",
hobby: "吃饭"
}
],
student: {
name: "张三4",
age: 17,
sex: "男",
hobby: "吃饭"
}
},
methods: {
}
})
</script>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="js/vue.js"></script>
</head>
<body>
<div id="app">
<!--
遍历对象
v-for=(value,key,index) in 对象
value 代表属性值
key 属性名
index 代表索引 从0开始IDE
-->
<p v-for="(value,key,index) in user">
<span>{{ index }}</span>
<span v-text="key"></span>
<span v-text="value"></span>
<br>
</p>
</div>
</body>
</html>
<script>
new Vue({
el:"#app",
data:{
user:{
name:"夏六",
age:17,
sex:"男",
hobby:"干饭"
}
}
})
</script>
(五)单向绑定解析表达式(v-bind)
作用:可以绑定标签上的任何属性
格式:v-bind:属性=“值”
简写格式:属性=“值”
属性值一部分进行替换的格式:属性=“‘常量值’+vue对象data中的数据”
案例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="js/vue.js"></script>
</head>
<body>
<!-- v-bind 绑定标签中的任何属性
格式: v-bind:属性名=值
简写: :属性名=值
字符串的拼接: 变量 + 常量 变量 + '常量'
-->
<div id="app">
<a v-bind:href="url">跳转到百度</a>
<a :href="url">点我1</a>
<a :href="'http://www.' + uri">点我</a>
<a :href=`http://www.${uri}`>点我</a>
姓名: <input type="text" :value="user.name">
年龄: <input type="text" :value="user.age">
</div>
</body>
</html>
<script>
new Vue({
el:"#app",
data:{
url:"http://www.baidu.com",
uri:"baidu.com",
user:{
name:"张三",
age:12
}
},
methods:{
}
})
</script>
(六)表单数据绑定(v-model)
作用:表单元素的绑定
特点:双向数据绑定
(1)vue对象中的数据发生变化可以更新到界面
(2)通过界面可以更改vue对象中的数据
(3)v-model会忽略所有表单元素的value、checked、selected特性的初始值而总是将Vue实力的数据作为数据来源。应该在data选项中声明初始值。
案例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="js/vue.js"></script>
</head>
<body>
<!--
v-model 双向绑定 绑定表单中的元素
双向绑定:
data中的数据更新,视图也会随着更新
用户修改了视图,data中的数据也会随之更新
-->
<div id="app">
{{ message }} <br>
绑定属性: <input type="text" :value="message"> <br>
<!-- 1、输入框 v-model忽略value 绑定的是value值-->
双向绑定: <input type="text" v-model="message"> <br>
<!-- 2、单选框
v-model绑定sex
选中单选框,data中的数据默认更新成对应的value
-->
{{sex}} <br>
<input type="radio" name="sex" v-model="sex" value="男"> 男
<input type="radio" name="sex" v-model="sex" value="女"> 女 <br>
<!--
3、复选框
-->
{{ hobby }} <br>
<input type="checkbox" name="hobby" v-model="hobby" value="吃">吃
<input type="checkbox" name="hobby" v-model="hobby" value="喝">喝
<input type="checkbox" name="hobby" v-model="hobby" value="rap">rap
<input type="checkbox" name="hobby" v-model="hobby" value="睡觉">睡
觉 <br>
<!--
4、下拉列表
-->
{{ school }} <br>
<select name="school" v-model="school">
<option value="小学">小学</option>
<option value="中学">中学</option>
<option value="大学">大学</option>
</select>
</div>
</body>
</html>
<script>
new Vue({
el:"#app",
data:{
message:"hello vue1",
sex:"女",
hobby:["吃","喝"],
school:"大学"
},
methods:{
}
})
</script>
(七)计算属性computed
再插值表达式中使用js表达式是非常方便的,而且也经常被用到。
案例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="js/vue.js"></script>
</head>
<body>
<div id="app">
<!-- 定字符串进行反转
split 切割 reverse() 数组的反转 join 将数组拼接成字符串
-->
{{ str.split('').reverse().join("") }}
<!-- str.length 获取字符串的长度 -->
{{ str.length == 1 ? '短' : '长' }}
<!-- 定义方法 -->
{{ test() }}
<!-- 计算属性 -->
{{ test01 }}
</div>
</body>
</html>
<script>
new Vue({
el:"#app",
data:{
str:"abcdefg"
},
methods: {
test() {
return this.str.split('').reverse().join("");
}
},
//计算属性
computed: {
test01() {
return this.str.split('').reverse().join("");
}
}
})
</script>
(八)监控属性watch
watch可以让我们监控一个值的变化,从而做出相应的反应。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="js/vue.js"></script>
</head>
<body>
<div id="app">
{{ n }} <br>
<button @click="fun1()">点我n++</button>
</div>
</body>
</html>
<script>
new Vue({
el:"#app",
data:{
n:1
},
methods:{
fun1() {
this.n++;
}
},
watch:{
//监控值的变化
//newval 新值 oldval 老值
n(newval,oldval) {
console.log(newval,oldval);
}
}
})
</script>
5、Vue声明周期
每个Vue实力在被创建时都要经过一系列的初始化过程:创建实例,装载模板,渲染模板等等。Vue为生命周期中的每个状态都设置了钩子函数(监听函数)。每当Vue实力处于不同的生命周期时,对应的函数就会被触发调用。
Vue生命周期的作用:Vue生命周期中有多个事件钩子,让我们在控制整个Vue实例过程时更容易形成好的逻辑。
Vue生命周期分为几个阶段:可以分为八个阶段。
Vue的生命周期顺序:
案例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="js/vue.js"></script>
</head>
<body>
<div id="app">
</div>
</body>
</html>
<script>
new Vue({
el:"#app",
data:{
},
methods:{
fun1() {
console.log("请求后台查询数据");
}
},
//想在加载页面的时候就去向后台发送请求,拿到所有的用户信息
//创建vue的钩子函数 可以当成js中的页面加载完成事件使用 window.onload
created(){
console.log("创建vue的钩子函数执行了");
this.fun1();
}
})
</script>
6、Vue的Ajax(axios)
在Vue.js中发送网络请求本质还是ajax,我们可以使用插件方便操作。
1、vue-resource:Vue.js的插件,不推荐使用
2、axios:不是vue的插件,可以在任何地方使用,推荐
3、通过Http请求的不同类型(POST/DELETE/PUT/GET)来判断是什么业务操作(CRUD)HTTP方法规则举例
(一)安装
方式:使用cdn链接axios
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
(二)axios请求
let params = new URLSearchParams();
params.append("name", "lisi");
params.append("age", 17);
axios({
// 请求方式
method: 'post',
url: 'api',
// 传递参数
params: params,
responseType: 'json'
}).then(response => {
// 请求成功
let res = response.data;
console.log(res);
}).catch(error => {
// 请求失败,
console.log(error);
});
(三)GET请求
axios.get('/user?id=12345')
.then(response => {
console.log(response.data);
})
.catch(error => {
console.dir(error)
});
(四)POST请求
axios.post('/user?name=迪丽热巴&age=23') .then(response => {
console.log(response.data);
})
.catch(error => {
console.dir(err)
});
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="js/vue.js"></script>
<script src="js/axios-0.18.0.js"></script>
</head>
<body>
<div id="app">
<button @click="fun1()">点我1</button>
<button @click="fun2()">点我2</button>
<button @click="fun3()">点我3</button>
</div>
</body>
</html>
<script>
new Vue({
el: "#app",
data: {
},
methods: {
fun1() {
/*
1、axios请求
axios({
请求的地址
url:"",
//请求的方式get/post
method:"",
//携带的参数
data:"",
//返回数据类型 json
responseType:""
}).then(resp => {
//请求成功的回调函数
resp.data代表返回的数据
}).catch(_ => {
//请求发生错误的回调函数
})
2、axios请求参数接收问题
1、使用data传递参数 后台接收不到
2、使用params传递参数 后台可以接收到
3、使用这种方式传递参数
创建URLSearchParams对象
append方法去组装参数
*/
//通过对象去组装参数
let params = new URLSearchParams();
params.append("name", "lisi");
params.append("age", 17);
axios({
url: "http://localhost:8080/day19/studentServlet",
method: "get",
params: params,
responseType: "text"
}).then(resp => {
//resp.data代表的是返回的数据
console.log(resp.data);
}).catch(_ => {
console.log("请求发生了异常");
})
},
fun2() {
/*
2、axios.get请求
1、请求的地址建议使用多行字符串
2、参数拼接到url地址后面 拼接参数用? 多个参数用&
3、不用写返回的数据类型 自动匹配
*/
let name = 'wangwu';
let age = 17;
axios.get(`http://localhost:8080/day19/studentServlet?
name=${name}&age=${age}`).then(resp => {
console.log(resp.data);
}).catch(_ => {
console.log("请求报错");
})
},
fun3() {
/*
3、axios.post请求
*/
let name = 'wangwu';
let age = 17;
axios.post(`http://localhost:8080/day19/studentServlet?
name=${name}&age=${age}`).then(resp => {
console.log(resp.data);
}).catch(_ => {
console.log("请求报错");
})
}
}
})
</script>
(五)跨域问题
什么是跨域?
指的是浏览器不能执行其它网站的脚本。它是由浏览器的同源策略造成的,是浏览器对JavaScript施加的安全限制。
什么是同源策略?
是指协议,域名,端口都要相同,其中有一个不同都会产生跨域,在请求数据时,浏览器会在控制台中报一个异常,提示拒绝访问。
跨域问题怎么出现的?
开发一些前后端分离的项目,后台代码在一台服务器上启动,前台代码在另一台电脑上启动,此时就会出现问题。
解决方式:后台解决(自定义过滤器)
package com.ujiuye.com.ujiuye.filter;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebFilter("/*")
public class Demo01Filter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse
servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletResponse response = (HttpServletResponse) servletResponse;
HttpServletRequest request = (HttpServletRequest) servletRequest;
// 不使用*,自动适配跨域域名,避免携带Cookie时失效
String origin = request.getHeader("Origin");
response.setHeader("Access-Control-Allow-Origin", origin);
// 自适应所有自定义头
String headers = request.getHeader("Access-Control-Request-Headers");
response.setHeader("Access-Control-Allow-Headers", headers);
response.setHeader("Access-Control-Expose-Headers", headers);
// 允许跨域的请求方法类型
response.setHeader("Access-Control-Allow-Methods", "*");
// 预检命令(OPTIONS)缓存时间,单位:秒
response.setHeader("Access-Control-Max-Age", "3600");
// 明确许可客户端发送Cookie,不允许删除字段即可
response.setHeader("Access-Control-Allow-Credentials", "true");
filterChain.doFilter(request, response);
}
@Override
public void destroy() {
}
}