Vue

前言

做个期末项目还得我会前端,这不是为难我嘛,本来就对前端没有太多的知识积累。导致我还得现去学习Vue。本来前端这一块是想留着小学期的时候来好好学的
目前看来只能现快速过一遍了。

Vue创建

基于Vue开发项目的环境要求

  • node.js 安装教程

  • npm 这个一般在安装node.js的时候会同时安装,这个不用过多纠结

  • Vue CLI
    基于Vue进行快速开发的完整系统,实现交互式的项目脚手架

    1
    npm i @vue/cli -g

使用 Vue CLI 创建前端工程

  • 打开一个文件夹,最好是不要有中文的

  • 在文件夹中cmd

  • 输入 vue create 项目名称

    1
    vue creat vue-demo-1
  • 选择Vue2,还是Vue3

  • 回车等待创建完成就行了

vue ui (网页界面创建:心情不好不想放图片了)

  • 打开一个文件夹,最好是不要有中文的
  • 在文件夹中cmd
  • 输入 vue ui
  • 回车后会给你一个网页连接,点进去到浏览器创建就行了很直观的创建方式
  • 还可以直接在上面看见自己的依赖和插件,同时也可以安装插件

启动前端项目

  • vscode中打开创建项目所生成的那个文件夹
  • 在vscode中按:ctrl+j 打开终端
  • 终端中输入
    1
    npm run serve
    上面那个serve取决于package.json里面的serve,那个叫什么名字
    run 后面就写什么名字。
  • 回车后出现链接,点击就行了
  • 停止跟linux是一样的ctrl+c

修改项目端口号

需要更改项目的端口号,在文件中找到vue.config.js文件中输入
注意空格

1
2
3
4
5
6
7
const { defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({
transpileDependencies: true,
devServer: {
port: 7070
}
})

Vue基础

vue组件

Vue的组件文件以.vue结尾,每个组件由三部分组成:

<template> 结构:

  1. 只有一个根元素
  2. 由它生成HTML代码

<style> 样式

  1. 编写CSS,控制页面展示效果
  2. 全局样式: 影响所有组件
  3. 局部样式: 只作用于当前组件

<script> 逻辑

插值

使用方式:{{}}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<template>
<div class="hello">
{{name}}
{{age > 60 ? '老年':'青年'}}
</div>
</template>

<script>
export default {
data(){
return{
name: '张三',
age: 70
}
}
}
</script>

属性绑定

用法:v-bind:xxx 简写 :xxx

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<template>
<div class="hello">
{{name}}
{{age > 60 ? '老年':'青年'}}
<input type="text" v-bind:value="name"/>
<input type="text" :value="age"/>
<img :src="src"/>
</div>
</template>

<script>
export default {
data(){
return{
name: '张三',
age: 70,
src: 'https://tse1-mm.cn.bing.net/th/id/OIP-C.00HEmqYJSK44tQgKfX9dWAHaEo?rs=1&pid=ImgDetMain'
}
}
}
</script>

事件绑定

用法: v-on:xxx 简写 @xxx

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
<template>
<div class="hello">
{{name}}
{{age > 60 ? '老年':'青年'}}
<input type="text" :value="name"/>
<input type="text" :value="age"/>
<img :src="src">

<input type="button" value="保存" v-on:click="handleSave"/>
<input type="button" value="保存" @click="handleSave1"/>

</div>
</template>

<script>
export default {
name: 'HelloWorld',
props: {
msg: String
},
data() {
return {
name: 'zhangsan',
age: '70 ',
src: '../assets/logo.png'
}
},
methods: {
handleSave() {
alert('你点击了保存按钮')
},
handleSave1() {
alert('简写后的保存按钮')
}
}
}
</script>

双向绑定

  • 作用:表单输入项和data方法中的属性进行绑定,任意一方改变都会同步给另一方
  • 用法: v-model
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    <template>
    <div class="hello">
    {{name}}
    <input type="text" v-bind:value="name"/>
    <input type="text" v-model="name" />
    <input type="button" value="修改name" @click="handleChange" />
    </div>
    </template>

    <script>
    export default {
    data(){
    return {
    name: '张三'
    }
    },
    methods:{
    handleChange(){
    this.name = '李四'
    }
    }
    }
    </script>

条件渲染

作用:根据表达式的值来动态渲染页面元素

用法:v-if、v-else、v-else-if

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<template>
<div class="hello">
<div v-if="sex==1">男</div>
<div v-else-if="sex==0">女</div>
<div v-else>为止</div>
</div>
</template>

<script>
export default {
data(){
return {
sex: 1
}
},

}
</script>

Vue基本使用方式-axios

Axios是一个基于promise的网络请求库,作用于浏览器和node.js中

安装命令

1
npm install axios

导入命令:这个放到js里面

1
import axios from 'axios' 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77

<template>
<div class="hello">
{{name}}
{{age > 60 ? '老年':'青年'}}
<input type="text" :value="name"/>
<input type="text" :value="age"/>
<img :src="src">

<input type="button" value="保存" v-on:click="handleSave"/>
<input type="button" value="保存" @click="handleSave1"/>
<input type="text" v-model="name" />
<input type="button" value="修改name" @click="handleChange"/>

<div v-if="sex==1">

</div>
<div v-else-if="sex==2">

</div>
<div v-else>
未知
</div>
<input type="button" value="发送POST请求" @click="handleSend"/>
<input type="button" value="发送GET请求" @click="handleSend1"/>
</div>
</template>

<script>
import axios from 'axios'
export default {
name: 'HelloWorld',
props: {
msg: String
},
data() {
return {
name: 'zhangsan',
age: '70 ',
src: '../assets/logo.png',
sex: 1
}
},
methods: {
handleSave() {
alert('你点击了保存按钮')
},
handleSave1() {
alert('简写后的保存按钮')
},
handleChange() {
this.name = '李四'
},
handleSend() {
//通过axios发送请求
axios.post('/api/admin/employee/login',{
username: 'admin',
password: '123456'
}).then(res => {
console.log(res.data)
}).catch(error =>{
console.log(error.response)
})
},
handleSend1() {
axios.get('/api/admin/shop/status',{
headers: {
token: 'eyJhbGciOiJIUzI1NiJ9.eyJlbXBJZCI6MSwiZXhwIjoxNzE2NzIwNDE2fQ.HJ-OJPpgK_87F7jWnBkdGrXHGLrw564fSzx1nR4DBq'
}
}).then(res =>{
console.log(res.data)
})
}
}
}
</script>

跨域问题

所谓跨域,就是这个Vue运行在一个容器里面,并且端口号7070,后端tomcat容器又是在8080端口
相当于就是两个容器了,要想直接访问的话是不行的。

为了解决跨域问题,可以在vue.config.js文件中配置代理。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
const { defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({
transpileDependencies: true,
devServer: {
port: 7070,
proxy: {
'/api': {
target: 'http://localhost:8080',
pathRewrite: {
'^/api' : ''
}
}
}
}
})

当前端口是7070,想往8080发送请求,解决方法是配置代理。前端请求先请求到代理,然后代理转发服务请求到后端。proxy是代理的意思。/api要求前端发送的请求都以/api开始,才进行代理。会转发到指定的target的服务上。pathRewrite会将/api配置成空串。

Vue路由

创建带有路由功能的项目

这里有两种创建的方式,第一种是在Vue ui中创建

  1. 在终端输入
    1
    vue ui
  2. 进入终端中,找到项目管理器,然后创建新项目
  3. 在预设界面选择手动配置项目
  4. 找到Router打开,然后点击下一步就行了
  5. 创建完成后package.json中会出现相应的依赖

第二种是在已有项目中,输入

1
npm install vue-router

回车后效果是一样的

路由逻辑分析

VueRouter:路由器,根据路由请求在路由视图中动态渲染对应的视图组件。简单解释就是我们点击前端按钮后,会替我们发起一个请求

<router-link>:路由链接组件,浏览器会解析成<a> 路由接受到了以后,就会在路由表中找相应的页面

<router-view>:路由视图组件,用来展示与路由路径匹配的视图组件。 这个就是占位的地方,要让相应的页面展示到什么地方

首先在package.json里面加入“vue-router”,然后在main.js中引入router,找到router下面有一个index.js,然后在这个文件里引入VueRouter(在vue-router里)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
 import Vue from 'vue'
import VueRouter from 'vue-router'
import HomeView from '../views/HomeView.vue'

Vue.use(VueRouter)
//维护路由表,某个路由路径对应的哪个视图组件
const routes = [
{
path: '/',
name: 'home',
component: HomeView
},
{
path: '/about',
name: 'about',
// route level code-splitting
// this generates a separate chunk (about.[hash].js) for this route
// which is lazy-loaded when the route is visited.
component: () => import(/* webpackChunkName: "about" */ '../views/AboutView.vue')
},
{
path: '/404',
component: () => import('../views/404View.vue')
},{
path: '*',
redirect: '/404'
}
]

const router = new VueRouter({
routes
})

export default router

上述代码展示了两种两种导入方式:

  • 第一种component: HomeView 就是静态导入方式
    在页面开始加载的时候就会默认都加载了,不管用不用这种相对于资源的加载来说比较占用系统资源

  • 第二种则是图片加载中的懒加载方式,只有要用的时候才加载,不用就不加载

编程式路由

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<template>
<div id="app">
<nav>
<input type="button" value="编程式路由跳转" @click="jump"/>
</nav>
<router-view/>
</div>
</template>

<script>
export default{
methods:{
jump(){
//使用编程式路由跳转
this.$router.push('/about')
}
}
}
</script>

this.$router是获取到路由对象。push方法是根据url进行跳转。

访问的页面没有

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
import Vue from 'vue'
import VueRouter from 'vue-router'
import HomeView from '../views/HomeView.vue'

Vue.use(VueRouter)

const routes = [
{
path: '/',
name: 'home',
component: HomeView
},
{
path: '/about',
name: 'about',
component: () => import('../views/AboutView.vue')
},
{
path: '/404',
component: () => import('../views/404View.vue')
},
{
path: '*',
redirect: '/404'
}
]

const router = new VueRouter({
routes
})

export default router

嵌套路由

嵌套路由:组件内要切换内容(也就是变化的时候只改变页面的一部分,另一部分不改变),需要用到嵌套路由。
一样的,要在创建的时候要勾选路由那个选项,或者直接npm安装也行
然后会出现router文件夹下面就是嵌套和不嵌套的示例代码,这里时间问题我就暂时不解释了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60

import Vue from 'vue'
import VueRouter from 'vue-router'
import HomeView from '../views/HomeView.vue'


Vue.use(VueRouter)
//维护路由表,某个路由路径对应的哪个视图组件
const routes = [
{
path: '/',
name: 'home',
component: HomeView
},
{
path: '/about',
name: 'about',
// route level code-splitting
// this generates a separate chunk (about.[hash].js) for this route
// which is lazy-loaded when the route is visited.
component: () => import(/* webpackChunkName: "about" */ '../views/AboutView.vue')
},
{
path: '/c',
// route level code-splitting
// this generates a separate chunk (about.[hash].js) for this route
// which is lazy-loaded when the route is visited.
component: () => import(/* webpackChunkName: "about" */ '../views/contaner/contanerView.vue'),
redirect:'/c/p1',//重定向
children: [
{
path: '/c/p1',
component: () => import('../views/contaner/P1View.vue')
},
{
path: '/c/p2',
component: () => import('../views/contaner/P2View.vue')
},
{
path: '/c/p3',
component: () => import('../views/contaner/P3View.vue')
}
]
}
,
{
path: '/404',
component: () => import('../views/404View.vue')
}, {
path: '*',
redirect: '/404'
}
]

const router = new VueRouter({
routes
})

export default router

1.安装并导入elementui,实现页面布局

在vscode的控制台输入如下命令:

1
npm i element-ui -S

提供子视图组件,用于效果展示
在布局容器视图中添加,实现子视图组件展示

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
<template>
<el-container>
<el-header>Header</el-header>
<el-container>
<el-aside width="200px">
//这边这个是左边栏,将链接放到左边栏,然后换行美化格式
<router-link to="/c/p1">p1</router-link><br>
<router-link to="/c/p2">p2</router-link><br>
<router-link to="/c/p3">p3</router-link><br>
</el-aside>
<el-main>
<router-view/>
</el-main>
</el-container>
</el-container>
</template>

<script>
export default {

}
</script>

<style>
.el-header,
.el-footer {
background-color: #B3C0D1;
color: #333;
text-align: center;
line-height: 60px;
}

.el-aside {
background-color: #D3DCE6;
color: #333;
text-align: center;
line-height: 200px;
}

.el-main {
background-color: #E9EEF3;
color: #333;
text-align: center;
line-height: 160px;
}

body>.el-container {
margin-bottom: 40px;
}

.el-container:nth-child(5) .el-aside,
.el-container:nth-child(6) .el-aside {
line-height: 260px;
}

.el-container:nth-child(7) .el-aside {
line-height: 320px;
}
</style>

状态管理vuex

vuex是一个专为Vue.js应用程序开发的状态管理库。

vuex可以在多个组件之间共享数据,并且共享的数据是响应式的,即数据的变更能及时渲染到模板。
简单点就是例如将未登录用户展示出来,当用户登录后,又将其展示为当前用户的名字

安装命令:

1
npm install vuex@next --save

state:状态对象,集中定义各个组件共享的数据。

mutations:类似于一个事件,用于修改共享数据,要求必须是同步函数。

actions:类似于mutation,可以包含异步操作,通过调用mutation来改变共享数据。

创建vue项目管理器

1
vue ui

在项目管理器中勾选相应的功能就行

同一个变量多个地方展示

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
import Vue from 'vue'
import Vuex from 'vuex'
import axios from 'axios'

Vue.use(Vuex)

export default new Vuex.Store({
//共享数据
state: {
name: '未登录游客'
},
getters: {
},
//修改共享数据只能通过mutation实现,必须是同步操作
mutations: {
setName(state, newName) {
state.name = newName
}
},
//通过actions可以调用到mutations,在actions中可以进行异步操作
actions: {
setNameByAxios(context) {
axios({
url: 'api/admin/employee/login',
method: 'post',
data: {
username: 'admin',
password: '123456'
}
}).then(res => {
if (res.data.code == 1) {
//异步请求后,需要修改共享数据
context.commit('setName',res.data.data.name)
}

})
}
},
modules: {
}
})

将App.vue中的内容替换如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
<template>
<div id="app">
欢迎你{{ $store.state.name }}

<input type="button" value="通过mutations修改共享数据" @click="handleUpdate" />
<input type="button" value="调用actions中定义的函数" @click="handleCallAction" />
<img alt="Vue logo" src="./assets/logo.png">
<HelloWorld msg="Welcome to Your Vue.js App" />
</div>
</template>

<script>
import HelloWorld from './components/HelloWorld.vue'

export default {
name: 'App',
components: {
HelloWorld
},
methods: {
handleUpdate() {
//mutations中定义的函数不能直接调用,必须通过这种方式来调用
//setName为mutations中定义的函数名称
this.$store.commit('setName', '李四')
},
handleCallAction() {
//调用函数固定写法
this.$store.dispatch('setNameByAxios')
}
}
}
</script>

<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>

mutations修改变量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
import Vue from 'vue'
import Vuex from 'vuex'
import axios from 'axios'

Vue.use(Vuex)

export default new Vuex.Store({
//共享数据
state: {
name: '未登录游客'
},
getters: {
},
//修改共享数据只能通过mutation实现,必须是同步操作
mutations: {
setName(state, newName) {
state.name = newName
}
},
//通过actions可以调用到mutations,在actions中可以进行异步操作
actions: {
setNameByAxios(context) {
axios({
url: 'api/admin/employee/login',
method: 'post',
data: {
username: 'admin',
password: '123456'
}
}).then(res => {
if (res.data.code == 1) {
//异步请求后,需要修改共享数据
context.commit('setName',res.data.data.name)
}

})
}
},
modules: {
}
})

actions修改变量含有异步操作

所谓异步感觉就是有先后顺序的操作,前一步的结果可能作为下一步的参数使用。
安装axios:

1
npm install axios

context是上下文,有了上下文就可以调用到mutations里面的方法。

在异步请求后,需要修改共享数据,只能通过mutations中的方法。

然后就是配置跨域的问题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
const { defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({
transpileDependencies: true,
devServer:{
port:7777,
proxy:{
'/api':{
target:'http://localhost:8080',
pathRewrite:{
'^/api':''
}
}
}
}
})

TypeScript介绍

基本类型定义

字符串类型 (string): 用于定义字符串类型的变量。
typescript
let username: string = ‘zhangsan’;

  • 数字类型 (number): 用于定义数字类型的变量。

let age: number = 123;

  • 布尔类型 (boolean): 用于定义布尔类型的变量。

let isTrue: boolean = true;

  • 函数定义
    函数类型注解: 可以为函数的参数和返回值指定类型。

function printText(s: String, alignment: ‘left’ | ‘right’) {
console.log(s, alignment);
}

  • 接口定义
    接口 (interface): 用于定义对象的结构。
    interface Cat {
    name: string,
    age?: number; // 加问号表示可选
    }
  • 实现接口: 类可以通过 implements 关键字实现一个或多个接口。

class Bird implements Animal {
// …
}

  • 类定义
    类的基本使用 (class):
    定义属性。
    构造方法 (constructor): 初始化属性。
    方法定义。

class User {
name: string;
constructor(name: string) {
this.name = name;
}
study() {
console.log(this.name + “正在学习”);
}
}

  • 类的继承 (extends): 子类可以继承父类的属性和方法。

class Parrot extends Bird {
say() {
console.log(this.name + ‘say hello’);
}
}

  • 实例化对象
    创建对象实例: 使用 new 关键字创建类的实例。

const user = new User(‘zhangsan’);
const b1 = new Bird(‘yanzi’);
const myParrot = new Parrot(‘polly’);

  • 访问属性和方法
    访问属性: 通过实例访问类的属性。
    console.log(user.name);
    console.log(b1.name);
    console.log(myParrot.name);
  • 调用方法: 通过实例调用类的方法。
    user.study();
    b1.eat();
    myParrot.say();
    myParrot.eat();
    TypeScript 与 Vue 的结合
    Vue 类型扩展: TypeScript 可以与 Vue 一起使用,通过扩展 Vue 的类型系统来增强开发体验。
    import { extend } from “vue/types/umd”;