2.3 iHRM人力资源 - 路由、左侧菜单栏、处理token失效、退出登录、修改密码

iHRM人力资源 - 处理token失效、退出登录、修改密码

文章目录

  • iHRM人力资源 - 处理token失效、退出登录、修改密码
  • 一、退出登录
    • 1.1 处理token失效
    • 1.2 调整下拉菜单
    • 1.3 退出登录
  • 二、修改密码
    • 2.1 弹出层dialog
    • 2.2 表单结构
    • 2.3 表单校验
    • 2.4 表单提交
  • 三、路由
    • 3.1 清理多余组件和路由
    • 3.2 创建路由与页面
    • 3.3 批量创建路由和组件
  • 四、解析左侧菜单渲染
  • 五、显示项目logo

一、退出登录

1.1 处理token失效

流程图如下所示

image-20240122231649850

拦截器在如下所示的位置

image-20240122232240424

// 创建响应拦截器,并且两个参数都是回调函数
service.interceptors.response.use(// 请求成功时响应,此时的响应默认包裹了一层data,即response.data才是后台服务返回的内容(response) => {// 一次性解析出response.data中的三个属性const { data, message, success } = response.dataif (success) {// 此时响应正常return data} else {Message({ type: 'error', message: message })return Promise.reject(new Error(message))}},// 请求失败时响应async(error) => {if (error.response.status === 401) {Message({ type: 'warning', message: 'token 超时了,请重新登录' })// token超时,调用action退出登录// dispatch返回的是一个promise,这里会等dispatch执行完再执行路由跳转await store.dispatch('user/logout')// 主动跳转到登录页router.push('/login')return Promise.reject(error)}// this.$message.warning 不能这么使用,因为此时的this不是组件实例对象Message({ type: 'error', message: error.message })// 默认支持promise的,下面语句相当于终止了当前promise的执行return Promise.reject(error)}
)

async…await:

我们store.dispatch(‘user/logout’)中的dispatch其实是一个Promise,这里加一个“async…await”是为了将用户的信息全部删除完成后再跳转到登录页router.push(‘/login’)

加上“async…await”后,就会强制等待把用户信息、token全部删除干净了再跳转到登录页

拦截器中需要调用vuex内容

image-20240122235908561

// Mutations类似java中的数据层,只对数据进行操作,不对业务操作(比如数据加减乘除)
const mutations = {// 从浏览器缓存删除tokenremoveToken(state) {// 删除vuex的tokenstate.token = null// 删除缓存中的tokenremoveToken()},setUserInfo(state, userInfo) {state.userInfo = userInfo}..........
}/*** actions似java中的业务逻辑层,对逻辑操作,然后向mutations发送数据,在这个业务逻辑中也可以互相调用* actions可以做异步操作*/
const actions = {// 退出登录的actionlogout(context) {// 删除用户tokencontext.commit('removeToken')// 删除用户信息(设置用户信息为空对象)context.commit('setUserInfo', {})},...................
}

1.2 调整下拉菜单

我们现在菜单的内容是英文的形式,现在调整成中文的形式

image-20240309202917031

其实就是页面这部分的内容:

image-20240309222522752

代码中的位置如下图所示:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

代码如下图所示:

<template><div class="navbar"><hamburger :is-active="sidebar.opened" class="hamburger-container" @toggleClick="toggleSideBar"/><breadcrumb class="breadcrumb-container"/><div class="right-menu"><el-dropdown class="avatar-container" trigger="click"><div class="avatar-wrapper"><!--用户头像,v-if判断用户头像是否存在--><img v-if="avatar" :src="avatar" class="user-avatar"><!--如果用户头像不存在的时候执行下面的v-else,显示用户名的第一个字--><!--当name时null或者undefined时name.charAt(0)会报错,但是当在name之后加上“?”后,如果name为null或者undefined,就不会执行charAt(0),也不会报错了--><!-- "name?" 可选操作符,表示验证name是否一定有值。 此语法需要vue2.7.0之后的版本--><span v-else class="username">{{ name?.charAt(0) }}</span><!--用户名称--><span class="name">{{ name }}</span><!--图标(设置图标,是一个齿轮的样式)--><i class="el-icon-setting"/></div><el-dropdown-menu slot="dropdown" class="user-dropdown"><router-link to="/"><el-dropdown-item><!--Home-->首页</el-dropdown-item></router-link><a target="_blank" href="https://github.com/PanJiaChen/vue-admin-template/"><el-dropdown-item><!--Github-->项目地址</el-dropdown-item></a><a target="_blank" href="https://panjiachen.github.io/vue-element-admin-site/#/"><el-dropdown-item><!--Docs-->修改密码</el-dropdown-item></a><!--divided 属性是在列的上面有个分割线,我们去掉--><!--<el-dropdown-item divided @click.native="logout">--><el-dropdown-item @click.native="logout"><span style="display:block;"><!--Log Out-->退出登录</span></el-dropdown-item></el-dropdown-menu></el-dropdown></div></div>
</template>

1.3 退出登录

实现退出登录功能

image-20240309223116817

我们之前在处理token失效的时候写过退出的Action,我们直接调用就好了,调用完Action,直接将页面跳转到登录页面

<el-dropdown-item @click.native="logout"><span style="display:block;"><!--Log Out-->退出登录</span>
</el-dropdown-item>

native:事件的修饰符,此时是修饰@click点击事件,目的是注册组件的根元素的原生事件(也就是H5事件)

因为el-dropdown-item的标签并不是H5的标签,@click.native表示el-dropdown-item标签最终形成的H5的标签去注册H5标签的点击事件

如果不写“.native”表示注册的这个组件的自定义事件,而这个组件本身并没有click这个自定义事件,所以我们需要native触发click点击事件

对于某个标签有没有点击事件,el开头的标签我们开element-ui文档即可,通过下面的文档发现,el-dropdown-item并没有点击事件

image-20240309223851432

  methods: {async logout() {// 清除用户信息await this.$store.dispatch('user/logout')// await表示等待上面的代码执行完毕后,执行下面的代码,跳转页面到登录界面this.$router.push('/login')}}

点击“退出登录”后,其实就跳转到了http://localhost:9528/#/login页面

二、修改密码

实现下面的一个效果

说明:超级管理员的密码不可修改,修改密码的时候要有校验功能

image-20240309224505993

修改密码的整体流程

image-20240309225036204

依然是下面这个位置

image-20240309223116817

2.1 弹出层dialog

解释修饰符sync

可以接收子组件传过来的事件和值

我们点击弹出层dialog的“×”号后,所以“showDialog”接收到了el-dialog传过来的false值

这些事情是在el-dialog源码中写的

<template><div><!--放置dialog--><!--title是dialog的标题; :visible.sync用来控制是否显示弹出层 sync作用是点击“×”号时能把弹出层关闭掉--><el-dialog title="修改密码" :visible.sync="showDialog" width="450px"><!--放置dialog表单--></el-dialog></div>
</template>
data() {return {// 控制弹层的显示和隐藏showDialog: false}
},methods: {updatePassword() {// 弹出层显示this.showDialog = true}
}

2.2 表单结构

如下图所示的结构

image-20240309231143181

<!--放置dialog-->
<!--title是dialog的标题; :visible.sync用来控制是否显示弹出层 sync作用是点击“×”号时能把弹出层关闭掉-->
<el-dialog title="修改密码" :visible.sync="showDialog" width="450px"><!--放置dialog表单--><!--设置完成label-width="120px"后,提示信息就和输入框在同一行了--><el-form label-width="120px"><!--label属性其实就是此item的提示信息--><el-form-item label="旧密码"><el-input show-password size="small"></el-input></el-form-item><!--show-password 属性表示输入的内容是密文--><el-form-item label="新密码"><el-input show-password size="small"></el-input></el-form-item><el-form-item label="重复密码"><el-input show-password size="small"></el-input></el-form-item><!--按钮--><el-form-item><el-button size="mini" type="primary">确认修改</el-button><el-button size="mini">取消修改</el-button></el-form-item></el-form>
</el-dialog>

2.3 表单校验

其实就是实现下图所示的功能

image-20240310202632467

<!--放置dialog-->
<!--title是dialog的标题; :visible.sync用来控制是否显示弹出层 sync作用是点击“×”号时能把弹出层关闭掉-->
<el-dialog title="修改密码" :visible.sync="showDialog" width="450px"><!--放置dialog表单--><!--设置完成label-width="120px"后,提示信息就和输入框在同一行了--><!--ref属性是为了获取整个表单的属性--><el-form label-width="120px" :model="passForm" :rules="rules" ref="passForm"><!--label属性其实就是此item的提示信息--><el-form-item label="旧密码" prop="oldPassword"><el-input show-password v-model="passForm.oldPassword" size="small"></el-input></el-form-item><!--show-password 属性表示输入的内容是密文--><el-form-item label="新密码" prop="newPassword"><el-input show-password v-model="passForm.newPassword" size="small"></el-input></el-form-item><el-form-item label="重复密码" prop="confirmPassword"><el-input show-password size="small" v-model="passForm.confirmPassword"></el-input></el-form-item><!--按钮--><el-form-item><el-button size="mini" type="primary">确认修改</el-button><el-button size="mini">取消修改</el-button></el-form-item></el-form>
</el-dialog>
data() {return {// 控制弹层的显示和隐藏showDialog: false,// 修改密码功能表单内容passForm: {// 旧密码oldPassword: '',// 新密码newPassword: '',// 确认密码confirmPassword: ''},// 修改密码功能的表单校验内容rules: {// 旧密码oldPassword: [// trigger: 'blur' 表示失去焦点的时候再触发校验功能{ required: true, message: '旧密码不能为空', trigger: 'blur' },{}],// 新密码newPassword: [{ required: true, message: '新密码不能为空', trigger: 'blur' },{ min: 6, max: 16, message: '新密码长度6-16', trigger: 'blur' }],// 确认密码confirmPassword: [{ required: true, message: '重复密码不能为空', trigger: 'blur' },// 当满足第一个required: true触发规则后,才会触发下面的这个规则// 自定义校验规则validator,参数1:rule规则,参数2:value参数值,也是就是重复密码的值参数3:callback必须执行的回调函数{trigger: 'blur', validator: (rule, value, callback) => {// 只有当此方法是牵头函数的时候,此处的this才指代组件实例对象if (this.passForm.newPassword === value) {// 用户输入的新密码和重复密码是相等的,我们执行一下callback回调函数callback()} else {// 否则就放入一个错误对象callback(new Error('重复密码和新密码输入不一致'))}}}]}}
}

2.4 表单提交

image-20240310210025070

如果调用接口失败的话,我们可以不用处理,我们在拦截器中配置了失败时候的提示信息

image-20240310210127225

接口可以写在下面这个问题里

image-20240310211037761

<!--按钮-->
<el-form-item><el-button @click="btnOK" size="mini" type="primary">确认修改</el-button><el-button @click="btnCancel" size="mini">取消修改</el-button>
</el-form-item>
btnOK() {this.$refs.passForm.validate(async isOK => {if (isOK) {// 表示校验通过,下一步调用接口await updatePassword(this.passForm)// 只要执行到这里,说明一定是执行成功this.$message.success('修改密码成功')this.btnCancel()// // 关闭Dialog// this.showDialog = false// // 重置表单// this.$refs.passForm.resetFields()}})
},
btnCancel() {// 关闭Dialogthis.showDialog = false// 重置表单this.$refs.passForm.resetFields()
}

api请求内容

// 更改用户密码
export function updatePassword(data) {return request({url: '/sys/user/updatePass',method: 'PUT',// 下面这行参数可以简写成 datadata: data})
}

修改下面的bug

当我们点击右上角的叉号后,再打开此页面,会出现下面这个情况,还会有表单验证的提示

image-20240310212724782

按理说我们这是重新打开的表单,不能用表单验证提示,所以改一下

其实就是加了一个@close属性

<!--放置dialog-->
<!--title是dialog的标题; :visible.sync用来控制是否显示弹出层 sync作用是点击“×”号时能把弹出层关闭掉-->
<!--除此之外我们还要添加@close="btnCancel,因为我们只添加sync,当关闭dialog再打开后,表单验证的内容还会存在,所以再加一个@close,当dialog关闭后会执行@close-->
<el-dialog title="修改密码" @close="btnCancel" :visible.sync="showDialog" width="450px">
</el-dialog>   

三、路由

3.1 清理多余组件和路由

  1. 我们现在只保留登录页面、主页、404页面,其他的全部删除

image-20240310213219563

下面选中的全部删除

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  1. 删除页面后,我们对应的路由配置也要删除

image-20240310213238532

import Vue from 'vue'
import Router from 'vue-router'Vue.use(Router)/***  Layout @/在vue中代表路径别名*  @ 符号表示当前目录的src*  @/ 表示src下的layout,而layout又是一个目录,所以会拉取index.vue文件*  即index.vue组件就是我们的路由组件,会实现二级路由* */
import Layout from '@/layout'export const constantRoutes = [{path: '/login',component: () => import('@/views/login/index'),hidden: true},{path: '/404',component: () => import('@/views/404'),hidden: true},{path: '/',component: Layout,redirect: '/dashboard',children: [{path: 'dashboard',name: 'Dashboard',component: () => import('@/views/dashboard/index'),meta: { title: 'Dashboard', icon: 'dashboard' }}]},// 404 page must be placed at the end !!!// 下面这行路由是兜底的方案,如果找不到页面,就会匹配最后的*,然后跳转到404页面{ path: '*', redirect: '/404', hidden: true }
]const createRouter = () => new Router({// mode: 'history', // require service supportscrollBehavior: () => ({ y: 0 }),routes: constantRoutes
})const router = createRouter()// Detail see: https://github.com/vuejs/vue-router/issues/1234#issuecomment-357941465
export function resetRouter() {const newRouter = createRouter()router.matcher = newRouter.matcher // reset router
}export default router

目前的首页内容如下图所示

image-20240310213738742

  1. 请求模块多余的内容也删除

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

选中的内容删除

image-20240310213823084

3.2 创建路由与页面

人力资源项目的业务模块如下图所示

image-20240310214152327

建立对应的路由组件-路由配置

image-20240310214337965

其实相当于把上面的八个功能都模块化了,组件模块化、路由模块化

创建department组织架构模块

image-20240310220111172

创建department的路由信息

image-20240310220042378

// 这个相当于一级路由
import layout from '@/layout/index.vue'// 默认导出
export default {// 路由信息path: '/department',// 一级路由component: layout,// 二级路由children: [{// 二级路由path为空,表示'/department'路径时显示一级路由+二级路由// 并且按需导入department文件下的组件path: '',component: () => import('@/views/department'),// name属性在这里可以用来跳转,也可以用来标记路由// 为什么要标记路由?因为我们后面要做权限的控制,对权限做细分化,name: 'department',// 路由的元信息,其实就是用来存储数据的,比如说图标信息// 在我们的基础模板里面读取了meta的icon和title,并显示在了页面左侧菜单上meta: {icon: 'tree', // 菜单的图标title: '组织' // 菜单的标题}}]
}

在总路由配置中引用department路由

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

import Vue from 'vue'
import Router from 'vue-router'Vue.use(Router)/***  Layout @/在vue中代表路径别名*  @ 符号表示当前目录的src*  @/ 表示src下的layout,而layout又是一个目录,所以会拉取index.vue文件*  即index.vue组件就是我们的路由组件,会实现二级路由* */
import Layout from '@/layout'
import departmentRouter from '@/router/modules/department'export const constantRoutes = [{path: '/login',component: () => import('@/views/login/index'),hidden: true},{path: '/404',component: () => import('@/views/404'),hidden: true},{path: '/',component: Layout,redirect: '/dashboard',children: [{path: 'dashboard',name: 'Dashboard',component: () => import('@/views/dashboard/index'),meta: { title: 'Dashboard', icon: 'dashboard' }}]},departmentRouter,// 404 page must be placed at the end !!!// 下面这行路由是兜底的方案,如果找不到页面,就会匹配最后的*,然后跳转到404页面{ path: '*', redirect: '/404', hidden: true }
]const createRouter = () => new Router({// mode: 'history', // require service supportscrollBehavior: () => ({ y: 0 }),routes: constantRoutes
})const router = createRouter()// Detail see: https://github.com/vuejs/vue-router/issues/1234#issuecomment-357941465
export function resetRouter() {const newRouter = createRouter()router.matcher = newRouter.matcher // reset router
}export default router

主页面内容

image-20240310220410829

3.3 批量创建路由和组件

总路由配置

import Vue from 'vue'
import Router from 'vue-router'Vue.use(Router)/***  Layout @/在vue中代表路径别名*  @ 符号表示当前目录的src*  @/ 表示src下的layout,而layout又是一个目录,所以会拉取index.vue文件*  即index.vue组件就是我们的路由组件,会实现二级路由* */
import Layout from '@/layout'
import departmentRouter from '@/router/modules/department'
import approvalRouter from '@/router/modules/approval'
import attendanceRouter from '@/router/modules/attendance'
import employeeRouter from '@/router/modules/employee'
import permissionRouter from '@/router/modules/permission'
import roleRouter from '@/router/modules/role'
import salaryRouter from '@/router/modules/salary'
import socialRouter from '@/router/modules/social'export const constantRoutes = [{path: '/login',component: () => import('@/views/login/index'),hidden: true},{path: '/404',component: () => import('@/views/404'),hidden: true},{path: '/',component: Layout,redirect: '/dashboard',children: [{path: 'dashboard',name: 'Dashboard',component: () => import('@/views/dashboard/index'),meta: { title: '首页', icon: 'dashboard' }}]},departmentRouter,roleRouter,employeeRouter,permissionRouter,attendanceRouter,approvalRouter,salaryRouter,socialRouter,// 404 page must be placed at the end !!!// 下面这行路由是兜底的方案,如果找不到页面,就会匹配最后的*,然后跳转到404页面{ path: '*', redirect: '/404', hidden: true }
]const createRouter = () => new Router({// mode: 'history', // require service supportscrollBehavior: () => ({ y: 0 }),routes: constantRoutes
})const router = createRouter()// Detail see: https://github.com/vuejs/vue-router/issues/1234#issuecomment-357941465
export function resetRouter() {const newRouter = createRouter()router.matcher = newRouter.matcher // reset router
}export default router

页面展示

image-20240310222101712

四、解析左侧菜单渲染

我们上面通过建立路由生成了左侧的菜单,那到底是怎么实现的

我们的左侧菜单栏是一个叫“sidebar”的菜单组件,会根据路由组件渲染出左侧的菜单内容

image-20240310223951555

siderbar组件会读取路由信息并且会遍历,然后生成一个叫做siderbarItem的组件且会生成很多个(有多少个路由就会生成多少个)

并不是有多少个siderbarItem就会显示多少个左侧菜单,我们会针对siderbarItem组件进行条件渲染,来判断会不会显示

比如登录、404页面就没有在侧边栏展示

如果确定某个组件显示,我们就又会用上一个组件叫做Item组件,此Item组件会渲染咱们传进去的标题和图标,也是就一个渲染过程

image-20240310224400152

我们查看一下这个组件的代码

image-20240310224502216

五、显示项目logo

在settings.js文件中会有许多的配置选项,其中sidebarLogo属性表示是否显示logo标志

module.exports = {title: '人力资源后台管理系统',/*** @type {boolean} true | false* @description Whether fix the header*/fixedHeader: false,/*** @type {boolean} true | false* @description Whether show the logo in sidebar*/sidebarLogo: true
}

image-20240310225909176

当设置为true后,我们这里就会有一个图标

image-20240310225921463

但是这个图标并不是我们想要的,所以我们要去左侧菜单里那里进行修改

image-20240310230028453

<template><!--当菜单栏缩小的时候会有一个collapse,当这个类collapse存在,则就是在缩小的情况下--><div class="sidebar-logo-container" :class="{'collapse':collapse}"><transition name="sidebarLogoFade"><router-link key="collapse" class="sidebar-logo-link" to="/"><img src="@/assets/common/logo.png" class="sidebar-logo"></router-link></transition></div>
</template><script>
export default {name: 'SidebarLogo',props: {collapse: {type: Boolean,required: true}},data() {return {title: 'Vue Admin Template',logo: 'https://wpimg.wallstcn.com/69a1c46c-eb1c-4b46-8bd4-e9e686ef5251.png'}}
}
</script><style lang="scss" scoped>
.sidebarLogoFade-enter-active {transition: opacity 1.5s;
}.sidebarLogoFade-enter,
.sidebarLogoFade-leave-to {opacity: 0;
}.sidebar-logo-container {position: relative;width: 100%;height: 50px;line-height: 50px;//background: #2b2f3a;text-align: center;overflow: hidden;& .sidebar-logo-link {height: 100%;width: 100%;& .sidebar-logo {width: 140px;//height: 32px; 高度自适应vertical-align: middle;margin-right: 12px;}& .sidebar-title {display: inline-block;margin: 0;color: #fff;font-weight: 600;line-height: 50px;font-size: 14px;font-family: Avenir, Helvetica Neue, Arial, Helvetica, sans-serif;vertical-align: middle;}}&.collapse {.sidebar-logo {margin-right: 0px;width: 32px;height: 32px;}}
}
</style>

页面样式

image-20240310230717402

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

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

相关文章

面试:lock 和 synchronized

一、语法层面 synchronized 是关键字&#xff0c;源码在jvm中&#xff0c;用c语言实现Lock 是接口&#xff0c;源码由jdk提供&#xff0c;用java语言实现使用synchronized时&#xff0c;退出同步代码块锁会自动释放&#xff0c;而使用Lock时&#xff0c;需要手动调用unlock方法…

用于扩展Qt自身的插件(下)

扩展Qt自身的插件 引言必须满足项创建插件示例代码生成插件配置加载插件的环境创建使用插件的项目配置库和头文件依赖的步骤:应用程序代码运行结果总结引言 本文继上篇的扩展Qt自身的插件,接着记录Qt自身的插件,只不过本文提及的用于扩展Qt自身的插件是可以在QtCreator的设…

Java反序列化基础-类的动态加载

类加载器&双亲委派 什么是类加载器 类加载器是一个负责加载器类的对象&#xff0c;用于实现类加载的过程中的加载这一步。每个Java类都有一个引用指向加载它的ClassLoader。而数组类是由JVM直接生成的&#xff08;数组类没有对应的二进制字节流&#xff09; 类加载器有哪…

基于ubuntu22.04系统安装nvidia A100驱动与NVLink启用

1、官方仓库 针对驱动包下载认准nvidia官网 dpkg -i nvidia-driver-local-repo-ubuntu2204-550.54.15_1.0-1_amd64.deb apt update apt search nvidia-driver-5502、安装 根据步骤1apt search nvidia-driver-550查出版本&#xff1a;此驱动包封在nvidia-driver-local-repo-ub…

基于springboot的医护人员排班系统

随着信息技术在管理上越来越深入而广泛的应用&#xff0c;管理信息系统的实施在技术上已逐步成熟。本文介绍了医护人员排班系统的开发全过程。通过分析医护人员排班系统管理的不足&#xff0c;创建了一个计算机管理医护人员排班系统的方案。文章介绍了医护人员排班系统的系统分…

【数据结构与算法】之双向链表及其实现!

​ 个人主页&#xff1a;秋风起&#xff0c;再归来~ 数据结构与算法 个人格言&#xff1a;悟已往之不谏&#xff0c;知来者犹可追 克心守己&#xff0c;律己则安&#xff01; 目录 1、双向链表的结构及概念 2、双向链表的实现 2.1 要实现的接口…

算法设计与分析实验报告c++实现(矩阵链相乘、投资问题、完全背包问题、数字三角形、最小生成树、背包问题)

一、实验目的 1&#xff0e;加深学生对分治法算法设计方法的基本思想、基本步骤、基本方法的理解与掌握&#xff1b; 2&#xff0e;提高学生利用课堂所学知识解决实际问题的能力&#xff1b; 3&#xff0e;提高学生综合应用所学知识解决实际问题的能力。 二、实验任务 用动态…

【微信小程序之分包】

微信小程序之分包 什么是分包分包的好处分包前的结构图分包后的结构图分包的加载规则分包的体积限制使用分包打包原则引用原则独立分包独立分包的配置方法独立分包的引用原则分包预下载配置分包的预下载分包预下载限制 什么是分包 分包指的是把一个完整小程序项目&#xff0c;…

突破编程_前端_SVG(使用 svg-pan-zoom 库进行平移与缩放)

1 svg-pan-zoom 概述 svg-pan-zoom 是一个轻量级、高性能且易于使用的 JavaScript 库&#xff0c;专为增强 SVG 图像的浏览体验而设计。它提供了平移和缩放功能&#xff0c;使用户能够无缝探索大型或复杂的 SVG 图形。这个库允许用户对SVG图像进行交互操作&#xff0c;包括缩放…

新版AndroidStudio使用switch-case语句时出现Constant expression required错误

原因: 在新版的Android Studio中使用JDK17以上版本&#xff0c;会出现switch语句报错"Constant expression required"的问题&#xff0c;这是因为在JDK17中switch语句的条件表达式支持使用枚举类型&#xff0c;而这个特性还没有被支持。 解决方法: ①在gradle.prope…

Github 2024-04-12 开源项目日报 Top10

根据Github Trendings的统计,今日(2024-04-12统计)共有10个项目上榜。根据开发语言中项目的数量,汇总情况如下: 开发语言项目数量Python项目6TypeScript项目2Cuda项目1C++项目1C项目1HTML项目1Jupyter Notebook项目1JavaScript项目1Python - 100天从新手到大师 创建周期:22…

HTTP/1.1特性总结

优点 【简单&#xff0c;灵活和易于扩展&#xff0c;应用广泛和跨平台】 1.简单&#xff1a; http基本的报文格式就是headerbody&#xff0c;头部信息也是key-value简单的文本形式&#xff0c;易于理解&#xff0c;降低了学习和使用的门槛 2.灵活和易于扩展&#xff1a; &…