Vue 框架
一、 Vue.js概述
1. 简介
Vue是一个渐进式(真正用到才引用)的JavaScript框架与其它大型框架不同的是,Vue 被设计为可以自底向上逐层应用。Vue 的核心库只关注视图层,不仅易于上手,还便于与第三方库或既有项目整合。另一方面,与现代化的工具以及各种支持类库结合使用时,Vue 也完全能够为复杂的单页应用提供驱动。
2. SPA介绍
Vue.js属于SPA一员。
英文全称:Single Page Web Application ,SPA
中文全称:单页Web应用。
整个应用就一个页面,客户端页面通过与服务端的交互动态更新页面中内容。
2.1 优点
符合前后端分离工作模式:单页面应用可以结合Restful,符合前后端分离开发。
良好的用户体验:应用没有页面跳转,全是局部刷新,整体页面更流畅。
减轻服务器端压力:由于都是局部刷新对服务器压力更小。
多平台共享:无论是移动端、电脑端都可以共享服务端接口。通过作用域传值就无法实现接口共享。
@RequestMapping("/page")
public String showPage(Model model){
model.addAttribute("test","jqk");
return "page";
}
2.2 缺点
SEO难度大 对于单页面应用在SEO搜索时可能页面搜索到的就是空的<div>。
首页渲染耗时长首页需要一次加载多个请求,渲染时间可能会比较长。
3. MVVM介绍
Vue.js使用了前端中常用的分层思想MVVM。
MVVM分为M、V、VM
- M(Model) 也就是页面中单独数据
- V (View)是页面中HTML结构
- VM(View-Model) 当V需要调用M中数据时,由VM做中间处理
3.1 示例
data(){} 里面的内容就是数据。也就是Model。
<template> 页面内容。也就是View。
{
{name}} 把data中数据传递给<template>是由Vue帮助完成的。也就是VM。
<template>
<div id="app">
我们的名称为:{{name}},已经成立了{{age}}年了。
</div>
</template>
<script>
export default {
name: 'App',
data(){
return {
name:"北京",
age: 15
}
}
}
</script>
二、 名词解释
1. Node.js
对Chrome V8引擎进行了封装,使得JavaScript能够脱离浏览器环境,独立运行(给我的感觉是写了一个项目,项目中只有页面相关代码,发布到服务器中运行,可以浏览器访问这些页面内容)。同时能通过Node.js直接访问数据库的能力。
目前前端市场都是使用基于Node.js的框架。而不是直接使用Node.js。
前后端分离之所以前端项目能够独立运行就是借助Node.js.
2. npm
npm是Node.js中的一个工具。通过npm可以实现一些组件的安装。效果和Linux中的yum有类似。
使用Node.js时不是一下所有东西都能下载下来,有一些是第三方提供的,有些是插件,当需要使用这些东西的时候,通过npm install 进行安装即可。
3. webpack
是前端开发中的项目管理工具。和我们在开发Java时Maven的作用类似。
4. Vue-cli
Vue-cli是Vue.js的客户端工具。通过Vue-cli可以实现Vue项目脚手架功能等,进行快速搭建。
5. cnpm
淘宝镜像提供的工具。解决了npm使用国外地址下载资源慢的问题。需要安装淘宝镜像后就可以使用了。
偶尔会出现工具无法连接淘宝服务器的情况。每次在使用时都是先通过cnpm命令查看是否能够连接淘宝镜像。才去使用。
三、 总体环境准备
相关软件下载链接
Node.js: https://nodejs.org/zh-cn/download/
vue官方网站 :https://vuejs.org/
github官方网站下载vue.js :https://github.com/vuejs/vue
1. Node.js安装
运行软件中node-v12.16.1-x64.msi,所有的过程都点击next按钮。
安装完成后在命令行中运行命令查看是否安装成功。
查看node的版本
node -v
查看npm版本
npm -v
2 安装npm淘宝镜像
国内使用npm进行下载资源时比较慢,可以使用国内镜像提升下载速度。
本次课程使用淘宝镜像进行操作,在命令行输入命令进行安装。
npm install -g cnpm --registry=https://registry.npm.taobao.org
运行完成后通过cnpm命令查看是否安装成功,成功会提示下面信息。如果没有成功会提示没有cnpm命令,然后在进行安装一次即可。
以后所有官方文档中使用npm install 的命令都换成cnpm install
安装完成后,如果IDEA正在启动,需要关闭IDEA,让IDEA加载Node.js相关信息。
3. 安装webpack
其中-g表示全局安装,以后不需要在安装了。如果没有-g表示只能在当前目录(运行命令时所在目录)中使用。如果重新建立项目,换了文件夹还需要重新安装。
在命令行输入
cnpm install -g webpack webpack-cli
4. 安装 Vue Cli
在命令行输入
cnpm install -g @vue/cli
5. 安装Vue.js插件
在IDEA中
菜单settings -> plugins -> 搜索vue -> Vue.js 点击install -> 安装后重启idea
官方插件离线下载网址
https://plugins.jetbrains.com/plugin/9442-vue-js/versions
四、 第一个Vue.js项目
1. 选择项目类型
依次点击菜单 File -> New -> Project -> Static Web -> Vue.js
2. 填写项目信息
Project name:项目名。项目名称不支持大写。
Project location: 项目路径。
Node interpreter: node工具。安装node.js会自动加载本机Node工具,如果没有安装此处为红色none,提示没有none环境。
Vue Cli:Vue工具。如果安装了Vue工具会提示下面信息,如果没有安装会有一个安装命令,此命令运行特别慢,所以一定要按照环境安装步骤安装Vue Cli。
3. 初始化项目
每次创建Vue项目都需要通过Vue Cli脚手架初始化项目信息。
如果是第一次创建项目会在控制台提示我们是否把镜像切换到淘宝镜像提示是否要切换到https://registry.npm.taobao.org,输入Y即可。
如果不是第一次创建项目会自动使用Vue脚手架初始化整个项目。非常明显的在Run面板自动在下载安装内容。当下载安装完成后会出现。内容中说明: Successfully:已经成功创建项目
npm run serve 如果使用命令运行这个目录时需要执行的命令。在IDEA中有可视化操作,直接和JAVA项目一样点击
和输入命令效果一样。
4. 运行项目
使用脚手架搭建的项目已经具备基本条件,选择npm serve后直接点击绿色运行按钮即可。
运行完成后会在控制台显示URL信息,默认占用8080端口
5. 访问项目
在浏览器输入 http://localhost:8080 会显示下面页面
五、 Vue项目结构
1. 目录结构
使用Vue Cli创建出来的项目内容比较多,关注点在src文件夹即可。
-- src
-- assets
-- logo.png 图片
-- components
-- HelloWorld.vue 组件。所有可复用页面都可以做成组件。
-- App.vue 主组件。也是SPA项目中所有内容都是显示在这个页面中的。当访问http://localhost:8080时实际上访问的就是这个页面。
-- main.js 入口js文件。整个项目的总体配置。
-- package.json 包含当前项目所依赖的所有组件的信息。
六、 模板语法
1. 普通文本
Vue使用{
{ key }}获取js中data() 函数返回值。获取的值中如果包含HTML代码,不会解析,原格式输出。
1.1 修改代码
修改项目中App.vue代码。
下面代码符合MVVM。
data() 函数返回值就是Model 对象。方法data()是固定的。
{
{}}就是从Model中取值。
<template>
<div id="app">
<img alt="Vue logo" src="./assets/logo.png">
<HelloWorld msg="Welcome to Your Vue.js App"/>
<p>
我们的名称为:{{name}},已经成立了{{age}}年了。
</p>
</div>
</template>
<script>
import HelloWorld from './components/HelloWorld.vue'
export default {
name: 'App',
components: {
HelloWorld
},
data(){
return {
name:"北京",
age: 15
}
}
}
</script>
1.2 页面
修改后不需要重启项目,会自动帮助我们重新编译项目,页面也不需要刷新就可以显示最终效果。(这点太人性了)
2. HTML支持
如果希望能够解析HTML,必须使用v-html指令。
v-html是任意HTML标签的属性,v-html的取值可以是Model中定义的字段。
<template>
<div id="app">
<img alt="Vue logo" src="./assets/logo.png">
<HelloWorld msg="Welcome to Your Vue.js App"/>
<p>
我们的名称为:{{name}},已经成立了{{age}}年了。<br>
描述:<span v-html="desc"></span>
</p>
</div>
</template>
<script>
import HelloWorld from './components/HelloWorld.vue'
export default {
name: 'App',
components: {
HelloWorld
},
data(){
return {
name:"北京",
age: 15,
desc:"我是<b>好人</b>"
}
}
}
</script>
七、 指令
在vue中所有以v-开头的HTML属性都是叫做指令。之前学习Thymeleaf时就是通过属性控制标签。指令的作用和Thyemeleaf中条件判断等功能是一样的。
1. 条件判断
条件判断最多支持
v-if=”表达式”
v-else-if=”表达式”
v-else
联合使用。也可以像Java中一样单用v-if或v-if和v-else结合使用。
表达式中的变量来源于Model。如果是字符串类型值使用单引号包含。
<template>
<div id="bjsxt">
<p v-if="age<10">
不到10年了
</p>
<p v-else-if="age<14 && age >=10">
不到14年了
</p>
<p v-else>
大于14年了
</p>
</div>
</template>
<script>
export default {
name: 'App',
data() {
return {
name: "北京",
age: 15
}
}
}
</script>
2. 循环遍历
语法:
v-for=”迭代变量 in 数组属性”
:key=”迭代变量” 此属性必须写,否则页面报错
实例:
<template>
<div id="bjsxt">
<ul>
<li v-for="subject in subjects" :key="subject">
{{subject}}
</li>
</ul>
</div>
</template>
<script>
export default {
name: 'App',
data() {
return {
name: "北京",
age: 15,
subjects: ["Java", "AI", "大数据","前端"]
}
}
}
</script>
八、 Vue的事件处理
Vue的事件都是使用 v-on:事件类型 进行绑定。也可以使用@事件类型进行操作。其中事件类型和之前学习jQuery中事件名称是一样。示例中都是以点击事件为例。
1 直接操作属性值
代码示例中通过点击按钮对counter值加一。下面<p>中显示属性值。所以会出现点击按钮后下面数字在变化的效果
<template>
<div id="app">
<button v-on:click="counter += 1">Add 1</button>
<p>The button above has been clicked {{ counter }} times.</p>
</div>
</template>
<script>
export default {
name: 'App',
data() {
return {
counter: 0
}
}
}
</script>
也可以把上面的v-on:click换成@click。
<button @click="counter += 1">Add 1</button>
2. 事件处理方法
Vue中事件也可以绑定给特定的方法进行处理。
@click取值是方法名称
methods是固定属性。里面定义了多有事件能绑定的方法。
jqk:function(event){}
中
- jqk 是方法名。
- event是方法形参,在js中方法形参名称随意。只要@click中使用没有参数的方法时,都会默认传递事件对象。如果方法中不使用事件对象,function里面就不需要写event了,在Vue中变量声明后必须使用。
<template>
<div id="app">
<button @click="jqk">click</button>
</div>
</template>
<script>
export default {
name: 'App',
data(){
return {
field:"值"
};
},
methods:{
jqk:function (event) {
// this是当前Vue对象
alert(this.field);
if(event){
alert(event.target.tagName)
}
}
}
}
</script>
3. 事件传参
事件传参只需要在调用方法时加上括号和要传递的参数就可以了。
注意:
-
字符串值必须有单引号。
-
没有单引号参数(field),调用data()中属性
-
方法中不需要使用事件对象时就不写
ev
e
n
t
。
但
是
如
果
需
要
使
用
事
件
对
象
,
必
须
手
动
传
递
事
件
对
象
,
且
必
须
叫
做
event。但是如果需要使用事件对象,必须手动传递事件对象,且必须叫做
e
v
e
n
t
。
但
是
如
果
需
要
使
用
事
件
对
象
,
必
须
手
动
传
递
事
件
对
象
,
且
必
须
叫
做
event,$event是全局Vue对象原型(prototype)里面的属性。 -
事件调用方法时传递了多个参数,在定义方法时可以只接收参数中前N个(N>=0&&N<=调用时参数个数),但是一定接收了,就必须使用。
代码:
<template>
<div id="app">
<button @click="jqk('name',$event)">click</button>
<button @click="jqk(field,$event)">click</button>
</div>
</template>
<script>
export default {
name: 'App',
data(){
return {
field:"值"
};
},
methods:{
jqk:function (name,event) {
alert("name:"+name);
if(event){
alert(event.target.tagName)
}
}
}
}
</script>
九、 组件
组件:如果项目中多次用到类似效果,就可以把这个效果进行自定义组件。
新建项目后默认存在HelloWorld.vue就是一个组件。
import Helloworld … 组件文件必须导入才能使用。其中Helloworld为自定义名称,通过这个名称就可以调用对应组件。如果import时直接写组件名(大小写相同)IDEA会提升生成组件的路径,所以一般习惯上都是把名称定义为组件文件名。
components: 组件文件只import是不能被使用的。必须在components中注册组件,注册后在<template>中就可以通过组件名直接引用组件了。在<template>中组件以标签形式存在,标签名为组件名。其中msg是在Helloworld中定义的props参数,表示需要传递给组件的数据。
1. 新建vue文件
在Vue中组件就是可复用的页面内容。以.vue文件形式存在。
在src/components中新建一个文件。名称任意。示例中叫做MyComponent.vue。
在Vue中组件的文件名多使用大驼峰。
【{
{jqk}} 获取组件传递参数的值】 【props:定义组件传递的参数名称和类型】
<template>
<div>
<div>这是一个组件</div>
<div>{{jqk}}</div>
</div>
</template>
<script>
export default {
name: "MyComponent",
props: {
jqk: String
}
}
</script>
<style scoped>
</style>
2. 修改App.vue
<MyComponent>就是下面定义的组件名称。
【jqk是参数名】【import 导入组件并设置名称为MyComponent】【components 声明组件】
<template>
<div id="app">
<MyComponent jqk="这是传递的内容"/>
</div>
</template>
<script>
import MyComponent from "@/components/MyComponent";
export default {
name: 'App',
components:{
MyComponent
}
}
</script>
3. 组件类型
类型名 | 说明 |
---|---|
String | 字符串 |
Number | 数字 |
Boolean | 布尔 |
Array | 数组 |
Object | 对象 |
Function | 函数 |
Promise | 构造方法 |
4. 当传递数值类型时
当传递数值类型时,必须使用v-bind指令进行设置,这时参数表示一个表达式而不是一个字符串。其他步骤省略,演示参数定义和参数传递
4.1 定义参数
<script>
export default {
name: "Bjsxt",
props:{
name:String,
age:Number
}
}
</script>
4.2 传递参数
如果直接使用age=12进行传参效果依然可以实现,但是会在浏览器出现错误,提示要一个12的参数值,但是发现传递的是”12”
<Bjsxt name="名字" v-bind:age="12" ></Bjsxt>
十、 路由(Route)
1. 路由介绍
1.1 组件和页面的区别?
组件和页面文件中内容是完全相同,唯一区别是组件可能被多次使用,import时会给组件定义个名称,而页面文件可能只使用一次,import时就不需要定义名称。在项目中为了区分页面和组件,把组件放在components文件夹而页面放在pages(名称随意,一般多叫pages)文件夹下。
1.2 为什么使用路由?
在项目中创建了First.vue和Second.vue。如果按照组件方式进行操作这个两个页面中数据固定显示在App.vue中。但是我们知道正常项目都是通过不同的URL控制显示不同页面。在SPA项目中也是需要通过不同的URL在App.vue中显示不同的数据。
现在缺少一个可以通过URL控制哪个页面显示在App.vue中的功能/组件。路由就是做这件事情的。
1.3 什么是路由?
在Vue中路由就是控制显示哪个页面。通过路由显示的页面是显示在App.vue中的,这符合SPA,当更改URL后只改变App.vue页面中路由对应的部分的内容,也就是说通过路由显示时也是属于局部刷新效果。
在App.vue中通过<router-view/>显示路由内容。
简单一句话说明:通过识别URL显示页面的功能。
2. 安装路由依赖
在IDEA中的terminal面板运行命令。–save表示把添加的依赖写入到package.json。如果没有–save效果上也可以,但是加上可以更好的知道项目都使用了哪些组件。
cnpm install --save vue-router
使用terminal时也需要注意下,命令是否在当前项目的根路径下。
运行成功后会在package.json中多了router相关依赖。
3. 新建两个页面
在src下新建了page文件夹。在文件夹下新建了两个.vue的页面
页面内容也只是写了字符串first。另一个页面first换成second,其他都相同。
此时这两个页面是无法访问的。
<template>
<div>
first
</div>
</template>
<script>
export default {
name: "First"
}
</script>
<style scoped>
</style>
4. 修改main.js
import Vue from 'vue'
import App from './App.vue'
// 导入路由依赖。安装了vue-router组件后系统带有的依赖。
import VueRouter from 'vue-router'
// 导入两个页面
import First from "@/pages/First";
import Second from "@/pages/Second";
Vue.config.productionTip = false;
// 使用路由
Vue.use(VueRouter);
// 创建路由对象。new VueRouter为上面import设置的名称
const router = new VueRouter({
// 没有history,访问URL会有#
mode:"history",
routes:[
{
path:"/first",
component:First
},
{
path:"/second",
component:Second
}
]
});
new Vue({
// 使用router对象
router,
render: h => h(App),
}).$mount('#app')
5. 修改App.vue
必须要有<router-view/> 否则无法显示路由控制的页面。
<template>
<div id="app">
<router-view/>
<MyComponent jqk="这是传递的内容"/>
</div>
</template>
6. 优化结构
把main.js中和路由相关的内容放到一个单独的js文件中。这样维护更好。
6.1 编写index.js文件
在src下新建router文件夹,在文件夹中新建index.js。
注意文件的第一行和最后一行。
// 必须有这个导入,否则使用路由报错
import Vue from 'vue'
// 导入路由依赖
import VueRouter from 'vue-router'
// 导入两个页面
import First from "@/pages/First";
import Second from "@/pages/Second";
// 使用路由
Vue.use(VueRouter);
// 创建路由对象。new VueRouter为上面import设置的名称
const router = new VueRouter({
// 没有history,访问URL会有#
mode:"history",
routes:[
{
path:"/first",
component:First
},
{
path:"/second",
component:Second
}
]
});
// 必须有这个导出,否则main.js无法获取router对象
export default router
6.2 修改main.js
引入router下index.js文件。
import Vue from 'vue'
import App from './App.vue'
// Vue中index.js是默认js文件名。下面引用时省略了index
import router from "@/router";
Vue.config.productionTip = false
new Vue({
router,
render: h => h(App),
}).$mount('#app')
十一、 通过js控制路由跳转
1. JS控制跳转
保证在项目中生效路由组件和引入路由规则
// 渐进式开发,让组件生效
Vue.use(VueRoute)
new Vue({
// 生效规则
router,
render: h => h(App),
}).$mount('#app')
可以在当前项目任意页面中通过this.$router调用路由对象。
通过下面代码可以实现路由跳转
this.$router.push(“/first”)
十二、 发起网络请求和跨域处理
Vue中使用axios进行网络请求。使用起来和jQuery中
.
g
e
t
和
.get和
.
g
e
t
和
.post功能类似。
给定服务端控制器代码。可以接收name和age参数,设置到Map中并返回。
一定要注意:控制器上有跨域注解。前后端分离都是跨域请求。且端口不能是8080端口。
@RestController
@CrossOrigin
public class DemoController {
@RequestMapping("/demo")
public Map<String,Object> demo(String name ,Integer age){
Map<String,Object> result = new HashMap<>();
result.put("name",name);
result.put("age",age);
return result;
}
}
1. 安装依赖
cnpm install --save axios
2. get请求
<template>
<div>
发起请求
</div>
</template>
<script>
import axios from "axios"
export default {
name: "axios",
// 页面加载事件。
mounted() {
axios.get("http://localhost:8081/demo?name=bjsxt&age=12")
.then(res => {
console.log(res.data);
})
.catch(error => {
console.log(error);
})
}
}
</script>
<style scoped>
</style>
3. post方式
下面演示了使用POST获取值后把name显示在页面的过程。
注意:
- POST也支持URL重写方式传参。通过?和&传参数。
- 如果使用下面这种方式传参必须要结合querystring使用。
- post的第二个参数为请求体数据。如果没有借助querystring组件,服务器端在接收时需要通过@RequestBody进行接收。
<template>
<div>
发起请求获取到的结果。
{{name}}
</div>
</template>
<script>
import axios from "axios"
import qstring from "querystring"
export default {
name: "axios",
data() {
return {
name: ""
};
},
mounted() {
axios.post("http://localhost:8081/demo", qstring.stringify({
name: "张三",
age: 12
}))
.then(res => {
console.log(res.data.name);
this.name = res.data.name;
})
.catch(error => {
console.log(error);
})
}
}
</script>
<style scoped>
</style>
4. axios全局设置
如果使用上面的方式,将需要在每个页面中都导入axios。
也可以全局绑定axios。
4.1 修改main.js
Vue.prototype.
a
x
i
o
s
=
a
x
i
o
s
中
,
【
V
u
e
全
局
V
u
e
对
象
】
【
p
r
o
t
o
t
y
p
e
原
型
。
设
置
全
局
属
性
】
【
axios=axios 中,【Vue 全局Vue对象】【prototype 原型。设置全局属性】【
a
x
i
o
s
=
a
x
i
o
s
中
,
【
V
u
e
全
局
V
u
e
对
象
】
【
p
r
o
t
o
t
y
p
e
原
型
。
设
置
全
局
属
性
】
【
axios 随意设置的名称】【axios 依赖对象名】
import Vue from 'vue'
import App from './App.vue'
// Vue中index.js是默认js文件名。下面引用时省略了index
import router from "@/router";
import axios from "axios"
import qstring from "querystring"
Vue.prototype.$axios = axios
Vue.prototype.$qstring=qstring
Vue.config.productionTip = false
new Vue({
router,
render: h => h(App),
}).$mount('#app')
4.2 页面中写法
在任何页面中都可以直接使用this.$axios进行设置。
<template>
<div>
这是首页。所有内容都显示在这个页面中。SPA<br/>
姓名:{{name}}, 年龄:{{age}}
</div>
</template>
<script>
export default {
data() {
return {
name:"",
age:0
};
},
mounted() {
this.$axios.post("http://localhost:8081/demo",this.$qstring.stringify({
name:"北京尚学堂",
age:15
}))
.then(response => {
this.name = response.data.name;
this.age = response.data.age
})
.catch(error => {
console.log(error)
})
}
}
</script>
十三、 请求代理
1.请求代理
在Vue中发起网络请求时URL都使用完整URL,可以把公共URL提出,提出后发起网络请求时URL只写路径部分。省略协议、ip、端口。
如果没有请求代码每次在浏览器开发者工具看见真实请求服务器地址,这样话就把服务器暴露给客户端了。使用代理后只能看见代理前请求,保护真实服务器地址。
在项目根路径(不是src)下新建vue.config.js名称固定
这个配置文件操作完成后必须重启
module.exports = {
devServer: {
proxy: {
// 当请求Vue项目路径以/api开头时转发给下面
'/api': {
// 服务器端URL
target: 'http://localhost:8081/',
ws: true,
pathRewrite: {
// 把路径中api去掉
// /api/demo -> /demo
'^/api': ''
},
changeOrigin: true
}
}
}
}
发起请求时可以使用/api/xxx 的形式
this.$axios.get("/api/demo?name=bjsxt&age=16")
在开发者工具中看见的请求
十四、 Vue Element
Vue Element 就是Vue的扩展插件。
在课堂上使用ElementUI 提供的Vue 2.0插件。
网址:
https://element.eleme.cn/#/zh-CN
建议:按照官网中文档进行学习。写项目时复制官网代码进行修改。
1. 添加依赖
安装element-ui。直接在IDEA中terminal中运行
cnpm install --save element-ui
2. 引入Element依赖
修改main.js ,添加三行代码(第2、3、6行)。表示引入ElementUI。(官网文档 -> 快速上手中就是下面代码)
import Vue from 'vue'
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
import App from './App.vue'
Vue.config.productionTip = false
Vue.use(ElementUI);
new Vue({
render: h => h(App),
}).$mount('#app')
3. 添加标签
在App.vue中添加Eleme官网中组件内容。以按钮举例。
<template>
<div id="app">
<el-button type="primary">主要按钮</el-button>
</div>
</template>
4. 查看页面
在页面中会显示带有样式的按钮