以下是对文中提到的前端面试问题的详细解答:
HTML- HTML5新增了哪些内容或API,使用过哪些
新增内容:新的语义化标签,如<header>、<footer>、<article>、<section>等,使页面结构更清晰;多媒体标签,如<audio>、<video>,方便嵌入音频和视频;表单增强元素,如<input>的type新增了email、url、date等类型。
新增API:Canvas绘图API,可用于绘制图形、制作动画等;Web Storage API,包括localStorage和sessionStorage,用于在客户端存储数据;Geolocation API,可获取用户的地理位置信息。
使用情况:在实际项目中,使用语义化标签构建页面结构,提高代码可读性和SEO优化;使用<video>标签嵌入宣传视频;利用localStorage存储用户登录状态等数据。
- input和textarea的区别
用途:input元素通常用于接收单行文本输入,如用户名、密码等;textarea元素用于接收多行文本输入,如评论、留言等。
属性:input有type属性,可指定不同的输入类型;textarea没有type属性,但有rows和cols属性,用于设置文本区域的行数和列数。
样式控制:input的高度通常由字体大小和行高决定,难以直接设置固定高度;textarea可以通过height属性轻松设置固定高度。
- 用一个div模拟textarea的实现
基本思路:创建一个div元素,设置其contenteditable属性为true,使其可编辑;通过CSS设置div的样式,如边框、背景色、内边距等,使其外观类似textarea;监听div的输入事件,获取用户输入的内容。
示例代码:
<!DOCTYPE html><html><head> <style> .my-textarea { width: 300px; height: 150px; border: 1px solid #ccc; padding: 10px; overflow-y: auto; } </style></head><body> <div class="my-textarea" contenteditable="true"></div></body></html><!DOCTYPE html><html><head> <meta name="format-detection" content="telephone=no"></head><body> <p>这是一个电话号码:1234567890,在移动设备上不会被识别为可拨打的电话号码。</p></body></html>CSS- 左右布局:左边定宽、右边自适应,不少于3种方法
方法一:使用浮动
<!DOCTYPE html><html><head> <style> .left { float: left; width: 200px; background-color: lightblue; } .right { margin-left: 200px; background-color: lightgreen; } </style></head><body> <div class="left">左边定宽</div> <div class="right">右边自适应</div></body></html>- 方法二:使用绝对定位<!DOCTYPE html><html><head> <style> .container { position: relative; } .left { position: absolute; left: 0; width: 200px; background-color: lightblue; } .right { margin-left: 200px; background-color: lightgreen; } </style></head><body> <div class="container"> <div class="left">左边定宽</div> <div class="right">右边自适应</div> </div></body></html>- 方法三:使用Flexbox布局<!DOCTYPE html><html><head> <style> .container { display: flex; } .left { width: 200px; background-color: lightblue; } .right { flex: 1; background-color: lightgreen; } </style></head><body> <div class="container"> <div class="left">左边定宽</div> <div class="right">右边自适应</div> </div></body></html>- CSS3用过哪些新特性
选择器:如:nth-child()、:nth-of-type()等,可更精确地选择元素。
盒模型:box-sizing属性,可设置border-box,使元素的宽度和高度包含内边距和边框。
过渡和动画:transition属性可实现元素的过渡效果,animation属性可创建更复杂的动画。
变换:transform属性可对元素进行旋转、缩放、平移等操作。
渐变:线性渐变linear-gradient和径向渐变radial-gradient,可用于创建背景渐变效果。
- BFC、IFC
BFC(Block Formatting Context,块级格式化上下文):是一个独立的渲染区域,内部元素的布局不会影响外部元素。触发BFC的条件包括:根元素、浮动元素、绝对定位元素、overflow不为visible的元素等。BFC可以解决外边距合并、浮动元素高度塌陷等问题。
IFC(Inline Formatting Context,行内格式化上下文):用于处理行内元素的布局。在IFC中,行内元素会在一行内从左到右依次排列,当一行放不下时,会自动换行。
- 对栅格的理解
概念:栅格是一种将页面划分为多个等宽或不等宽列的布局方式,通过将元素放置在不同的列中,实现页面的整齐排列和响应式设计。
优点:提高页面的可维护性和可扩展性,使页面布局更加灵活和规范;方便实现响应式设计,适应不同屏幕尺寸的设备。
实现方法:可以使用CSS框架如Bootstrap、Foundation等提供的栅格系统,也可以自己编写CSS代码实现栅格布局。
- (水平)居中有哪些实现方式
行内元素水平居中:将父元素设置为text-align: center,示例代码如下:
<!DOCTYPE html><html><head> <style> .parent { text-align: center; } </style></head><body> <div class="parent"> <span>行内元素水平居中</span> </div></body></html>- 块级元素水平居中:设置块级元素的`margin-left`和`margin-right`为`auto`,示例代码如下:<!DOCTYPE html><html><head> <style> .child { width: 200px; margin-left: auto; margin-right: auto; background-color: lightblue; } </style></head><body> <div class="child">块级元素水平居中</div></body></html>- 使用Flexbox布局:将父元素设置为`display: flex`,`justify-content: center`,示例代码如下:<!DOCTYPE html><html><head> <style> .parent { display: flex; justify-content: center; } .child { width: 200px; background-color: lightblue; } </style></head><body> <div class="parent"> <div class="child">使用Flexbox水平居中</div> </div></body></html><!DOCTYPE html><html><head> <style> .border-1px { position: relative; } .border-1px::after { content: ""; position: absolute; left: 0; bottom: 0; width: 100%; height: 1px; background-color: #000; transform: scaleY(0.5); } </style></head><body> <div class="border-1px">1像素边框示例</div></body></html> - 使用`border-image`:通过设置`border-image`属性,使用一张包含边框的图片来实现`1px`边框效果。 - 使用`box-shadow`:通过设置`box-shadow`属性,模拟`1px`边框效果。JavaScript<!DOCTYPE html><html><head> <style> img { display: block; width: 300px; height: 200px; margin-bottom: 10px; } </style></head><body> <img data-src="https://example.com/image1.jpg"
src="placeholder.jpg" alt="Image 1"> <img data-src="https://example.com/image2.jpg"
src="placeholder.jpg" alt="Image 2"> <img data-src="https://example.com/image3.jpg"
src="placeholder.jpg" alt="Image 3"> <script> function lazyLoad() { const images = document.querySelectorAll('img[data-src]'); const viewportHeight = window.innerHeight; const scrollTop = document.documentElement.scrollTop || document.body.scrollTop; images.forEach(img => { const imgTop = img.getBoundingClientRect().top; if (imgTop < viewportHeight + scrollTop) { img.src = img.dataset.src; img.removeAttribute('data-src'); } }); } window.addEventListener('scroll', lazyLoad); window.addEventListener('load', lazyLoad); </script></body></html>- 实现页面加载进度条
基本思路:通过监听页面的加载事件,如DOMContentLoaded、load等,根据页面的加载进度更新进度条的显示。
实现方法:
使用<progress>元素创建进度条。
监听document.onreadystatechange事件,根据document.readyState的值更新进度条的进度。
也可以使用第三方库,如NProgress,它提供了更丰富的功能和样式。
示例代码(使用原生JS):
<!DOCTYPE html><html><head> <style> #progress-bar { width: 100%; height: 10px; background-color: #f0f0f0; } #progress { height: 100%; background-color: #4CAF50; width: 0%; transition: width 0.3s ease; } </style></head><body> <div id="progress-bar"> <div id="progress"></div> </div> <script> document.onreadystatechange = function () { const progress = document.getElementById('progress'); if (document.readyState === 'interactive') { progress.style.width = '50%'; } else if (document.readyState === 'complete') { progress.style.width = '100%'; setTimeout(() => { document.getElementById('progress-bar').style.display = 'none'; }, 500); } }; </script></body></html><!DOCTYPE html><html><body> <ul id="list"> <li>Item 1</li> <li>Item 2</li> <li>Item 3</li> </ul> <script> const list = document.getElementById('list'); list.addEventListener('click', function (event) { if (event.target.tagName === 'LI') { console.log('Clicked:', event.target.textContent); } }); </script></body></html>function extend(target, source) { for (const key in source) { if (source.hasOwnProperty(key)) { target[key] = source[key]; } } return target;}const obj1 = { a: 1 };const obj2 = { b: 2, c: 3 };const result = extend(obj1, obj2);console.log(result); - 为什么会有跨域的问题以及解决方式
跨域问题产生的原因:浏览器的同源策略,即协议、域名、端口号相同的请求才是同源请求,否则就是跨域请求。为了安全考虑,浏览器会限制跨域请求的发起和响应的接收。
解决方式:
JSONP:利用<script>标签不受同源策略限制的特点,通过动态创建<script>标签,向服务器发送请求,服务器返回一个回调函数调用的JavaScript代码,实现跨域数据获取。
CORS(Cross-Origin Resource Sharing):服务器设置Access-Control-Allow-Origin等响应头,允许跨域请求。
postMessage:用于在不同窗口或iframe之间进行跨域通信。
代理服务器:在同源的服务器上设置代理,将跨域请求转发到目标服务器,再将响应返回给客户端。
- jsonp原理、postMessage原理
jsonp原理:
客户端定义一个回调函数,如handleResponse。
动态创建一个<script>标签,将其src属性设置为服务器接口地址,并在地址中带上回调函数名作为参数,如
https://example.com/api?callback=handleResponse
。服务器接收到请求后,将数据包装在回调函数中返回,如handleResponse({data: 'example'})。
客户端的<script>标签加载完成后,会自动执行返回的JavaScript代码,调用回调函数处理数据。
postMessage原理:
postMessage是HTML5提供的一种跨文档通信(Cross-Document Messaging)API,允许不同源的窗口或iframe之间进行数据传递。
发送消息的窗口使用window.postMessage(message, targetOrigin)方法发送消息,其中message是要发送的数据,targetOrigin是目标窗口的源,用于限制消息的接收方。
接收消息的窗口监听message事件,在事件处理函数中获取发送的消息数据。
- 实现拖拽功能,比如把5个兄弟节点中的最后一个节点拖拽到节点1和节点2之间
实现步骤:
为需要拖拽的元素设置draggable属性为true。
监听元素的dragstart事件,记录被拖拽的元素。
监听文档的dragover事件,阻止默认行为,以便可以放置元素。
监听文档的drop事件,获取放置位置,将被拖拽的元素插入到相应位置。
示例代码:
<!DOCTYPE html><html><head> <style> .item { width: 100px; height: 100px; margin: 10px; background-color: lightblue; cursor: move; } </style></head><body> <div class="container"> <div class="item" draggable="true">Item 1</div> <div class="item" draggable="true">Item 2</div> <div class="item" draggable="true">Item 3</div> <div class="item" draggable="true">Item 4</div> <div class="item" draggable="true">Item 5</div> </div> <script> let draggedItem = null; const items = document.querySelectorAll('.item'); items.forEach(item => { item.addEventListener('dragstart', function (event) { draggedItem = this; event.dataTransfer.effectAllowed = 'move'; }); }); document.addEventListener('dragover', function (event) { event.preventDefault(); }); document.addEventListener('drop', function (event) { event.preventDefault(); const container = document.querySelector('.container'); const item1 = container.children[0]; if (draggedItem === container.children[container.children.length - 1]) { container.insertBefore(draggedItem, item1.nextSibling); } }); </script></body></html>- 动画:setTimeout何时执行,requestAnimationFrame的优点
setTimeout何时执行:setTimeout用于在指定的延迟时间后执行一次函数,但它的执行时间并不精确,会受到浏览器事件循环、其他任务执行等因素的影响。
requestAnimationFrame的优点:
性能优化:requestAnimationFrame会在浏览器下一次重绘之前执行,与浏览器的刷新频率保持一致,通常为60Hz,即每16.7毫秒执行一次,能提供更流畅的动画效果。
节能:当页面处于隐藏状态时,浏览器会自动暂停requestAnimationFrame的执行,减少不必要的计算和渲染,节省电量。
- 手写parseInt的实现
function myParseInt(str) { let result = 0; let sign = 1; let i = 0; if (str[0] === '-') { sign = -1; i = 1; } else if (str[0] === '+') { i = 1; } for (; i < str.length; i++) { const char = str[i]; if (char >= '0' && char <= '9') { result = result * 10 + (char.charCodeAt(0) - '0'.charCodeAt(0)); } else { break; } } return result * sign;}console.log(myParseInt('123')); console.log(myParseInt('-456')); console.log(myParseInt('+789')); - 编写分页器组件的时候,为了减少服务端查询次数,点击“下一页”怎样能确保还有数据可以加载(请求数据不会为空)
方法一:服务端返回总页数或总数据量:在首次请求数据时,服务端返回总页数或总数据量,客户端根据当前页码和总页数判断是否还有下一页数据。
方法二:服务端返回是否有下一页的标识:服务端在返回当前页数据时,同时返回一个标识,如hasNextPage,客户端根据该标识判断是否还有下一页数据。
方法三:客户端缓存数据:客户端在加载数据时,可以提前多加载一页数据并缓存起来,当用户点击“下一页”时,先从缓存中获取数据,同时向服务端请求下一页数据,如果缓存中有数据,则直接显示,避免出现空白页。
- ES6新增了哪些特性,使用过哪些,也有当场看代码说输出结果的
新增特性:
变量声明:let和const,用于声明块级作用域的变量,解决var的变量提升和作用域问题。
箭头函数:简化了函数的写法,this指向固定为定义时所在的对象。
模板字符串:使用反引号`定义字符串,可以方便地嵌入变量和表达式。
解构赋值:可以从数组或对象中提取值,赋值给变量。
类(Class):提供了更面向对象的语法,用于定义类和继承。
模块化(Module):使用import和export实现模块的导入和导出。
代码示例及输出结果:
// 箭头函数const add = (a, b) => a + b;console.log(add(2, 3)); // 模板字符串const name = 'Alice';console.log(`Hello, ${name}!`); // 解构赋值const arr = [1, 2, 3];const [x, y, z] = arr;console.log(x, y, z);