所属专栏: Vue 开发学习进步
说实话都是逼出来的,对于前端没干过ES6都不会的人,vue视频也就看了基础的一些
但没办法,接下来做微服务架构,前端就用 vue,这块你负责。。。。说多了都是泪,脚手架框架布了都没看过
干就完事,不过好在做好了,这里写下给和我一样苦逼的同学能快点适应入门下,当然一些基础的东西还是要知道的
主要分为几个部分
安装
准备工作
mock 假数据页面
axios 连接后台真数据
正式环境部署
前端完整代码
肯定有地方不太对的,麻烦大家指出来
安装
前端我推荐用 vscode 就是好用
安装node.js及npm
下载node,安装很简单一直下一步就可以了。
win+R 输入cmd进入命令行 输入
-
node -v
-
npm -v
出现以上信息说明node.js及npm安装成功
下载 vue-element-admin,并启动
官方:https://github.com/PanJiaChen/vue-element-admin
框架里的组件样式可以从 element 上找
element:http://element-cn.eleme.io/#/zh-CN/component/table
可以直接下载压缩包解压,也可以通过 git 下载
-
# 克隆项目
-
git clone https://github.com/PanJiaChen/vue-element-admin.git
-
-
#设置淘宝仓库
-
npm install --registry=https://registry.npm.taobao.org
-
-
# 安装依赖
-
npm install
-
-
# 启动服务
-
npm run dev
-
├── build // 构建相关
-
├── config // 配置相关
-
├── src // 源代码
-
│ ├── api // 所有请求
-
│ ├── assets // 主题 字体等静态资源
-
│ ├── components // 全局公用组件
-
│ ├── directive // 全局指令
-
│ ├── filtres // 全局 filter
-
│ ├── icons // 项目所有 svg icons
-
│ ├── lang // 国际化 language
-
│ ├── mock // 项目mock 模拟数据
-
│ ├── router // 路由
-
│ ├── store // 全局 store管理
-
│ ├── styles // 全局样式
-
│ ├── utils // 全局公用方法
-
│ ├── vendor // 公用vendor
-
│ ├── views // view
-
│ ├── App.vue // 入口页面
-
│ ├── main.js // 入口 加载组件 初始化等
-
│ └── permission.js // 权限管理
-
├── static // 第三方不打包资源
-
│ └── Tinymce // 富文本
-
├── .babelrc // babel-loader 配置
-
├── eslintrc.js // eslint 配置项
-
├── .gitignore // git 忽略项
-
├── favicon.ico // favicon图标
-
├── index.html // html模板
-
└── package.json // package.json
准备工作
汉化
打开vscode后
Windows、Linux 快捷键是:ctrl+shift+p
macOS 快捷键是:command + shift + p
搜索 Configure Language,选择下图第一个选项。
将"locale":“en” 修改为 “locale”:“zh-CN” ,保存文件。
选择左侧左下方的扩展按钮,搜索chinese 安装下图的插件
安装成功以后重启vscode,语言就改成中文了。
推荐安装一些好用的扩展
Auto Close Tag 自动闭合HTML标签
Auto Rename Tag 修改HTML标签时,自动修改匹配的标签
Beautify 代码美化
ESLint ESLint 插件,高亮提示
File Peek 根据路径字符串,快速定位到文件
HTML CSS Support css提示(支持vue)
HTMLHint HTML格式提示
JavaScript (ES6) code snippets ES6语法代码段
Vetur Vue代码高亮及补全
VS Color Picker vs颜色选择器
Vue 2 Snippets Vue2代码补全
open in browser 在浏览器中预览
ESLint
刚开始很难用,疯狂报错,那是因为没配好,配好后一些小的问题,会自动修正,在保存的时候
文件 ➡ 首选项 ➡ 设置 ➡ 搜索 ESLint ➡ 点击在 setting.json 中编辑 ➡ 粘进去,保存,完事
-
{
-
"files.autoSave": "off",
-
"eslint.validate": [
-
"javascript",
-
"javascriptreact",
-
"vue-html",
-
{
-
"language": "vue",
-
"autoFix": true
-
}
-
],
-
"eslint.run": "onSave",
-
"eslint.autoFixOnSave": true
-
}
dev.env.js
先来看下 config 文件夹下的 dev.env.js
这个文件夹里的 BASE_API 后台接口的就是公共路径,调后台的时候要记得改,这是本地的,剩下的 prod 和 sit 分别是正式环境打包和 测试环境打包的
/src/router/index.js
先来看下目录
详细的解释在这个目录文件的上面有,每个属性什么意思,可以在上面看
mock 假数据页面
mock 主要是帮助前后分离的项目为前端提供数据,这样才好测试
先来画个页面,一个分页列表吧,路径 /src/service/dataLog.vue 用来显示一些信息
我在 element 组件里找了一个列表功能和分页功能
/src/service/dataLog.vue
dataLog.vue 的 template 部分
-
<template>
-
<div class="app-container">
-
<!-- 查询框 双向绑定 keyword-->
-
<el-input
-
v-model="keyword"
-
placeholder="请输入关键字"
-
clearable
-
style="width:500px" />
-
<!-- 搜索按钮 绑定点击事件 -->
-
<el-button type="primary" icon="el-icon-search" @click="getDataLog()">搜索</el-button>
-
<!-- data就是绑定数据用的 -->
-
<el-table
-
:data="dataLog"
-
style="width: 100%">
-
<el-table-column type="expand">
-
<template slot-scope="props">
-
<el-form label-position="left" inline class="demo-table-expand">
-
<el-form-item label="错误信息">
-
<span>{{ props.row.log }}</span>
-
</el-form-item>
-
</el-form>
-
</template>
-
</el-table-column>
-
<el-table-column
-
label="服务单"
-
prop="data"/>
-
<el-table-column
-
label="时间"
-
prop="time"/>
-
</el-table>
-
<!-- 分页 -->
-
<pagination
-
v-show="total>0"
-
:total="total"
-
:page.sync="listQuery.page"
-
:limit.sync="listQuery.limit"
-
@pagination="getDataLog" />
-
<!-- total总条数
-
listQuery.page 当前页
-
listQuery.limit 每页几条
-
getDataLog 后买点击分页时候要回调的函数 -->
-
</div>
-
</template>
注意 template 下只能有一个节点,两个就报错了,可以试下,所有我放在一个统一的 div 里
至于这些值为啥这样写,我只能说照着人家给的模板改就好,人家写啥你写啥,样式啥的人家上面都有
样式部分就不贴了,最后会把完整的代码贴出来,来看下 js 的部分
这里解释下分页,分页除了初始化给了第 1 页和每页 10 条后,之后每次点击页码,数据都会双向绑定到值上,所有在调后台函数的时候,直接取 page 和 limit 值就行了,不想要再去想我怎么去拿 div 上面的数字
-
<script>
-
// 这里要调用我使用的 api
-
// 括号里的是要使用的函数接口,多个的话逗号隔开
-
import { getDataLog } from '@/api/service/dataLog'
-
// 引入分页组件
-
import Pagination from '@/components/Pagination'
-
-
export default {
-
// 这里需要把分页组件注册进来
-
components: { Pagination },
-
data() {
-
return {
-
// 搜索关键字
-
keyword: '',
-
// 数据条数
-
total: 0,
-
// 分页参数
-
listQuery: {
-
page: 1,
-
limit: 10
-
},
-
// 列表数据
-
dataLog: []
-
}
-
},
-
// 这个是生命周期函数,这个时候是 data 和 methods 都初始化好了,具体看基础知识
-
created() {
-
this.getDataLog()
-
},
-
methods: {
-
// 函数部分
-
getDataLog() {
-
// 参数
-
this.listQuery = {
-
page: this.listQuery.page,
-
limit: this.listQuery.limit,
-
object: this.keyword
-
}
-
// 调用上面引入的 api 里的 getDataLog
-
// 不引入就报函数未定义了,刚开始一个人折腾好久,老子明明定义在这了,为啥还没定义
-
getDataLog(this.listQuery).then(response => {
-
// 返回值处理
-
this.dataLog = []
-
this.total = response.data.total
-
this.dataLog = response.data.items
-
// 查询后要把关键字给清空
-
this.keyword = ''
-
})
-
}
-
}
-
}
-
</script>
接下来看看上面的 api 接口
/src/api/service/dataLog.js
每次点击就会去调用 api 接口里的方法,参数都看得懂
上面引用的 request 文件使得每次调用的时候都会对请求进行拦截,上面的 BASE_API 就会在里面被拼上去
-
import request from '@/utils/request'
-
-
// 获取错误信息列表
-
export function getDataLog(query) {
-
return request({
-
url: '/log/getDataLog',
-
method: 'get',
-
params: query
-
})
-
}
/src/mock/service/dataLog.js
接下来就是使用 mock 假数据,我就循环了10条,因为假的分页,特意去实现太费劲了
如果有多个接口的数据要返回,可以在 export default 里写多个接口去返回
-
import Mock from 'mockjs'
-
-
const List = []
-
-
const count = 10
-
-
// 模拟错误信息
-
for (let i = 0; i < count; i++) {
-
List.push(Mock.mock({
-
data: '12987122',
-
time: '好滋好味鸡蛋仔',
-
log: '江浙小吃、小吃零食江浙小吃、小吃零食'
-
}))
-
}
-
-
export default {
-
// 获取错误信息列表
-
getDataLog: () => {
-
return {
-
total: List.length,
-
items: List,
-
limit: 10
-
}
-
}
-
}
/src/mock/index.js
上面的写完还不行,因为通过 api 提交的请求,mock 不知道哪些是需要请求假数据的,所有需要在 index 文件里进行拦截
直接加就好了,就这两行,把刚写的假数据引用进来,对请求进行拦截
第一个参数,就是要拦截的 url 这里就和 api 挂钩起来了
第二个参数,get 类型请求
第三个参数,/src/mock/service/dataLog.js 里 export 的对应接口,这样就和 mock 假数据也挂钩起来了
需要拦截多少个请求就要写多少个
然后 npm run dev 运行测试就好了
axios 连接后台真数据
这里我偷了个懒,由于 utils/request.js 已经帮我们把 axios 都弄好了,像 BASE_API 的路径拼接,我又不想再写个 api 文件,所以我就直接拿过来用了
先引入
import request from '@/utils/request'
js 部分:
-
methods: {
-
getDataLog() {
-
this.listQuery = {
-
page: this.listQuery.page,
-
limit: this.listQuery.limit,
-
object: this.keyword
-
}
-
// mock 请求假数据
-
// getDataLog(this.listQuery).then(response => {
-
// this.dataLog = []
-
// this.total = response.data.total
-
// this.dataLog = response.data.items
-
// // 查询后要把关键字给清空
-
// this.keyword = ''
-
// })
-
// 请求后台获得真实数据
-
request({
-
url: '/log/getDataLog/',
-
method: 'post',
-
data: this.listQuery
-
}).then(response => {
-
this.dataLog = []
-
this.total = response.data.pageEntity.total
-
this.dataLog = response.data.retData
-
})
-
}
-
}
这里访问路径就是 http://127.0.0.1:8081/log/getDataLog,如果全路径访问也是可以的,url 前面带了 “/”意思就是会进行路径的拼接,如果写的是 url: 'log/getDataLog' 那么访问就报错了,因为前缀没拼上,还有要把 mock 里的 index.js 文件里的注掉,要不会拦截变成假数据
这里用的是 post 方法,后台部分直接用 @RequestBody 接收参数就好了
也可以用 get 方法,把参数拼在 url 上传递,我这采用 restful 形式的接口,用 @PathVariable 接收参数
这时候你可能会遇到跨域问题
新建 config 包
-
@Configuration
-
public class CorssDomainConfig implements WebMvcConfigurer {
-
-
@Autowired
-
private CorsInterceptor corsInterceptor;
-
-
@Override
-
public void addInterceptors(InterceptorRegistry registry) {
-
InterceptorRegistration registration = registry.addInterceptor(corsInterceptor);
-
registration.addPathPatterns("/**");
-
}
-
-
}
然后新建 interceptor 包
-
@Component
-
public class CorsInterceptor extends HandlerInterceptorAdapter {
-
-
@Override
-
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
-
throws Exception {
-
// 添加跨域CORS
-
response.setHeader("Access-Control-Allow-Origin", "*");
-
response.setHeader("Access-Control-Allow-Headers", "Origin,X-Requested-With,Content-Type,Accept,Authorization,token, x-token");
-
response.setHeader("Access-Control-Allow-Methods", "GET, HEAD, POST, PUT, DELETE, TRACE, OPTIONS, PATCH");
-
return true;
-
}
-
}
项目再启动时,addInterceptors 就会把 preHandle 给注册成对象,后续请求都会经过 preHandle 接口对请求做出处理
正式环境部署
我这前端采用 Nginx 作为前端的运行容器
详细部署:Docker 上部署 Nginx
我 Nginx html 文件夹下我保留了 dist目录
所以 /conf.d/default.conf 要改下
vue 里 config/sit.env.js,这里我配置了测试服的,然后在 prod.env.js 配置了正式服的
-
module.exports = {
-
NODE_ENV: '"production"',
-
ENV_CONFIG: '"sit"',
-
// 项目访问根路径
-
// 测试服
-
BASE_API: '"http://xx.xx.xxx.xxx:xxxx"',
-
}
-
#测试服打包
-
npm run build:sit
-
-
#正式服打包
-
npm run build:prod
命令就在 package.json 里
打包后会在根目录生成 dist 文件夹,把文件夹放到服务器的 html 文件夹下就好了,然后启动 Nginx,启动过就不用启动了,由于我 Nginx 直接配置了 80 端口的,所以直接服务器路径访问就行了
PS:如果遇到了打包报错的情况,那就把 npm 更新下 npm install ,这会在项目根目录生成 node_modules 文件夹,这些是需要的依赖,在 linux 上打包我这试了不行,依赖更新了也不对,不知道问题出在哪,应该是 windows 和 linux 依赖不太一样吧
前端完整代码
/src/views/service/dataLog.vue
-
<template>
-
<div class="app-container">
-
<!-- 查询框 双向绑定 keyword-->
-
<el-input
-
v-model="keyword"
-
placeholder="请输入关键字"
-
clearable
-
style="width:500px" />
-
<!-- 搜索按钮 -->
-
<el-button type="primary" icon="el-icon-search" @click="getDataLog()">搜索</el-button>
-
<!-- data就是绑定数据用的 -->
-
<el-table
-
:data="dataLog"
-
height="600"
-
style="width: 100%">
-
<el-table-column type="expand">
-
<template slot-scope="props">
-
<el-form label-position="left" inline class="demo-table-expand">
-
<el-form-item label="错误信息">
-
<div v-html="props.row.log"/>
-
</el-form-item>
-
</el-form>
-
</template>
-
</el-table-column>
-
<el-table-column
-
label="服务单"
-
prop="data"/>
-
<el-table-column
-
label="时间"
-
prop="time"/>
-
</el-table>
-
<!-- 分页 -->
-
<pagination
-
v-show="total>0"
-
:total="total"
-
:page.sync="listQuery.page"
-
:limit.sync="listQuery.limit"
-
@pagination="getDataLog" />
-
<!-- total总条数
-
listQuery.page 当前页
-
listQuery.limit 每页几条
-
getDataLog 后买点击分页时候要回调的函数 -->
-
</div>
-
</template>
-
-
<script>
-
// import { getDataLog } from '@/api/service/dataLog'
-
import Pagination from '@/components/Pagination'
-
import request from '@/utils/request'
-
-
export default {
-
components: { Pagination },
-
data() {
-
return {
-
// 搜索关键字
-
keyword: '',
-
// 数据条数
-
total: 0,
-
// 分页参数
-
listQuery: {
-
page: 1,
-
limit: 10
-
},
-
// 列表数据
-
dataLog: []
-
}
-
},
-
created() {
-
this.getDataLog()
-
},
-
methods: {
-
getDataLog() {
-
this.listQuery = {
-
page: this.listQuery.page,
-
limit: this.listQuery.limit,
-
object: this.keyword
-
}
-
// mock 请求假数据
-
// getDataLog(this.listQuery).then(response => {
-
// this.dataLog = []
-
// this.total = response.data.total
-
// this.dataLog = response.data.items
-
// // 查询后要把关键字给清空
-
// this.keyword = ''
-
// })
-
// 请求后台获得真实数据
-
request({
-
url: '/log/getDataLog/',
-
method: 'post',
-
data: this.listQuery
-
}).then(response => {
-
this.dataLog = []
-
this.total = response.data.pageEntity.total
-
this.dataLog = response.data.retData
-
})
-
}
-
}
-
}
-
</script>
-
-
<style>
-
.demo-table-expand {
-
font-size: 0;
-
}
-
.demo-table-expand label {
-
width: 90px;
-
color: #99a9bf;
-
}
-
.demo-table-expand .el-form-item {
-
margin-right: 0;
-
margin-bottom: 0;
-
width: 50%;
-
}
-
</style>
/src/api/service/dataLog.js
-
import request from '@/utils/request'
-
-
// 获取错误信息列表
-
export function getDataLog(query) {
-
return request({
-
url: '/log/getDataLog',
-
method: 'get',
-
params: query
-
})
-
}
/src/mock/service/index.js
拦截原因,请求后台就注掉
// Mock.mock(/\/log\/getDataLog/, 'get', dataLogAPI.getDataLog)
/src/mock/service/dataLog.js
-
import Mock from 'mockjs'
-
-
const List = []
-
-
const count = 10
-
-
// 模拟错误信息
-
for (let i = 0; i < count; i++) {
-
List.push(Mock.mock({
-
data: '12987122',
-
time: '好滋好味鸡蛋仔',
-
log: '江浙小吃、小吃零食江浙小吃、小吃零食'
-
}))
-
}
-
-
export default {
-
// 获取错误信息列表
-
getDataLog: () => {
-
return {
-
total: List.length,
-
items: List,
-
limit: 10
-
}
-
}
-
}