编程题目
- 链表反转
- 手写深拷贝
- CSS 渐变动画的几个实现方式
- 九宫格布局实现
- flex:1意味着什么
- position有哪些取值,relative脱离文档流吗,左移会挤开左边的盒子吗
- 重排和重绘
- v-if和v-show
- vue实现数据双向绑定的过程
- vue的keep-alive
- vite的缺点
- webpack和vite的区别
- vite热更新为什么快
- https四次握手,随机数生成,证书生成
链表反转
牛客BM1:
思路:
- 新链表先为空,因为链表最后一个都指向空
- head变成最后一个
- head 要先开始变,要先指向新链表,但是head->一旦改变,无法找到下一个,所以我们定义新的节点t,保存next
- 此时head->next已经反转,所以我们要继续处理第二个节点
- 所以如下图,new往前移动,变成head,head往前移动,变成head->next,注意!!由于我们next已经改变,所以这里需要赋值为我们暂时保存的t,如此不断循环,直至,我们的head变成null,也就意味着链表结束,new此时就是最新的反转链表
ListNode* ReverseList(ListNode* head) {
// write code here
ListNode* node=nullptr;
while(head){
ListNode * t=head->next;
head->next=node;
node=head;
head=t;
}
return node;
}
function ReverseList( head ) {
// write code here
let node =null;
while(head){
let t= head.next;
head.next=node;
node=head;
head=t;
}
return node;
}
手写深拷贝
浅拷贝,引用的还是同一块内存地址,所以新的改变旧的也改变;深拷贝,新的改变旧的不改变
方法一:
方法二:利用json
json.parse(json.stringify)
CSS 渐变动画的几个实现方式
渐变
linear-gradient线性渐变属性
- 可以指定多个颜色
- to top···指定方向
- 角度指定方向
background-image: linear-gradient(to right,red, green, blue);
background-image: linear-gradient(45deg, red 10%, green 85%, blue 90%);
radial-gradient径向渐变
使用方法和线性渐变一样
动画
- transition:渐变动画,可指定过度的css名称,时间
- transform:可以平移、缩放、旋转、倾斜
- animation:通过@keyframes rotate指定关键帧
@keyframes rotate{
from{
transform: rotate(0deg);
}
to{
transform: rotate(360deg);
}
}
@keyframes rotate{
0%{
transform: rotate(0deg);
}
50%{
transform: rotate(180deg);
}
100%{
transform: rotate(360deg);
}
}
animation: rotate 2s;
九宫格布局实现
flex实现
利用flex-wrap:wrap设置换行属性,将子盒子每一个的宽设置为父元素的三分之一即可实现
grid实现
指定长宽盒子数及其大小
grid-template-columns: repeat(3, 1fr);
grid-template-rows: repeat(3, 1fr);
float实现
- 给每一个小盒子设置浮动属性,统一浮动方向,并且宽度是父盒子的三分之一
- 浮动的元素怒会脱离文档流,跟随在浮动元素后面,如果没有浮动元素就会另起一行
- 浮动会脱离文档流,会导致元素重叠,父盒子塌陷等
- clear:清除浮动,清除左边右边或者both的浮动(比如我们有四个盒子,我们想要两两一行,就需要第三个盒子清除左浮动,因为如果四个都是浮动,他们都会在一行,如果第三个不浮动,就意味着他没有脱离文档流,相当于他是文档流第一个盒子,他会叠在第一个盒子下面,不是我们想要的效果,而且第四个盒子是浮动,第三个不是,那么第四个会另起一行:如下情况,所以我们需要清除浮动)
tabel实现
也就是表格
<table class="box-inner">
<tbody>
<tr>
<td>九宫格1</td>
<td>九宫格2</td>
<td>九宫格3</td>
</tr>
<tr>
<td>九宫格1</td>
<td>九宫格2</td>
<td>九宫格3</td>
</tr>
<tr>
<td>九宫格1</td>
<td>九宫格2</td>
<td>九宫格3</td>
</tr>
</tbody>
</table>
flex:1
- 相当于同时设置了
flex-grow: 1
、flex-shrink: 1
、flex-basis: 0
这三个属性。比如子盒子设置flex1,这个项目的大小将填充整个Flex容器,并且在容器内不会留下任何空间。- flex-grow:如果一个项目的flex-grow属性为2,其他项目都为1,则前者占据的剩余空间将比其他项多一倍。
- flex-shrink:如果所有项目的flex-shrink属性都为1,当空间不足时,都将等比例缩小。如果一个项目的flex-shrink属性为0,其他项目都为1,则空间不足时,前者不缩小。
- flex-basis:子元素宽度为父元素宽度的百分比值
position有哪些取值,relative脱离文档流吗,左移会挤开左边的盒子吗
- static:正常文档流
- relative:不脱离,只改变自身位置
- absolute:脱离
- fixed:脱离
- sticky:脱离
也就是说relative不脱离文档流,改变自身位置不会挤开其他盒子,视觉上体现为重叠,两个relative的盒子不会相互影响
重排和重绘
前端 - 【面试系列一】如何回答如何理解重排和重绘 - 桃园 - SegmentFault 思否
- 重排:元素的 位置发生变动 时发生重排,也叫回流。此时在 Layout 阶段,计算每一个元素在设备视口内的确切位置和大小。
- 重绘:元素的 样式发生变动 ,但是位置没有改变。此时在关键渲染路径中的 Paint 阶段,将渲染树中的每个节点转换成屏幕上的实际像素,这一步通常称为绘制或栅格化。
- 重排必定引起重绘,重绘不一定涉及重排。这就跟渲染路径有关系了,(可以说一下完整的浏览器渲染路径)重排时确定了元素的大小和位置接下来就是将元素渲染到屏幕上,所以重排必定会引起重绘。但只是样式改变,浏览器就会跳过重排,直接进行重绘。
引起重排
- 元素位置的改变
- 尺寸的改变
- 视图窗口变化
- 文本变化、图片变化
引起重绘
- 元素的外观改变,但不影响dom
- 颜色
- 文本方向修改
requestAnimationFrame
浏览器在下次重绘之前调用指定的回调函数,确保动画的每一帧都与浏览器的刷新率同步,这样可以使动画更加流畅。当用户切换标签页或最小化浏览器时
requestAnimationFrame
会暂停,避免不必要的计算和渲染,从而提高性能。并节省资源。避免由于setTimeout
或setInterval
导致的卡顿或不流畅现象。
v-if和v-show
- v-show隐藏是通过displaynone,v-if是删除整个dom元素 也就是说v-show在页面加载的时候就会加载,但是v-if只有为true的时候才会开始渲染,如果需要频繁的切换的话用v-show会好一点,比如一些添加订单的弹窗,v-if就运用于一些条件很少改变的情况
vue实现数据双向绑定的过程
什么是?
就是把Model和view进行绑定,js代码更新model的时候,view也会自动更新;同样,用户更新view,model的数据自动被更新
原理 双向绑定的三个重要组成部分
- 数据层(model):应用数据和业务逻辑
- 视图层(view):应用的展示效果
- 业务逻辑层(viewmodel):框架封装的核心,将数据和视图关联起来
viewmodel 职责
- 数据变化后更新视图
- 视图变化后更新数据
组成部分
- 监听器(observer):对所有数据的属性进行监听
- 解析器(compiler):扫描解析每个节点的指令,根据指令模板去替换数据和绑定相应的更新函数
实现双向绑定
new Vue的时候,observer对data执行响应化操作,同时,compiler对模板执行编译,找到动态绑定的数据。同时定义一个watcher,当数据变化时watcher调用更新函数,总的过程就是data数据一旦改变,会先找到对应的dep(key可能出现多次,所以每一个key需要一个管家dep,来管理多个watcher),通知watcher来执行更新函数
vue的keep-alive
字面意思就是保持活跃,不会被destroy掉。
作用:
一般情况下,组件实例被替换之后会被销毁(比如我从一个组件切换到另外一个组件),这就导致会丢失在这个组件内部的所有状态,我们想要保存这些状态,那么就会用到keep-alive
//vue2
//切换的时候组件处于inactive状态
<keep-alive>
<router-view></router-view>
</keep-alive>
//vue3
<!-- 非活跃的组件将会被缓存! -->
<KeepAlive>
<router-view></router-view>
</KeepAlive>
include/exclude 决定哪些组件会被缓存
<KeepAlive include="a,b" :max='10'>
<component :is="view" />
</KeepAlive>
max指定最大缓存数
keepalive结合router使用
这样配置的话,就不用在include指定,方便维护
vite的缺点
- 首屏加载慢:因为运行的时候没有进行打包,会导致大量的http请求
- 懒加载缓慢
- 兼容性(要求客户浏览器比较新的版本)
webpack和vite的区别
在模块化开发的过程当中,模块需要经过webpack打包之后,我们才能运行使用打包后的文件,而vite通过esmodule直接可以去识别模块引入的代码,这样就省去了一个打包的过程所以他快,而且是模块越多越快
esmodule:
- webpack会先打包,再启动开发服务器,请求服务的时候直接给予打包结果。
- 而vite直接启动服务器,请求哪个模块再对哪个模块进行实时编译(就比如,如果我在子组件当中引入了一个不存在的组件,那么在使用webpack的情况下,我们运行项目就会报错,但是vite并不会,因为vite是按需构建的),而且由于启动的时候不需要打包也就是说不需要分析模块大量的依赖,而是使用esbuild预构建依赖,所以启动速度非常快
vite热更新为什么快
热更新:html5当中添加了websocket,服务器检测代码是否修改,修改了就通知浏览器,浏览器通过修改的文件选择局部刷新或者全局刷新
https四次握手,随机数生成,证书生成
这里的四次握手时tls的四次握手,注意区分http请求过程当中的tcp三次握手和tls四次握手
tls四次握手
- 客户端支持版本协议、随机数、支持的密码套件列表
- 确定的版本协议、服务器的随机数、选定的密码套件、服务器的证书
- 客户端验证证书合法性、生成随机数并使用证书公钥加密发送
- 服务端使用私钥解密 最后双方根据确定的加密方法,使用前面的三个随机数生成对话密钥,来加密整个对话过程