此部分 涉及 登录页 — > 首页的显示 (LAYOUT)布局 以及 动态路由
Vue 框架建议 花裤衩版本 + mock + 动态路由 + Webapi
【提示】
如果从第一部分的vue 想要实现第三部分的内容,框架体系都要修改,如果是从 vue-element-admin版本,那么基本框架都有了,一般需要修改几个地方就能用了
第一部分的Vue前端只是用于了解用途,实际开发不会那么写,需要完善的内容很多,那么第一部分到 vue-element-admin 的版本之间,差异还是很大的,其中重要的几个部分如下:
(1)Axios基础封装过了
(2)Vuex的Store也有,element-ui组件也有、首页Layout布局也有
(3)路由守卫的判断也有、token等
就算是 vue-element-admin 下面几部分后期也需要进行完善 – 至少静态路由要精简一下,留几个vue即可
(1)如果数据想从mock改成Webapi中的实际数据
(3)静态路由需要精简、动态路由修改不从mock获取,初期可以用mock试试 – 因为后端Webapi可能还太完善
vue如何使用mock.js数据
vue-element-admin
Vue中import from的来源:省略后缀与加载文件夹
// 当设置 true 的时候该路由不会在侧边栏出现 如401,login等页面,或者如一些编辑页面/edit/1 hidden: true // (默认 false)
affix: true // 如果设置为true,它则会固定在tags-view中(默认 false)布局
页面整体布局是一个产品最外层的框架结构,往往会包含导航、侧边栏、面包屑以及内容等
一般项目页面,刷新的是 黄色边框内容、红色导航栏标签,分成不同的vue
路由 和 侧边栏是组织起一个后台应用的关键骨架。
依据前面的学习,在路由 router文件夹下的 index.js 中,静态路由,比如登录页
{
path: ‘/login’, // 指定要跳转的路径,就是网站后缀
component: () => import(‘@/views/login/index’), // 指定要跳转的组件
hidden: true
}
首页 — > import Layout from ‘@/layout’ 依据判断规则,第一符合条件 index.vue(组合组件)
{
path: ‘/’, // 访问的路径地址
component: Layout, // 引入的组件,在上面有定义 import Layout from ‘@/layout’
redirect: ‘/dashboard’, // 重定向,就是ie地址栏/ 变成/dashboard的内容
children: [{
path: ‘dashboard’,
name: ‘Dashboard’,
component: () => import(‘@/views/dashboard/index’), // 组件的引入,第二种方式
meta: { title: ‘首页’, icon: ‘dashboard’, affix: true } // 文字 加上图标,affix如果设置为true,则标记将粘贴在“标记”视图中
}]
}
页面部分 子组件sidebar 、navbar、app-main
<template>
<div :class="classObj" class="app-wrapper">
<div v-if="device==='mobile'&&sidebar.opened" class="drawer-bg" @click="handleClickOutside" />
<sidebar class="sidebar-container" />
<div :class="{hasTagsView:needTagsView}" class="main-container">
<div :class="{'fixed-header':fixedHeader}">
<navbar />
<tags-view :v-if="needTagsView" />
</div>
<app-main />
</div>
</div>
</template>
import { Navbar, Sidebar, AppMain, TagsView } from ‘./components’
import ResizeMixin from ‘./mixin/ResizeHandler’
路由地址的变更,对应route数组对应关系,显示不同的vue页面
this.$router.push({ path: this.redirect || ‘/’ })
[提示]
Vue使用import … from …来导入组件,库,变量等。而from后的来源可以是js,vue,json。这个是在webpack.base.conf.js中设置的:
而上面定义的这3类可导入文件,js和vue是可以省略后缀的:
import test from ‘./test.vue’ 等同于:import test from ‘./test’
import test from ‘./test.js’ 等同于:import test from ‘./test’
那么,若test.vue,test.js同时存在于同一个文件夹下,则import的导入优先级是:
js>vue
from后的来源除了文件,还可以是文件夹:
import test from ‘./components’
因此若from的来源是文件夹,那么在package.json存在且设置正确的情况下,会默认加载package.json;若不满足,则加载index.js;若不满足,则加载index.vue。
import Layout from ‘@/layout’ 加载这个文件夹,里面的判断如下 – json > JS >VUE
package.json不存在,那么查找index.js。index.js是不存在,index.vue存在 于是加载。
在 这个 index.vue中
import { Navbar, Sidebar, AppMain, TagsView } from ‘./components’
在这个 components文件夹下面 那么查找package.json不存在,index.js。index.js存在于是加载
打开index.js:看到几个export,都没有后缀,所以其类型vue,js 和文件夹 都是有可能的。
同一级目录下,存在AppMain.vue和Navbar.vue,没有同名js,所以可以判断出这两个都是加载的vue文件,即:
export { default as Navbar } from ‘./Navbar.vue’
export { default as Navbar } from ‘./Navbar’
export { default as Sidebar } from ‘./Sidebar’
export { default as AppMain } from ‘./AppMain’
export { default as TagsView } from ‘./TagsView/index.vue’
而Sidebar只有一个文件夹,所以是加载的文件夹。打开Sidebar文件夹:
优先找package.json。不存在。
然后找index.js,不存在。
最后找index.vue,存在。
于是:
export { default as Sidebar } from ‘./Sidebar’
相当于:
export { default as Sidebar } from ‘./Sidebar/index.vue’
这样,Layout.vue就通过加载一个文件夹,获得了几个vue组件。
花裤衩版本的简化+ 优化内容如下
(1)登录页login.vue 我们稍微简化一下,只留账号密码登入功能
2)原先太多用不着的vu额页面,简化vue,原先不常用的vue页面删除 … 或者直接下载简化版本
GitHub - PanJiaChen/vue-admin-template: a vue2.0 minimal admin template 基础模板的版本
2.1 src文件夹内 的 views中,删除部分vue
2.2 route中的index.js 路由数组中,删除对于关系
2.3 title: 'formn 修改成 中文 'title: ‘表单’ 等
(3)组合式api引入 + element-ui引入(先在dev控制台输入npm i element-ui --save)
npm install @vue/composition-api --或者 npm install --save @vue/composition-api
然后在 main.js 添加
import VueCompositionAPI from ‘@vue/composition-api’
Vue.use(VueCompositionAPI)
import ElementUI from ‘element-ui’
import ‘element-ui/lib/theme-chalk/index.css’
Vue.use(ElementUI)
(4)Axios 的封装 + mock模拟数据替换Webapi + 跨域处理 (一般项目都是前后端分离,提前准备好,如果是只学前端,那么 这一步可以跳过,就拿mock数据模拟也是可以的)
分析:目前这个版本的vue-element-admin的数据是取mock模拟的,所以要改成从后端webapi接口,去Sql的数据表中获取,后来的用户登陆菜单清单,也是如此
src/ utils /auth.js
const TokenKey = 'J1_token'
// sessionStorage 是HTML5新增的一个会话存储对象,用于临时保存同一窗口(或标签页)的数据,在关闭窗口或标签页之后将会删除这些数据。
// 采用setItem()方法存储 ,这里的 TokenKey是key的含义,方便后期用 key来 getItem
// 通过getItem()方法取值
// 通过removeToken移除值
export function getToken() {
return sessionStorage.getItem(TokenKey)
}
export function setToken(token) {
return sessionStorage.setItem(TokenKey, token)
}
export function removeToken() {
return sessionStorage.removeItem(TokenKey)
}
4.1 Axios 的封装 – 结合项目中的封装
在 src/utils 工具文件夹里的 request.js 进行修改
然后配置档修改
# base api
VUE_APP_BASE_API = '/dev-api' // 原先的内容
VUE_APP_BASE_API = ''
VUE_APP_BASE_URL = 'http://localhost:5222/' // 自己实际的后台
然后 依据 import { post } from ‘./base’
所以 在 src/api 新建立一个 base.js 里面建立一个post的方法
修改 在 src/api 新建立一个 user.js 里面的代码
login 登陆方法、getInfo获取用户信息、logout退出、获取路由getRoutes
import request from '@/utils/request'
import { post } from './base' // 后期封装了request的Axios
// 登陆
export function login(username, password) {
const url = '/ApiAuth/GetToken'
const data = { 'UID': username.trim(), 'SecretKey': password }
return post(url, data)
}
// 获取用户信息
export function getInfo() {
return request({
url: '/ApiAuth/GetUserInfo',
method: 'get'// ,
// params: { token }
})
}
// 退出
export function logout() {
return request({
url: '/ApiAuth/logout',
method: 'post'
})
}
// 获取路由
export function getRoutes() {
return request({
url: '/ApiAuth/GetOwnMenu',
method: 'get'
})
}
在store中,模块module下面的user.js – 登陆按钮,先到这里的actions里面
import { loginSystem, logout, getInfo } from '@/api/user'
import { getToken, setToken, removeToken } from '@/utils/auth'
import { resetRouter } from '@/router'
import { Message } from 'element-ui'
const getDefaultState = () => {
return {
token: getToken(),
userNo: '',
name: '',
avatar: '',
funcs: []
}
}
const state = getDefaultState()
const mutations = {
RESET_STATE: (state) => {
Object.assign(state, getDefaultState())
},
SET_TOKEN: (state, token) => {
state.token = token
},
SET_NAME: (state, name) => {
state.name = name
},
SET_USERNo: (state, userNo) => {
state.userNo = userNo
},
SET_FUNCS: (state, funcs) => {
state.funcs = funcs
},
SET_AVATAR: (state, avatar) => {
state.avatar = avatar
}
}
const actions = {
// user login
async login({ commit }, userInfo) {
const { username, password } = userInfo
const { State, Msg, DataValue } = await loginSystem(username, password)
// console.log(State)
// console.log(Msg)
if (State === 'OK') {
commit('SET_TOKEN', DataValue)
setToken(DataValue)
} else {
Message({
message: Msg || '执行发生异常',
type: 'error',
duration: 5 * 1000
})
}
},
getInfo({ commit, state }) {
return new Promise((resolve, reject) => {
// 下面的getInfo函数,是import { loginSystem, logout, getInfo } from '@/api/user' 里面的 getInfo
getInfo().then(response => {
const { State, UserInfo, ModuleFuncInfo } = response
if (!State || State === 'ERR') {
return reject('验证失败,请重新登录.')
}
const { EmpName, EmpNo } = UserInfo
commit('SET_NAME', EmpName)
commit('SET_USERNo', EmpNo)
commit('SET_AVATAR', '')
commit('SET_FUNCS', ModuleFuncInfo)
resolve(UserInfo)
}).catch(error => {
reject(error)
})
})
},
logout({ commit, state }) {
return new Promise((resolve, reject) => {
logout().then(() => {
removeToken() // must remove token first
resetRouter()
commit('RESET_STATE')
resolve()
}).catch(error => {
reject(error)
})
})
},
resetToken({ commit }) {
return new Promise(resolve => {
removeToken() // must remove token first
commit('RESET_STATE')
resolve()
})
}
}
export default {
namespaced: true,
state,
mutations,
actions
}
提示:这个时候后端Webapi 必须要有对应的准备,以便这个时候登陆测试、验证等
(后端非常多的补充代码,框架目录一大堆,一环套一环,慢慢来 – 也可以直接使用目前的J2后端框架)
—> 数据库链接修改成 自己的数据库,用于测试 —> REDIS 是否开启,自己看情况
后端的 Controllers下面,新建文件夹Api -->
4.2 mock模拟数据替换
4.3 前后端的跨域问题的处理
在config文件下的 index.js 添加 vue2项目的话
proxyTable: { // 有些是使用 proxy
'/api': {
target: 'http://localhost:5222', //设置你调用的接口域名和端口号 别忘了加http,9001端口按照实际
changeOrigin: true,
pathRewrite: {
'^/api': '' //这里理解成用‘/api’代替target里面的地址,后面组件中我们掉接口时直接用api代替
// 比如我要调用'http://40.00.100.100:3002/user/add',直接写‘/api/user/add’即可
}
}
(5)动态路由数组 + 路由守卫