自我介绍
自我介绍
- 项目经验
- 技术面试
- 综合能力(怎么学习前端知识、遇到不会的问题如何处理、对未来职业有什么规划)
- 目前是否离职,上一家离职原因
java后端
Java、MyBatis、ZooKeeper、Dubbo、Elasticsearch、Memcached、Redis、MySQL、Spring、Spring Boot、Spring Cloud、RabbitMQ、Kafka、Linux
java8
Java后端学习路线的建议:
基础知识:
- 学习Java语言基础,包括语法、数据类型、面向对象编程等。
- 掌握Java集合框架,如List、Set、Map等。
- 学习异常处理机制和文件IO操作。
数据库:
- 学习SQL语言,了解数据库的基本概念和操作。
- 掌握MySQL或其他关系型数据库的使用,包括表的创建、查询、更新和删除等操作。
- 学习JDBC(Java Database Connectivity)来连接和操作数据库。
Web开发:
- 学习HTML、CSS和JavaScript,掌握前端页面的基本布局和交互。
- 学习Servlet和JSP,了解Web应用的基本原理和开发流程。
- 掌握Spring框架,包括IoC(控制反转)、AOP(面向切面编程)和MVC(模型-视图-控制器)等核心概念。
- 学习Spring Boot,快速搭建和开发基于Spring的应用程序。
分布式系统:
- 学习分布式系统的基本原理和概念,如负载均衡、缓存、消息队列等。
- 掌握Spring Cloud,用于构建微服务架构的分布式系统。
- 学习Docker容器化技术,用于部署和管理应用程序。
性能优化:
- 学习JVM(Java虚拟机)的基本原理和调优方法,如内存管理、垃圾回收等。
- 掌握常见的性能优化技巧,如代码优化、数据库优化、缓存优化等。
- 学习使用工具进行性能分析和调优,如JProfiler、VisualVM等。
安全:
- 学习常见的安全漏洞和攻击方式,如SQL注入、跨站脚本攻击等。
- 掌握常见的安全防御措施,如输入验证、加密、权限控制等。
- 学习使用安全框架和工具,如Spring Security、OAuth2等。
持续集成和部署:
- 学习使用版本控制系统,如Git,进行代码管理和团队协作。
- 掌握持续集成工具,如Jenkins,实现自动化构建和测试。
- 学习使用容器编排工具,如Kubernetes,进行应用程序的部署和管理。
java
nginx代理模式,如何限制IP访问? 通过nginx日志找到访问量最高的ip 怎么查看80端口是否占用? 两台服务器之间怎么传文件? Linux如何设置开机自启?systemctl
说下常用的docker命令,怎么提高docker的性能 说下实际项目中解决的docker或者k8s的坑
怎么挂载硬盘? 简述DNS进行域名解析的过程
MySQL如何解决死锁问题,如何查看慢sql mysql数据备份 Tomcat、nginx日志每天增长,导致硬盘空间报警,怎么解决和防止后续还报警
实际项目中可能需要你去给用户培训,是否有做过? 需要你联系用户了解问题,如何面对态度较差的用户?沟通了解问题?
运维工作都是晚上,是否能加班?
找甲方申请资源或者协调事情,甲方不愿意配合怎么办?
在职还是离职,多久可以入职?
期望薪资?
注解
冒泡排序
2层循环,每次循环和下个数据对比,如果大于则完成交互
public static void bubbleSort(int[] arr) {
int n = arr.length;
for (int i = 0; i < n; i++) {
// 每轮遍历将最大的数移到末尾
for (int j = 0; j < n - i - 1; j++) {
if (arr[j] > arr[j+1]) {
int temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
}
}
}
}
分组
- 通过java8 实现,
Map<Long, List<TreeVO>> parentMap = treeVOS.stream()
.collect(Collectors.groupingBy(TreeVO::getPid));
- 通过map实现
List<WlWorkPlanQty> wlWorkPlanQties = wlWorkPlanQtyService.selectWlWorkPlanQtyList(wlWorkPlanQty);
Map<Long,List<WlWorkPlanQty>> groupMap = Maps.newHashMap();
for (WlWorkPlanQty workPlanQty : wlWorkPlanQties) {
if(!groupMap.containsKey(workPlanQty.getPlanId())){
groupMap.put(workPlanQty.getPlanId(),new ArrayList<WlWorkPlanQty>());
}
groupMap.get(workPlanQty.getPlanId()).add(workPlanQty);
}
登录考虑
负载均衡,主备服务等等,所以在登录这块如何考虑
使用tocken,缓存在如redis中
java8新特性
待整理
数据角色设计
java导入导出
poi
导入校验怎么考虑的,数据的长度校验,小数位数限定
数据量大的情况如果处理
运行jar 包项目
项目打包jar
## cmd 到目录下
java -jar test2-0.0.1-SNAPSHOT.jar
java -jar test2-0.0.1-SNAPSHOT.jar --server.port=8082

Redis
缓存,你们用作那些场景
Redis能干嘛
内存存储和持久化 (运行在内存中但是可以持久化到磁盘) :redis支持异步将内存中的数据写到硬盘上
发布、订阅消息系统
地图信息分析
定时器、计数器
特性
- 多样的数据类型
- 持久化
- 集群
- 事务
redis的应用场景
- redis由于数据的读取和操作都在内存当中操作,读写的效率较高,所以经常被用来做数据的缓存。把一些需要频繁访问的数据,而且在短时间之内不会发生变化的,放入redis中进行操作。从而提高用户的请求速度和降低网站的负载,降低数据库的读写次数,就把这些数据放到缓存中。
- 一些常用的实时计算的功能。需要实时变化和展示的功能,就可以把相关数据放在redis中进行操作。大大提高效率。
- 消息队列,经常用来构建类似实时聊天系统的功能,大大提高应用的可用性。
Redis的持久化
持久化的2种方式,RDB和AOF
Redis主从复制
- 主从复制,是指将一台Redis服务器的数据,复制到其他的Redis服务器。前者称为主节点(Master/Leader),后者称为从节点(Slave/Follower), 数据的复制是单向的!只能由主节点复制到从节点(主节点以写为主、从节点以读为主)。
- 默认情况下,每台Redis服务器都是主节点,一个主节点可以有0个或者多个从节点,但每个从节点只能由一个主节点。
nginx
1.2 nginx可以提供的服务
- web 服务.
- 负载均衡 (反向代理)
- web cache(web 缓存)
1.3 nginx 的优点
- 高并发。静态小文件
- 占用资源少。2万并发、10个线程,内存消耗几百M。
- 功能种类比较多。web,cache,proxy。每一个功能都不是特别强。
- 支持epoll模型,使得nginx可以支持高并发。
- nginx 配合动态服务和Apache有区别。(FASTCGI 接口)
- 利用nginx可以对IP限速,可以限制连接数。
- 配置简单,更灵活。
1.4 nginx应用场合
- 静态服务器(图片,视频服务),另个lighttpd。并发几万,html,js,css,flv,jpg,gif等。
- 动态服务,nginx—fastcgi 方式运行PHP,jsp。(PHP并发约500-1500,MySQL 并发约300-1500)。
- 反向代理,负载均衡。日pv2000W以下,都可直接用nginx做代理。
- 缓存服务。类似 SQUID,VARNISH。
Nginx指定文件路径有两种方式root和alias =============
alias: [ˈeɪliəs]
- root
- alias /ˈeɪliəs/
这两者的用法区别在于对URI的处理方法不同。
location /folder/ {
root D:/workspace;
}
location /folder/ {
alias D:/workspace;
}
(1)alias是一个目录别名的定义,root则是最上层目录的定义。
例如:上文,使用root 访问geojson_data 则 其会到 D:/workspace/geojson_data/ 目录下去找
使用alias:则会到 D:/workspace 目录下查找
(2)还有一个重要的区别是alias后面必须要用“/”结束,否则会找不到文件的。而root则可有可无。
访问静态资源
D:\home\yjwyy\file\uploadPath\geojson_data\ 文件位置
server {
listen 1889;
server_name 192.168.4.24;
location / {
root html;
index index.html index.htm;
}
location /geojson_data/ {
#root D:/home/yjwyy/file/uploadPath/;
alias D:\home\yjwyy\file\uploadPath/geojson_data/;
}
}
反向代理
反向代理(Reverse Proxy)是指服务器接受客户端的请求,并将这些请求转发到内部网络上的其他服务器。客户端只能看到反向代理服务器,而不知道真正提供服务的服务器。这种方式隐藏了实际服务器的细节,提供了更高的安全性和负载均衡。
在 Nginx 中配置反向代理非常简单。以下是一个简单的 Nginx 反向代理的示例:
复制代码server {
listen 80;
server_name example.com;
location / {
proxy_pass http://backend_server;
}
}
在上面的示例中,Nginx 监听80端口,并将接收到的请求代理到名为 backend_server 的后端服务器。你需要将 backend_server 替换为实际提供服务的服务器的 IP 地址或域名。
此外,你还可以根据需要进行更多的配置,如设置代理请求的超时时间、添加请求头等。以下是一个带有进一步配置的示例:
复制代码server {
listen 80;
server_name example.com;
location / {
proxy_pass http://backend_server;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $host;
proxy_connect_timeout 30s;
proxy_read_timeout 60s;
}
}
在上面的示例中,我们设置了 X-Real-IP 和 Host 请求头,设置了连接超时时间为30秒,读取超时时间为60秒

MyBatis
MyBatis 的好处是什么?
1)MyBatis 把 sql 语句从 Java 源程序中独立出来,放在单独的 XML 文件中编写,给程序的 维护带来了很大便利。
2)MyBatis 封装了底层 JDBC API 的调用细节,并能自动将结果集转换成 Java Bean 对象, 大大简化了 Java 数据库编程的重复工作。
3)因为 MyBatis 需要程序员自己去编写 sql 语句,程序员可以结合数据库自身的特点灵活 控制 sql 语句,因此能够实现比 Hibernate 等全自动 orm 框架更高的查询效率,能够完成复 杂查询。
#{}和${}的区别
1)#{}是预编译处理,${}是字符串替换。
2)Mybatis 在处理#{}时,会将 sql 中的#{}替换为?号,调用 PreparedStatement 的 set 方法 来赋值;
3)Mybatis 在处理${}时,就是把${}替换成变量的值。
4)使用#{}可以有效的防止 SQL 注入,提高系统安全性。
如何获取⽣成的主键?
新增标签中添加:keyProperty=" ID " 即可
<insert id="insert" useGeneratedKeys="true" keyProperty="userId" >
insert into user(
user_name, user_password, create_time)
values(#{userName}, #{userPassword} , #{createTime, jdbcType= TIMESTAMP})
</insert>
批量操作
数据库连接属性allowMutiQueries=true
MyBatis 的缓存
MyBatis 的缓存分为一级缓存和二级缓存,一级缓存放在 session 里面,默认就有,二级缓 存放在它的命名空间里,默认是不打开的,使用二级缓存属性类需要实现 Serializable 序列化 接口(可用来保存对象的状态),可在它的映射文件中配置
Mybatis 是如何进行分页的、分页插件的原理是什么?
1)Mybatis 使用 RowBounds 对象进行分页,也可以直接编写 sql 实现分页,也可以使用 Mybatis 的分页插件。
2)分页插件的原理:实现 Mybatis 提供的接口,实现自定义插件,在插件的拦截方法内拦 截待执行的 sql,然后重写 sql。
举例:select * from student,拦截 sql 后重写为:select t.* from (select * from student)t limit 0,10
数据库
1. 行转列
wm_concat 实现行转列(存在限定,拼接超过4000后异常)
mysql 等价的是
GROUP_CONCAT函数
select t.office_id,
wm_concat(t.area_id) areaIds, --replace(wm_concat(area_id),',','|') 通过 replace替换成需要的连接字符串
wm_concat(to_char(a.name)) as areaNames-- 对于中文可能会出现 转义
from ZHCG_OFFICE_MANAGE_AREA t, sys_area a
where t.del_flag = '0'
and a.del_flag = '0'
and t.area_id = a.id
group by office_id
2. 列转行
日期行转列
SELECT TO_DATE('2021-05-01', 'YYYY-MM-DD') + ROWNUM - 1 DT FROM DUAL
CONNECT BY LEVEL <= (TO_DATE('2021-05-31', 'YYYY-MM-DD') - TO_DATE('2021-05-01', 'YYYY-MM-DD') + 1)
指定字符串 分割,转行
SELECT REGEXP_SUBSTR('1,2,3', '[^,]+', 1, LEVEL) NAME
FROM dual
CONNECT BY LEVEL <= REGEXP_COUNT('1,2,3', '[^,]+')
resultMap 构造一对多关系
column="engineerId"指定了用于关联的列名 ,实现树机构数据的构造
<resultMap type="cn.semdo.modules.projjl.entity.ProjJlEngineer" id="projJlEngineerMap">
<id column="ID" property="id"/>
<id column="engineerName" property="engineerName"/>
<collection property="projJlPositionList" ofType="cn.semdo.modules.projjl.entity.ProjJlPosition" column="engineerId">
<id column="positionId" property="id"/>
<id column="engineerId" property="engineerId"/>
<id column="positionName" property="name"/>
</collection>
</resultMap>
<select id="projJlEngineerList" resultMap="projJlEngineerMap">
SELECT
a.id,
a.engineer_Name as engineerName,
p.id AS "positionId",
p.engineer_id AS "engineerId",
p.name AS "positionName"
FROM proj_jl_engineer a
left join PROJ_JL_POSITION p on p.engineer_id = a.id
</select>
myBatis 使用collection
批量新增,和批量修改
< foreach collection="lineIds.split(',')" item="lineId" index="index" separator=", ">
oracle 递归

select
connect_by_root t.name as func_name_4_root ,t.type
,lpad(' - - - - - - -', (level - 1) * 10, ' ') || t.name as "name" --节点名称(带缩进)
, SYS_CONNECT_BY_PATH(name, '/') as pName
from sys_office t
start with id='xjbwgzb' --递归的写法,从指定节点,查询其下面的所有数据 (不可为空,否则查出的数据,会重复)
connect by t.parent_id=prior t.id;
说明:
- CONNECT_BY_ROOT 返回当前节点的最顶端节点 ---->connect_by_root t.name 返回的就是根节点的名称
- CONNECT_BY_ISLEAF 判断是否为叶子节点,如果这个节点下面有子节点,则不为叶子节点
- LEVEL 伪列表示节点深度 ------> 可以作为节点的层级
- SYS_CONNECT_BY_PATH函数显示详细路径,并用“/”分隔----> 拼接节点,可以找到所以父节点
存储过程
DBLINK
需要保证 两个数据库之间网络是相通的,而不是 执行plsql 的本地的电脑和 目标数据库之间想通
自定义函数
--第一种不带参数:
create or replace function get_user
return varchar2 is Result varchar2(50); --定义变量(返回值)
begin
select username into Result from user_users; --into 赋值,不要忘了加分号结尾
return(Result); --返回值
end get_user;
--第二种带参:
create or replace function get_sal(empname in varchar2)
return numbe is Result number;
begin
select sal into Result from emp where ename=empname;
return(Result);
end;
开窗函数,排序取最新
取分组取第一条记录(关键字:取最新,取第一条数据,取最后一条)
**切记用 row_number 而不是 DENSE_RANK **注:**切记 使用时不能left join 关联其他表
-- 最优方法:
select *
from (select USERID,
JD_GPS,
WD_GPS,
dwsj,
row_number() over(partition by USERID order by dwsj desc) mm
from ydxj_dw_dwjl_2016)
where mm = 1 // 要排过序后 才能 取第一条,不能直接就用rownum = 1 这样取出的数据,和没排序的一样
-- 方法2
select a.*
from ydxj_dw_dwjl_2016 a
where not exists (select 1
from ydxj_dw_dwjl_2016 b
where b.userid = a.userid
and b.dwsj > a.dwsj)
方法3 用于 ,mysql没有 row_number函数时
select t.*
from ydxj_dw_dwjl_2016 t
where dwsj = (
select max(t1.dwsj) from proj_base_trajectory t1 where t1.USERID = t.USERID
)
ajax
@RequestParam
@RequestBody
https://zhuanlan.zhihu.com/p/422730888
基础知识
1.前端化页面还是写交互
可视化大屏项目是否做过,地图
设计稿出来后,如何考虑布局,比如2个卡片的间距 (盒子模型)
每行3个卡片多行(每行两端没有空隙)
2.能简单介绍一下之前作过的项目
着重讲一下作过的vue项目
3.目前三大主流前端框架
- vue
- React
- Angular
4.适配
可有设计稿,怎么计算 尺寸的,如何划分的
- flexible.js + rem
- less + 媒体查询 + rem
lib-flexible 默认把屏幕划分为10份
媒体查询 @media (min-device-width: 1920px){ }
插件: px 转换rem 需要设置根字体大小,才能正常使用
VSCode: cssrem (cssrem中css自动转化为rem是参照默认插件的16转换的)
idea: px2rem
5.es6新特性
- 能够说出使用let关键字声明变量的特点
- 能够使用解构赋值从数组中提取值
- 能够说出箭头函数拥有的特性
- 能够使用剩余参数接收剩余的函数参数
- 能够使用拓展运算符拆分数组
- 能够说出模板字符串拥有的特性
5.1 Set 和 Map 区别
Set对象是值的集合,你可以按照插入的顺序迭代它的元素。Set 中的元素只会出现一次,即 Set 中的元素是唯一的。
Set的值是唯一的可以做数组去重,Map由于没有格式限制,可以做数据存储
5.2 模板字符串
document.write(`<font color="red">${name}</font>的主要技能是${skill}<br>`);
5.3 == 和 ===区别
相等操作符()会做类型转换,再进行值的比较,全等运算符(=)不会做类型转换
5.4 声明变量的关键字 let、const、var 的区别
- 使用 var 声明的变量,其作用域为该语句所在的函数内,且存在变量提升现象
- 使用 let 声明的变量,其作用域为该语句所在的代码块内,不存在变量提升
- 使用 const 声明的是常量,在后面出现的代码中不能再修改该常量的值
5.5 解构赋值
数组解构
let [a, b, c] = [1, 2, 3];
console.log(a)//1
console.log(b)//2
console.log(c)//3
//如果解构不成功,变量的值为undefined
对象解构
注意:
let {name: myName} = person;name 是 实际的对象的属性, myName 属于别名
5.6 扩展运算符
可以解决 对象赋值,修改新对象导致老对象变更
拓展: 浅拷贝 深拷贝
6.元素居中的几个方式
6.1 利用相对定位
parentElement{
position:relative;
}
childElement{
position: absolute;
top: 50%;
transform: translateY(-50%);
}
6.2 flex
display: flex;
align-items: center;
justify-content: center;/*子元素水平居中*/
6.3 通过line-height
height,line-height
6.4 margin:auto
6.5 不设置高度,通过padding 将内容撑起来
6.6 text-align: center;
7. 阴影 box-shadow---- 卡片添加立体效果
box-shadow: h-shadow v-shadow blur spread color inset;
h-shadow 必需。水平阴影的位置。允许负值。
v-shadow 必需。垂直阴影的位置。允许负值。
blur 可选。模糊距离。
spread 可选。阴影的尺寸。
color 可选。阴影的颜色。请参阅 CSS 颜色值。
inset 可选。将外部阴影 (outset) 改为内部阴影。(控制是否为内阴影)
x轴,y轴,阴影模糊距离,阴影颜色。
其中x-offset为正值时,生成右边阴影,反之为负值,生成左边阴影;y-offset为正值时,生成底部阴影,反之生成顶部阴影;阴影模糊半径如果为0,则 生成实影效果。如果加上阴影模糊半径,阴影清晰度向外扩散,更具阴影效果
7.1 box-shadow: 0 0 10px #f00
因没有使其X轴与Y轴移动 设置值 所在会在本身发生作用 半径范围,颜色
7.2 box-shadow:4px 4px 10px #f00;
与测试1不同 X轴与Y轴改变了正值(正值 向右 向下) 所以变成了这样
7.3 box-shadow:-4px -4px 10px #f00;
与测试2不同 之处是 X轴与Y轴改变成了负值(负值 向左 向上) 所以变成了这样
7.4 指定4个边,从左顺时针
box-shadow:-10px 0px 10px red, 左边阴影 0px -10px 10px #000, 上边阴影 10px 0px 10px green, 右边阴影 0px 10px 10px blue;" 下边阴影
7.5 内阴影 box-shadow: 0px 0px 10px red inset;
与上面写法相同 唯一不同的是添加了一个inset 其它属性与外阴影相同
8.文字超长
- overflow:hidden; 2. 文本不进行换行 3. 规定当文本溢出包含元素时省略号
- 单行文本溢出
overflow: hidden; // 溢出隐藏
text-overflow: ellipsis; // 溢出用省略号显示
white-space: nowrap; // 规定段落中的文本不进行换行
- 多行文本溢出
overflow: hidden; // 溢出隐藏
text-overflow: ellipsis; // 溢出用省略号显示
display:-webkit-box; // 作为弹性伸缩盒子模型显示。
-webkit-box-orient:vertical; // 设置伸缩盒子的子元素排列方式:从上到下垂直排列
-webkit-line-clamp:3; // 显示的行数
注意:由于上面的三个属性都是 CSS3 的属性,没有浏览器可以兼容,所以要在前面加一个-webkit- 来兼容一部分浏览器。
9. 文字渐变色
background-image: -webkit-linear-gradient(top, #a80b02, #ff3b30); /*设置颜色与渐变方向*/
background-clip:text;
-webkit-background-clip: text; /*主要用于剪掉文字以外的区域。*/
-webkit-text-fill-color: transparent; /*设置文本的填充颜色。*/
font-family: Arial, Helvetica, sans-serif;
10. calc
11. vue在css样式种使用data中的变量
- vue2
<template>
<div class="box" :style="styleVar"> <!-- 说明:这里不能少 类似js的作用域 否则 下面的style 中无法使用 -->
<div class='son'> 下面就可以使用 </div>
</div>
</template>
<script>
export default {
props: {
height: {
type: Number,
default: 94,
},
whith: {
type: Number,
default: 200,
},
},
computed: {
styleVar() {
return {
'--box-width': this.whith + 'px',
'--box-height': this.height + 'px'
}
}
},
}
</script>
<style lang="scss" scoped>
.son {
height: var(--box-height); /* 这里调用 --box-height 要和上面 定义的变量 保存一致*/
width: var(--box-width);
background: red;
}
</style>
- vue3
9. 动画
变形& 延迟&css 动画
.xx{
transform: scale(1.1);
transition: all 0.6s;
}
.img_button:active{
animation-name: example;
animation-duration: 4s;
}
@keyframes example {
0% {opacity: 0;}
25% {opacity: 1;}
50% {opacity: 0.4;}
100% {opacity: 1;}
}
10.CSS模块化---Css的命名规范
Css的命名规范(BEM,OOCSS)
https://www.jianshu.com/p/900e26060c09
https://blog.csdn.net/weixin_34688110/article/details/112090373https://blog.csdn.net/weixin_41996102/article/details/121658875
css模块化的好处:
- 提高代码重用率
- 降低耦合
- 提高开发效率、减少沟通成本
- 易于维护
10.1 BEM 方式 Bem是块(block)、元素(element)、修饰符(modifier)
.site-search{} /* 块 */
.site-search__field{} /* 元素 */
.site-search--full{} /* 修饰符 */
Block:一个独立的,可以复用而不依赖其他组件的部分,可作为一个块
Element:属于块的某部分,可作为一个元素
Modifier:用于修饰块或元素,体现出外形行为状态等特征的,可作为一个修饰器
1)保证各个部分只有一级B__E–M,修饰器需要和对应的块或元素一起使用,避免单独使用。
2)仅以类名作为选择器,不使用ID或标签名来约束选择器,且css中的选择器嵌套不超过2层
3)避免 .block__el1__el2 的格式
10.2 OOCSS 表示的是面向对象 CSS
OOCSS 表示的是面向对象 CSS(Object Oriented CSS)
OOCSS最关键的一点就是:提高他的灵活性和可重用性。这个也是OOCSS最重要的一点。OOCSS主张是通过在基础组件中添加更多的类,从而扩展基础组件的CSS规则,从而使CSS有更好的扩展性。
- 减少CSS代码。
- 具有清洁的HTML标记,有语义的类名,逻辑性强的层次关系。
- 语义标记,有助于SEO。
- 更好的页面优化,更快的加载时间(因为有很多组件重用)。
- 可扩展的标记和CSS样式,有更多的组件可以放到库中,而不影响其他的组件。
- 能轻松构造新的页面布局,或制作新的页面风格。
11.页面布局
flex布局:--盒子模型 父项常见属性 flex-direction设置主轴的方向 justify-content flex-wrap 设置是否换行
12.rem、em、vh、px各自代表的含义?
px:绝对单位,页面按精确像素展示 em:相对单位,基准点为父节点字体的大小,如果自身定义了font-size按自身来计算,整个页面内1em不是一个固定的值 rem:相对单位,可理解为root em, 相对根节点html的字体大小来计算 vh、vw:主要用于页面视口大小布局,在页面布局上更加方便简单
13. 本地存储的方式有哪些?区别及应用场景?
javaScript本地缓存的方法我们主要讲述以下四种:
- cookie
- sessionStorage
- localStorage
- indexedDB
13.1 区别
关于cookie、sessionStorage、localStorage三者的区别主要如下:
- 存储大小:
cookie数据大小不能超过4k,sessionStorage和localStorage虽然也有存储大小的限制,但比cookie大得多,可以达到5M或更大 - 有效时间:
localStorage存储持久数据,浏览器关闭后数据不丢失除非主动删除数据;sessionStorage数据在当前浏览器窗口关闭后自动删除;cookie设置的cookie过期时间之前一直有效,即使窗口或浏览器关闭 - 数据与服务器之间的交互方式,
cookie的数据会自动的传递到服务器,服务器端也可以写cookie到客户端;sessionStorage和localStorage不会自动把数据发给服务器,仅在本地保存
13.2 应用场景
在了解了上述的前端的缓存方式后,我们可以看看针对不对场景的使用选择:
- 标记用户与跟踪用户行为的情况,推荐使用
cookie - 适合长期保存在本地的数据(令牌),推荐使用
localStorage - 敏感账号一次性登录,推荐使用
sessionStorage - 存储大量数据的情况、在线文档(富文本编辑器)保存编辑历史的情况,推荐使用
indexedDB
14. js分组
- 通过 Array.prototype.reduce() 进行分组
const groupedData = data.reduce((result, item) => {
if (!result[item.weekNum]) { // 针对数据会多次的情况
result[item.weekNum] = [];
}
result[item.weekNum].push(item);
return result;
}, {});
// 针对每组只会一个的情况
const groupedData = data.reduce((result, item) => {
result[item.weekNum] = item;
return result;
}, {});
- 普通
const groups = {}
arr.forEach(item=>{
const key = item.xx;
if (!groups[key]) {
groups[key] = []
}
groups[key].push(item);
})
15. calc属性
场景比如100% - 10px
calc()函数用于动态计算属性的值
16. 渐变色
https://blog.csdn.net/qq_18661257/article/details/50640633
linear-gradient
从上到下
从左到右
17 引入自定义字体
/*引入 自定义数字样式 字体*/
@font-face {
font-family: 'electronicFont';
src: url("../images_new/LESLIEB_.TTF");
}
/*自定义数字样式*/
.number_style {
font-family: 'electronicFont';
color: #018BFF;
}
18. 数组常用方法
数组在js中经常用于保存数据,是操作频率非常高的数据类型,js也提供了很多方法来对数组进行操作。下面介绍常用的方法。
join()、push()、pop()、shift() 、 unshift()、sort()、reverse()、concat()、slice()、splice()、indexOf()、 lastIndexOf()、forEach() 、map() 、filter() 、every() 、some()
19. 深拷贝&浅拷贝
vue 相关知识
页面缓存
列表 + 添加界面 交互,缓存列表页面,并且需要能手动刷新,如何实现
$bus
computed和watch的使用场景
计算属性和监听
computed: /kəmˈpjuːtɪd/
computed属性用于声明一个计算属性,它会根据依赖的数据动态地计算出一个新的值,并将结果缓存起来,只有当依赖的数据发生改变时,才会重新计算。computed属性适合用于需要基于其他数据进行复杂计算,并且希望缓存计算结果的情况。computed的特点是具备缓存性,只有在依赖的响应式数据发生改变时,才会重新计算,否则直接返回缓存结果。- 由于
computed属性是基于响应式数据的,所以它是具有响应性的,并可以像普通属性一样在模板中使用。
以下是一些适合使用 computed 属性的场景:
- 对数据进行过滤或排序。
- 根据多个数据计算出一个新的值。
- 对数据进行格式化或处理,例如日期格式化。
- 对列表进行计数、求和等操作。
watch:
watch属性用于观察(监视)一个数据的变化,在数据发生变化时执行相应的回调函数。它可以监听一个或多个数据,并对其进行处理。watch适合用于需要在数据变化时执行异步操作、复杂操作或对数据变化做出响应的场景。watch的特点是它允许执行异步操作,例如发起一个 API 请求,或者在数据变化后执行一些昂贵的计算操作。watch还可以深度监听对象或数组的变化。watch不具备缓存性,每当被监听的数据发生改变,回调函数都会被执行。
以下是一些适合使用 watch 属性的场景:
- 监听单个数据的变化并进行相应的处理,如发送网络请求或执行复杂的计算操作。
- 监听多个数据的变化,并根据变化执行一些相关的操作。
- 执行需要在数据变化后立即触发的操作。
created 和 mounted 的区别
在 Vue 组件的生命周期中,created 和 mounted 是两个不同的钩子函数,它们在组件的不同生命周期阶段被触发,并具有不同的用途和特点。
- created 钩子函数:
created是在组件实例被创建之后立即调用的钩子函数。- 在
created阶段,组件实例已经完成了数据观测(data observer)和事件初始化,但此时尚未将组件挂载到页面中。 - 可以在
created钩子函数中进行一些数据的初始化、异步请求、事件监听器的注册等操作。 - 此时组件内部的 DOM 元素和其它子组件都还没有被渲染到页面上,因此无法获取到对应的 DOM 元素和其它组件实例。
- mounted 钩子函数:
mounted是在组件被挂载到页面之后调用的钩子函数。- 在
mounted阶段,组件已经被添加到了页面中,此时可以访问到组件的 DOM 元素,并且可以与其它已挂载的组件进行交互。 mounted钩子函数常用于需要操作 DOM、执行异步请求、初始化第三方库等场景。- 通常情况下,如果需要在组件渲染完毕后进行一些操作,比如获取计算后的 DOM 元素尺寸、绑定事件监听器等,应该放在
mounted钩子函数中。
总结来说,created 钩子函数在组件实例被创建后立即调用,适合进行数据初始化和一些异步操作。而 mounted 钩子函数在组件挂载到页面后调用,适合进行与 DOM 相关的操作、第三方库的初始化等场景。
请注意,在 Vue 3.x 版本中,beforeMount 钩子函数替代了 Vue 2.x 版本中的 mounted 钩子函数。因此,如果你使用的是 Vue 3.x 版本,可以参考 beforeMount 钩子函数的使用方式。
自定义组件实现双向绑定
父组件数据会传递到子组件,子组件更改后传递给父组件,那这样就可能出现父组件的又回去修改子组件,思路:单向数据流规则
1.如何处理组件数据异步加载问题
比如Echarts 初始化时加载默认,数据获取后如何更新
1. axios [æk'siːəʊ]
传递数组,传递对象,请求头
2.组件化开发与模块化开发
组件式开发,组件的拆分 比如列表页面,细分的化,有头部、导航栏,列表,按钮
自定义组件 实现 v-module
less scss 优点
父子组件通信方式
整理vue中8种常规的通信方案
- 通过 props 传递
- 通过
$emit触发自定义事件 - 使用 ref
- EventBus
$parent或$root- attrs 与 listeners
- Provide 与 Inject
- Vuex
缓存+数据更新
列表页面一般都会加缓存,那如果跳转到详情界面操作保存,列表页面总不能手动刷新吧,所以对于这块你是怎么处理的,或者可有想法
页面缓存,如何手动更新
Vue的生命周期的详解 vue 在组件中具体的方法有:beforeCreate、created、 beforeMount、mounted、beforeUpdate、 updated、beforeDestroy、destroyed
修饰符 1.事件修饰符 vue中提供的事件修饰符一共有4种
.stop:用来阻止事件冒泡(防止事件向父标签传递)
.prevent:用来阻止标签的默认行为
.self:只监听自身标签触发的事件
.once:该事件只触发一次
2.按键修饰符 事件修饰符可以对所有事件进行修饰 按键修饰符用于对键盘事件进行修饰 键盘事件:比如keyup,keydown等等 vue中的键盘修饰符
.enter:对回车键修饰
.tab:对tab键修饰
.delete(捕获删除和退格键)
.esc:对esc修饰
.space:对空格修饰
.up:对 上
.down:对 下
.left:对 左
.right:对 右
1. 路由导航守卫 控制访问权限
如果知道,路由导航守卫 在需要确认 如何 保持登录 的
const router = new Router({
routes: [
{ path: '/', redirect: '/login' },
{ path: '/login', component: Login },
{ path: '/home', component: Home }
]
})
// 挂载路由导航守卫
router.beforeEach((to, from, next) => {
// to 将要访问的路径
// from 代表从哪个路径跳转而来
// next 是一个函数,表示放行
// next() 放行 next('/login') 强制跳转
if (to.path === '/login') {
return next();
}
// 获取token
const tokenStr = window.sessionStorage.getItem('token');
if (!tokenStr) {
return next('/login');
}
next();
})
export default router
2. 登录实现,如何保持登录
http 是无状态的 ,登录成功后需要记录登录状态
- 通过 cookie和session
- 通过 cookie 在客户端记录状态
- 通过 session 在服务器端记录状态
- 通过 token 方式维持状态
3. 通过axios请求拦截器添加token,
axios请求拦截器 保证拥有获取数据的权限
interceptors [ˌɪntəˈseptə(r)]
Authorization [ˌɔːθərəˈzeɪʃ(ə)n]
// axios请求拦截
axios.interceptors.request.use(config => {
// 为请求头对象,添加 Token 验证的 Authorization 字段
config.headers.Authorization = window.sessionStorage.getItem('token')
return config
})
//
axios.interceptors.response.use((config) => {
// done进度条结束
nProgress.done();
return config;
})
vuex
确认是否接触过 webpack
确认一下是否对项目优化过
对项目的打包发布过程做自定义的配置
加载外部 CDN 资源
14.生成打包报告
打包时,为了直观地发现项目中存在的问题,可以在打包时生成报告。生成报告的方式有两种:
① 通过命令行参数的形式生成报告
## 通过 vue-cli 的命令选项可以生成打包报告
## --report 选项可以生成 report.html 以帮助分析包内容
vue-cli-service build --report
② 通过可视化的UI面板直接查看报告(推荐) 在可视化的UI面板中,通过控制台和分析面板,可以方便地看到项目中所存在的问题。
通过 vue.config.js 修改 webpack 的默认配置
通过 vue-cli 3.0 工具生成的项目,默认隐藏了所有 webpack 的配置项,目的是为了屏蔽项目的配置过程,让程 序员把工作的重心,放到具体功能和业务逻辑的实现上。 如果程序员有修改 webpack 默认配置的需求,可以在项目根目录中,按需创建 vue.config.js 这个配置文件,从 而对项目的打包发布过程做自定义的配置(具体配置参考 https://cli.vuejs.org/zh/config/#vue-config-js)。
路由懒加载
对于SPA单页应用,当打包构建时,JavaScript包会变得非常大,影响页面加载速度,将不同路由对应的组件分割成不同的代码块,然后当路由被访问的时候才加载对应组件,这就是路由的懒加载。 具体需要 3 步:
① 安装 @babel/plugin-syntax-dynamic-import 包。
② 在 babel.config.js 配置文件中声明该插件。
③ 将路由改为按需加载的形式,示例代码如下:
const Foo = () => import(/* webpackChunkName: "group-foo" */ './Foo.vue')
const Bar = () => import(/* webpackChunkName: "group-foo" */ './Bar.vue')
const Baz = () => import(/* webpackChunkName: "group-boo" */ './Baz.vue')
注: 组件分组,例如上面 通过 webpackChunkName 指定分组名称,将 Foo 和Bar 分到 group-foo 组,在编译时, Foo 和Bar 生成一个js 文件,当访问其中一个时,才会加载该js 文件
关于路由懒加载的详细文档,可参考如下链接: https://router.vuejs.org/zh/guide/advanced/lazy-loading.html
通过 externals 加载外部 CDN 资源
解决单文件体积过大的问题,
默认情况下,通过 import 语法导入的第三方依赖包,最终会被打包合并到同一个文件中,从而导致打包成功 后,单文件体积过大的问题。 为了解决上述问题,可以通过 webpack 的 externals 节点,来配置并加载外部的 CDN 资源。凡是声明在 externals 中的第三方依赖包,都不会被打包。
国内常用静态资源 CDN 公共库加速服务
1.BootCDN BootCDN 是 Bootstrap 中文网和又拍云共同支持并维护的前端开源项目免费 CDN 服务,由又拍云提供全部 CDN 支持,致力于为 Bootstrap、jQuery、Angular 一样优秀的前端开源项目提供稳定、快速的免费 CDN 加速服务。BootCDN 所收录的开源项目主要同步于 cdnjs 仓库。 自2013年10月31日上线以来已经为上万家网站提供了稳定、可靠的免费 CDN 加速服务。
2.字节跳动静态资源公共库
字节跳动静态资源库支持多协议、资源动态拼接、快速检索及资源的动态更新,安全、稳定、实时。
3.又拍云常用JavaScript库CDN服务 又拍云为您托管常用的JavaScript库,您可以在自己的网页上直接通过script标记引用这些资源。这样做不仅可以为您节省流量,还能通过我们的CDN加速,获得更快的访问速度。
4.百度静态资源公共库 是稳定,快速,全面,开源的国内CDN加速服务。 由百度遍布全国各地100+个CDN节点提供加速服务。 让开源库享受与百度首页静态资源同等待遇。 全面,开源 收录超过180+开源库,并且这个数字正在不断增加。 百度静态资源公共库服务不仅在Github开源库上接受任何人的提交请求,同时实时同步国外如CDNJS上优秀的开源库。
5.新浪云计算公共Js库 新浪云计算是新浪研发中心下属的部门,主要负责新浪在云计算领域的战略规划,技术研发和平台运营工作。主要产品包括 应用云平台Sina App Engine(简称SAE)。 SAE的CDN节点覆盖全国各大城市的多路(电信、联通、移动、教育)骨干网络,使开发者能够方便的使用高质量的CDN服务。
6.Staticfile CDN 像 Google Ajax Library,Microsoft ASP.net CDN,SAE,Baidu,Upyun 等 CDN 上都免费提供的 JS 库的存储,但使用起来却都有些局限,因为他们只提供了部分 JS 库。当然,我们还可以有像 CDNJS 这样的平台,存储了大部分主流的 JS 库,甚至 CSS、image 和 swf,但国内的访问速度却不是很理想,并且缺少很多国内优秀开源库。 因此,我们提供这样一个仓库,让它尽可能全面收录优秀的开源库,并免费为之提供 CDN 加速服务,使之有更好的访问速度和稳定的环境。同时,我们也提供开源库源接入的入口,让所有人都可以提交开源库,包括 JS、CSS、image 和 swf 等静态文件。
7.360 前端静态资源库 60 前端静态资源库是由奇舞团支持并维护的开源项目免费 CDN 服务,支持 HTTPS 和 HTTP/2,囊括上千个前端资源库和 Google 字体库。 本站静态资源库数据均同步于 cdnjs,如发现版本更新不及时或未收录,欢迎向 cdnjs 提交 PR。
7.Microsoft ASP.net CDN
ASP.Net开发团队推出的一个新的微软Ajax CDN(Content Delivery Network,内容分发网络)服务,该服务提供了对AJAX库(包括jQuery 和 ASP.NET AJAX)的缓存支持。该服务是免费的,不需任何注册,可用于商业性或非商业性用途。
https://docs.microsoft.com/en-us/aspnet/ajax/cdn/overview
8.jsDelivr开源CDN A free super-fast CDN for developers and webmasters jsDelivr开源CDN(内容分发网络)是一个公开的,任何人都可以提交。 通过使用GitHub,允许社区完全与jsDelivr通过添加和更新文件。
如何发布的,通过 node 还是 nginx
通过 node 创建 web 服务器
创建 node 项目,并安装 express,通过 express 快速创建 web 服务器,将 vue 打包生成的 dist 文件夹, 托管为静态资源即可
具体实现:
2.1 初始化npm
新建文件夹,然后命令行执行 npm init
运行完之后会出现一个package.json的配置文件,说明初始化npm成功
2.2 安装express
执行 npm i express
2.3 创建app.js 文件
const express = require('express')
// 创建 web 服务器
const app = express()
// 托管静态资源
app.use(express.static('./dist'))
// 启动 web 服务器
app.listen(80, () => {
console.log('web server running at http://127.0.0.1')
})