图书信息管理系统(一)

这篇文章是我在学习完Vue2.0之后做的实战项目,该项目是图书信息管理系统,后台数据库是使用虚拟技术EasyMock来实现的。
这一整个项目的搭建流程我都会持续更新,全部的文章我都会更新在我的专栏图书信息管理系统里面,大家有需要的可以去看看。


前言

今天记录的主要是在写图书信息管理系统项目的基础框架搭建的知识点。由于时间有限,所以此项目主要记录了一些重点难点便于理解记忆,对于比较难以理解的知识点的标题下面我都会写上自己的理解总结,大家如果不懂的可以多看看标题下面的总结部分,主要讲解了比较复杂的运行逻辑和难以理解的重点难点。


一、项目介绍

图书信息管理系统——单页面前后端分离项目。

1.1、项目展示

在这里插入图片描述在这里插入图片描述

1.2、项目技术栈

vue.js(2.6.11):构建用户界面的 MVVM 框架,核心思想:数据驱动、组件化。
vue-cli (@vue/cli 4.2.3):是 vue 的脚手架工具。
webpack:项目打包构建工具。
vue-router (3.1.5):是官方提供的路由器,使用 vue.js 构建单页面应用程序变得轻而易举。
axios (axios@0.19.2):官方推荐的发送异步请求插件。
vuex(3.1.3): 是一个专为 vue.js 应用程序开发的状态管理模式,简单来说 Vuex 就是集中管理数据的,也是官方推荐的插件。
Element (2.13.1):一套为开发者、设计师和产品经理准备的基于Vue 2.0 的桌面端组件库。
Easymock:Easy Mock 是一个可视化,并且能快速生成 模拟数据 的持久化服务,内置 mock.js(1.1.0),旨在帮助前端独立于后端进行开发,帮助编写单元测试。
Echarts(4.7.0):动态生成图表。

二、引入ElementUI

2.1、安装 Element UI

npm i element-ui –S

2.2、入口文件 main.js 导入 elementui

import ElementUI from 'element-ui' //element-ui 不能写错,是组件名称。这里引入的是 js 文件,还要单独引入 css 文件
import 'element-ui/lib/theme-chalk/index.css';//index.css 这个文件当然在项目下的相应目录下有的
Vue.use(ElementUI);//指明要使用 ElementUI 组件了

2.3、安装 Element UI Snippets 插件

为了更方便的使用 element,为 vscode 安装插件 Element UISnippets,安装后会有智能提示。

三、封装 axios 对象,以便更好处理异步请求

概述:
因为项目中很多组件中都要通过 axios 发送异步请求,所以为了更好的使用 axios 对象,就需要自己封装一个 axios 对象。加入请求拦截器和响应拦截器。

总结:
这里的意思就是,首先我们自己封装一个myaxios用来获取代替axios,在src/utils下,myaxios里面指定了请求规则(请求路径和请求超时的时间),还定义了请求拦截器和响应拦截器(这里没有用到,以后会用到),最后不要忘了导出myaxios供别处使用。然后在public下放要请求的数据data.json,接着在src/api下创建一个test.js文件用来发送Ajax请求,先引入myaxios,然后因为发送请求获取数据后的请求结果是要展示在前端页面上的,所以这里只写发送请求获取数据的功能,不要在这里展示数据,因此这里只定义了一个getList()方法,export default 导出的是一个对象,对象里面我们给定义一个方法 getList(),通过这个方法返回 myaxios()执行结果,是一个 promise对象。然后我们再在HelloWorld.vue里面来展示结果。在HelloWorld.vue里面先引入test.js,然后调用里面的方法来发送请求获取数据,再根据结果的正确与否来展示结果或者返回请求失败。

3.1、安装 axios

npm i -S axios

3.2、在项目的 src\utils(存放工具文件)下创建一个 myaxios.js,在该文件中自己封装一个 axios 对象。

为了测试请求数据,在 public 文件夹下新建一个 data.json。输入几条数据如下:

// json 文件不能使用单引号,标准是使用双引号,使用单引号容易出问题,在 js 文件中单引号、双引号都没问题
[
{"id":1,"bookname":"vue 前端设计","price":58}, {"id":2,"bookname":".net core 实战开发","price":88}, {"id":3,"bookname":"C#程序设计","price":68}
]

3.3、原生 axios 发送请求

myaxios.js 文件初始内容如下:

import axios from 'axios' //采用原生的 axios 发送 get 请求。
//表示发送 get 请求,请求 data.json 文件(会自动到 public 文件夹下找,不能显示写出 public),请求成功输出 resp.data,请求失败,打印请求失败
axios.get('/data.json')
.then(resp => {
console.log(resp.data)
})
.catch(err => {
console.log("请求失败")
})

要使用 myaxios.js 就要在相应的组件中导入该 js 文件,比如在Helloworld.vue 中导入。在 Helloworld.vue 增加黄色底纹代码:
import myaxios from ‘…/utils/myaxios.js’

<script>
import myaxios from '../utils/myaxios.js' 
export default {
name: "HelloWorld", props: {
msg: String
}
};
</script>

3.4、改进/封装原生的 axios

参考官网如下截图代码:即是通过 axios 的 create 方法,该方法返回的还是 axios 对象在这里插入图片描述

(1)先封装一个简单的 axios 对象 myaxios,如下:

//这里变量 myaxios 就是自己创建出来的 axios 对象
const myaxios=axios.create({
baseURL: '/',//基础路径什么意思呢?就是 axios 对象发送请求时路径的前缀,/代表默认在public目录下找
timeout: 5000,//单位是毫秒
})

(2)然后改为使用自己创建的 axios 对象 myaxios 进行发送异步请求。

myaxios.get('data.json')
.then(resp => {
console.log(resp.data)
})
.catch(err => {
console.log("请求失败")
})

测试自定义的 myaxios 对象没问题了就可以导出该
myaxios 对象了,方便其他地方使用。然后再把测试代码注释掉或者删除,之后 myaxios.js 内容如下:在这里插入图片描述

3.5、拦截器

概述:
为了让系统更健壮更友好等,在 axios 对象里还经常要封
装发送请求的拦截器和响应拦截器。这是为什么呢?比如发送请求的拦截应用场景:
 前端发送要上传的图片,这时就可以先拦截下来,对它进行
先压缩处理,然后再上传到后端;
 发送前经拦截器清空一些无用字段;
 一些固定的请求头信息,会用到这种情况。
 在向后端请求数据时,先拦截显示正在加载数据图标
响应拦截场景:
 后端返回的数据不适合前端 UI 组件直接使用,拦截下来先处
理;
 后端返回回来一种怪异的数据格式(不是 json),需要先拦截
下来,处理成前端友好的格式(json);
 根据后台返回的 status,提前封装判断是成功还是错误,至
于错误又是什么错误,从而友好的在前端给用户提示。
 后端给出响应时,响应拦截关闭加载数据图标

所以就先在 myaxios.js 文件里写好拦截器代码结构,直接复制官网的代码即可。具体处理函数代码后续再写

//请求拦截器
axios.interceptors.request.use(function (config) {
// Do something before request is sent
return config;//一定要返回,也就处理完了返回,然后再发送到后端
}, function (error) {
// Do something with request error
return Promise.reject(error); //抛出错误信息
});
//响应拦截器
axios.interceptors.response.use(function (response) {
// Any status code that lie within the range of 2xx cause this function to trigger
// Do something with response data
return response;//一定要返回这个响应,要不能前端获取不到
}, function (error) {
// Any status codes that falls outside the range of 2xx cause this function to trigger
// Do something with response error
return Promise.reject(error);
});

3.6、使用封装后的 axios 对象发送请求返回数据到前端

概述:
上节封装了一个自己的用于发送 ajax 的对象 myaxios,上节测试自己封装的 myaxios 对象的有效性也直接是在 myaxios.js 中写,实际上为了更好的解耦,发送 ajax 请求的代码要另外写在别的文件中。因此接下来在 src 文件夹下新建文件夹 api,然后新建一个 test.js文件。即src/api/test.js。

说明:一般都是在 api 文件夹下创建对应的 js 文件,在 js 文件中去向服务端接口发送 ajax 请求。

3.6.1、编写 test.js

导入自定义的 axios 对象 myaxios,然后发送 ajax 请求

//import myaxios from '../utils/myaxios' //用下面的更好,@能直接定位到 src 目录
import myaxios from '@/utils/myaxios'//@就表示 src 目录的
myaxios.get('data.json')
.then(resp => {
console.log(resp.data)
})
.catch(err => {
console.log("请求失败")
})

3.6.2、使用

在组件 HelloWorld.vue 中去使用,这个时候就不要导入 utils
文件夹下的,而是导入 api 文件夹下的 test.js 文件,从而发送 ajax请求。

<script>
// import myaxios from '../utils/myaxios.js' 
import testApi from '@/api/test.js' export default {
name: "HelloWorld", props: {
msg: String
}
};

最终测试运行是ok的。

3.6.3、改进发送 ajax 请求的语法形式,以便灵活改写发送 ajax 的method(改写 test.js)

//import myaxios from '../utils/myaxios' //用下面的更好,@能直接定位到 src 目录
import myaxios from '@/utils/myaxios'//@就表示 src 目录的
/* myaxios.get('data.json')
.then(resp => {
console.log(resp.data)
})
.catch(err => {
console.log("请求失败")
}) */
myaxios({
method:'get', 
url:'data.json'
})
.then(resp => {
console.log(resp.data)
})

思考: 这里响应结果直接在控制台输出了,不合理,实际开发中响应结 果应该返回给前端,让前端进行展示或处理。那如何改进呢?

3.6.4、持续改进 test.js 文件,方便响应的数据返回到前端组件中

将上面的代码改成下面的代码,myaxios()实际返回的是一个 promise 对象,然后通过该对象的 then()方法进行响应处理。

//import myaxios from '../utils/myaxios' //用下面的更好,@能直接定位到 src 目录
import myaxios from '@/utils/myaxios'//@就表示 src 目录的
/* myaxios.get('data.json')
.then(resp => {
console.log(resp.data)
})
.catch(err => {
console.log("请求失败")
}) */
const promise1 = myaxios({
method: 'get', 
url: 'data.json' })
promise1.then(resp => {
console.log(resp.data)
})

现在不应该在这里直接给出响应,那么只返回 myaxios()执行结果就好。因此就可改为如下:

export default {
getList(){
const promise1 = myaxios({
method: 'get', url: 'data.json' })
return promise1
}
}

说明:export default 导出的是一个对象,对象里面我们给一个方法 getList(),通过这个方法返回 myaxios()执行结果,是一个 promise对象。

3.6.5、持续改进前端组件 Helloworld.vue 以获取到 ajax 请求的响应数据

<script>
// import myaxios from '../utils/myaxios.js' import testApi from "@/api/test.js"; //导入 test 对象
export default {
//钩子函数,组件创建完毕时执行
created() {
this.fetchData();
},methods: {
fetchData() { //通过导入的 test 对象的 getList()返回的是 promise对象,然后就可以通过 then 执行成功的回调,通过 catch 执行失败的回调
testApi.getList()
.then(resp => {
console.log(resp.data);
})
.catch(err => {
console.log("请求失败");
});
}
},name: "HelloWorld", props: {
msg: String
}
};
</script>

上面就是 HelloWorld.vue 组件中获得了数据,因此,就可以在该组件中渲染数据了。如何渲染呢?见下面黄色底纹代码:即是先定义 data,用来存储数据的,返回值是一个数组;然后在请求成功后,把获取到的数据赋给该数组;最后把数组在 template 中展示出来。

<template>
<div class="hello">
<h1>{{ msg }}</h1>
<h3>{{ list }}</h3>
<ul>
<li v-for="(value,index) in list" :key="index">{{ value.bookna
me }}</li>
</ul>
</div>
</template>
<script>
// import myaxios from '../utils/myaxios.js' import testApi from "@/API/test.js"; //导入 test 对象
export default {
data(){
return {
list:[]
}
},//钩子函数,组件创建完毕时执行
created() {
this.fetchData();
},methods: {
fetchData() { //通过导入的 test 对象的 getList()返回的是 promise对象,然后就可以通过 then 执行成功的回调,通过 catch 执行失败的回调
testApi.getList()
.then(resp => {
console.log(resp.data);
this.list=resp.data
})
.catch(err => {
console.log("请求失败");
});
}
},name: "HelloWorld", props: {
msg: String
}
};
</script>

3.6.6、全部代码展示

myaxios.js:

import axios from 'axios';
//发送Ajax请求
// axios.get("/data.json")
//     .then(resp => {
//         console.log(resp.data)
//     })
//     .catch(err => {
//         console.log("请求失败")
//     });
//指定请求规则
const myaxios = axios.create({
    //baseURL: /,  //就是axios对象发送请求时请求的路径的前缀
    baseURL: process.env.VUE_APP_BASE_API,//  /dev-apis
    timeout: 3000,
});
//请求拦截器
axios.interceptors.request.use(function (config) {
    // Do something before request is sent
    return config;//一定要返回,也就处理完了返回,然后再发送到后}, function (error) {
    // Do something with request error
    return Promise.reject(error); //抛出错误信息
});
//响应拦截器
axios.interceptors.response.use(function (response) {
    // Any status code that lie within the range of 2xx cause this function to trigger
    // Do something with response data
    return response;//一定要返回这个响应,要不能前端获取不到
}, function (error) {
    // Any status codes that falls outside the range of 2xx cause this function to trigger
    // Do something with response error
    return Promise.reject(error);
});

export default myaxios

test.js:

import myaxios from "@/utils/myaxios"; //@符号就是直接定位到src目录下
export default {
    getList() {
        const promise1 = myaxios({
            method: 'get',
            url: 'data.json'
        })
        return promise1
    }
}

HelloWorld.vue:

<template>
  <div class="hello">
    <h1>{{ msg }}</h1>
    <h3>{{ list }}</h3>
    <ul>
      <li v-for="(value, index) in list" :key="index">
        {{ value.bookname }}
      </li>
    </ul>
  </div>
</template>
 <script>
import testApi from "@/api/test.js";
// import { defineComponent } from '@vue/composition-api' defineComponent(

export default {
  data() {
    return {
      list: [],
    };
  },
  created() {
    this.fetchData();
  },
  methods: {
    fetchData() {
      testApi
        .getList()
        .then((resp) => {
          console.log(resp.data);
          this.list = resp.data;
        })
        .catch((err) => {
          console.log("请求失败");
        });
    },
  },
  name: "Helloworld",
  props: {
    msg: String,
  },
};
</script>

四、开发环境通过代理解决跨域请求

总结:
而所谓的跨域请求就是指:当前发起请求的域与该请求指向的资源所在的域不一样。这里的域指的是这样的一个概念:我们认为若协议 + 域名 + 端口号均相同,那么就是同域。
前端与后端(API 服务)之间存在跨域,不能直接访问,但是中间代理服务能够直接访问后端,那么可以让前端发送请求先到中间代理服务器上,然后再通过中间代理服务器进行转发。
我们这里是要请求的端口号不同,第21章请求第十九章的数据,而这里解决的方法就是通过在vue.config.js中配置proxy代理作为中间商。而根据不同环境动态更改 Vue.config.js 配置就是在.env.development和.env.production文件中配置好接口服务地址和开发环境路径前缀。用这两者分别代替target目标地址和/dev-apis前缀,以后关于开发环境路径前缀和代理转发(接口服务地址)的修改都只要在.env.development 文件中进行即可

4.1、跨域引发的问题

假设上面 test.js 不是访问当前项目下的 data.json,我们把
data.json 复制到第 19 章的项目的 public 目录下,并启动运行第19 章的项目,测试下能否访问到 data.json 数据,如下图所示,访问到了,现在就把 19 章的这个地址作为获取数据的接口地址:http://localhost:8081/data.json在这里插入图片描述因为访问的端口号不同,所以肯定是失败的。

4.2、通过代理服务解决

前端与后端(API 服务)之间存在跨域,不能直接访问,但是中间代理服务能够直接访问后端,那么可以让前端发送请求先到中间代理服务器上,然后再通过中间代理服务器进行转发。

开发环境中,在 vue.config.js 文件中使用 devServer.proxy
选项进行代理配置。
参考:https://cli.vuejs.org/zh/config/#devserver

由于第 21 章的项目不能访问 http://localhost:8081 (第十九章的数据)这个地址,那么 test.js 中请求的 url 改为如下:先在 data.json 前任意加一个前缀,比如 dev-apis

export default {
getList(){
const promise1 = myaxios({
method: 'get', url: ' /dev-apis/data.json' })
return promise1
}
}

然后修改项目 vue.config.js 文件如下:增加 devServer.proxy选项进行代理配置(在devserve中配置)。

devserve:{
proxy:{ //设置/dev-apis 去代理访问
'/dev-apis':{
target:'http://localhost:8081/', changeOrigin:true,//开启代理服务,就去进行请求转发
pathRewrite: {
'^/dev-apis': '' // rewrite path
}}}}

说明:proxy 选项值为对象,对象的键就为 test.js 中设置的请求前缀,然后值又为一个对象,其中 target 为目标服务器地址,即是要通过这个代理访问地址;设置 changeOrigin:true,//开启代理服务,就去进行请求转发;通过 pathRewrite:进行路径重写,不重写这个时候访问到的就是http://localhost:8081/dev-apis/data.json,通过这个属性把 dev-apis 替换为空,这样就能访问到了http://localhost:8081/data.json
启动运行测试——ok。
注意,作为服务接口地址的项目(被访问的目标文件项目)也要是启动状态。另外 vue.config.js更改了,需要重新启动运行项目。

4.3、配置访问的前缀(基础路径)

由于基础路径(dev-apis)可能多个地方用到,为了后续修改的方便,可以定义一个常量作为基础路径。

在 test.js 文件中:
增加:const BASE_URL=‘/dev-apis’//定义路径前缀作为常量。
修改:访问地址由 url: ‘/dev-apis/data.json’ 改为如下
url: BASE_URL+‘/data.json’

这样,即是用 BASE_URL 代替前缀 dev-apis,然后和 data.json进行拼接。
再次运行测试——ok。

4.4、根据不同环境动态更改 Vue.config.js 配置

思考:
上面 vue.config.js 中的 proxy 中路径前缀和访问目标都是写死的,而实际开发中,在开发环境下和生成环境下肯定是不同的,那么能否做到根据环境不同自动更换呢?
参考:https://cli.vuejs.org/zh/guide/mode-and-env.html

在 项 目 根 目 录 下 分 别 创 建 两 个 文 件 .env.development和.env.production,名称不能写错,他们分别是针对开发环境和生产环境的配置。

4.4.1、配置.env.development 文件

(1)把proxy代理中的 target 属性值改为动态的
在.env.development 文件中(该文件中#就是注释符号)添加以下代码:
# 接口服务地址, 就是 vue.config.js 中 target 值
VUE_APP_SERVICE_URL = 'http://localhost:8081/
说明:变量名必须以 VUE_APP 开头,这样在 vue.config.js 中 process.env.VUE_APP_****就会自动获取到.env.development 文 件中 VUE_APP_****的变量值。然后 vue.config.js 中 target 的值修 改见下蓝色框住(有红勾)。在这里插入图片描述

(2)接口地址前缀的动态配置
在.env.development 文件中添加以下代码:
#开发环境路径前缀
VUE_APP_BASE_API = ‘/dev-apis’
然后 vue.config.js 中 target 的值修改见上蓝色框住,注意外面要有[ ]。
再次运行测试:——ok。
注意,作为服务接口地址的项目也要启动。另外vue.config.js 更改了,需要重新启动项目。
同时再把 test.js 中路径前缀常量值也修改下:
// const BASE_URL='/dev-apis’改为如下:
const BASE_URL=[process.env.VUE_APP_BASE_API]

4.4.2、配置.env. production 文件

先只写如下的路径前缀。由于跨域请求在生产环境下不是进行代理配置,要通过 nginx 配置,后面再讲
#生产环境路径前缀
VUE_APP_BASE_API = ‘/prod-api’

4.4.3、再改进自定义的 myaxios

把 myaxios 中 baseURL: 的 值 由 ’/’ 改 为
process.env.VUE_APP_BASE_API,
在这里插入图片描述
这样在 test.js 中用到 BASE_URL 地方就都不需要了,因为在myaxios 里面已经封装了前缀。在这里插入图片描述
以后关于开发环境路径前缀和代理转发(接口服务地址)的修改都只要在.env.development 文件中进行即可。

五、修改网站标题及图标

项目脚手架搭建之后,利用 VSCode 打开项目,打开项目的主
页面文件/唯一的一个网页文件 public/index.html
在这里插入图片描述
在这里插入图片描述注意,图片是放在和这个网页并行的目录下:在这里插入图片描述
最终效果:在这里插入图片描述

💕 原 创 不 易 , 还 希 望 各 位 大 佬 支 持 一 下 \textcolor{blue}{原创不易,还希望各位大佬支持一下}

👍 点 赞 , 你 的 认 可 是 我 创 作 的 动 力 ! \textcolor{orange}{点赞,你的认可是我创作的动力!}

收 藏 , 你 的 青 睐 是 我 努 力 的 方 向 ! \textcolor{red}{收藏,你的青睐是我努力的方向!}

🥕 评 论 , 你 的 意 见 是 我 进 步 的 财 富 ! \textcolor{green}{评论,你的意见是我进步的财富!}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小小福仔

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值