700字范文,内容丰富有趣,生活中的好帮手!
700字范文 > .7.13-人力资源后台管理系统

.7.13-人力资源后台管理系统

时间:2023-02-28 05:21:14

相关推荐

.7.13-人力资源后台管理系统

人力资源管理项目

准备工作

在文件资源管理器中shift+右键=>Powershell输入git clone git@:panjiachen/vue-admin-template.git hm-hr

自动生成克隆文件夹在本地 项目目录

├── src # 源代码目录│ ├── api# 所有请求│ ├── assets # 主题 字体等静态资源│ ├── components # 全局公用组件│ ├── icons # 项目所有 svg icons│ ├── layout # 全局 layout│ ├── router # 路由│ ├── store # 全局 store管理│ ├── styles # 全局样式│ ├── utils # 全局公用方法│ ├── views # views 所有页面│ ├── App.vue# 入口页面│ ├── main.js# 入口文件 加载组件 初始化等│ └── permission.js# 权限管理│ └── settings.js # 配置文件

将package.json中手动修改版本号 “core-js”: “3.6.5”=> “core-js”: “3.25.5” 或者命令npm i core-js@3.25.5

npm i

npm run dev

删除main.js中的 mock

全部删除

部分删除

部分删除

部分删除

重启项目npm run serve无报错

初始化仓库=>删除文件中的 .git(没有显示隐藏项目)

初始化仓库=>完成项目的初始化

准备素材
素材svg矢量文件,设置矢量图标, (电子电路领域) ,显示图标=>login页面可以看到效果图标

<svg-icon icon-class="password" /><svg-icon icon-class="bug" /><svg-icon icon-class="chart" /><svg-icon icon-class="404" />

查找svg-coin文件

svg组件

svg组件loader : 加载器=>处理其他文件(svg)的

结构梳理

基础设置settings.js和导航守卫permission.js
settings.js导出网站基础配置,包括: 网站标题、固定header、显示logologopermission.js(权限),主要负责路由导航守卫

//settings.jsmodule.exports = {title: 'Vue Admin Template',/*** @type {boolean} true | false* @description Whether fix the header*/fixedHeader: true,/*** @type {boolean} true | false* @description Whether show the logo in sidebar*/sidebarLogo: true}

完成了user.js的配置

写登录模块

实现登录表单验证=>element-ui 手动校验=>validate方法=>ref拿到表单实例$refs自动校验
跨域:协议,域名,端口号任意一个不一样就会发生跨域

协议:http<==>https域名:localhost<==>端口号: 9528<==>443

http协议默认端口号80(可省略)

https默认端口443(可省略)

post会发生两次请求

预检请求(Preflight Request)是在进行跨域资源共享(Cross-Origin Resource Sharing,CORS)时,浏览器发送的一种额外的HTTP OPTIONS请求。它用于向服务器请求权限信息,以确定实际请求是否安全。

option预检:是否能发出请求(浏览器主动发起预检请求,跟后端没有关系)

get,post是简单请求不需要预检(复杂请求才会预检),发预检请求的都是options

预检是有时间效的,这一次预检在多久时间内的会有效,浏览器会根据失效时间来判断这次还需不需要预检

预检请求是一个OPTIONS请求服务器收到预检请求后,会检查请求头中的Origin、Access-Control-Request-Method和Access-Control-Request-Headers字段,然后根据这些信息来判断是否允许实际请求。服务器通过响应头中的Access-Control-Allow-Origin、Access-Control-Allow-Methods和Access-Control-Allow-Headers字段来告诉浏览器是否允许跨域请求。预检请求的目的是为了在实际请求被发送之前,确保服务器会对跨域请求做出适当的响应。这样可以防止恶意网站对其他网站进行跨域攻击,保护用户和服务器的安全。预检请求是CORS机制的一部分,用于实现跨域资源共享。跨域是浏览器行为,没有浏览器就不会发生跨域

当服务器允许跨域请求时,在响应头中会包含以下字段和值:

Access-Control-Allow-Origin: 指定允许访问该资源的源站。可以是具体的域名,也可以是通配符"*",表示允许任意域名的访问。

Access-Control-Allow-Methods: 指定允许的HTTP方法。例如,GET、POST、PUT等。这个字段通常是一个逗号分隔的字符串,列出允许的方法。

Access-Control-Allow-Headers: 指定允许的自定义请求头字段。这个字段通常是一个逗号分隔的字符串,列出允许的自定义请求头。

Access-Control-Allow-Credentials: 指定是否允许发送跨域请求时携带cookie等凭据。它的值可以是true或false。

Access-Control-Max-Age: 指定预检请求的有效期,单位为秒。在有效期内,可以复用之前的预检结果,在浏览器不再发起预检请求。

这些字段和值告诉浏览器允许指定的源站、HTTP方法、自定义请求头和凭据进行跨域请求。浏览器在收到这些响应头后,会判断是否符合跨域规则,并决定是否允许实际请求的发送。这种方式通过限制允许跨域请求的源站、方法和请求头的方式,确保跨域请求的安全性。

服务器和服务器之间会不会受跨域影响?为什么?

服务器和服务器之间不会受跨域影响。

跨域请求的概念是指在浏览器中,由JavaScript发起的跨源(不同源的)HTTP请求。跨域请求受到同源策略(Same Origin Policy)的限制,它是一种浏览器安全机制,用于保护用户数据和减少安全风险。然而,当服务器与服务器之间进行通信时,而不是通过浏览器作为中介,跨域问题就不存在了。跨域问题主要针对浏览器环境中的跨源请求,用于保护用户的隐私和安全。

解决开发时的跨域
所有发往/api的请求(包含/api的请求)==>全部转发到target指定的地址中去http://localhost:9528/api/sys/login==>https://heimahritheimanet/api/sys/login

day2

复习
请求拦截器: 请求发出去之前最后一次加工 (token注入)响应拦截器 :在发送请求后,接收到服务器返回的响应之前,对响应进行拦截和处理的功能。 在人资项目中,错误的统一处理,就是给用户提示错误信息 浏览器如何知道某条资源的是什么类型的? 响应报文Response Headers里面包含Content-Type服务器返回来的Content-Type

axios

看请求==> 点开network ,headers,preview,payload都要看 get请求没有payload,放在URL中其他请求放在body中

status=200段,不代表接口的调用逻辑(登录业务)一定是成功的,有可能用户名是错误status不是200段,代表接口的调用逻辑(登录业务)一定是失败的

//utils/request.js// 响应拦截器// 在人资项目中,错误的统一处理,就是给用户提示错误信息service.interceptors.response.use((response) => {// 请求成功的回调:http的状态码就位2XXconst {data, message, success } = response.data // 默认json格式if (success) {// 调用成功,业务也成功return data}// 调用成功,业务失败this.$Message({type: 'error', message })return Promise.reject(new Error(message))}, async(error) => {// http状态码不为200段的情况// error.messagethis.$Message({type: 'error', message: error.message })return Promise.reject(error)})

区分环境
开发环境 .env.development中设置开发环境变量默认 NODE_ENV 值为development

生产环境 .env.production中设置生产环境变量默认 NODE_ENV 值为 production

使用process.env.属性的方式获取自定义环境变量:必须以VUE_APP_开头

打包命令npm run build:prod

npm run dev / npm run serve=>开发环境

npm run build / npm run build:prod=>生产环境

在开发环境,填入用户名,生产环境为空

主页权限验证

登录流程
登录按钮表单校验调接口,拿token(异步修改state中的数据=>actions中实现=>必有mutations),跳转页面

获取用户资料在Vuex中共享

登录之后获取当前用户的资料

获取的用户资料在Vuex中共享

函数名使用小驼峰命名

获取资料action的调用位置

有token的位置再获取资料

charAt表示选择第几个字符
修饰符
trim=>去掉空格native:原生自定义事件不支持原生事件,加上.native就支持原生事件了

<el-dropdown-item divided @click.native="logout"><span style="display:block;">登 出</span></el-dropdown-item>

处理token过期

失效的token调接口=>401

补充

结论1: 定义在data中的数据,才是响应式数据结论2: 动态添加到响应式对象上的新属性,不是响应式结论3:要想让态添加的属性也是响应式的话,需要使用$set 方法

在页面初始化的过程中,通常会有一个生命周期钩子函数或方法,比如created被调用的时刻就是在组件实例被创建后,但是在DOM渲染之前。

如果在created钩子函数中没有进行相关数据的初始化或数据绑定操作,那么在此之前页面是没有内容显示的,因为此时页面的渲染还没有开始

0714作业:回答下面的问题:
重点:动态添加到组件上的数据为什么不能实现视图更新? 因为不是绑定在data上的,只有绑定在data上的数据才是响应式数据动态添加在响应式对象上的新属性,不是响应式的 重点:动态添加到组件数据对象上的新属性,是不是响应式? 不是 重点:如果要给组件的数据对象上添加一个具有响应式能力的新属性,应该怎么办? 需要使用$set 方法 重点:登出逻辑是什么?精髓一句话 从哪来,回哪去,怎么来的,怎样回去清除用户的身份认证信息和相关状态,使其无法再访问需要登录才能进行的操作或页面。 重点:获取用户资料最合理的时机是什么时候? 登录之后,跳转到首页之前 重点:环境变量起到什么作用,如何读取环境变量的值,如何判断当前所处的环境? 环境变量可以用于存储不同环境下的配置信息可以通过环境变量来区分程序运行在开发环境或生产环境中.env.development中设置开发环境变量默认 NODE_ENV 值为development.env.production中设置生产环境变量默认 NODE_ENV 值为 production可以使用 process.env 来访问环境变量 重点:如何自定义环境变量?举一个自定义环境变量应用的例子; 自定义环境变量:必须以VUE_APP_开头

VUE_APP_BASE_API = '/dev-api'VUE_APP_VERSION = '1.0.3'VUE_APP_MOBILE= '13800000002'VUE_APP_PASSWORD = 'hm#qd@23!'

重点:如何解决跨域问题(开发环境跨域)? proxy所有发往/api的请求(包含/api的请求)==>全部转发到target指定的地址中去 重点:什么是同源策略?web中的哪些操作会受到同源策略的影响? 两个页面地址的协议,域名,端口号一直就是同源,否则就是跨域当web页面使用多个元素或者打开其他浏览器窗口的时候,这一策略就会起作用

day3

修饰符
.prevent阻止默认行为

一般用于原生HTML标签

@click.prevent="updatePassworda标签的默认跳转.native 表示给vue的自定义组件添加原生事件.sync支持子组件修改父组件的值

修改密码的弹框
绑定数据绑定规则

给绑定规则: 1.定义规则2.给 el-form 绑定 :model 和 :rules3.给 el-form-item 设置 prop

封装组件

封装组件本质做什么
封装组件的目的 :是为了抽离独立的功能封装组件,本质上可以理解为封装函数
封装函数的时候,要确认什么
函数是干啥用的 组件的功能 函数名 组件名 入参 自定义属性=>props 出参 函数的返回值=>给到父组件(父组件接受子组件的值=>子组件给父组件传值)=>自定义事件=>$emit
图片加载失败=>触发 οnerrοr=" "
图片加载成功=>触发 οnlοad=" "图片加载失败=>触发 οnerrοr=" " 如何知道img图片加载失败给img绑定一个事件@error=“onLoadError”
抽离组件的报错

不能直接在子组件中修改父组件中的值

.sync支持子组件修改父组件的值

抽离组件=>3种方法
修改密码组件优化,使用.sync简化双向数据传递

.sync语法糖原理

.sync在vue3中原理就是:属性+@update属性v-model原理就是:value +@input(属性绑定+自定义事件)

完成修改密码组件抽离,使用props和自定义事件实现组件的显示和隐藏
第一种写法抽离组件

//父组件Navbar.vue<ChangePassword :show-dialog="showPassDialog" @updateShowDialog="updatePassDialog" />

//子组件ChangePassword/index.vue<el-dialog width="500px" title="修改密码" :visible="showDialog" :modal-append-to-body="false" @close="onDialogClose">

子组件的el-dialog弹框显示与隐藏受visible的控制,visible的true/false被showDialog控制着,showDialog的开关与否,在父组件中是被showPassDialog把控

在父组件中定义了一个函数updatePassword定义了showPassDialog的true,控制他的开启=>进而影响showDialog的开启=>el-dialog会开启弹框updateShowDialog是由子组件传给父组件的自定义事件,由父组件自行修改,子组件同时传入false值控制弹框的关闭, 将false传给showPassDialog控制其变为false,进而关闭el-dialog的弹窗

修改密码组件优化,使用.sync简化双向数据传递
第二种写法抽离组件

//完整写法//修改密码的弹框<ChangePassword :show-dialog="showPassDialog" @update:showDialog="showPassDialog = $event " />

.sync 语法糖的作用: 简化对数据的双向操作,允许子组件触发固定形式的自定义事件,来修改父组件的值固定形式的自定义事件: update:属性名 (来源于 props)

// .sync简化写法//修改密码的弹框<ChangePassword :show-dialog.sync="showPassDialog" />

优化修改密码组件,使用$ref+ref .open方案实现弹框打开和隐藏
this.$refs.ref.open() 在子组件定义一个open方法在父组件调用$ref+ref .open

<ChangePassword ref="passDialog" />openPassDialog() {// 能够打开修改密码的弹框即可// 只要能调到 open(),弹框就可以打开// 如何调用到 子组件 的方法??// $refs + refthis.$refs.passDialog.open()}

day4

动态规划

贪心算法

cookie

清理组件和路由
导入文件

删除文件

创建项目所需要的组件和路由

├── approval # 审批管理├── attendance# 考勤管理├── department# 组织架构├── employee # 员工管理├── permission# 权限管理├── role# 角色管理├── salary # 工资管理├── social # 社保管理

//router/index.js// 引入其他路由import approval from './modules/approval'import attendance from './modules/attendance'import department from './modules/department'import employee from './modules/employee'import permission from './modules/permission'import role from './modules/role'import salary from './modules/salary'import social from './modules/social'export const constantRoutes = [approval,attendance,department,employee,permission,role,salary,social,]

改变左侧菜单的图标和文字&& 在左侧sidebar菜单下显示与否

组织架构

树形结构
element-ui提供了树组件el-tree属性 data(绑定数据)props (设置属性) children(设置子节点的字段名)label(设置显示内容的字段名) default-expand-all (默认展开所有节点)

<template><div class="container"><div class="app-container"><!-- 组织架构的属性组件 --><el-tree default-expand-all :data="data" :props="defaultProps" @node-click="handleNodeClick" /></div></div></template><script>export default {name: 'Department',data() {return {data: [{username: 'hello',kids: [{username: '1.1'}]},{username: 'world',kids: [{username: '2.1'},{username: '3.1',kids: [{username: '3.1.1'},{username: '3.1.2'}]}]}],defaultProps: {children: 'kids',label: 'username'}}},methods: {handleNodeClick(data) {console.log(data)}}}</script>

获取组织架构数据 — 平面结构

用真实数据渲染=>获取接口

定义接口=>api文件夹

组织架构 — 递归转化树形结构

怎么写递归

递归本质是一种循环,所以写递归,一定要先找到循环体 循环是广度遍历递归是深度遍历 递归一定要有开始条件或者要有结束条件

递归 — 爬楼梯问题(一维动态规划)
有一个N个台阶的楼梯, 每一步只能爬 1阶 或 2阶,问爬到楼梯的顶部有多少种爬法

假设N=3 =>3种 111,12,21

假设N=4 =>5种 1111,112,121,211,22

假设N=10 => 89种

从第四层到第五层=>1种

从第三层到第五层=>2种

斐波那契数列

1=>1种

2=>2种

3=>3种

4=>5种

5=>8种

6=>13种

function fibo(N) {if(N === 1) return 1if(N === 2) return 2returnfibo(N-1)+fibo(N-2)}console.log(fibo(5))//8种console.log(fibo(10))//89种

组织架构-添加子部门-新建弹层组件

补充

空对象和空数组转成if判断的时候都是true
逻辑运算!!(非非) / 双重否定
“!” 是一个逻辑非运算符,它用于取反一个布尔值。“!!” 则是对该逻辑非的再次运算,相当于两次取反。使用 “!!” 运算符的主要目的是将一个值转换为对应的布尔值。具体规则如下:

如果操作数是一个真值(例如非零数、非空字符串、非空对象),“!!” 运算符将返回 true。

如果操作数是一个假值(例如零、空字符串、null、undefined 或者 false),“!!” 运算符将返回 false。

逻辑值 !!1 对上一次的逻辑值 !1 取反

!(!1) true

空字符串false转成逻辑值也是false

var value1 = 0;var value2 = "Hello";var value3 = null;console.log(!!value1); // falseconsole.log(!!value2); // trueconsole.log(!!value3); // false

双重否定运算符 “!!” 并不改变操作数本身的值,它只是返回一个相应的布尔值。

补充面试题
判断p是不是某个的实例 p instanceof Person

构造函数能不能不new直接调用 可以,但大部分都是undefined构造函数没有返回值,相当于返回了undefined函数调完有结果=>一定有返回值=>return123

为什么(普通函数调用)直接返回和直接调用(构造函数new)的返回值不同如果 return 的是引用数据类型,比如 数组,对象的话,new 的结果就是 return 的结果;如果 return 的是非引用类型,比如 number,boolean的话,new 的结果不受影响;=>则打印是实例对象

new Boolean(false)转为布尔值=>true

!!new Boolean(false)=true

对数据进行布尔转换的时候,不能使用new Boolean转换=>因为new的结果都是实例对象=>永远是true

如果想得到某个内置包装类型的值, 使用实例对象的一个方法 .valueOf()=>取值

单独调用构造函数,判断this指向 this指向window 单独调用普通函数,this指向是,谁调用指向谁,直接调用指向window构造函数可以单独调用,function可以当构造函数使用,内部不一定有this,语法没有问题,但实际没有意义构造函数一般没有return ,写了return的话,new完构造函数会返回什么===>

构造函数如果有返回值,return,new 的结果会受到 return 的影响2.如果 return 的是引用数据类型,比如 数组,对象的话,new 的结果就是 return 的结果;3.如果 return 的是非引用类型,比如 number,boolean的话,new 的结果不受影响;=>则打印是实例对象Person{name:‘hello’}内置包装类型:Number,Boolean,Stringtostring(n) 表示把 前面的数字,转成 n 进制的字符串当我们把一个普通的值, 当做对象去调用时, JS内部的机制会帮我们把这个值包装成一个对应类型的实例对象

const num = 123;console.log(num.tostring(2)) // tostring(n) 表示把 前面的数组,转成 n 进制的字符串'abc'.includes('c') // true// 以上 123 和'abc'都是简单的值,值不是对象,但是却可以当成对象去使用。为什么?// 因为有内部的包装类型// num ==> Number(123) ==> new Number(123)const num2 = new Number(123)console.log(num2.tostring(2)) // 二进制的字符串//当我们把一个普通的值, 当做对象去调用时, JS内部的机制会帮我们把这个值包装成一个对应类型的实例对象,new了一把,进而可以调用includes方法

构造函数是Function的实例对象

Number instanceof Function //trueNumber.tostring === Function.prototype.tostring//trueNumber.prototype.tostring === (123).tostring//trueNumber.toString === Function.prototype.toString//trueNumber.tostring === string.tostring//true

day5

函数式编程:把函数作为入参或者出参来

git stash 暂存

git stash pop把暂存文件拿回来

错误

代码: 表单规则已定义,表单数据和规则已绑定,但是表单校验不起作用;

原因:绑定的属性 :model 拼错了,写成了 :mode

结论:下次表单校验不生效要首先查三个属性有没有写对,:model :rules prop

day6

想要获取什么参数,可以通过传进一个箭头函数,在函数内部中调用传过来的箭头函数来读取其值 => 函数式编程

设计模式

生成校验函数

高阶函数: 一个函数调用之后,返回之后是另一个函数

// 高阶函数(2阶)function createValidator(key) {//闭包const fun = async(rule, value, callback) => {const list = await getDepartmentList()const fn = this.isEdit ? item => item.id !== this.formData.id : () => trueconst isExist = list.filter(fn).some(item => item[key] === value)isExist ? callback(new Error('部门中已经有该名称了')) : callback()return fun}}export default{data(){return{rules: {name: [{required: true, message: '部门名称不能为空', trigger: 'blur' },{min: 2, max: 10, message: '部门名称的长度为2-10个字符', trigger: 'blur'},{trigger: 'blur',// 自定义校验模式validator: createValidator('name', this, '名称')}], // 部门名称code: [{required: true, message: '部门编码不能为空', trigger: 'blur' },{min: 2, max: 10, message: '部门编码的长度为2-10个字符', trigger: 'blur'},{trigger: 'blur',validator: createValidator('code', this, '编码')}], // 部门编码}}}

闭包=>技术点

高阶函数=>设计函数

闭包: 一个函数执行一下,返回另一个函数

设计模式 =>对缓存进行=>包装器

设计方案=>闭包=>包装器

进阶思考 4:上面校验唯一性的时候,每次都会重新调接口,有点浪费

现在需要对获取部门列表的接口做数据缓存,缓存时间2小时

也就是说,如果两小时内重复调用获取部门列表的接口,就返回之前缓存的数据

如果超过2小时,再重新调接口获取新数据

手写一个防抖函数

对传入的fn进行防抖处理,支持传入时间

一段时间内点击多次,只执行最后一次

function debounce(fn,time){//定义一个防抖函数let timer=null//初始化定时器为空return function (){//返回一个匿名函数作为闭包if(timer !== null ){//如果定时器不为空clearTimerout(timer)//如果定时器存在,则清除之前的定时器}timer=setTimeout(fn,time)//设置一个新的定时器,延迟time执行传入的函数fn}}debounce(createValidator)()

判断是否为质数 => 暴力枚举法

牛课题

const arr=[]function zhiyinizi(num){for (let i = 2 ; i <= num ; i++){if( num % 2 === 0) {arr.push(i) //2 2 3 3 5zhiyinzi(num / i)return }}}zhiyinzi(180)console.log(arr) //{2,2,3,3,5}

角色管理

role/index.vue

行内编辑
如何知道点击的是当前行=>插槽 v-solt条件渲染 => 添加的数据必须为响应式为何数据变了,视图没更新 直接添加的新属性不是响应式,所以没有触发视图更新this.$set(row,'isEdit',false)这种是响应式的

发数据报错

查看=>地址,类型,字段名,字段值将true/false => 1/0row.editRow = { ...row }是将名为 row 的对象进行浅拷贝,并将拷贝后的对象赋值给 row.editRow。 { …row } 使用了展开语法 ,它将对象 row 中的所有属性和值都展开为一个新的对象。这个新的对象与原始对象 row 是浅拷贝关系,即新对象中的属性值是原始对象中的引用。所以,row.editRow 将引用一个与 row 相同的对象,但是它是一个新的对象,对 row.editRow 的修改不会影响到 row 对象本身。这在一些场景中常用于备份原始数据,以便在编辑过程中进行对比或回滚。 编辑修改后取消,再点编辑是修改后的数据 => 修改复制数据的拷贝的时机 => 保留状态 点编辑之前复制 => 非保留状态,每次都是修改取消前的数据

补充 => 位运算

进制

每个数字所占的位,表示的是有几个N

八进制

10215 => 2表示2个 (8个8)

十六进制

0x343455

二进制

b101001010

2^0 +

2^1 +

2^2 +

+…2^9

字节+比特位

18yte = 8bit

18=8b

1字节最多能存放256

每个比特位有两种情况 , 一个字节最多有256种情况 ,最大能表示得数是255

=>1字节最多存放256

8位通道色 1600万色

在JS里面,一般使用8个字节来存放一个数字 2^64

32转为二进制console.log(num.toString(2)) // 00100000

左移运算符 << 双元运算符 => 左右都必须有值console.log(32 << 1) // 6400100000 => 01000000console.log(32 << 2) // 128console.log(128 << 1) // 256右移运算符console.log(32 >>1) //16console.log(32 >> 2) // 8console.log(32 >> 3) // 4console.log(32 >> 32) // 0按位与 & (位运算的时候 低位要对齐)

00100000 => 32

00010000 => 16

----------------------- &(第一位对齐)

00000000 => 0 (都为1才为1) 运算逻辑: 每一位进行比较 ,从低位开始逐位比较 , 都为1 ,结果为1, 否则为0 按位或 | (位运算的时候 低位要对齐) 运算逻辑:每一位进行比较,从低位开始逐位比较,有一个为 1 ,结果就位 1,都为 结果才为

100000

010000

110000 => 48

按位异或按位取反

day7

员工

自定义列表的项=>插槽 在 Vue 组件中,以下哪个对数组的操作可以触发视图更新?

A. sort()

B. split()

C. indexOf()

D. replace() 触发视图=>数据改变=>哪个数组可以改变数据=> sort()

场景兼容

组件复用要考虑场景兼容,使用v-if条件判断

设置高亮
这里需要给定node-key属性,否则setCurrentKey方法不知道设置的是哪个字段的值 setCurrentKey方法是给node-key绑定监听id属性名所对应的属性值,即departmentId

<el-treeref="deptTree"node-key="id":data="depts":props="defaultProps"default-expand-all:expand-on-click-node="false"highlight-current@current-change="selectNode"/>

补充:为什么使用 n e x t T i c k ,因为我们设置完树形之后立刻选中首个节点,此时更新还没有完成,必须等待更新完成后,再去选中首个节点,所以需要使用 nextTick,因为我们设置完树形之后立刻选中首个节点,此时更新还没有完成,必须等待更新完成后,再去选中首个节点,所以需要使用 nextTick,因为我们设置完树形之后立刻选中首个节点,此时更新还没有完成,必须等待更新完成后,再去选中首个节点,所以需要使用nextTick

深度监听
监听对象中的属性,可以使用key:value键值对的写法(不需要深度监听) 使用 watch 侦听器坚监听keyword 的变化,因为是复杂数据类型,所以要进行深度监听,也可以直接写成"queryParamskeyword " : function(){this.onKeywordChange}监听深度变化的时候,不能使用箭头函数 因为箭头函数绑定了当前上下文的作用域,会导致监听函数内部的this指向发生变化,从而无法正确地访问到Vue实例的属性或方法。只能使用具名函数或者function函数通常会使用watch选项来监听对象的深度变化。在watch选项中,可以通过指定一个普通函数作为监听函数,这样就能确保函数内部的this指向是正确的。

属性组件=>组件的递归调用
组件自己调自己=> 组件递归 数据有子节点,组件就有子节点不管是methods和created都不能使用箭头函数,箭头函数没有自己的this指向

补充 位运算符的使用 左移(十进制转二进制)得到二进制数的高位(第二个8位数)和低位(第一个八位数)

二进制转十进制

有一个数 num = 19,num 的有效字节为 2 个,分别为 3 和 232

1000 => 900311 1111969

解释:1000 的8个字节中,只有低位的2个字节有值,这两个字节分别为 3 和 232求 12,234 表示的数是多少?

12 => 00001109

234 ==> 11101010

思路1=>算法一:先把这两个数分别转为二进制,并补到8 位二进制转十进制parseInt(110011101010,2)//3306例1

求 12,234 表示的数是多少?算法一

//求 12,234 表示的数是多少?//十进制转位二进制(1000).toString(2)//'1111101000'(12).toString(2)//'1100'(234).toString(2)//'11101010'//将12和234的二进制数(补齐8位)拼接起来=>转为十进制parseInt('0000110011101010',2)//3306

算法二

求 12,234 表示的数是多少?

将12左移8位 ,与234=>3306

12<<8|234 //3306

例2

//求 121,9,201 表示的数是多少?(121).toString(2)//'1111001'=>'01111001'(9).toString(2)//'1001'=>'00001001'(201).toString(2)//'11001001'//将121,9,201的二进制(补齐8位)拼接起来,再转为十进制parseInt('011110010000100111001001',2)//7932361

算法二 使用左移运算符

求 121,9,201 表示的数是多少?

121<<16|9<<8|201//7932361

任何数和255与完都是那个数

1000 & 0xff =>1000

1000 & 255 =>1000

任何数与0都是0

1000&255 //2321000>>8 &255 //3

day8

Response Headers
浏览器如何知道请求发送出去之后返回的是JSON格式 ? 浏览器通常根据服务器响应的Content-Type标头来确定返回的数据格式。

只有JSON才能直接解构

2进制文件流

.hex 16进制文件.bin 2进制文件

3. 可以将2进制文件转为blob对象,比较好处理(2进制文件流很难处理)

4. 怎样转

通过配置项: 告诉axios对请求返回的数据,自动转成blob格式

// 导出Excelexport function exportEmployeeExcel() {// 通过配置项: 告诉axios将下面的请求返回数组,处理成blob类型// 处理成blob的目的- 方便后续通过js代码处理文件// 当前场景,是服务器会返回二进制文件流 ==> 遇到二进制文件流可以使用 blob 格式来处理// 其他场景:返回图片,返回文件 ===> blobrequest.request.get('/sys/user/export', {responseType: 'blob' })}

处理成blob的目的 方便后续通过js代码处理文件 当前场景,是服务器会返回二进制文件流 ==> 遇到二进制文件流可以使用 blob 格式来处理其他场景:返回图片,返回文件 ===> blob哪个接口需要转,就单独配置哪个接口,没有配置的接口不受影响目的是 点击导出按钮,将文件下载到本地 1.二进制文件流不方便直接下载,所以需要转 blob2.拿到 blob 格式以后,就可以通过某种方法 (s方法) 来实现下载

3.todo: 百度一下,如何将一个 blob 数据已文件的形式下载到本地?

blob下载思路:

Vue axios使用Blob下载二进制流文件(get 传参)

exportExcel() {exportEmployeeExcel().then(res => {console.log(res)const blob = new Blob([res], {type: 'application/vnd.ms-excel'}) // 为blob设置文件类型,这里以.xlsx为例const url = window.URL.createObjectURL(blob) // 创建一个临时的url指向blob对象const a = document.createElement('a')a.href = urla.download = '人资员工信息表(使用a标签下载方法).xlsx'a.click()// 释放这个临时的对象urlwindow.URL.revokeObjectURL(url)})}

还可以封装为一个组件,方便 导入模板下载时 使用

// 导出Excelexport function exportEmployeeExcel() {// 通过配置项: 告诉axios将下面的请求返回数组,处理成blob类型// 处理成blob的目的- 方便后续通过js代码处理文件// 当前场景,是服务器会返回二进制文件流 ==> 遇到二进制文件流可以使用 blob 格式来处理// 其他场景:返回图片,返回文件 ===> blobreturn request.get('/sys/user/export', {responseType: 'blob' })}// 目的是 点击导出按钮,将文件下载到本地// 1.二进制文件流不方便直接下载,所以需要转 blob// 2.拿到 blob 格式以后,就可以通过某种方法(s方法) 来实现下载// 3.todo: 百度一下,如何将一个 blob 数据已文件的形式下载到本地?

export function saveAs(blob, filename) {const url = window.URL.createObjectURL(blob) // 创建一个临时的url指向blob对象const a = document.createElement('a')a.href = urla.download = filenamea.click()// 释放这个临时的对象urlwindow.URL.revokeObjectURL(url)}

import {saveAs } from '@/utils/index'async exportExcel() {const result = await exportEmployeeExcel()// 认为,我而要的结果(result)就应该是一个 Blob 对象console.log(result)// 想法办讲 blob 对象以文件的形式下载到本地?exportEmployeeExcel().then(res => {console.log(res)const blob = new Blob([res], {type: 'application/vnd.ms-excel' })// 为blob设置文件类型,这里以.xlsx为例saveAs(blob, '人资员工信息表(使用a标签下载方法).xlsx')})}

安装file-saver包,实现下载Blob文件npm run file-saver

// 导出Excelexport function exportEmployeeExcel() {// 通过配置项: 告诉axios将下面的请求返回数组,处理成blob类型// 处理成blob的目的- 方便后续通过js代码处理文件// 当前场景,是服务器会返回二进制文件流 ==> 遇到二进制文件流可以使用 blob 格式来处理// 其他场景:返回图片,返回文件 ===> blobreturn request.get('/sys/user/export', {responseType: 'blob' })}// 目的是 点击导出按钮,将文件下载到本地// 1.二进制文件流不方便直接下载,所以需要转 blob// 2.拿到 blob 格式以后,就可以通过某种方法(s方法) 来实现下载// 3.todo: 百度一下,如何将一个 blob 数据已文件的形式下载到本地?

import FileSaver from 'file-saver'async exportExcel() {const result = await exportEmployeeExcel()// 认为,我而要的结果(result)就应该是一个 Blob 对象console.log(result)// 想法办讲 blob 对象以文件的形式下载到本地?FileSaver.saveAs(result, '人资员工信息表.xlsx')}

员工管理-员工导入-上传excel
form-data=> 内置对象=>可以new一个

const formData = new FormData()formData.append('file", file)

change事件要触发,input的value必须要改变需要对input文件域的值做一下清空操作文件域type="file"

e.target.value=’ ’this.$refs.属性名 和 this.$refs[属性名] 等价文件域样式很难改,一般隐藏掉

day9

员工头像
对大小进行校验

腾讯云

存储桶

配置跨域

存储桶

密钥

AKIDKYZP4bw99wWvfHk18E9sPiroYBh4FC9v

e4INI1X0MVP73ogP83mGZXMzOcx60iHx

使用步骤

执行命令npm i cos-js-sdk-v5 --save安装 SDK 依赖

引入import COS from 'cos-js-sdk-v5';

前端使用固定密钥计算签名,该格式适用于前端调试,若使用此格式,请避免泄露密钥

const cos = new COS({SecretId: 'SECRETID',SecretKey: 'SECRETKEY',});

上传对象

改参数

uploadImg({file }) {console.log(file)const cos = new COS({SecretId: 'AKIDKYZP4bw99wWvfHk18E9sPiroYBh4FC9v',SecretKey: 'e4INI1X0MVP73ogP83mGZXMzOcx60iHx'})cos.uploadFile({Bucket: 'hm-hr-0724-1319629237', /* 填写自己的 bucket,必须字段 */Region: 'ap-nanjing', /* 存储桶所在地域,必须字段 */Key: 'file.name', /* 存储在桶里的对象键(例如:1.jpg,a/b/test.txt,图片.jpg)支持中文,必须字段 */Body: file, // 上传文件对象SliceSize: 1024 * 1024 * 5, /* 触发分块上传的阈值,超过5MB使用分块上传,小于5MB使用简单上传。可自行设置,非必须 */onProgress: function(progressData) {console.log(JSON.stringify(progressData))}// 上传进度}, function(err, data) {if (err) {console.log('上传失败', err)} else {console.log(data)console.log('上传成功')this.$emit('input', 'https://' + data.Location)}})}

上传成功

回显成功

用完就删除桶, 避免产生流量费用

面试题提问补充

v-model
v-model="count"<=>:value="count" @input="count = $event"只要组件内部支持 :value 和 @input 事件,外部调用组件时就可以使用自定义组件也可以实现v-model指令,只要入参value,出参input就可以实现v-modelv-model默认实现方案是 :value和@input默认情况下,model 选项中的 prop 值为 value ,event 值为 input可以使用 model 修改 v-model 的实现方案

model:{prop:'value',event:'input'}

model:{prop:'value',event:'change'}

day10

权限

权限点的操作 访问权限:能否看到页面 => 路由按钮的操作权限:能否看见按钮或者能否点击 如何实现 按钮的操作权限 按钮的条件渲染(能否看见按钮)按钮的disabled(能否点击) 人太多,分配权限太麻烦 =>RBAC给角色分配权限 < 直接给员工分配权限(间接拥有权限)通过员工和角色的关系,一个员工不一定只有一个角色RBAC给用户分配角色,给角色分配权限 一级权限: 路由权限二级权限: 按钮权限

简历

要: 耐心毅力接受否定
简历
个人信息:姓名,性别,年龄,联系电话,学历,贴照片 重点体现优势,靠前写=> 学历:本科不是优势的不写或者模糊写技术栈的描述

熟练掌挥媒体查询技术,能够实现响应式网页布局,掌握rem、vw/vh移动适配方案

媒体查询

熟练掌握ES6新特性例:let , const.模板字符串、箭头函数、解构赋值,promise等;

熟练使用ajax和axios插件与后台进行数据交互;

熟练使用elemnt-ui、vant等UI组件库快速的进行页面开发

熟练使用Git进行版本控制,以及进行团队协作开发:

熟练使用调试工具,能够快速解决编码问题

了解webpack的基本配置和使用了解ECharts,能实现简单的数据可视化;

有良好的代码风格和编程习惯。

英文水平良好,可流畅阅读英文文档

具有基本的英文阅读能力,善于翻阅资料,查询相关文档解决问题

广度 深度

不要写精通

写一两个,不要太多了解 , 少写熟悉

先写熟练 , 再写了解

就职经历 倒序书写项目经历倒序书写项目组成 : PC端+移动端+小程序端+大屏数据可视化技术找组成: Vue2 + Vue3 + TS + Sass/Less + Axios + Element-UI (其他UI框架)技术栈和项目的加分项 : websocket + WebWoker + 设计模式 + 基于Vue的低代码开发 + GIS + 3D地图不要出现OA 人资 小兔鲜 学成在线 品优购 黑马面经 优医问诊之类的字眼

day11

复习

闭包

一般形式: 一个函数调完返回另一个函数,内部函数使用外部函数的变量,可以延长作用域链

高阶函数
当一个函数调用完返回另一个函数,那个函数就叫高阶函数作用:在 设计模式 可以做 包装器
ext.js

ext.js(又称为Sencha Ext JS)是一个JavaScript应用程序框架,用于构建跨平台的富客户端应用程序。

它提供了丰富的UI组件、数据管理和模块化开发工具,可以帮助开发者快速构建功能强大、交互性强的Web应用程序。

补充 : async => 并发请求 => 静态方法 => Promise.all

任何一个被async修饰的函数 , 都会变成异步函数 , 这个异步函数的返回值是一个promise

await+函数=>函数只能是异步的await只发生在当前调用内有效(只发生在局部)有 await 的地方,一定有 async ==> 近朱者赤一个函数的内部只要有异步调用,并且异步调用需要被 await 等待的话,这个函数就一定是异步函数,所以要加 async有 async 的地方,不一定有 await并发请求:同时向服务器发送请求 , 两条请求是并发的,请求总耗时是耗时长的那个请求(最大值)能不能并发由业务决定,业务上没有先后顺序的接口,可以并发调用 ==>为了节省时间获取请求是为了渲染页面 , 获取角色列表和获取用户拥有的角色在业务上没有先后关系 , 因为数据绑定的不同 , 所以可以并发请求实现并发的方式: 直接并列着写,不要 await就是并发用Promise.all Promise.all就是用来处理并发请求的(静态方法)静态方法:挂载在构造函数上的方法Array.isArray()Object.keys()Object.assign()Object.values()Object.defineProperty()Promise.all() Promise.all=> 静态方法 调用之后 , 返回值是Promise对象(不能直接forEach[数组可以直接forEach]).then之后的res才是数组入参 => Promise数组: 数组里面的每一项都是Promise对象 如何得到两个并发请求(如何写入参) 直接调这俩函数 => Promise对象Promise.all([this.getRoleList() , getUserInfo(id)]).then(res => {})

Promise.all的then方法中,拿到的结果 => 数组

权限

路由权限 => 根据用户权限添加动态路由
根据用户权限分离静态路由和动态路由

// 需要根据用户权限进行动态注册的路由表登录之后 , 进入首页之前细化 => 获取用户信息之后,跳转后台首页之前 => permission.js静态路由+动态路由将筛选出来的路由,动态注册。如何动态注册? router 可以动态注册新的路由,addRoutes([动态注册的路由列表])router.addRoutes(routes)menus字段中有角色对应的权限路由解决 侧边栏同步更新 将筛选出的动态路由,更新到 user 模块的 routes 中mit('user/setRoutes',routes )登出 清空注册的路由信息删除token 重置路由mit('setRoutes')调用已经写好的方法resetRouter()

按钮权限

实现按钮操作权限:条件渲染 / 自定义指令

按钮显示与否v-if="points.includes('addUser')自定义指令Vue.directive('自定义指令名,不带v-' , {自定义指令的配置项})

补充

set和map是ES6新语法(可以去重)
Set
Set 一种数据结构,存放不重复的数的集合

-const set = new Set()使用字面量创建的引用数据类型,引用地址是不一样的例1

例2

const set = new Set([1,1,2]) // 1,2set.add(1) // 1,2set.add('hello')set.add([1,2])set.add([1,2])// [] === [] ==> false 使用字面量创建的引用数据类型,引用地址是不一样的const arr = [1, 2]const list = arrset.add(arr)set.add(arr)set.add(list)console.log(set) //6条数据

例3

是否含有(true / false)console.log(set.has({}))

读长度console.log(set.size ) //7

set.clear()清空

Map
Map 一种数据结构,存放键值对,类似于 object,但 Map 对键的类型没有要求const map = new Map()删除delete obj.name
现有一个 Person 构造函数,有四个实例对象

// 现有一个 Person 构造函数,有四个实例对象function Person(name) {this.name = name}const p1 = new Person('张三')const p2 = new Person('李四')const p3 = new Person('王五')const p4 = new Person('老六')map.set(p1,0)map.set(p2,0)map.set(p3,0)map.set(p4,0)map.set(p1, map.get(p1) + 1)// 现在观众对 p1 ~ p4 四位选手进行投票,投票分 A B C D 四类,如果选手投了 A ,则 张三 得一分// 以此类推,D 老六得一分// 已知现在已经回收观众投票,投票结果为:const res ='ABCDBCBSHCBSABCBSODHABDOAJDBSCDJABDCDBABDABCABDGSBCDHAHDWS'// 请对上述结果进行统计,超出 A B D 四类的票为无效投票,不计入// 请分别计算出 p1 ~ p4 四位选手的得票数

// 两数之和// 有一个数组,arr = [1,4,2,7,6,8,3,9]// 给一个target =6// 求数组中两数和等于 target 的元素的索引是多少// 输出:[1,2]// 假设 target = 10// 求满足条件的第一个组合的索引是多少? [1,4]

day12

增加初始字段

结论:遇到对对象进行连续访问的时候,就要考虑中间的某一次访问可能会得到undefined/null

那么这个时候继续访问的话,就会报错:

怎么解决:可以使用可选链操作符

在模板数据中,可以使用初始字段vue中引入echarts

1.在template中找到绘制图表的位置加上div标签

2.给div加入ref属性

3.什么时候渲染?渲染要等到获取数据之后

4.根据需求去修改图表样式当屏幕进行缩放的时候,echarts图表怎么自适应?chart.resize()

窗口大小发生变化的时候,就调用chart.resize()方法

在mounted/created中监听窗口大小的改变使用window.addEventLinstener('resize',()=>{调chart.resize()方法})

总结:em是相对于自身字号的一个相对单位,自身字号如果不设置的话就去继承父元素的字号,就会变成相对于父元素的相对单位,如果自身设置了字号,就是相对于自己的相对单位盒模型:标准盒模型的宽度是内容的宽度,width属性只表示设置内容宽怪异盒模型的宽度是内容+内边距+边框的宽度,width属性表示设置总宽如何在打包项目的时候排除一些文件?

1.在vue.config.js中的configureWebpack下配置externals来设置外部依赖以达到排除打包的目的

externals:{//项目中的包名(在package.json中找):外部包的包名(可以在百度上问CDN引入的element-ui叫什么 )//排除打包以后其实就是用外部的包名替换内部的包名'element-ui':'ELEMENT'}

排除打包总结:减少项目体积,目的:为了让用户打开页面的速度更快,怎么实现:在vue.config.js的webpack的配置项中设置externals,最后在public文件下的index.html中引入样式文件和js文件

部署上线

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。