阅读 157

Project(2)-vue3.0+ts+elementUi-Plus

开发条件:需要会vuex+vue-router

页面开发

.vue文件

<template>
  // 页面dom渲染
</template>

<script lang="ts">
  // 页面逻辑处理
</script>
<style>
  // 页面样式
</style>
复制代码

由登录页面起手

考虑因素

  1. 输入网址进入项目首页
  2. 在进入项目首页时候进行路由判断,看是否携带签名(即:检验是否可以免密登录)
    • 有则直接展示
    • 没有则跳转到登录页面
  3. 进行登录页面的编写(表单验证+防抖/限制提交)
  4. 用户信息托管给vuex去进行管理 (收录用户信息)

编写开始

1.创页面并在路由中注册

// router/index.ts
import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router'
import Index from '../views/index/index.vue'

const routes: Array<RouteRecordRaw> = [
  {
	path: '/',
	name: 'Index',
	component: Index,
	redirect: '/dashboard',
	children: [{
		path: '/dashboard',
		component: () => import('@/views/dashboard/index.vue'),
		name: 'Dashboard',
		meta: {
			title:'XX后台管理系统'
		}
	}]
	
  },
  {
	 path:'/login',
	 name:'Login',
	 component: () => import('../views/login/index.vue'),
         meta: {
			title:'登录'
		}
  }
]

const router = createRouter({
  history: createWebHistory(process.env.BASE_URL),
  routes
})

export default router
复制代码

2.进行导航守卫的编写permission.ts

自行学习vue-router

// permission.ts
import router from '@/router/index';
// 导航守卫对路由跳转前进行处理
let whiteList = ['/login']
router.beforeResolve((to:any, from:any, next:any) => {
	let token = ""; // 预留字段
        document.title = to.meta.title; // 网页标题
	if(token){
		if(to.path === '/login'){
			next('/')
		}else{
			// ...这里需要进行路由的重写权限配置
		}
	}else{
		if (whiteList.indexOf(to.path) !== -1) {
		  next()
		} else {
		  next('/login')
		}
	}
})
复制代码

3.cookie的方法封装,也可以使用插件

// cookie.ts
/**
 * 功能:全局存cookie
 */ 
export function setForeverCookie(name:string,value:string) {
	var date =new Date()
	if(value != null&&name !== null){
		date.setTime(date.getTime()+12*30*24*60*60*1000)
		document.cookie = name +"="+value+";path=/;expires="+date.toUTCString()
	}
}
/**
 * 说明:增加/修改会话cookie 
 */ 
export function setCookie(name:string,value:string,time:number) {
	var date =new Date()
	if(time != undefined){
		date.setTime(date.getTime()+time*1000)
		document.cookie = name +"="+value+";expires="+date.toUTCString()
	}else{
		document.cookie = name+"="+value
	}
}
/**
 * 说明:删除cookie 
 */ 
export function delCookie(name:string) {
	var date =new Date()
	if(name != null){
		date.setTime(date.getTime()-1000)
		document.cookie = name +"=null;expires="+date.toUTCString()
	}
}
/**
 *说明:获得cookie 
 */ 
export function getCookie(name:string):string {
	var arr = document.cookie.split(';')
	var cookieValue = ''
	if(name === "all"){
		cookieValue = document.cookie
	}else{	
		for(const i in arr){
			if(document.cookie.split(';').join(',').split('=')[0] === name){
				cookieValue = document.cookie.split(';').join(',').split('=')[1]
			}
		}
	}
	return cookieValue
}
复制代码

4.axios进行一波封装

// request.ts
import axios from 'axios'
import { ElMessage } from 'element-plus'
import store from '@/store'
import { getCookie } from './cookie'
 /**
  * 说明:基于axios的请求封装
  */
const service = axios.create({
  baseURL: process.env.VUE_APP_BASE_API,
  timeout: 60 * 2 * 1000
});
/**
 * 说明:请求前拦截
 * 功能:携带token
 */
service.interceptors.request.use(
  (config) => {
    if (store.getters.token) {
      config.headers['token'] = getCookie('admin-token')
    }
    return config
  },
  (error:any) =>  Promise.reject(error)
)
/**
 * 说明:响应拦截
 * 
 */
service.interceptors.response.use(
	(response:any) =>{
		if(response.data.errorCode === true){
				ElMessage({
			            showClose: true,
			            message: response.data.resultMsg,
			            type: 'error'
			          });
		}else if(response.data.retCode === true){
			return response
		}
	}
)
export default service
复制代码

5.进行login.vue编写

<template>
  <div class="login flex-c-center">
    <el-form :model="formData" :hide-required-asterisk="true"  class="loginForm">
      <el-form-item
        prop="username"
        :rules="[
          { required: true, message: '账号不能为空'},
        ]"
      >
        <el-input placeholder="请输入账号" v-model="formData.username" autocomplete="off">
        </el-input>
      </el-form-item>
	  <el-form-item
	    prop="password"
	    :rules="[
	      { required: true, message: '密码不能为空'},
	    ]"
	  >
	    <el-input placeholder="请输入密码" v-model="formData.password" show-password>
            </el-input>
	  </el-form-item>
      <el-form-item>
		<div class="flex-r-between loginForm">
			<el-button class="btn" type="primary" @click="submit">提交</el-button>
			<el-button class="btn" @click="reset">重置</el-button>
		</div>
      </el-form-item>
    </el-form>
  </div>
</template>

<script lang="ts">
import { Vue , Options } from 'vue-class-component'
import {login} from './service'

@Options({
    data(){
		return{
			formData : {
				username:'',
				password:''
			}
		}
	},
	methods:{
		reset(){
			this.formData.username = "",
			this.formData.password = ""
		},
		submit(){
		    // ... 登录的逻辑我准备写在vuex里面
		}
	}
})
export default class extends Vue {

}
</script>
<style lang="scss">
	.login{
		width: 100%;
		height: 100%;
		background: linear-gradient(-32deg, #2246BE, #333333 50%, #ff3f00);
		opacity: 0.8;
	}
	.loginForm{
		width: 400px;
	}
	.btn{
		width: 150px;
	}
</style>
复制代码

这里的标签类flex-c-centerflex-r-between是外部定义的。

对于页面的请求我是放在页面同级目录下的方便管理
// service.ts
import request from '@/utils/request'
// 登录
export const login = (data:any) => {
	request({
		url:'/userLogin',
		method:'post',
		data
	})
}
复制代码

axios的用法还是建议去官网看看axios

6.vuex的使用

首先确定需要进行管理的数据

  1. 用户信息的数据管理
  2. 权限业务衍生出的路由进行管理
思路整理
|permission.ts
    |vuex.user
        |获得用户权限信息
    |vuex.permission
        |router 获得路由
        |接收传入的权限对路由进行筛选
        |返回权限路由
// 路由权限配置在meta中的privs,用户直接获取privs然后做出判断
复制代码
用户信息管理

用户对象起名:user,
其属性结合业务暂定为:

  • name 名字
  • headImg 头像
  • role 角色
  • privs 权限

这里直接结合模块化去使用,方便管理

// user.ts
import {login} from '@/views/login/service'
// user对象状态管理
const user = {
	namespaced: true,
	state:{
		username:'',
		token:'',
		role:'',
		privs:[]
	},
	mutations:{
		SET_USER: (state:any,username:string) => {state.username = username},
		SET_TOKEN: (state:any,token:string) => {state.token = token},
		SET_ROLES: (state:any,role:string) => {state.role = role},
		SET_PRIVS: (state:any,privs:string[]) => {state.privs = privs}
	},
	actions:{
		setUser({commit}:any,data:any){
			commit("SET_USER",data.username)
		},
		
	}
}

 export default user
复制代码
权限管理
权限设计思路:
|在路由注册时在meta中配入权限
    |store.user中先给出模拟数据,及对应路由的读写权限
    |store.permission中去根据用户权限进行筛选得到对应的路由
        |根据筛选的路由进行分配展示路由以及注册路由
复制代码
代码设计:
// user.ts
import { login,getInfo } from '@/views/login/service';
import { setForeverCookie,getCookie } from '@/utils/cookie';
// user对象状态管理
const user = {
	namespaced: true,
	state:{
		username:'',
		token:'',
		role:'',
		privs:[]
	},
	mutations:{
		SET_USER: (state:any,username:string) => {state.username = username},
		SET_TOKEN: (state:any,token:string) => {state.token = token},
		SET_ROLES: (state:any,role:string) => {state.role = role},
		SET_PRIVS: (state:any,privs:string[]) => {state.privs = privs}
	},
	actions:{
		// 获得用户token
		async setUser({commit}:any,data:any){
			// let res = await login(data);
			let res = {
				data:{
					token:"ajswiqkxindasdswwrt",
					username:'admin',
				}
			}
			if(res.data.token){
				console.log('res',res.data.token)
				setForeverCookie('token',res.data.token);
				console.log('vuex',getCookie('token'))
				commit("SET_USER",res.data.username);
				commit("SET_TOKEN",res.data.token);
			}
		},
		// 获得用户信息
		async getInfo({commit}:any){
			const token = getCookie('token');
			// let res = await getInfo(token);
			let res = {
				data:{
					role:'0',
					privs:["QUESTION_LIST_WRITE","QUESTION_LIST_READ","QUESTION_CLASS_WRITE","QUESTION_CLASS_READ","ORDER_LIST_WRITE","ORDER_LIST_READ","ORDER_CLASS_WRITE","ORDER_CLASS_READ","GOODS_CLASS_WRITE","GOODS_CLASS_READ","GOODS_LIST_WRITE","GOODS_LIST_READ","QUESTION_CLASS_WRITE","QUESTION_CLASS_READ","QOURSE_LIST_WRITE","QOURSE_LIST_READ"]
				}
			}
			commit("SET_ROLES",res.data.role);
			commit("SET_PRIVS",res.data.privs);
		}
		
	}
}

 export default user
复制代码
// permission.ts
import { RouteRecordRaw,RouteMeta } from 'vue-router'
import { asyncRoutes,constantRoutes } from '@/router/index';

function screen(router:RouteRecordRaw[],privs:string[]):RouteRecordRaw[]{
	let res:RouteRecordRaw[] = [];
	router.forEach((item:RouteRecordRaw) => {
		if(item.children){
			item.children = screen(item.children,privs)
			res.push(item)
		}
// item.meta运行会报错,不知道咋解决可以通过ts配置文件"strict": false,但是这样不符合开发规范
		let bo = privs.some((priv:string) => (<Array<string>>item.meta.privs).includes(priv))
		if(bo){
			res.push(item)
		}
	})
	return res
}
// 权限对象状态管理
const permission = {
	namespaced: true,
	state:{
		routers:[],
		addRouter:[]
	},
	mutations:{
		SET_ROUTERS: (state:any,routers:Array<RouteRecordRaw>) => {state.routers = routers},
		SET_ADDROUTER: (state:any,addRouter:Array<RouteRecordRaw>) => {state.addRouter = addRouter},
	},
	actions:{
		// 获得权限路由
		async screenRouter({commit}:any,data:string[]){
			let router = screen(asyncRoutes,data)
			commit('SET_ADDROUTER',router)
			commit('SET_ROUTERS',router.concat(constantRoutes))
		}
	}
}

 export default permission
复制代码

筛选过的权限就通过addRouter去注册到路由中就可以正常使用了

7.节流设置

思路:
|点击登录按钮后直接锁死登录按钮等待回调
复制代码

登录编写完成

项目规划

|系统管理容器
    |侧边栏
    |navbar
    |tagbar
    |main
复制代码
文章分类
前端
文章标签