├── src # 源代码目录
│ ├── api # 所有请求
│ ├── assets # 主题 字体等静态资源
│ ├── components # 全局公用组件
│ ├── icons # 项目所有 svg icons
│ ├── layout # 全局 layout
│ ├── router # 路由
│ ├── store # 全局 store管理
│ ├── styles # 全局样式
│ ├── utils # 全局公用方法
│ ├── views # views 所有页面
│ ├── App.vue # 入口页面
│ ├── main.js # 入口文件 加载组件 初始化等
│ └── permission.js # 权限管理
│ └── settings.js # 配置文件
npm i
npm run dev
重启项目 npm run serve 无报错
<svg-icon icon-class="password" />
<svg-icon icon-class="bug" />
<svg-icon icon-class="chart" />
<svg-icon icon-class="404" />
//settings.js
module.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
}
预检请求(Preflight Request)是在进行跨域资源共享(Cross-Origin Resource Sharing,CORS)时,浏览器发送的一种额外的HTTP OPTIONS请求。它用于向服务器请求权限信息,以确定实际请求是否安全。
option预检:是否能发出请求(浏览器主动发起预检请求,跟后端没有关系)
get,post是简单请求不需要预检(复杂请求才会预检),发预检请求的都是options
预检是有时间效的,这一次预检在多久时间内的会有效,浏览器会根据失效时间来判断这次还需不需要预检
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方法、自定义请求头和凭据进行跨域请求。浏览器在收到这些响应头后,会判断是否符合跨域规则,并决定是否允许实际请求的发送。这种方式通过限制允许跨域请求的源站、方法和请求头的方式,确保跨域请求的安全性。
服务器和服务器之间不会受跨域影响。
//utils/request.js
// 响应拦截器
// 在人资项目中,错误的统一处理,就是给用户提示错误信息
service.interceptors.response.use((response) => {
// 请求成功的回调:http的状态码就位2XX
const { 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.message
this.$Message({ type: 'error', message: error.message })
return Promise.reject(error)
})
获取资料action的调用位置
有token的位置再获取资料
<el-dropdown-item divided @click.native="logout">
<span style="display:block;">登 出</span>
</el-dropdown-item>
失效的token调接口=>401
在页面初始化的过程中,通常会有一个生命周期钩子函数或方法,比如created被调用的时刻就是在组件实例被创建后,但是在DOM渲染之前。
如果在created钩子函数中没有进行相关数据的初始化或数据绑定操作,那么在此之前页面是没有内容显示的,因为此时页面的渲染还没有开始
VUE_APP_BASE_API = '/dev-api'
VUE_APP_VERSION = '1.0.3'
VUE_APP_MOBILE= '13800000002'
VUE_APP_PASSWORD = 'hm#qd@23!'
不能直接在子组件中修改父组件中的值
.sync支持子组件修改父组件的值
.sync语法糖原理
//父组件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把控
//完整写法
//修改密码的弹框
<ChangePassword :show-dialog="showPassDialog" @update:showDialog="showPassDialog = $event " />
// .sync简化写法
//修改密码的弹框
<ChangePassword :show-dialog.sync="showPassDialog" />
<ChangePassword ref="passDialog" />
openPassDialog() {
// 能够打开修改密码的弹框即可
// 只要能调到 open(),弹框就可以打开
// 如何调用到 子组件 的方法??
// $refs + ref
this.$refs.passDialog.open()
}
动态规划
贪心算法
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,
]
<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=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 1
if(N === 2) return 2
return fibo(N-1)+fibo(N-2)
}
console.log(fibo(5))//8种
console.log(fibo(10))//89种
如果操作数是一个真值(例如非零数、非空字符串、非空对象),“!!” 运算符将返回 true。
如果操作数是一个假值(例如零、空字符串、null、undefined 或者 false),“!!” 运算符将返回 false。
var value1 = 0;
var value2 = "Hello";
var value3 = null;
console.log(!!value1); // false
console.log(!!value2); // true
console.log(!!value3); // false
双重否定运算符 “!!” 并不改变操作数本身的值,它只是返回一个相应的布尔值。
如果想得到某个内置包装类型的值, 使用实例对象的一个方法 .valueOf()=>取值
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方法
Number instanceof Function //true
Number.tostring === Function.prototype.tostring//true
Number.prototype.tostring === (123).tostring//true
Number.toString === Function.prototype.toString//true
Number.tostring === string.tostring//true
函数式编程:把函数作为入参或者出参来
git stash 暂存
git stash pop把暂存文件拿回来
代码: 表单规则已定义,表单数据和规则已绑定,但是表单校验不起作用;
原因:绑定的属性 :model 拼错了,写成了 :mode
结论:下次表单校验不生效要首先查三个属性有没有写对,:model :rules prop
// 高阶函数(2阶)
function createValidator(key) {
//闭包
const fun = async(rule, value, callback) => {
const list = await getDepartmentList()
const fn = this.isEdit ? item => item.id !== this.formData.id : () => true
const 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 5
zhiyinzi(num / i)
return
}
}
}
zhiyinzi(180)
console.log(arr) //{2,2,3,3,5}
row.editRow = { ...row }
是将名为 row 的对象进行浅拷贝,并将拷贝后的对象赋值给 row.editRow。进制
每个数字所占的位,表示的是有几个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) // 64
console.log(32 << 2) // 128
console.log(128 << 1) // 256
console.log(32 >>1) //16
console.log(32 >> 2) // 8
console.log(32 >> 3) // 4
console.log(32 >> 32) // 0
110000 => 48
组件复用要考虑场景兼容,使用v-if条件判断
<el-tree
ref="deptTree"
node-key="id"
:data="depts"
:props="defaultProps"
default-expand-all
:expand-on-click-node="false"
highlight-current
@current-change="selectNode"
/>
"queryParamskeyword " : function(){this.onKeywordChange}
有一个数 num = 19,num 的有效字节为 2 个,分别为 3 和 232
1000 => 900311 1111969
解释:1000 的8个字节中,只有低位的2个字节有值,这两个字节分别为 3 和 232求 12,234 表示的数是多少?
12 => 00001109
234 ==> 11101010
parseInt(110011101010,2)//3306
//求 12,234 表示的数是多少?
//十进制转位二进制
(1000).toString(2)//'1111101000'
(12).toString(2)//'1100'
(234).toString(2)//'11101010'
//将12和234的二进制数(补齐8位)拼接起来=>转为十进制
parseInt('0000110011101010',2)//3306
12<<8|234 //3306
//求 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<<16|9<<8|201//7932361
任何数和255与完都是那个数
1000 & 0xff =>1000
1000 & 255 =>1000
任何数与0都是0
1000&255 //232
1000>>8 &255 //3
3. 可以将2进制文件转为blob对象,比较好处理(2进制文件流很难处理)
4. 怎样转
// 导出Excel
export function exportEmployeeExcel() {
// 通过配置项: 告诉axios将下面的请求返回数组,处理成blob类型
// 处理成blob的目的- 方便后续通过js代码处理文件
// 当前场景,是服务器会返回二进制文件流 ==> 遇到二进制文件流可以使用 blob 格式来处理
// 其他场景:返回图片,返回文件 ===> blob
request.request.get('/sys/user/export', { responseType: 'blob' })
}
blob下载思路:
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 = url
a.download = '人资员工信息表(使用a标签下载方法).xlsx'
a.click()
// 释放这个临时的对象url
window.URL.revokeObjectURL(url)
})
}
// 导出Excel
export function exportEmployeeExcel() {
// 通过配置项: 告诉axios将下面的请求返回数组,处理成blob类型
// 处理成blob的目的- 方便后续通过js代码处理文件
// 当前场景,是服务器会返回二进制文件流 ==> 遇到二进制文件流可以使用 blob 格式来处理
// 其他场景:返回图片,返回文件 ===> blob
return 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 = url
a.download = filename
a.click()
// 释放这个临时的对象url
window.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')
})
}
// 导出Excel
export function exportEmployeeExcel() {
// 通过配置项: 告诉axios将下面的请求返回数组,处理成blob类型
// 处理成blob的目的- 方便后续通过js代码处理文件
// 当前场景,是服务器会返回二进制文件流 ==> 遇到二进制文件流可以使用 blob 格式来处理
// 其他场景:返回图片,返回文件 ===> blob
return 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')
}
form-data
=> 内置对象=>可以new一个const formData = new FormData()
formData.append('file", file)
文件域type="file"
this.$refs.属性名 和 this.$refs[属性名] 等价
执行命令 npm i cos-js-sdk-v5 --save
安装 SDK 依赖
前端使用固定密钥计算签名,该格式适用于前端调试,若使用此格式,请避免泄露密钥
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-20230724-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"
v-model
指令,只要入参value,出参input就可以实现v-modelmodel:{
prop:'value',
event:'input'
}
model:{
prop:'value',
event:'change'
}
熟练掌挥媒体查询技术,能够实现响应式网页布局,掌握rem、vw/vh移动适配方案
媒体查询
熟练掌握ES6新特性例:let , const.模板字符串、箭头函数、解构赋值,promise等;
熟练使用ajax和axios插件与后台进行数据交互;
熟练使用elemnt-ui、vant等UI组件库快速的进行页面开发
熟练使用Git进行版本控制,以及进行团队协作开发:
熟练使用调试工具,能够快速解决编码问题
了解webpack的基本配置和使用了解ECharts,能实现简单的数据可视化;
有良好的代码风格和编程习惯。
英文水平良好,可流畅阅读英文文档
具有基本的英文阅读能力,善于翻阅资料,查询相关文档解决问题
广度 深度
不要写精通
写一两个,不要太多了解 , 少写熟悉
先写熟练 , 再写了解
一般形式: 一个函数调完返回另一个函数,内部函数使用外部函数的变量,可以延长作用域链
ext.js(又称为Sencha Ext JS)是一个JavaScript应用程序框架,用于构建跨平台的富客户端应用程序。
它提供了丰富的UI组件、数据管理和模块化开发工具,可以帮助开发者快速构建功能强大、交互性强的Web应用程序。
任何一个被async修饰的函数 , 都会变成异步函数 , 这个异步函数的返回值是一个promise
router.addRoutes(routes)
store.commit('user/setRoutes',routes )
context.commit('setRoutes')
resetRouter()
实现按钮操作权限:条件渲染 / 自定义指令
const set = new Set()
const set = new Set([1,1,2]) // 1,2
set.add(1) // 1,2
set.add('hello')
set.add([1,2])
set.add([1,2])
// [] === [] ==> false 使用字面量创建的引用数据类型,引用地址是不一样的
const arr = [1, 2]
const list = arr
set.add(arr)
set.add(arr)
set.add(list)
console.log(set) //6条数据
是否含有(true / false) console.log(set.has({}))
读长度console.log(set.size ) //7
set.clear()
清空
const map = new Map()
delete obj.name
// 现有一个 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]
chart.resize()
chart.resize()
方法window.addEventLinstener('resize',()=>{调chart.resize()方法})
externals:{
//项目中的包名(在package.json中找):外部包的包名(可以在百度上问CDN引入的element-ui叫什么 )
//排除打包以后其实就是用外部的包名替换内部的包名
'element-ui':'ELEMENT'
}
排除打包总结:减少项目体积,目的:为了让用户打开页面的速度更快,怎么实现:在vue.config.js的webpack的配置项中设置externals,最后在public文件下的index.html中引入样式文件和js文件
部署上线