前情提要:着重基础。
- 自我介绍
- 关于实习:用的什么框架,实习过程参加的工作,实习经历和在学校里做的项目有什么区别(单独问了代码层面有什么区别?)
- 前端相关基础知识: (1)自适应的两栏布局,左边占1/3,右边设2/3,如何实现,代码上细说
- 第一个是浮动方案,给父元素设置
overflow:hidden;清除浮动,给左元素设置float:left;width:33.33%;;右元素设置:float:left;width:66.67%; - 第二个是使用flex布局,给父亲设置
display:flex;左元素设置flex:1;右元素设置flex:2;就可以了。
(2)写一个div元素让它水平垂直居中,在生产上一般怎么写?
- 使用flex布局,给父亲设置
display:flex;justify-content: center; /* 水平居中 */ align-items: center; /* 垂直居中 */,如果想要盒子中的文字水平垂直居中,给div自身加入text-align:center;以及设置line-height等于元素高度,让文本垂直居中。 - 或者使用grid布局,给父亲加上
place-items: center;; - 也可以使用绝对定位,给父亲加上
position:relative;给div自身加上position: absolute; top: 50%; left: 50%;以及transform: translate(-50%, -50%);(因为当你将一个元素设置为绝对定位并通过top: 50%; left: 50%;来试图将其中心放置在父容器的中心时,元素的左上角实际上会被放置在父容器的中心位置(50% 的宽度和高度)。这意味着元素的实际中心并不在父容器的中心,而是位于其左上角。)
- 介绍一下CSS中的选择器以及它们的优先级
基本选择器:ID选择器,类选择器,元素选择器;组合选择器:后代选择器( ),子选择器(>),相邻兄弟选择器(+),通用兄弟选择器(~),分组选择器(,);属性选择器:(1)通过元素的属性值选择元素,如
input[type="text"] { border: 1px solid black; }选择所有type属性为text的<input>元素。(2)部分匹配的属性选择器:
^=选择以指定值开头的属性。*=选择包含指定值的属性。$=选择以指定值结尾的属性。
伪类选择器:(动态伪类用于描述元素的状态)如a:hover { text-decoration: underline; } 鼠标悬停时的链接样式。input:focus { border-color: blue; } 输入框获得焦点时的样式。(结构性伪类用于选择特定的位置)li:first-child { font-weight: bold; } 选择每个父元素下的第一个 <li>。p:nth-child(2n) { color: red; } 选择每个父元素下的偶数 <p> 元素。
伪元素选择器:(用于选择元素的一部分。)如::before 和 ::after 可以在元素内容之前或之后插入内容。p::first-letter { font-size: 2em; } 选择每个段落的首字母。
CSS选择器的优先级:
- 内联样式:1000
- ID 选择器:100
- 类、属性和伪类选择器:10
- 元素和伪元素选择器:1
- 默认:0
- 补充:组合选择器的优先级需要计算内部的选择器优先级来决定;然后相同优先级的选择器,后写的优先。
- 学校里都上一些什么课程,有没有系统学习过web开发;
- js数据类型
js中数据类型分为7种基础数据类型和5种引用数据类型。其中基础数据类型有:Undefined Null Number BigInt Boolean String Symbol(Symbol 是 ES6(ECMAScript 2015)引入的一个新数据类型,用于表示唯一的标识符。每个 Symbol 值都是唯一的,这使得它们非常适合用作对象属性的键,以避免命名冲突。);引用数据类型包括:Object Array Function Date RegExp。
- 怎么检查js中的基础类型和引用类型
使用typeof运算符即可。(Null会返回Object,这是一个历史遗留的错误)
当然也可以使用 instanceof来判断引用类型。
- 怎么区别Null和Object呢
使用严格相等运算符或者Object.prototype.toString().call()(在 JavaScript 中,所有对象都继承自 Object,而 Object 对象的 toString 方法在未重写的情况下,返回的是一个描述对象内部类型的字符串。这是 ECMAScript 规范定义的。当你调用Object.prototype.toString.call(value) 时,这里的 call 方法将 value 的上下文(即 this)设置为要检测的值。这使得 toString 方法能够返回该值的内部类别。)
- 想把字符类型的‘123’改成Number类型,怎么办?‘123abc’呢?
使用Number(),使用一元加号,使用parseInt/parseFloat,或Math.floor()、Math.ceil() 或 Math.round()。这些在碰到字符串中带有字母时都会输出NaN。
- 讲述一下js的事件流
在js中,事件流指的是时间在DOM中传播的过程,事件流主要有三个阶段:捕获,目标和冒泡阶段。
- 捕获:在这个阶段,事件从根节点向下传播到事件的目标节点。也就是说,当一个事件发生时,它会先从window对象开始,逐层下降到具体的目标元素,这一阶段允许在事件到达目标元素之前对其进行处理。
- 目标:在这个阶段,事件会到达最初触发事件的目标元素,此时可以对目标元素执行一些特定的操作。
- 冒泡:事件在目标节点处理完之后会向上冒泡,返回到根节点,直到window对象。冒泡是事件流的默认行为,这意味着如果没有特别处理,事件将自动冒泡到父级元素。
在js中可以使用
addEventListener()的useCapture参数来选择是否在捕获或者冒泡阶段进行处理。如果为true,则事件在捕获阶段被处理;如果为false或省略,事件在冒泡阶段被处理。
12.冒泡会带来什么问题,怎么阻止冒泡?preventDefault()又是干什么的?
冒泡可能会导致意外触发父级事件,由于事件冒泡,子元素的事件可能会导致意外触发父元素上绑定的相同的事件处理程序。
可以使用event.stopPropagation()来阻止冒泡。preventDefault()阻止事件的默认行为。比如取消链接的默认跳转行为,取消表单的默认提交行为(在表单提交时,浏览器通常会刷新页面)等。
- 讲一下JS的事件循环
- JS是单线程的,这意味着一次只能执行一个操作,那么js为了执行效率支持异步编程,碰到异步操作时不阻塞代码继续执行,当异步事件完成时会触发回调函数,类似操作系统中的并发。事件循环可以分为三个部分,在ES6之前分为js引擎的调用栈,宿主环境(一般是浏览器)和任务队列。js引擎读取每一条指令,碰到同步操作直接执行,碰到异步操作推给宿主环境执行,等待事件完成。异步事件完成之后由浏览器推入任务队列。只有调用栈空闲之后才会去执行任务队列中的任务,并将队列中的任务一次清空,再看调用栈中的任务。
- ES6引入了Promise对象,js引擎本身也可以发起和管理异步操作了。Promise本身是同步的,但是then和catch回调是异步的。此时任务队列被分为了两部分,宏任务队列和微任务队列,宏任务中是由浏览器环境执行的异步代码,比如JS脚本执行,定时器,Ajax请求,用户交互;微任务中是由js引擎环境执行的异步代码,比如Promise对象的回调和MutationObserver。每次调用栈空闲之后会优先清空微任务队列,再去清空宏任务队列。
- 讲一下浏览器的存储方式都有哪些?
- (1)Cookies:Cookies是由服务器发送到客户端并存储在浏览器中的小型文本文件,它们可以用来存储用户偏好,会话信息等。大小限制为4KB,可以设置过期时间,每次HTTP请求都会随着请求一起发送。
- (2)Local Storage:允许以键值对的形式在用户的浏览器中存储数据。没有过期时间,除非主动删除,只能存储字符串型的数据,需要使用JSON.stringify和JSON.parse转换对象。适合于需要长期存储的数据。大小在5-10MB,Chrome约5MB,Edge约10MB。
- (3)Session Storage:用于在一个会话中临时存储数据。仅在页面会话生命周期内有效,关闭标签页或浏览器后消失。大小与Local Storage一样,5-10.适合于短期存储。
- (4)IndexedDB:用于在客户端存储大量结构化数据,包括文件和blobs。可达数百MB或GB。基于事务实现ACID特性,使用异步API,不会阻塞主线程。
- 还有已废弃的webSQL和实验阶段的File System Access API。
- 详细讲讲HTTP状态码有哪些,表示什么?
- 1xx:信息性状态码 表示请求已被接受,继续处理。100 Continue:客户端可以继续发送请求的剩余部分;101 Switching Protocols:服务器正在切换协议。
- 2xx:成功状态码:200 OK,请求成功,并返回请求的数据。201 Created 请求成功并创建了新的资源,通常用于POST请求。202 Accepted:请求已接收但尚未处理。204 No Content:服务器成功处理了请求但没有返回数据。
- 3xx:重定向状态码:301 Moved Permanently:请求的资源已永久移动到新位置,响应中包含新 URL。302 Found:请求的资源临时重定向到另一个url。304 Not Modified:资源未被修改,可以使用缓存的版本。
- 4xx:客户端出现错误。400 Bad Request:请求无效或者格式错误,服务器无法理解。401 Unauthorized 请求未授权,需要认证;403 Forbidden:服务器理解请求,但是拒绝执行(通常因为权限问题) 404 Not Found 请求的资源不存在;405 Method Not Allowed:请求的方法对于该资源不被允许。
- 5xx:服务器发生错误。500 Internal Server Error:服务器遇到意外情况。501 Not Implemented:服务器不支持请求所需的功能;502 Bad Gateway:作为网关或代理的服务器收到无效响应;503:服务器当前无法处理请求,可能是由于过载或维护。504:Gateway Timeout:作为网关或代理的服务器未能及时从上游服务器获取请求。
- 讲讲v-show和v-if的区别吧
-
v-if:
- 当条件为
false时,完全不会渲染对应的 DOM 元素。 - 首次渲染时会创建和销毁元素(即当条件变为
true时,元素被创建;当条件变为false时,元素被销毁)。 - 适用于需要在条件变化时动态添加或移除元素的场景。
- 当条件为
-
v-show:
- 始终渲染对应的 DOM 元素,只是通过 CSS 的
display属性来控制元素的显示与隐藏。 - 当条件为
false时,元素仍然存在于 DOM 中,但其display属性设置为none。 - 适用于频繁切换显示状态的场景,如 tab 切换等。
- 始终渲染对应的 DOM 元素,只是通过 CSS 的
-
由于涉及到 DOM 的创建和销毁,
v-if在初次渲染时可能会稍微慢一些,但在不需要频繁切换的情况下比较节省内存。
- 直接在组件上使用v-if和v-show对组件的生命周期有什么影响?
v-if会让组件重新创建和挂载,也会导致组件的销毁,触发相应的生命周期函数。而v-show只是在组件根节点的样式上控制display属性,与组件生命周期无关。
- 讲一讲组件之间的通信方式。
- 父子组件通信:Props(双向传递数据);自定义事件(在子组件中使用emit派发事件,在父组件上监听,用于子传父);ref(通过$refs获取到子组件实例,就能拿到子组件的数据);
- 兄弟组件通信:Event Bus总线(双向传递,并且不限于兄弟使用);parent 或 root(通过共同祖辈
$parent或者$root搭建通信桥梁,比如兄弟组件this.$parent.on('add',this.add)另一个兄弟组件this.$parent.emit('add')); - 祖孙通信:
$attrs和$listeners:包含了父级作用域中不作为prop被识别 (且获取) 的特性绑定 ( class 和 style 除外);provide与inject,在祖先组件定义provide属性,返回传递的值在后代组件通过inject接收组件传递过来的值: - 祖先组件
provide(){
return {
foo:'foo'
}
}
后代组件
inject:['foo'] // 获取到祖先组件传递过来的值
Vuex:可用于任意组件间通信。
- 刚刚讲到的vuex和event bus有什么区别?你会选择在什么情况下分别使用这两个?
如果应用规模较小,或者是在原型开发阶段想快速迭代且组件关系简单,使用事件总线是一种轻量级的方案,而不需要引入状态管理工具;又或者说只需要在临近组件之间传递简单的事件且不需要持久化状态时,总线就很合适。 那么当组件关系较复杂时,仓库可以帮助管理全局状态,避免状态多层嵌套时多层传递props会比较难以维护。
- jsx和js有什么区别?(听到这个问题眼前一黑,因为直觉上就是需要被编译呗 但是又害怕是什么特别的答案)
- JSX 是 JavaScript 的一种语法扩展,需要被 Babel 或其他编译工具转换为标准的 JavaScript 代码。在转换后,JSX 会被转化为
React.createElement调用。这意味着你必须有构建步骤(例如使用 Webpack 或 Create React App)来处理 JSX。 - 你可以直接在浏览器中运行 JavaScript 代码,无需任何转换。
-
进入到问别的环节:在学校里是怎么学习前端相关或者技术相关?
-
学习前端过程中碰到了什么问题,是怎么解决的?
-
有没有读过前端相关书籍,特别提了JS的高级程序设计,推荐我去读。