41. JS 放在 head ⾥和放在 body ⾥有什么区别?【热度:420】 将 JavaScript 代码放在 <head> 标签内部和放在 <body> 标签内部有⼀些区别: 1. 加载顺序:放在 <head> ⾥会在⻚⾯加载之前执⾏ JavaScript 代码,⽽放在 <body> ⾥会在⻚ ⾯加载后执⾏。 2. ⻚⾯渲染:如果 JavaScript 代码影响了⻚⾯的布局或样式,放在 <head> ⾥可能会导致⻚⾯渲染延迟,⽽放在 <body> ⾥可以减少这种影响。 3. 代码依赖:如果 JavaScript 代码依赖其他元素,放在 <body> ⾥可以确保这些元素已经加载。 4. 全局变量和函数:放在 <head> ⾥的 JavaScript 代码中的全局变量和函数在整个⻚⾯⽣命周期内都可⽤。 以下是⼀个简单的⽰例代码,展⽰了如何在 <head> 和 <body> 中放置 JavaScript 代码:
1 <!DOCTYPE html><html<head<script
2 console.log("这是在 head 中执⾏的 JavaScript 代码。");
</script</head<body<script
3 console.log("这是在 body 中执⾏的 JavaScript 代码。");</script</body</html
在这个⽰例中,分别在
<head>
和
<body>
中放置了简单的 JavaScript 代码,⽤于在控制台输出
信息,以便观察执⾏顺序。
42. Eslint 代码检查的过程是啥?【热度: 111】
ESLint 是⼀个插件化的静态代码分析⼯具,⽤于识别 JavaScript 代码中的问题。它在代码质量和编码⻛格⽅⾯有助于保持⼀致性。代码检查的过程通常如下:
1.
配置:
⾸先需要为 ESLint 提供⼀套规则,这些规则可以在
.eslintrc
配置⽂件中定义,或者在项⽬的
package.json
⽂件中的
eslintConfig
字段⾥指定。规则可以继承⾃⼀套已有的规则集,
如
eslint:recommended
,或者可以是⼀个流⾏的样式指南,如
airbnb
。也可以是⾃定义
的规则集。
2.
解析:
当运⾏ ESLint 时,它会使⽤⼀个解析器(如
espree
,默认的解析器)来解析代码,将代码转换
成⼀个抽象语法树(AST)。AST 是代码结构的⼀个树状表⽰,能让 ESLint 理解代码的语义结构。
3.
遍历:
⼀旦代码被转换成 AST,ESLint 则会遍历该树。它会查找树的每个节点,检查是否有任何规则适⽤于该节点。在遍历过程中,如果发现违反了某项规则,ESLint 将记录⼀个问题(通常称为“lint 错
误”)。
4.
报告:
在遍历完整个 AST 之后,ESLint 会⽣成⼀份报告。这份报告详细说明了它在代码中找到的任何问
题。这些问题会被分类为错误或警告,根据配置设置的不同,某些问题可能会阻⽌构建过程或者被
忽略。
5.
修复:
对于某些类型的问题,ESLint 提供了⾃动修复的功能。这意味着你可以让 ESLint 尝试⾃动修复它
所发现的问题,不需⼈⼯⼲预。
6.
集成:
ESLint 可以集成到 IDE 中,这样就可以在代码编写过程中即时提供反馈。它也可以被集成到构建⼯具如 Webpack 或任务运⾏器 Grunt、Gulp 中,作为构建过程或提交代码到版本控制系统前的⼀个步骤。
通过以上步骤,ESLint 帮助开发者在编码过程中遵循⼀致的⻛格和避免出现潜在的错误。
43. 虚拟混动加载原理是什么, ⽤ JS 代码简单实现⼀个虚拟滚动加加载。【热度: 354】
原理
虚拟滚动(Virtual Scrolling)是⼀种性能优化的⼿段,通常⽤于处理⻓列表的显⽰问题。在传统的滚动加载中,当⾯对成千上万项的⻓列表时,直接在 DOM 中创建并展⽰所有项会导致严重的性能问题,因为浏览器需要渲染所有的列表项。⽽虚拟滚动的核⼼原理是仅渲染⽤⼾可视范围内的列表项,以此减少 DOM 操作的数量和提⾼性能。
实现虚拟滚动,我们需要:
1.
监听滚动事件,了解当前滚动位置。
2.
根据滚动位置计算当前应该渲染哪些列表项⽬(即在视⼝内的项⽬)。
3.
只渲染那些项⽬,并⽤占位符(⽐如⼀个空的 div)占据其它项⽬应有的位置,保持滚动条⼤⼩不变。
4.
当⽤⼾滚动时,重新计算并渲染新的项⽬。
基础版本实现以下是⼀个简单的虚拟滚动实现的 JavaScript 代码⽰例:
1 class VirtualScroll {
2 constructor(container, itemHeight, totalItems, renderCallback)
{this.container = container; // 容器元素this.itemHeight = itemHeight; // 每个项的
⾼度this.totalItems = totalItems; // 总列表项数this.renderCallback =
renderCallback; // 渲染每⼀项的回调函数this.viewportHeight =
container.clientHeight; // 视⼝⾼度this.bufferSize =
Math.ceil(this.viewportHeight / itemHeight) * 3; // 缓冲⼤⼩this.renderedItems
= []; // 已渲染项的数组this.startIndex = 0; // 当前渲染的开始索引this.endIndex =
this.bufferSize; // 当前渲染的结束索引
3 container.addEventListener("scroll", () => this.onScroll());this.update();
4 }
5 onScroll() {const scrollTop = this.container.scrollTop;const newStartIndex =
Math.floor(scrollTop / this.itemHeight) - this.bufferSize / 2;const
newEndIndex = newStartIndex + this.bufferSize;
6 if (newStartIndex !== this.startIndex || newEndIndex !== this.endIndex)
{this.startIndex = Math.max(0, newStartIndex);this.endIndex =
Math.min(this.totalItems, newEndIndex);this.update();
7 }
8 }
9 update() {// 清空已有内容this.container.innerHTML = "";
10 // 计算并设置容器的总⾼度const totalHeight = this.totalItems *
this.itemHeight;this.container.style.height =
11 ${totalHeight}px
12 ;
13 // 渲染视⼝内的项const fragment = document.createDocumentFragment();for (let i =
this.startIndex; i < this.endIndex; i++) {const item = this.renderCallback(i);
14 item.style.top = `${i * this.itemHeight}px`;
15 fragment.appendChild(item);
16 }this.container.appendChild(fragment);
17 }
18 }
19
20 // 创建⼀个列表项的函数function createItem(index) {const item =
document.createElement("div");
21 item.className = "list-item";
22 item.innerText =
23 Item ${index}
24 ;
25 item.style.position = "absolute";
26 item.style.width = "100%";return item;
27 }
28
29 // 初始化虚拟滚动const container = document.querySelector(".scroll-container");
// 容器元素需要预先在HTML中定义const virtualScroll = new VirtualScroll(container,
30, 10000, createItem);
这个例⼦中,我们创建了⼀个
VirtualScroll
类,通过传⼊容器、项⾼度、总项数和渲染回调函数
来进⾏初始化。该类的
update ⽅法⽤于渲染出当前可视范围内部分的项⽬,并将它们放到⽂档碎⽚中,然后⼀次性添加到容器中。这样可以避免多次直接操作 DOM,减少性能消耗。当滚动时,
onScroll
⽅法将计算新的
startIndex
和
endIndex
,然后调⽤ update ⽅法进⾏更新。请注意,实际应⽤可能需要根据具体情况调整缓冲区⼤⼩等参数。
进阶版本:使⽤ IntersectionObserver 来实现
使⽤
IntersectionObserver
实现虚拟滚动就意味着我们会依赖于浏览器的 API 来观察哪些元素
进⼊或离开视⼝(viewport),⽽⾮直接监听滚动事件。这样我们只需在需要时渲染或回收元素。
以下是⼀个简化版使⽤
IntersectionObserver
来实现虚拟滚动的例⼦:
1 class VirtualScroll {
2 constructor(container, itemHeight, totalItems, renderItem) {this.container =
container;this.itemHeight = itemHeight;this.totalItems =
totalItems;this.renderItem = renderItem;
3 this.observer = new IntersectionObserver(this.onIntersection.bind(this), {
4 root: this.container,
5 threshold: 1.0,
6 });
7 this.items = new Map();
8 this.init();
9 }
10 init() {// 填充初始屏幕的元素for (let i = 0; i < this.totalItems; i++) {const
placeholder =
this.createPlaceholder(i);this.container.appendChild(placeholder);this.observer
.observe(placeholder);
11 }
12 }
13 createPlaceholder(index) {const placeholder = document.createElement("div");
14 placeholder.style.height = `${this.itemHeight}px`;
15 placeholder.style.width = "100%";
16 placeholder.dataset.index = index; // store indexreturn placeholder;
17 }
18 onIntersection(entries) {
19 entries.forEach((entry) => {const index = entry.target.dataset.index;if
(entry.isIntersecting) {const rendered =
this.renderItem(index);this.container.replaceChild(rendered,
entry.target);this.items.set(index, rendered);
20 } else if (this.items.has(index)) {const placeholder =
this.createPlaceholder(index);this.container.replaceChild(placeholder,
this.items.get(index));this.observer.observe(placeholder);this.items.delete(ind
ex);
21 }
22 });
}
}
// Render item functionfunction renderItem(index) {const item =
document.createElement("div");
item.classList.add("item");
item.textContent =
Item ${index}
;
item.dataset.index = index;
item.style.height = "30px"; // Same as your itemHeight in VirtualScrollreturn
item;
}
// Example usage:const container = document.getElementById("scrollcontainer"); // This should be a predefined element in your HTMLconst
itemHeight = 30; // Height of each itemconst itemCount = 1000; // Total number
of items you haveconst virtualScroll = new VirtualScroll(container,
itemHeight, itemCount, renderItem);
在这⾥我们创建了⼀个
VirtualScroll
类,构造函数接收容器元素、每个项的⾼度、总项⽬数和
⽤于渲染每个项⽬的函数。我们在初始化⽅法中,为每个项⽬创建了⼀个占位符元素,并且向
IntersectionObserver
注册了这些占位元素。
当⼀个占位元素进⼊到视⼝中时,我们就会渲染对应的项,并且将它替换这个占位符。当⼀个项离开视⼝,我们⼜会将它替换回原来的占位符并取消它的注册。
这种⽅法的优势包括:
•
不需要绑定滚动事件,防⽌滚动性能问题。
•
浏览器会⾃动优化观察者的回调。
•
不需要⼿动计算当前应该渲染的项⽬,当⽤⼾快速滚动时也不会遇到空⽩内容。
44. [React] react-router 和 原⽣路由区别【热度: 434】
React Router 和浏览器原⽣ history API 在路由管理上主要有以下⼏个区别:
1.
抽象级别:
◦
React Router 提供了更⾼层次的抽象,如
<Router>
、
<Route>
、和
<Link>
等组件,
这些都是专⻔为了在 React 中更⽅便地管理路由⽽设计的。它处理了底层 history API 的很多细
节,把操作抽象成了 React 组件和 hooks。
◦
原⽣ history API 更底层,直接作⽤于浏览器的历史记录栈。使⽤原⽣ history API 需要开发者
⾃⼰编写更多的代码来管理 history 栈和渲染相应的组件。
2.
便利性:
◦
React Router 提供了声明式导航和编程式导航的选项,并且有⼤量的社区⽀持和⽂档,易于使
⽤和学习。
◦
原⽣ history API 需要开发者⾃⼰处理 URL 与组件之间的关系映射,以及⻚⾯渲染的逻辑。
3.
功能:
◦
React Router 除了包含对原⽣ history API 的基本封装外,还提供了如路由守卫、路由懒加载、
嵌套路由、重定向等⾼级功能。
◦
原⽣ history API 提供基本的历史记录管理功能,但是不包含上述 React Router 提供的⾼级应
⽤路由需求。
4.
集成:
◦
React Router 是专为 React 设计的,与 React 的⽣命周期、状态管理等密切集成。
◦
原⽣ history API 与 React 没有直接关联,需要⽤⼾⼿动实现整合。
5.
状态管理:
◦
React Router 可以将路由状态管理与应⽤的状态管理(如使⽤ Redux)结合起来,使路由状态
可预测和可管理。
◦
原⽣ history API 通常需要额外的状态管理逻辑来同步 UI 和 URL。
6.
服务器渲染:
◦
React Router 可以与服务器渲染⼀起使⽤,⽀持同构应⽤程序,即客⼾端和服务器都可以进⾏
路由渲染。
◦
原⽣ history API 主要是针对客⼾端的,因此在服务器端渲染中需要额外的处理来模拟 routing
⾏为。
在考虑是否使⽤ React Router 或者原⽣ history API 时,通常需要考虑项⽬的复杂性、团队的熟悉度以及项⽬对路由的特定需求。对于⼤多数 React 项⽬⽽⾔,React Router 的便利性和其附加的⾼级特性通常使得它成为⾸选的路由解决⽅案。
表格对⽐
45. html的⾏内元素和块级元素的区别【热度: 796】
HTML 中的⾏内元素(Inline elements)和块级元素(Block-level elements)在布局⾏为、外观以及如何参与⽂档流⽅⾯有所不同。以下是它们的主要区别:
即使块级元素和⾏内元素默认特征不同,你还是可以通过 CSS 的
display
属性来更改它们的⾏为。
例如,
display: inline;
会让块级元素表现得像⾏内元素,并且它们将在其⽗容器的同⼀⾏内显
⽰。另⼀⽅⾯,
display: block;
会让⾏内元素表现得像块级元素。
46. 介绍⼀下 requestIdleCallback api 热度: 290
requestIdleCallback
是⼀个 Web API,它允许开发者请求浏览器在主线程空闲时执⾏⼀些低
优先级的后台任务,这对于执⾏如分析、整理状态和数据等不紧急的任务是理想的。这种⽅法可以提⾼⽤⼾的响应性和⻚⾯的整体性能。
以下是
requestIdleCallback
API 的⼀些关键特点:
何时使⽤ requestIdleCallback
requestIdleCallback
特别适合那些不直接关联⽤⼾交互及响应的任务,这些任务可以延后执⾏
⽽不会明显影响⽤⼾体验。例如:
•
清理⼯作:如标记的 DOM 节点删除、数据的本地存储同步等。
•
⾮关键的解析:如解析⼤量数据。
•
状态更新:如发送不紧急的状态变更。
如何使⽤ requestIdleCallback
使⽤
requestIdleCallback
,你需要传递⼀个回调函数给它,此函数会在浏览器的空闲时间调
⽤。你可以指定⼀个超时参数,它定义了浏览器在“空闲期”最多可以花费的时间来执⾏你的回调。
1 requestIdleCallback(myNonCriticalFunction, { timeout: 5000 });
•
myNonCriticalFunction: 这是你想要浏览器在空闲时间执⾏的函数。
•
timeout: ⼀个可选的参数,表⽰回调执⾏时间的上限(以毫秒为单位)。如果超时,浏览器可能在下次空闲机会进⾏执⾏。
回调函数参数
你的回调函数会接收到⼀个
IdleDeadline
对象作为参数,通常命名为
deadline
。这个对象包
含两个属性:
•
didTimeout ⼀个布尔值,如果超时已经被触发为
true
。
•
timeRemaining 返回当前空闲阶段剩余时间的函数,单位是毫秒。
注意事项
•
requestIdleCallback
不保证你的回调会在⼀个特定的时刻被调⽤,它只在浏览器需要的时
候调⽤。
•
执⾏低优先级任务时,不应该太过频繁或执⾏时间太⻓,以免影响⻚⾯性能。
•
这个 API 为了最⼤化性能优化,会强制性地结束你的任务,在不迟于指定的超时时⻓执⾏结束。
Cross-Browser Compatibility (跨浏览器兼容性)
你可能需要 polyfills(垫⽚库)来确保
requestIdleCallback
的兼容性,因为它并不是在所有
浏览器中都有原⽣⽀持。
使⽤
requestIdleCallback
,开发者可以更好地利⽤浏览器的空闲序列来执⾏不紧急的任务,同
时保持⽤⼾交互的流畅度。
47. documentFragment api 是什么, 有哪些使⽤场景?热度: 115
DocumentFragment
是 Web API 中的⼀部分,它是
DOM
(⽂档对象模型)的⼀个⾮常轻量级的
节点,代表⼀组
DOM
节点的集合。它不是⼀个真实存在于
DOM
中的实体,因此被认为是“没有名
字”的节点,或者说它不在⽂档的主体中渲染,通常⽤来作为临时的
DOM
节点仓库。
对于
DocumentFragment
的⼀部分内容,当它们在
DocumentFragment
之外操作时,并不会
引起主 DOM 树的直接重排或重绘。然⽽,⼀旦你将整个
DocumentFragment 插⼊到 DOM 的⼀个永久节点上,那么在
DocumentFragment
内进⾏的更改将会触发 DOM 的重新渲染。
DocumentFragment API 有⼏个关键的特点和⽤途:
1.
轻量级:
DocumentFragment
不会引起布局重排,因为其不是真实渲染的⼀部分。
2.
节点集合:可以在
DocumentFragment
中节点集合进⾏分组,这个集合可以⼀次性插⼊到
DOM
的某⼀部分中。
3.
性能优化:通过在⼀个
DocumentFragment
中构建好⼀⼤块
DOM
树,然后将它整体插⼊到
主
DOM
中,从⽽减少重排次数,提⾼效率。
4.
事件不冒泡:因为
DocumentFragment
不是真实渲染的⼀部分,所以它的事件不会冒泡到上层
的 DOM 元素,除⾮它被插⼊到了
DOM
中。
使⽤场景
以下是⼀些使⽤
DocumentFragment
的常⻅场景:
•
批量操作:当你想要⼀次性添加多个节点到
DOM
树中时,使⽤
DocumentFragment
可以将这
些节点预先堆放在⼀个轻量级对象中,然后⼀次性添加。
•
离屏操作:如果你需要创建复杂的
DOM
结构,可以通过
DocumentFragment
在不触发⻚⾯重
排和重绘的情况下进⾏。
•
内容填充:在填充
DOM
元素内容之前,可以先创建⼀个
DocumentFragment
完成所有节点的
添加和排序,然后把它添加到
DOM
树中。
•
避免内存泄漏:在某些情况下,它可以作为防⽌因移动节点⽽造成的内存泄漏的⼀个办法。
⽰例代码
DocumentFragment 提供了⼀个⾼效的⽅式去操作 DOM ⽽不影响⻚⾯的渲染性能,在很多需要 进⾏批量 DOM 操作的场合⾮常有⽤。 48. git pull 和 git fetch 有啥区别?【热度: 355】 git pull 和 git fetch 是 Git 版本控制系统中的两个基本命令,它们都⽤于从远程仓库更新本 地仓库的信息,但执⾏的具体操作不同。 git fetch • git fetch 下载远程仓库最新的内容到你的本地仓库,但它并不⾃动合并或修改你当前的⼯ 作。它取回了远程仓库的所有分⽀和标签(tags)。 • 运⾏ git fetch 后,你可以在需要时⼿动执⾏合并操作(使⽤ git merge )或者重新基于 远程仓库的内容进⾏修改。 • fetch 只是将远程变更下载到本地的远程分⽀跟踪副本中,例如 origin/master 。 git pull • git pull 实际上是 git fetch 操作之后紧跟⼀个 git merge 操作,它会⾃动拉取远程 仓库的新变更,并尝试合并到当前所在的本地分⽀中。 • 当你使⽤ git pull ,Git 会尝试⾃动合并变更。这可能会引起冲突(conflicts),当然冲突需 要⼿动解决。 • git pull 等价于执⾏了 git fetch 和 git merge FETCH_HEAD 的组合。 使⽤场景 • 当你仅仅想要查看远程仓库的变动⽽不⽴即合并到你的⼯作,可以使⽤ git fetch 。 • ⽽当你想要⽴即获取远程的最新变动并快速合并到你的⼯作中,则可以使⽤ git pull 。 总之, git pull 是⼀个更加「激进」的命令,因为它⾃动将远程变更合并到你的当前分⽀,⽽ git fetch 更加「谨慎」,它只下载变更到本地,不做任何合并操作。 49. 前端如何做 ⻚⾯主题⾊切换【热度: 538】 ⻚⾯主题⾊切换通常涉及到修改⽹⻚中的颜⾊⽅案,以提供不同的视觉体验,例如从明亮模式切换到 暗⿊模式。实现这⼀功能,可以通过配合使⽤ CSS、JavaScript 和本地存储来进⾏。以下是实施⻚⾯ 主题⾊切换的⼏种⽅法: 使⽤ CSS ⾃定义属性 1. 定义⼀套主题变量:
1. 应⽤⾃定义属性到 CSS 规则中:
1. 使⽤ JavaScript 动态切换主题:
使⽤ CSS 类切换
1. 为每个主题创建不同的 CSS 类:1. ⼿动切换 CSS 类:
使⽤ LocalStorage 记录⽤⼾主题偏好
使⽤媒体查询⾃动应⽤暗⿊模式 某些现代浏览器⽀持 CSS 媒体查询 prefers-color-scheme 。你可以使⽤这个特性来⾃动根据⽤ ⼾的系统设置应⽤暗⿊模式或明亮模式,⽽⽆须 JavaScript:
1 @media (prefers-color-scheme: dark) {:root {--primary-color: #1e2a34; /* 暗⿊主
题⾊ */
2 --text-color: #ccc; /* 暗⿊主题⽂本颜⾊ */
3 }
4 }
5
6 @media (prefers-color-scheme: light) {:root {--primary-color: #5b88bd; /* 明亮主
题⾊ */
7 --text-color: #000; /* 明亮主题⽂本颜⾊ */
8 }
9 }
通过以上⽅法,开发⼈员能够为前端⻚⾯提供灵活的主题⾊切换功能,从⽽增强⽤⼾体验。
50. 前端视⻆ - 如何保证系统稳定性【热度: 566】
前端视⻆来做稳定性, 本是⼀个开放性话题,这⾥没有统⼀的解法, 作者在此提供⼏个思路和反向:
1.
静态资源多备份(需要有备份)
2.
⾸屏请求缓存
3.
请求异常报警
4.
⻚⾯崩溃报警
5.
E2E 定时全量跑⽤例
更多前端面试资料无常分享 【点击领取】
标签:API,场景,container,渲染,DOM,2024,item,git,攻略
From: https://blog.csdn.net/gaotlantis/article/details/143879998