Vue.js(读⾳ /vjuː/, 类似于 view) 是⼀套构建⽤户界⾯的渐进式框架。Vue 只关注视图层, 采⽤⾃底向上增量开发的设计。
Vue 的⽬标是通过尽可能简单的 API 实现响应的数据绑定和组合的视图组件。
Vue.JS是优秀的前端 JavaScript 框架
- 随着项⽬业务场景的复杂,传统模式(html+jquery)已⽆法满⾜需求,就出现了Angular/React/Vue等框架
企业需求、主流框架之⼀、易⽤、灵活、⾼效
最⼤程度上解放了 DOM 操作
单⻚web项⽬开发
传统⽹站开发
① 解耦视图与数据
② M-V-VM模型 关注模型和视图
M:即Model,模型,包括数据和⼀些基本操作。
V:即View,视图,⻚⾯渲染结果
VM:即View-Model,模型和视图间的双向操作
③ 双向数据绑定
开发⼈员从后端获取需要的数据模型,然后要通过DOM操作Model渲染到View中。⽽后当⽤户操作视图,我们还需要通过DOM获取View中的数据,然后同步到Model中
⽽MVVM中的VM要做的事情就是把DOM操作完全封装起来,开发⼈员不⽤再关⼼Model和View之间是如何互相影响的:
- 只要我们Model发⽣了改变,View上⾃然就会表现出来。
- 当⽤户修改了View,Model中的数据也会跟着改变把开发⼈员从繁琐的DOM操作中解放出来,把关注点放在如何操作Model上
vue是⼀个前端框架,也是其实是⼀个js⽂件,下载vue.js⽂件并在⻚⾯中引⼊
vue.js的下载⽅式:
① 可以引⼊在线的vue.js(公共的CDN服务)
② 可以离线下载vue.js
开发版本: https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js
⽣产版本: https://cdn.jsdelivr.net/npm/vue@2
③ npm包资源管理器,可以下载vue.js
初始化:npm init -y
安装vue:npm install vue --save
注:切记重启计算机
注意:
NPM是Node提供的模块管理⼯具,可以⾮常⽅便的下载安装很多前端框架,包括Jquery、AngularJS、
VueJs都有。为了后⾯学习⽅便,我们先安装node及NPM⼯具
node.js下载地址:https://nodejs.org/en/download/,安装完成Node应该⾃带了NPM了,在控制台
输⼊npm -v查看
注:
① 在v12.16.2以上版本就不在⽀持window7系统。
② npm默认的仓库地址是在国外⽹站,速度较慢,建议⼤家设置到淘宝镜像。但是切换镜像是⽐较麻烦
的。推荐⼀款切换镜像的⼯具:nrm
安装命令:npm install nrm -g 这⾥-g代表全局安装
查看npm的仓库列表:nrm ls
指定镜像源:nrm use taobao
测试速度:nrm test npm
Title
{{name}},欢迎你!
Vue参数详解:
- body中,设置Vue管理的视图
- 引⼊vue.js
- 实例化Vue对象 new Vue();
- 设置Vue实例的选项:如el、data…
new Vue({选项:值});- 在 中通过{{ }}使⽤data中的数据
指令 (Directives) 是带有 v- 前缀的特殊attribute。是Vue框架提供的语法,扩展了html标签的功能、⼤部分的指令的值是js的表达式。⽤于取代DOM操作
类似innerText和innerHTML
① v-text:更新标签中的内容
② v-html:更新标签中的内容/标签
DOCTYPE html>
<html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Vue⼊⻔title>
head> <body> <div id="app">
<p v-text="t">这是啥p>
<p v-html="h">你猜p>
div> <script src="./node_modules/vue/dist/vue.js">script> <script type="text/javascript">
const v = new Vue({
el:"#app",
data:{
t:"哈哈",
h:"嘿嘿"
}
})
script>
body>
html>
根据表达式的boolean值进⾏判断是否渲染该元素
DOCTYPE html>
<html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Vue⼊⻔title>
head> <body> <div id="app">
<p v-if="b">这是啥p>
<p v-show="b">你猜p>
div> <script src="./node_modules/vue/dist/vue.js">script> <script type="text/javascript">
const v = new Vue({
el:"#app",
data:{
b:false
}
})
script>
body>
html>
① 作⽤:使⽤ v-on 指令绑定 DOM 事件,并在事件被触发时执⾏⼀些 JavaScript 代码。
② 语法:
v-on:事件名.修饰符 = “methods中的⽅法名”;
v-on的简写⽅法: @事件名.修饰符 = “methods中的⽅法名”;
DOCTYPE html>
<html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Vue⼊⻔title>
head> <body> <div id="app">
<button v-on:click="num++">按钮01button><br />{{num}}
<hr>
<button @click="fn1()">按钮02button>
<button @click="fn2(num)">按钮03button>
<button @click="fn3">按钮04button>
div> <script src="./node_modules/vue/dist/vue.js">script> <script type="text/javascript">
const v = new Vue({
el:"#app",
data:{
num:0
},
methods:{
fn1:function(){
console.info("fn1 调⽤了。。。"+this.num);
this.num++;
},
fn2:function(n){
console.info("fn2 调⽤了...."+n);
},
fn3:function(){
console.info("fn3 调⽤了....");
}
}
})
script>
body>
html>
① 作⽤:列表渲染,当遇到相似的标签结构时,就⽤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 name="viewport" content="width=device-width, initial-scale=1.0"> <title>Vue⼊⻔title>
head> <body> <div id="app">
<table border="1">
<tr v-for="(item, index) in userList">
<td>{{index}}td>
<td>{{item.id}}td>
<td>{{item.username}}td>
<td>{{item.age}}td>
tr>
table>
<form action="">
<p><label>id:<input type="text" v-model="user.id">label>p>
<p><label>⽤户名:<input type="text" v-model="user.username">label>p>
<p><label>年龄:<input type="text" v-model="user.age">label>p>
form>
<form action="">
<p v-for="(value, key, index) in user">
<label>{{index}}-{{key}}:<input type="text" v-model="user[key]">
label>
p>
form>
div> <script src="./node_modules/vue/dist/vue.js">script> <script type="text/javascript">
const v = new Vue({
el:"#app",
data: {
userList: [
{ id: 1, username: 'helen', age: 18 },
{ id: 2, username: 'peter', age: 28 },
{ id: 3, username: 'andy', age: 38 }
],
user:{
id: 1,
username: 'helen',
age: 18
}
}
})
script>
body>
html>
① 作⽤: 可以绑定标签上的任何属性
② 格式:v-bind:属性=“值”
③ 简写格式::属性=“值”
④ 属性值⼀部分进⾏替换的格式::属性=“‘常量值’ + vue对象data中的数据”
DOCTYPE html>
<html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Vue⼊⻔title>
head> <body> <div id="app">
<font v-bind:color="v1">有就业font>
<font :color="v2">这是v-bindfont>
<a :href="'http://'+u">百度a>
div> <script src="./node_modules/vue/dist/vue.js">script> <script type="text/javascript">
const v = new Vue({
el:"#app",
data:{
v1:"red",
v2:"yellow",
u:"www.baidu.com"
}
})
script>
body>
html>
① 作⽤:表单元素的绑定
② 特点:双向数据绑定
(1)vue对象中的数据发⽣变化可以更新到界⾯
(2)通过界⾯可以更改vue对象中数据
(3)v-model 会忽略所有表单元素的 value、 checked 、 selected 特性的初始值⽽总是将 Vue 实
例的数据作为数据来源。应该在data选项中声明初始值。
DOCTYPE html>
<html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Vue⼊⻔title>
head> <body> <div id="app">
<form>
⽤户名:<input type="text" v-model="user.name"><br>
⽤户名:<input type="text" v-model="v"><br>
密码:<input type="password" v-model="user.password"><br>
<input type="button" @click="fun1" value="获取">
<input type="button" @click="fun2" value="修改">
form>
div> <script src="./node_modules/vue/dist/vue.js">script> <script type="text/javascript">
const v = new Vue({
el:"#app",
data:{
user:{name:"root",password:"1234"},
v:"hehe"
},
methods:{
fun1:function(){
console.info(this.user.name);
console.info(this.user.password);
},
fun2:function(){
this.user.name="admin";
this.user.password="111";
}
}
})
script>
body>
html>
在插值表达式中使⽤js表达式是⾮常⽅便的,⽽且也经常被⽤到。
但是如果表达式的内容很⻓,就会显得不够优雅,⽽且后期维护起来也不⽅便
DOCTYPE html>
<html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Vue⼊⻔title>
head> <body> <div id="app">
{{message}}
<p>{{birthday}}p>
没计算属性:<p>{{new Date(birthday).getFullYear() + '-'+ new
Date(birthday).getMonth()+1+ '-' + new Date(birthday).getDate()}}p>
计算属性:<p>{{getBirth}}p>
div> <script src="./node_modules/vue/dist/vue.js">script> <script type="text/javascript">
const v = new Vue({
el:"#app",
data:{
message:"",
birthday:1610669793429
},
created(){
this.message = "创建啦.....";
console.info(this);
},
computed:{
getBirth(){
const d = new Date(this.birthday);
return d.getFullYear() + "-" + d.getMonth()+1 + "-" + d.getDate();
}
}
})
script>
body>
html>
watch可以让我们监控⼀个值的变化。从⽽做出相应的反应。
DOCTYPE html>
<html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Vue⼊⻔title>
head> <body> <div id="app">
<input type="text" v-model="hello">
div> <script src="./node_modules/vue/dist/vue.js">script> <script type="text/javascript">
const v = new Vue({
el:"#app",
data:{
hello:""
},
watch:{
hello(newVal, oldVal){
console.log(newVal, oldVal);
}
}
})
script>
body>
html>
查看控制台
每个 Vue 实例在被创建时都要经过⼀系列的初始化过程 :创建实例,装载模板,渲染模板等等。Vue为⽣命周期中的每个状态都设置了钩⼦函数(监听函数)。每当Vue实例处于不同的⽣命周期时,对应的函数就会被触发调⽤。
如:created代表在vue实例创建后;我们可以在Vue中定义⼀个created函数,代表这个时期的构造函数:
DOCTYPE html>
<html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Vue⼊⻔title>
head> <body> <div id="app">
{{message}}
div> <script src="./node_modules/vue/dist/vue.js">script> <script type="text/javascript">
const v = new Vue({
el:"#app",
data:{
message:""
},
created(){
this.message = "创建啦.....";
}
})
script>
body>
html>
我们通过Vue的component⽅法来定义⼀个全局组件。
DOCTYPE html>
<html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Vue⼊⻔title>
head> <body> <div id="app">
<con>con>
div> <script src="./node_modules/vue/dist/vue.js">script> <script type="text/javascript">
// 参数1:组件名 参数2:组件参数
Vue.component("con",{
template:"",
data(){
return {
count:0
}
}
})
const v = new Vue({
el:"#app"
})
script>
body>
html>
特点:
组件其实也是⼀个Vue实例,因此它在定义时也会接收:data、methods、⽣命周期函数等
不同的是组件不会与⻚⾯的元素绑定,否则就⽆法复⽤了,因此没有el属性。
但是组件渲染需要html模板,所以增加了template属性,值就是HTML模板
全局组件定义完毕,任何vue实例都可以直接在HTML中通过组件名称来使⽤组件了。
data的定义⽅式⽐较特殊,必须是⼀个函数。
注:定义组件要在Vue对象之前声明
⼀旦全局注册,就意味着即便以后你不再使⽤这个组件,它依然会随着Vue的加载⽽加载。因此,对于⼀些并
不频繁使⽤的组件,我们会采⽤局部注册。
DOCTYPE html>
<html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Vue⼊⻔title>
head> <body> <div id="app">
<conn>conn>
div> <script src="./node_modules/vue/dist/vue.js">script> <script type="text/javascript">
// 局部组件
const conn = {
template:"",
data(){
return {
count1:0
}
}
}
const v = new Vue({
el:"#app",
components:{
conn:conn //
}
})
script>
body>
html>
- components就是当前vue对象⼦组件集合。
其key就是⼦组件名称
其值就是组件对象的属性
效果与刚才的全局注册是类似的,不同的是,这个conn组件只能在当前的Vue实例中使⽤
注:定义组件要在Vue对象之前声明
在Vue.js中发送⽹络请求本质还是ajax,我们可以使⽤插件⽅便操作。
1、vue-resource: Vue.js的插件,已经不维护,不推荐使⽤
2、 axios :不是vue的插件,可以在任何地⽅使⽤,推荐
3、通过Http请求的不同类型(POST/DELETE/PUT/GET)来判断是什么业务操作(CRUD ) HTTP⽅法规则举例
说明:
① POST Create 新增⼀个没有id的资源
② GET Read 取得⼀个资源
③ PUT Update 更新⼀个资源。或新增⼀个含 id 资源(如果 id 不存在)
④ DELETE Delete 删除⼀个资源
⽅式1:使⽤npm安装
命令:npm install axios
⽅式2:使⽤cdn链接axios
axios({
// 请求⽅式
method: 'post',
url: 'api',
// 传递参数
data: obj, // URLSearchParam()
// 设置请求头信息
headers: {
key: value
},
responseType: 'json'
}).then(response => {
// 请求成功
let res = response.data;
console.log(res);
}).catch(error => {
// 请求失败,
console.log(error);
});
axios.get('/user?id=12345')
.then(response => {
console.log(response.data);
})
.catch(error => {
console.dir(error)
});
axios.post('/user', "URLSearchParams") .then(response => {
console.log(response.data);
})
.catch(error => {
console.dir(err)
});
补充
为⽅便起⻅,为所有⽀持的请求⽅法提供了别名
- axios.request(confifig)
- axios.get(url[, confifig])
- axios.delete(url[, confifig])
- axios.head(url[, confifig])
- axios.post(url[, data[, confifig]])
- axios.put(url[, data[, confifig]])
- axios.patch(url[, data[, confifig]])
- 什么是跨域?
指的是浏览器不能执⾏其他⽹站的脚本。它是由浏览器的同源策略造成的,是浏览器对javascript施加的安全限制。
- 什么是同源策略?
是指协议,域名,端⼝都要相同,其中有⼀个不同都会产⽣跨域,在请求数据时,浏览器会在控制台中报一个异常,提示拒绝访问。
- 跨域问题怎么出现的?
开发⼀些前后端分离的项⽬,⽐如使⽤ Servlet + Vue 开发时,后台代码在⼀台服务器上启动,前台代码在另外⼀台电脑上启动,此时就会出现问题。
⽐如:
后台 地址为 http://192.168.70.77:8081
前台 地址为 http://192.168.70.88:8080
此时 ip 与 端⼝号不⼀致, 不符合同源策略,造成跨域问题。
跨域前端错误演示
解决方法
⽅式1:后台解决(⾃定义过滤器)
HttpServletResponse response = (HttpServletResponse) resp;
HttpServletRequest request = (HttpServletRequest) req;
// 不使⽤*,⾃动适配跨域域名,避免携带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");
chain.doFilter(request, response);
① ⾸先npm安装好axios,其次在main.js中引⼊
import axios from 'axios'
//把axios挂载到vue的原型中,在vue中每个组件都可以使⽤axios发送请求
Vue.prototype.$axios = axios
//重要在于这⾥,Vue.prototype.HOME = '/api'是⼀个定值,默认指向localhost,所有修改
指向路径为'/api',配置⽂件index.js定义的可跨域路径
Vue.prototype.HOME = '/api'
② 修改上述所说的config>index.js配置⽂件
module.exports = {
dev: {
// Paths
assetsSubDirectory: 'static',
assetsPublicPath: '/',
proxyTable: { //axios跨域处理
'/api': { //此处并⾮和url⼀致
target:'http://192.168.2.80:8081/',
changeOrigin:true, //允许跨域
pathRewrite:{
'^/api': ''
}
}
}
}
③ 在⽂件中发送axios
<template>
<div id="app">
<button @click="fn">点击发送axios</button>
<router-view/>
</div>
</template>
<script>
export default {
name: 'App',
methods:{
fn:function(){
this.$axios.get(this.HOME+'/web02_war_exploded/servlet02')
.then(response => {
console.log(response.data);
})
.catch(error => {
console.dir(error)
});
}
}
}
</script>