前几日去B站面试了一次前端,不算资深B站用户,平常也蛮喜欢在B站观看视频的,能获得这样的面试机会,实在是受宠若惊。但无奈实力有限加上琐事缠身,并没有做好充足的准备,导致面试失败。
(ps:属实还是有点紧张,发挥也受到影响)
这次面试过程我思前想后觉得有必要总结一下,希望自己下次再有这样的机会的时候能够把握的更好。
因内容比较多,所以准备可能分多篇博客更新内容,这里给出传送门
- HTML布局、CSS选择器及JS基础综合能力知识点
- 算法基础:数组 flat、去重及排序
- react vue 理解及基础知识
- 跨域问题解决方案
- http协议状态码
- 缓存及更新问题
- webview与原生应用交互
- 服务器端知识
ps:这是大纲,后续可能有变化。比如服务器端知识,我没有接触过,面试官就没问,但确实是面试过程中的一个大类的问题。
面试感受
面试过程整体感觉很舒服,面试官很有耐心,面试题由浅入深,面试打分的话,我会给5颗星。
HTML布局、CSS选择器及JS基础综合能力知识点
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
* {
margin: 0;
padding: 0;
}
html,
body,
#app {
margin: 0;
padding: 0;
height: 100%;
}
#header, #footer {
height: 50px;
line-height: 50px;
text-align: center;
background: #555;
color: #fff;
}
#side {
width: 200px;
background: #eee;
}
/* css here */
</style>
</head>
<body>
<div id="app">
<header id="header">header</header>
<aside id="side">side</aside>
<div id="main">
<ul>
<li><a href="https://www.bilibili.com/1">Link1</a></li>
<li><a href="https://www.bilibili.com/1">Link2</a></li>
<li><a href="https://www.bilibili.com/1">Link3</a></li>
<br>
<li><a href="https://www.bilibili.com/1">Link4</a></li>
<li><a href="https://www.bilibili.com/1">Link5</a></li>
</ul>
</div>
<footer id="footer">footer</footer>
</div>
<script>
// JS here
</script>
</body>
</html>
不考虑兼容性且不能更改dom结构,需求如下:
- 完成经典的上 header ,下 footer ,左边是侧边栏,右边是内容。
- 去掉列表前面的 · ,列表项水平排列,注意里面的br标签需要换行,同时每两个li后有一条竖线。
- 点击列表项不跳转,弹出href内的内容。
ANSWER 1:
时光回溯:
这道面试题是基础题,我应该要多向面试官展示一下我的基本功,同时也要告诉面试官,我是有关注前端最新的动态的,既然不考虑兼容性,我得先用 Grid 的方案实现一遍,然后在告诉面试官我大概还有108种不同的解法,😃哈哈哈...。然后 Grid 除了 display: grid 外,好久没有写了,我都忘记的差不多了吧。在思考 Grid 的时候,时间浪费了太久,我得赶紧找个简单的写法先提交,不然基础题都得做这么久,印象肯定不行。
浮动解决方案:
/**
* calc 是 css的一个函数
* 不明白的同学我附上链接
* https://developer.mozilla.org/zh-CN/docs/Web/CSS/calc
*/
#side {
/* 设置 侧边栏 左浮动 */
float: left;
height: calc(100% - 100px);
}
#main {
height: calc(100% - 100px);
}
position 解决方案:
#app {
/* 父级元素 设置 相对定位 */
position: relative;
}
#side {
/* 左边栏 设置 绝对定位 */
position: absolute;
top: 50px;
bottom: 50px;
left: 0;
}
#main {
/* 内容区 设置 绝对定位 */
position: absolute;
top: 50px;
right: 0;
bottom: 50px;
left: 200px;
}
#footer {
/* footer 设置 绝对定位 */
position: absolute;
bottom: 0;
width: 100%; /* 设置浮动后,补上宽度 */
}
Flex 解决方案:
❌受限于无法更改 DOM 结构,我觉得难以使用 Flex 去实现这个需求。或者请求高人指点一二。
晚上吃饭的时候突然有了 Flex 解决这个问题的思路,感谢评论区同学给的帮助。
#app {
display: flex;
flex-wrap: wrap;
}
#header {
flex-basis: 100%;
}
#side {
height: calc(100% - 100px);
}
#main {
flex: 1;
height: calc(100% - 100px);
}
#footer {
flex-basis: 100%;
}
Grid 解决方案:
参考资料
本文不赘述Grid的所有内容,有需要的朋友可以传送门详细了解。下面我会介绍我用到的部分。
#app {
/* app 为 grid 布局的容器,所以在此处创建 grid 布局 */
display: grid;
/**
这是一种缩略的写法 等价于
grid-template-rows: 50px auto 50px;
grid-template-columns: 200px auto;
创建了一个 3 * 2 的格子
高度是 50px 自动 50px
宽度是 200px 自动
*/
grid: 50px auto 50px / 200px auto;
}
/* 这个时候其实打开页面看着很奇怪,header 缩在角落,等等 */
#header, #footer {
/**
-*- 重要 -*-
下面的写法 等价于
grid-column-star: 1;
grid-column-end: 3;
该 grid 的子项
开始与 第一根 column 线
结束与 第三根 column 线
*/
grid-column: 1 / 3;
}
#app {
display: grid;
/**
等价于
grid-template-rows: 50px auto 50px;
grid-template-columns: 200px auto;
grid-template-areas:
"header header"
"side main"
"footer footer";
注意: 每一 row 只是一个字符串
*/
grid: "header header" 50px "side main" auto "footer footer" 50px / 200px auto;
}
#header {
/* 注意: header 没有双引号 */
grid-area: header;
}
#footer {
grid-area: footer;
}
ANSWER 2:
时间回溯:
取消 · 没有难度。这个题目的难点就在这个 br 标签,本来可以直接使用 flex 布局,现在的话看情况应该只能使用 inline 或者 inline-block 的方式进行水平排列了。加竖线可以用伪类选择器和伪类元素选择器组合实现,但是我忘记了 :nth-of-type 伪类选择器。
ul {
/* 去掉 · */
list-style: none;
}
ul li {
/* 水平排列,两个都行*/
display: inline;
/* display: inline-block; */
}
当时最后一个加竖线的需求,我是这样写的。
/* 伪类选择器 + 伪类元素选择器 */
ul li:nth-child(2n)::after {
content: '|';
}
但是只有 Link2 Link5 后面会出现 "|",因为 br 标签的缘故,失败。
但只需要稍加修改就可以完成,但面试的时候没有完成。
/* 伪类选择器 + 伪类元素选择器 */
ul li:nth-of-type(2n)::after {
content: '|';
}
后来询问了面试官这个应该如何解决,得知可以考虑兄弟选择器试试。
TODO: 我目前还没有想出来如何处理。Help!
ANSWER 3:
没啥好说的。把事件绑定在父元素上,节约内存。考察点就是原生dom的一些操作吧。
document.querySelectorAll('ul')[0].addEventListener('click',event => {
if(event.target.tagName === 'A') {
event.preventDefault(); // 阻止默认行为
alert(event.target.getAttribute('href'));
}
});
总结:
- 前三种方式都是比较传统的布局方式,确实能解决问题,但是比较抽象。
- Grid 的布局方式是一个二维的基于网格的布局系统,它的目标是完全改变我们基于网格的用户界面的布局方式。当使用这种布局方式的时候,在chrome中打开调试,能很清晰的看见网格的存在。相对于前三种,直观方便快捷。
- 伪类选择器这种日常可能不常用的东西可能就是面试的盲点。
- javascript 工程化之后,轮子用的多了,但是也得了解底层才行啊。