一、项目初始化
目标
- 能使用 Vue CLI 创建项目
- 了解 ElementUI 组件库的导入方式
- 掌握制作使用字体图标的方式
- 理解 axios 请求模块的封装
使用 Vue CLI 创建项目
如果你还没有安装 VueCLI,请执行下面的命令安装或是升级:
yarn add --global @vue/cli
在命令行中输入以下命令创建 Vue 项目:
vue create vueadmin-m
Vue CLI v4.2.3
? Please pick a preset:
default (babel, eslint)
> Manually select features
default:默认勾选 babel、eslint,回车之后直接进入装包
manually:自定义勾选特性配置,选择完毕之后,才会进入装包
选择第 2 种:手动选择特性,支持更多自定义选项
? Please pick a preset: Manually select features
? Check the features needed for your project:
(*) Babel
( ) TypeScript
( ) Progressive Web App (PWA) Support
(*) Router
(*) Vuex
>(*) CSS Pre-processors
( ) Linter / Formatter
( ) Unit Testing
( ) E2E Testing
分别选择: Babel:es6 转 es5 Router:路由 Vuex:数据容器,存储共享数据 CSS Pre-processors:CSS 预处理器,后面会提示你选择 less、sass、stylus 等 Linter / Formatter:代码格式校验
3.x
>2.x
选择vue的版本
? Use history mode for router? (Requires proper server setup for index fallback in production) (Y/n) n
是否使用 history 路由模式,这里输入 n 不使用
? Pick a CSS pre-processor (PostCSS, Autoprefixer and CSS Modules are supported by default):
Sass/SCSS (with dart-sass)
Sass/SCSS (with node-sass)
> Less
Stylus
选择 CSS 预处理器,这里选择我们熟悉的 Less
? Pick a linter / formatter config:
ESLint with error prevention only
ESLint + Airbnb config
> ESLint + Standard config
ESLint + Prettier
选择校验工具,这里选择 ESLint + Standard config
? Pick additional lint features:
(*) Lint on save
>(*) Lint and fix on commit
选择在什么时机下触发代码格式校验:
- Lint on save:每当保存文件的时候
- Lint and fix on commit:每当执行
git commit提交的时候这里建议两个都选上,更严谨。
? Where do you prefer placing config for Babel, ESLint, etc.? (Use arrow keys)
> In dedicated config files
In package.json
Babel、ESLint 等工具会有一些额外的配置文件,这里的意思是问你将这些工具相关的配置文件写到哪里:
- In dedicated config files:分别保存到单独的配置文件
- In package.json:保存到 package.json 文件中
这里建议选择第 1 个,保存到单独的配置文件,这样方便我们做自定义配置。
? Save this as a preset for future projects? (y/N) N
这里里是问你是否需要将刚才选择的一系列配置保存起来,然后它可以帮你记住上面的一系列选择,以便下次直接重用。
这里根据自己需要输入 y 或者 n,我这里输入 n 不需要。
✨ Creating project in C:\Users\LPZ\Desktop\topline-m-fe89\topline-m-89.
� Initializing git repository...
⚙ Installing CLI plugins. This might take a while...
[ ........] - extract:object-keys: sill extract json5@2.1.1
向导配置结束,开始装包。 安装包的时间可能较长,请耐心等待......
⚓ Running completion hooks...
� Generating README.md...
� Successfully created project topline-m-89.
� Get started with the following commands:
$ cd vueadmin-m
$ npm run serve
安装结束,命令提示你项目创建成功,按照命令行的提示在终端中分别输入:
# 进入你的项目目录
cd vueadmin-m
# 启动开发服务
npm run serve
DONE Compiled successfully in 7527ms
App running at:
- Local: http://localhost:8080/
- Network: http://192.168.10.216:8080/
Note that the development build is not optimized.
To create a production build, run npm run build.
启动成功,命令行中输出项目的 http 访问地址。 打开浏览器,输入其中任何一个地址进行访问。
调整初始目录结构
默认生成的目录结构不满足我们的开发需求,所以这里需要做一些自定义改动。
这里主要就是下面的两个工作:
- 删除初始化的默认文件
- 新增调整我们需要的目录结构
1、将 App.vue 修改为
<template>
<div id="app">
<router-view />
</div>
</template>
<script>
export default {
name: 'App'
}
</script>
<style scoped lang="less"></style>
2、将 router/index.js 修改为
import Vue from 'vue'
import VueRouter from 'vue-router'
Vue.use(VueRouter)
const routes = [
]
const router = new VueRouter({
routes
})
export default router
3、删除
- src/views/AboutView.vue
- src/views/HomeView.vue
- src/components/HelloWorld.vue
- src/assets/logo.png
4、创建以下几个目录
-
src/api 目录
- 存储接口封装
-
src/utils 目录
- 存储一些工具模块
-
src/styles 目录
- index.less 文件,存储全局样式
- 在
main.js中加载全局样式import './styles/index.less'
调整之后的目录结构如下。
.
├── README.md
├── babel.config.js
├── package-lock.json
├── package.json
├── public
│ ├── favicon.ico
│ └── index.html
└── src
├── api
├── App.vue
├── assets
├── components
├── main.js
├── router
├── utils
├── styles
├── store
└── views
引入 Element-ui 组件库
Element,一套为开发者、设计师和产品经理准备的基于 Vue 2.0 的桌面端组件库
在我们的项目中主要使用 ElementUI作为核心组件库,下面我们根据官方文档将 Vant 导入项目中。
将 Element-UI 引入项目一共有四种方式:
-
方式一:自动按需引入组件
- 按需引入,但是加载更方便一些(需要额外配置插件babel-plugin-component)
- 优点:打包体积小
- 缺点:每个组件在使用之前都需要手动加载注册
-
方式二:导入所有组件
- Element-ui支持一次性导入所有组件,引入所有组件会增加代码包体积,因此不推荐这种做法
- 优点:导入一次,使用所有
- 缺点:打包体积大
这里建议为了前期开发的便利性我们选择方式二:导入所有组件,在最后做打包优化的时候根据需求配置按需加载以降低打包体积大小。
1、安装 element-ui
yarn add element-ui
2、在 main.js 中加载注册 ElementUI组件
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
Vue.use(ElementUI);
封装请求模块
和之前项目一样,这里我们还是使用 axios 作为我们项目中的请求库,为了方便使用,我们把它封装为一个请求模块,在需要的时候直接加载即可。
1、安装 axios
yarn add axios
2、创建 src/utils/request.js
/**
* 封装 axios 请求模块
*/
import axios from "axios"
const request = axios.create({
baseURL: "" // 基础路径
})
export default request
3、如何使用
- 方式一(简单方便,但是不利于接口维护):我们可以把请求对象挂载到
Vue.prototype原型对象中,然后在组件中通过this.xxx直接访问 - 方式二(推荐):我们把每一个请求都封装成每个独立的功能函数,在需要的时候加载调用,这种做法更便于接口的管理和维护
在我们的项目中建议使用方式二,更推荐(在随后的业务功能中我们就能学到)。
API模块和请求封装模块介绍
目标 介绍API模块的单独请求和 request模块的封装
Axios的拦截器介绍
该项目采用了API的单独模块封装和axios拦截器的方式进行开发
axios的拦截器原理如下
axios拦截器
axios作为网络请求的第三方工具, 可以进行请求和响应的拦截
通过create创建了一个新的axios实例
// 创建了一个新的axios实例
const service = axios.create({
baseURL: process.env.VUE_APP_BASE_API, // url = base url + request url
// withCredentials: true, // send cookies when cross-domain requests
timeout: 5000 // 超时时间
})
请求拦截器
请求拦截器主要处理 token的**统一注入问题**
// axios的请求拦截器
service.interceptors.request.use(
config => {
// do something before request is sent
if (store.getters.token) {
// let each request carry token
// ['X-Token'] is a custom headers key
// please modify it according to the actual situation
config.headers['X-Token'] = getToken()
}
return config
},
error => {
// do something with request error
console.log(error) // for debug
return Promise.reject(error)
}
)
响应拦截器
响应拦截器主要处理 返回的**数据异常** 和**数据结构**问题
// 响应拦截器
service.interceptors.response.use(
response => {
const res = response.data
// if the custom code is not 20000, it is judged as an error.
if (res.code !== 20000) {
Message({
message: res.message || 'Error',
type: 'error',
duration: 5 * 1000
})
if (res.code === 50008 || res.code === 50012 || res.code === 50014) {
// to re-login
MessageBox.confirm('You have been logged out, you can cancel to stay on this page, or log in again', 'Confirm logout', {
confirmButtonText: 'Re-Login',
cancelButtonText: 'Cancel',
type: 'warning'
}).then(() => {
store.dispatch('user/resetToken').then(() => {
location.reload()
})
})
}
return Promise.reject(new Error(res.message || 'Error'))
} else {
return res
}
},
error => {
console.log('err' + error) // for debug
Message({
message: error.message,
type: 'error',
duration: 5 * 1000
})
return Promise.reject(error)
}
)
这里为了后续更清楚的书写代码,我们将原有代码注释掉,换成如下代码
// 导出一个axios的实例 而且这个实例要有请求拦截器 响应拦截器
import axios from 'axios'
const service = axios.create() // 创建一个axios的实例
service.interceptors.request.use() // 请求拦截器
service.interceptors.response.use() // 响应拦截器
export default service // 导出axios实例
api模块的单独封装
我们习惯性的将所有的网络请求 放置在api目录下统一管理,按照模块进行划分
单独封装代码
import request from '@/utils/request'
export function login(data) {
return request({
url: 'login',
method: 'POST',
data,
})
}
上面代码中,使用了封装的request工具,每个接口的请求都单独**导出**了一个方法,这样做的好处就是,任何位置需要请求的话,可以直接引用我们导出的请求方法
\