8 Vue 开发方案

通用需求


axios 封装

封装 axios 请求
import axios from 'axios' // 导入 axios// 第一种: 直接配置在 axios 上(无法配置多个)
axios.defaults.baseURL = 'http://ttapi.research.itcast.cn/'// 第二种: 使用 create 方法创建一个 axios 实例化对象(能够配置多个)
// 1. 设置基准地址并暴露(request.js)
const request = axios.create({baseURL: 'http://ttapi.research.itcast.cn/' // 基础路径
})
export default request// 2. 针对不同组件暴露不同的方法(xxx.js)
import request from './request.js'
export const getUserInfoApi = () => {return request({method: 'GET',url: '/user'})
}// 3. 集中暴露(index.js)
import {getUserInfoApi} from './xxx.js'export default getUserInfoApi = getUserInfoApi

设置 axios 请求/拦截器
import axios from 'axios'
import router from '@/router'
import { Message } from 'element-ui'
import store from '@/store'
import { isTimeOut } from '@/utils/auth.js'const timeOut = 3600 * 1000 // 秒// 创建 axios 实例对象
const request = axios.create({baseURL: process.env.VUE_APP_BASE_API, // 请求基准地址timeout: 10 * 1000 // 请求超时(秒)
})// 请求拦截器
request.interceptors.request.use(config => {// 判断是否存在 tokenif (store.getters.token) {// 判断时间戳是否过期,如果过期则清空登录信息,返回登录页if (isTimeOut(timeOut)) {// 通过判断说明已超时,删除登录信息,主动跳转登录也store.dispatch('user/logout') // 清空登录信息router.push('/login') // 跳转登录页return Promise.reject(new Error('登录超时'))}config.headers['Authorization'] = `Bearer ${store.getters.token}` // 将 token 添加到请求头中}return config // 必须返回请求对象
}, error => {return Promise.reject(error) // 返回错误对象
})// 响应拦截器
request.interceptors.response.use(response => {const { success, message, data } = response.data // 解构数据(axios 默认包了一层data)// 判断返回状态if (success) {return data // 业务成功,返回数据}Message.error(message) // 提示错误信息return Promise.reject(new Error(message)) // 返回错误对象
}, error => {// 判断错误对象的 token 是否超时if (error.response && error.response.data && error.response.data.code === 10002) {store.dispatch('user/logout') // 清空数据router.push('/login')} else {Message.error(error.message) // 提示错误对象信息}return Promise.reject(error) // 返回错误对象
})export default request

页面适配

移动端 rem 适配方案

PostCSS CSS处理器

PostCSS 是一个处理 CSS 的处理工具,本身功能比较单一,它主要负责解析 CSS 代码,再交由插件来进行处理,它的插件体系非常强大,所能进行的操作是多种多样的
PostCSS 一般不单独使用,而是与已有的构建工具进行集成
Vue CLI 默认集成了 PostCSS,并且默认开启了 autoprefixer 插件

Vue CLI 内部使用了 PostCSS,可以通过 .postcssrc 或任何 postcss-load-config 支持的配置源来配置 PostCSS。也可以通过 vue.config.js 中的 css.loaderOptions.postcss 配置 postcss-loader
默认开启了 autoprefixer。如果要配置目标浏览器,可使用 package.json 的 browserslist 字段。

  • Autoprefixer 插件可以实现自动添加浏览器相关的声明前缀
  • PostCSS Preset Env 插件可以让你使用更新的 CSS 语法特性并实现向下兼容
  • postcss-pxtorem 可以实现将 px 转换为 rem

目前 PostCSS 已经有 200 多个功能各异的插件。开发人员也可以根据项目的需要,开发出自己的 PostCSS 插件

1. 利用 lib-flexible 动态设置 rem 基准值
npm i amfe-flexible // 安装// 自行配置可以如此书写 scss
@function rem($px) {@return calc($px / 37.5) + rem;
}width: rem(100);

2. 使用 postcss-pxtorem 将 px 转为 rem
npm install postcss-pxtorem -D // 安装.postcssrc.js // 配置文件
module.exports = {plugins: {'autoprefixer': { // 此配置 Vue/cli 默认配置,可以省略browsers: ['Android >= 4.0', 'iOS >= 8']},'postcss-pxtorem': {rootValue: 37.5, // 根据根字号配置propList: ['*'] // 需要转换的属性: 所有属性}}
}

3. 如何解决自身设计稿与 UI 组件设置不同

因为 rem 适配方案本质上是根据设计稿像素的十分之一来进行设定,而 UI 组件是固定的 375 ==> 37.5,这样就会导致不匹配的情况

.postcssrc.js // 配置文件
module.exports = {plugins: {'postcss-pxtorem': {rootValue({ file}) {return file.indexOf('vant') !== -1 ? 37.5 : 75 // 根据判断是否为 UI 组件设置大小(vant 37.5; 自身: 75)}propList: ['*'] // 需要转换的属性: 所有属性}}
}

模拟数据

登录加密

1. 安装插件

npm install crypto-js

2. 创建工具类

import CryptoJS from 'crypto-js'// 需要和后端一致
const KEY = CryptoJS.enc.Utf8.parse('1234567890123456')
const IV = CryptoJS.enc.Utf8.parse('1234567890123456')export default {/*** 加密* @param {*} word* @param {*} keyStr* @param {*} ivStr*/encrypt(word, keyStr, ivStr) {let key = KEYlet iv = IVif (keyStr) {key = CryptoJS.enc.Utf8.parse(keyStr)iv = CryptoJS.enc.Utf8.parse(ivStr)}let srcs = CryptoJS.enc.Utf8.parse(word)var encrypted = CryptoJS.AES.encrypt(srcs, key, {iv: iv,mode: CryptoJS.mode.CBC,padding: CryptoJS.pad.ZeroPadding})return CryptoJS.enc.Base64.stringify(encrypted.ciphertext)},/*** 解密* @param {*} word* @param {*} keyStr* @param {*} ivStr*/decrypt(word, keyStr, ivStr) {let key = KEYlet iv = IVif (keyStr) {key = CryptoJS.enc.Utf8.parse(keyStr)iv = CryptoJS.enc.Utf8.parse(ivStr)}let base64 = CryptoJS.enc.Base64.parse(word)let src = CryptoJS.enc.Base64.stringify(base64)let decrypt = CryptoJS.AES.decrypt(src, key, {iv: iv,mode: CryptoJS.mode.CBC,padding: CryptoJS.pad.ZeroPadding})let decryptedStr = decrypt.toString(CryptoJS.enc.Utf8)return decryptedStr.toString()}
}

3. 引入并加密

import aes from '@/utils/aes'let encryptionPassword = aes.encrypt(password)

Vue 脚手架代理

方案一: 简易配置

// vue.config.js 配置
devServer: {proxy:"http://localhost:5000"
}

方案二: 具体配置

// vue.config.js 配置
module.exports = {devServer: {proxy: {'/api1': {// 匹配所有以 '/api1'开头的请求路径target: 'http://localhost:5000',// 代理目标的基础路径changeOrigin: true,pathRewrite: {'^/api1': ''}},'/api2': {// 匹配所有以 '/api2'开头的请求路径target: 'http://localhost:5001',// 代理目标的基础路径changeOrigin: true,pathRewrite: {'^/api2': ''}}}}
}
/*changeOrigin设置为true时,服务器收到的请求头中的host为: localhost:5000changeOrigin设置为false时,服务器收到的请求头中的host为: localhost:8080changeOrigin默认值为true
*/

后台管理系统需求


登录

import { getToken, setToken, removeToken, setTimestamp } from '@/utils/auth.js'
import { loginAPI, getUserInfoAPI, getUserDetailByIdAPI } from '@/api/index.js'
import { resetRouter } from '@/router'const state = {token: getToken(), // 用户 tokenuserInfo: {} // 用户基本信息(不能设置为null,映射时访问null中的属性将报错)
}const mutations = {// * 设置 token 并持久化setToken(state, token) {state.token = token // 保存状态setToken(token) // 数据持久化},// * 删除 token 并重置持久化removeToken() {state.token = null // 重置状态removeToken() // 清空 token 数据持久化},// * 设置用户信息setUserInfo(state, data) {state.userInfo = data // 保存数据},// * 设置用户信息removeUserInfo() {state.userInfo = {} // 清空数据}
}const actions = {// * 异步登录async login(context, data) {const result = await loginAPI(data) // 调用后端接口请求数据context.commit('setToken', result) // 保存token// 此时已经获取到了 token ,加上时间戳,主动介入setTimestamp() // 设置时间戳},// * 异步获取用户信息async getUserInfo(context) {const result = await getUserInfoAPI() // 获取用户基本信息const baseInfo = await getUserDetailByIdAPI(result.userId) // 用户员工基本信息const baseResult = { ...result, ...baseInfo } // 合并数据context.commit('setUserInfo', baseResult) // 设置用户基本信息return baseResult // 返回合并数据(为权限控制做准备)},// * 退出登录logout(context) {context.commit('removeToken') // 删除 tokencontext.commit('removeUserInfo') // 删除用户信息resetRouter() // 重置路由表(去除动态路由权限)context.dispatch('permission/setRoutes', [], { root: true }) // 情况权限路由数据}
}export default {namespaced: true,state,mutations,actions
}

权限管理

权限是对特定资源的访问许可,所谓权限控制,也就是确保用户只能访问到被分配的资源,而前端权限归根结底是请求的发起权,请求的发起可能有下面两种形式触发
触发有页面加载触发和页面上的按钮点击触发,总的来说所有的请求发起都触发自前端路由或视图,所以我们可以从这两方面入手,对触发权限的源头进行控制

最终实现

  • 路由方面,用户登录后只能看到自己有权访问的导航菜单,也只能访问自己有权访问的路由地址,否则将跳转4xx提示页
  • 视图方面,用户只能看到自己有权浏览的内容和有权操作的控件
  • 最后再加上请求控制作为最后一道防线,路由可能配置失误,按钮可能忘了加权限,这种时候请求控制可以用来兜底,越权请求将在前端被拦截

实现方案

  • 接口权限: 接口权限目前一般采用jwt的形式来验证,没有通过的话一般返回401,跳转到登录页面重新进行登录,具体实现在于后端
  • 按钮权限:
    • 方案一: 通过 v-if 来判断控制是否能够点击
    • 方案二: 通过自定义指令通过权限鉴权,通过后端返回的权限数据判断对应的按钮是否可以点击
  • 菜单权限:
    • 方案一: 菜单与路由分离,菜单由后端返回,路由跳转时判断跳转信息是否在对应的权限菜单中来控制菜单访问权限
      • 缺点1: 菜单需要与路由做–对应,前端添加了新功能,需要通过菜单管理功能添加新的菜单,如果菜单配置的不对会导致应用不能正常使用
      • 缺点2: 全局路由守卫里,每次路由跳转都要做判断
    • 方案二: 菜单和路由都由后端返回,前端统一定义路由组件,在将后端返回路由通过addRoutes动态挂载之间,需要将数据处理一下,将component字段换为真正的组件
      • 缺点1: 全局路由守卫里,每次路由跳转都要做判断
      • 缺点2: 前后端的配合要求更高
  • 路由权限:
    • 方案一: 初始化就挂载所有的路由,通过标识数据在每次路由跳转时判断用户是否有权限来访问此页面
      • 缺点1: 加载所有的路由,如果路由很多,而用户并不是所有的路由都有权限访问,对性能会有影响。
      • 缺点2: 全局路由守卫里,每次路由跳转都要做权限判断。
      • 缺点3: 菜单信息写死在前端,要改个显示文字或权限信息,需要重新编译
      • 缺点4: 菜单跟路由耦合在一起,定义路由的时候还有添加菜单显示标题,图标之类的信息,而且路由不一定作为菜单显示,还要多加字段进行标识
    • 方案二: 初始化的时候先挂载不需要权限控制的路由,比如登录页,404等错误页。如果用户通过URL进行强制访问,则会直接进入404,相当于从源头上做了控制,登录后,获取用户的权限信息,然后筛选有权限访问的路由,在全局路由守卫里进行调用addRoutes添加路由
      • 缺点1: 全局路由守卫里,每次路由跳转都要做判断
      • 缺点2: 菜单信息写死在前端,要改个显示文字或权限信息,需要重新编译
      • 缺点3: 菜单跟路由耦合在一起,定义路由的时候还有添加菜单显示标题,图标之类的信息,而且路由不一定作为菜单显示,还要多加字段进行标识

路由权限设置

import router from '@/router' // 引入 router 实例
import store from '@/store' // 引入 vuex 实例
import NProgress from 'nprogress' // 引入一份进度条插件
import 'nprogress/nprogress.css' // 引入进度条样式// 白名单路径
const whilePath = ['/login', '/404']NProgress.configure({ showSpinner: false }) // NProgress 关闭顶部加载状态// 路由前置守卫
router.beforeEach(async(to, from, next) => {NProgress.start() // 开启进度条// 判断有无 tokenif (store.getters.token) {// 有 token 做免登陆功能if (to.path === '/login') {next('/') // 免登录到主页} else {// 请求用户数据,但要先判断用户数据是否存在if (!store.getters.userId) {// 因为获取用户数据是异步任务,所有需要使用 await 暂停函数运行const { roles } = await store.dispatch('user/getUserInfo') // 用户数据不存在获取用户数据// 此时用户数据已经获取,获取路由权限(actions 是异步操作)console.log(roles.menus)const asyncRoute = await store.dispatch('permission/filterRoutes', roles.menus)// 动态添加路由规则router.addRoutes([...asyncRoute, { path: '*', redirect: '/404', hidden: true }])// 使用动态添加路由规则后需要手动 next(地址) 不然会报错next(to.path)} else {next() // 其余直接放行}}} else {// 判断路径是否在白名单中if (whilePath.includes(to.path)) {next() // 在白名单,直接放行} else {next('/login') // 不在白名单,强制调整登录页}}NProgress.done() // 强制停止进度条,防止手动切换地址时不经过后置守卫而导致的错误
})// 路由后置守卫
router.afterEach((to, from) => {NProgress.done() // 关闭进度条
})

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/47808.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

MFC:以消息为基础的事件驱动系统和消息映射机制

以消息为基础的事件驱动系统和消息映射机制 (1)消息 A.What(什么是消息) 本质是一个数据结构,用于应用程序不同部分之间进行通信和交互 typedef struct tagMSG {HWND hwnd; // 接收该消息的窗口句柄UINT message; // 消息标…

【C语言】 利用栈完成十进制转二进制(分文件编译,堆区申请空间malloc)

利用栈先进后出的特性,在函数内部,进行除二取余的操作,把每次的余数存入栈内,最后输出刚好就是逆序输出,为二进制数 学习过程中,对存储栈进行堆区的内存申请时候,并不是很熟练,一开始…

双边性:构建神经网络的新方法

正如承诺的那样,这是最近我遇到的最有趣的想法之一的第二部分。如果你错过了,请务必观看本系列的第一部分 - 神经科学家对改进神经网络的看法 - 我们讨论了双边性的生物学基础以及我们大脑的不对称性质如何带来更高的性能。 在这篇文章中,我…

v-for 进行列表的 增删改查

通过对象下标替换属性值 但是通过实践此方法是错误的&#xff0c;Vue监听的是students这个对象&#xff0c;而不是这个对象里面的数组信息&#xff0c;也就是说&#xff0c;改变里面的值&#xff0c;并不能在页面上实现更新的功能 <!DOCTYPE html> <html lang"en…

springboot引入kafka

一. Kafka 简介 什么是 Kafka&#xff1f; Kafka 是一个分布式流处理平台&#xff0c;最初由 LinkedIn 开发&#xff0c;并于 2011 年开源。它用于构建实时数据管道和流应用&#xff0c;能够处理和分析流数据。Kafka 的核心概念 Producer&#xff08;生产者&#xff09;&#…

通俗地理解主动元数据管理

元数据管理&#xff0c;是企业开展数据管理的核心基础&#xff0c;内容涉及元数据的创建&#xff0c;确定需要捕获哪些元数据&#xff0c;通过哪些工具和流程进行创建&#xff0c;继而将元数据妥善存储&#xff0c;保障安全性和可访问性&#xff0c;并不断更新维护&#xff0c;…

git 总结2

记录今日学习内容&#xff1a; 项目组成&#xff1a; 一个master分支QA&#xff1a;开发分支bug修复分支个人开发功能需求分支 常用 从仓库拉取代码&#xff1a; git clone xxx创建并且切换到自己的分支&#xff1a;git checkout -b xxx切换到某分支&#xff1a;git checko…

开发面试算法题求教

在《无尽的拉格朗日》中&#xff0c;有许多不同的星系建筑物。每个星系建筑物的等级不同&#xff0c;带来的影响力也不同。 已知宇宙可以抽象为一个无穷大的平面直角坐标系&#xff0c;现在给定了每个星系建筑物的所在坐标(xi,yi)和它的影响力ri&#xff0c;距离其切比雪夫距离…

C++入门语法总结和STL回顾

目录 iostream和命名空间输入输出流循环输入输出 vector容器string字符串cpp链表操作hashTable哈希表set集合map映射范围for循环 stack栈queue队列list列表类和面向对象 iostream和命名空间 输入输出流 内置库iostream提供了输入和输出功能&#xff0c;允许开发者从键盘读取输…

[渗透测试] 反序列化漏洞

反序列化漏洞 ​ 序列化&#xff1a;将对象的状态信息转换为可以传输或存储的形式的过程。简单的来说&#xff0c;就是将一个抽象的对象转换成可以传输的字符串 &#xff0c;以特定的形式在进行之间实现跨平台的传输。 序列化大多以字节流、字符串、json串的形式来传输。将对…

linux/windows wps node.js插件对PPT状态监听并且通知其他应用

需求背景 公司要求对Window系统&#xff0c;和国产操作系统&#xff08;UOS&#xff09;的wps 软件在 PPT开始播放 结束播放&#xff0c;和播放中翻页 上一页 下一页 等状态进行监听&#xff0c;并通知到我们桌面应用。 技术方案 开发WPS插件&#xff0c;使用node.JS 插件开…

系统架构设计师①:计算机组成与体系结构

系统架构设计师①&#xff1a;计算机组成与体系结构 计算机结构 计算机的组成结构可以概括为以下几个主要部分&#xff1a;中央处理器&#xff08;CPU&#xff09;、存储器&#xff08;包括主存和外存&#xff09;、输入设备、输出设备&#xff0c;以及控制器、运算器、总线和…

如何查看jvm资源占用情况

如何设置jar的内存 java -XX:MetaspaceSize256M -XX:MaxMetaspaceSize256M -XX:AlwaysPreTouch -XX:ReservedCodeCacheSize128m -XX:InitialCodeCacheSize128m -Xss512k -Xmx2g -Xms2g -XX:UseG1GC -XX:G1HeapRegionSize4M -jar your-application.jar以上配置为堆内存4G jar项…

使用puma部署ruby on rails的记录

之前写过一篇《记录一下我的Ruby On Rails的systemd服务脚本》的记录&#xff0c;现在补上一个比较政治正确的Ruby On Rails的生产环境部署记录。使用Puma部署项目。 创建文件 /usr/lib/systemd/system/puma.service [Unit] DescriptionPuma HTTP Server DocumentationRuby O…

C语言中的文件创建、写入与读取

在C语言编程中&#xff0c;文件操作是一项基本且重要的技能。它允许程序与外部数据进行交互&#xff0c;如保存用户输入、读取配置文件或处理日志文件等。下面&#xff0c;我们将详细介绍如何在C语言中创建文件、向文件写入数据以及从文件中读取数据。 点击这里➡️➡️➡️ 锁…

[AWS]MSK调用,报错Access denied

背景&#xff1a;首先MSK就是配置一个AWS的托管 kafka&#xff0c;创建完成之后就交给开发进行使用&#xff0c;开发通常是从代码中&#xff0c;编写AWS的access_key 和secret_key进行调用。 但是开发在进行调用的时候&#xff0c;一直报错连接失败&#xff0c;其实问题很简单&…

Electron 企业级开发通信与本地存储实用解决方案

背景 之前写了一篇Electron通信的方式&#xff0c;讲述了一下三者之间的通信机制&#xff0c;比较恶心&#xff0c;后来发现有个electron/remote&#xff0c; Electron 渲染进程直接调用主进程的API库electron/remote引用讲解-CSDN博客文章浏览阅读58次。remote是个老库&…

蓝队黑名单IP解封提取脚本

应用场景&#xff1a;公司给蓝队人员一个解封IP列表&#xff0c;假如某个IP满足属于某某C段&#xff0c;则对该IP进行解封。该脚本则是进行批量筛选出符合条件的白名单IP 实操如下&#xff1a;公司给了一个已经封禁了的黑名单IP列表如下&#xff08;black&#xff09; 公司要求…

高清视频,无损音频,LDR6023——打造极致视听与高效充电的双重享受!

Type-C PD&#xff08;Power Delivery&#xff09;芯片是一种支持USB Type-C接口规范的电源管理单元&#xff0c;其主要功能包括&#xff1a; 快速充电&#xff1a;Type-C PD芯片支持高功率传输&#xff0c;能够提供更快的充电速度&#xff0c;使电子设备在短时间内充满电&…

微信小程序:多图片显示及图片点击放大,多视频显示

微信小程序&#xff1a;多图片显示及图片点击放大&#xff0c;多视频显示 01 多图片显示及图片点击放大02 多视频03 全部代码 01 多图片显示及图片点击放大 <view><view class"title">图片&#xff1a;</view><block wx:if"{{photoUrlList…