外观
240328面试 线上
作者:guo-zi-xin
更新于:2 个月前
字数统计:4k 字
阅读时长:13 分钟
ES6常用语法
CSS盒模型
盒模型是一个盛放内容的容器, 它由四部分组成 元素的具体内容content
、 内边距padding
、边框border
、外边距margin
组成
设置元素的宽高只是设置了内容区域的宽高,盒子真正的宽高应该是 内容宽高 + 内填充 + 边界边框 + 外边距
和模型有两种 标准盒模型和IE盒模型, 这两者的区别主要在于宽高的包含范围:
标准盒模型的宽高指的是内容区域content
的宽高, 而IE盒模型的宽高指的是内容区content
+ 内边距padding
+ 边框border
的宽高
Promise和 Async Await用法区别
Promise
Promise 是 JavaScript 中用来处理异步操作的对象,它代表一个异步操作最终的完成或失败,可以获取异步操作的结果或错误。 Promise 通过 then() 方法来处理异步操作的成功和失败情况,可以链式调用多个 then() 方法。 使用 Promise 时,需要手动处理异步操作的状态,即 pending、fulfilled(resolved)和 rejected 状态。
React组件传参
父组件传子组件
通过props参数进行传递
- 父组件
tsx
import React from 'react'
const Parent = ():React.FC => {
return <Child param1="1" param2="2"/>
}
- 子组件
tsx
import React from 'react'
const Child = ({ param1, param2 }):React.FC => {
return <>父组件传递的参数:{ param1 }, { param2 }</>
}
上述示例中, param1
和param2
就是父组件传递给子组件的参数,子组件运行结果为 父组件传递的参数:1,2
子组件传递给父组件
子组件传递给父组件严格来讲还是父传子, 通过props
或者ref
来实现传参效果
使用回调函数
在父组件中定义一个回调函数getChildVal
, 将这个函数绑定在子组件上通过props传入子组件,当子组件中是时间或者什么实际需要向父组件传值时, 在子组件内就可以调用这个函数并传入值,此时定义在父组件的函数被触发,并可以拿到子组件的传值
- 父组件
tsx
import React { useState } from 'react'
const Parent = ():React.FC => {
const [data, setData] = useState('')
const getChildVal = (value) => {
console.log('从子组件获取的值', value)
setData(value)
}
return (
<>
父组件接收到的值: {data}
<Child onchange={getChildVal}/>
</>
)
}
- 子组件
tsx
const Child = (props):React.FC =>{
const [value, setValue] = useState<number>(1)
const changeVal = () => {
setValue(value + 1)
props.onchange(value + 1)
}
return (
<>
{/* 当子组件需要向父组件传值时, 调用changeVal函数进行传值 */}
<div onClick={changeVal}>子组件传递给父组件</div>
</>
)
}
通过ref
子组件传递给父组件严格来讲还是父传子, 父组件传递给子组件ref
,子组件将想要暴露给父组件的值放在上面, 然后父组件就可以使用这个值;
首先需要导入对应模块包useImperativeHandle
、useRef
、forwardRef
tsx
import React, { useRef, useImperativeHandle, useEffect, forwardRef } from 'react'
- 父组件
tsx
const Parent = ():React.FC => {
const ref = useRef()
useEffect(()=> {
console.log(ref)
}, [])
return (
<Child ref={ref}/> // 将ref传递给子组件
)
}
- 子组件
tsx
// 如果ref是设置在自定义组件上, 则需要用forwardRef处理一下
const Child = forwardRef(({}, ref)=> {
useImperativeHandle(ref, () =>({
data: '我是子组件'
}))
return <>我是子组件</>
})
上述示例运行后控制台输出
json
{
"current": {
"data": "我是子组件"
}
}
跨组件传值(父组件传孙组件)
在跨组件传值过程中,我们可以使用父传子的方法,一层一层嵌套传递
- 父组件
tsx
const Parent = ():React.FC => {
return <Child1 param1="1" param2="2"/>
}
- 子组件
tsx
//子组件
const Child1 = ({ param1, param2 }) => {
return <Child2 param1={param1} param2={param2} />
}
- 孙组件
tsx
const Child2 = ({ param1, param2 }) => {
return <>父组件传递的参数:{param1},{param2}</>
}
通过层级嵌套传参 我们也可以实现跨组件传递,但如果有多层嵌套时,一层一层之间传递很非常冗余和麻烦,有时候也会搞混参数来源, 所以可以使用context
来解决这个问题
再项目目录创建一个context.ts
的文件,用于创建我们的context
typescript
import { createContext } from 'react'
const myContext = createContext(null)
export default myContext
然后在组件文件中引入定义的myContext
, 并引入react包:
tsx
import React, { useContext } from 'react'
import MyContext from '@/context'
- 父组件
tsx
const Parent = ():React.FC => {
//使用provider传值
return (<>
<MyContext.Provider value={{ param1: '1', param2: '2' }}>
<Child1/>
</MyContext.Provider>
</>)
}
- 子组件
tsx
//子组件无需改动
const Child1 = () => {
return <Child2 />
}
- 孙组件
tsx
const Child2 = () => {
//通过useContext获取父组件的值
const { param1, param2 } = useContext(MyContext)
return <>父组件传递的参数:{param1},{param2}</>
}
React 子组件如何传递给父组件参数
父组件通过设置onchange事件传递给子组件, 子组件通过调用props.onchange事件来传递参数
CSS3常用属性
- border-radius 边框圆角
允许创建元素的圆角边框
css
div {
border-radius: 10px
}
- box-shadow 容器阴影
添加元素的阴影效果
css
div {
box-shadow: 3px 3px 5px #000
}
- text-shadow 文本阴影
添加文本的阴影效果
css
div {
text-shadow: 2px 2px 4px #000000
}
- gradient 渐变
用于创建颜色渐变的背景
css
div {
background-image: linear-gradient(to right, red, yellow)
}
- transform 变换
用于对元素进行旋转、缩放、平移或倾斜
css
div {
transform: rotate(45deg); /**旋转 */
transform: translate(10px); /**平移 */
transform: scale(0.5); /**缩放 */
transform: skew(30deg) /**倾斜 */
}
- transition 过渡
用于在不同状态之间平滑地过渡CSS属性的值
css
div {
transition: width 2s
}
- animation 动画
用于创建自定义的动画效果
css
@keyframes slide {
from { left: 0px }
to { left: 100px }
}
div {
animation: slide 2s infinite, alternate;
}
- flex 弹性布局
用于创建灵活的布局结构
css
div {
display: flex;
}
- grid 网格布局
css
div {
display: grid
}
- media queries 媒体查询
用于根据设备特性(如屏幕尺寸、分辨率等) 应用不同的CSS样式
css
@media screen and (max-width: 768px) {
/** styles for screens up to 768px wide */
}
常用布局方式
在网页设计和前端开发中,有许多常用的布局方式可以实现不同的页面结构和样式。以下是一些常用的布局方式:
传统布局:
- 基于浮动(Float)和清除浮动(Clearfix)的布局。
- 使用定位(Positioning)属性(如
position: relative
和position: absolute
)来布局。
Flexbox 布局:
- 使用 Flexbox(弹性盒子布局)可以实现灵活的、自适应的布局。
- 通过设置容器的
display: flex
属性,可以指定其为 Flex 容器,然后使用各种 Flexbox 属性来控制其子元素的排列方式。
Grid 布局:
- 使用 CSS Grid(网格布局)可以创建复杂的网格结构。
- 通过设置容器的
display: grid
属性,可以指定其为 Grid 容器,然后使用网格行和列的属性来定义布局。
响应式布局:
- 使用媒体查询(Media Queries)可以根据不同的设备尺寸和屏幕宽度应用不同的样式。
- 可以使用相对单位(如百分比、em、rem 等)和 Flexbox/Grid 布局来实现响应式设计,使页面在不同设备上具有良好的显示效果。
流式布局:
- 使用百分比单位来设置宽度,使得元素可以根据父容器的大小自动调整大小,从而实现流式布局。
固定布局:
- 使用固定单位(如像素)来设置元素的宽度和高度,使得元素在不同设备上保持固定的大小和位置。
层叠布局:
- 使用定位属性(如
position: absolute
和position: relative
)来实现元素的层叠效果,使得页面元素可以重叠、覆盖和定位在不同的位置上。
- 使用定位属性(如
混合布局:
- 可以结合使用以上多种布局方式,根据具体需求来实现复杂的页面结构和样式。
CSS实现垂直居中
在 CSS 中实现垂直居中可以使用多种方法,以下是其中几种常见的方式:
使用 Flexbox
css.container { display: flex; align-items: center; /* 垂直居中 */ }
使用表格布局
css.container { display: table; } .content { display: table-cell; vertical-align: middle; /* 垂直居中 */ }
使用绝对定位和负边距
css.container { position: relative; } .content { position: absolute; top: 50%; transform: translateY(-50%); /* 垂直居中 */ }
使用网格布局
css.container { display: grid; place-items: center; /* 垂直和水平居中 */ }
使用 Flexbox 和伪元素
css.container { display: flex; } .container::before, .container::after { content: ''; flex: 1; } .content { align-self: center; /* 垂直居中 */ }
使用 line-height 属性(适用于单行文本)
css.container { line-height: 200px; /* 父容器高度的一半 */ }
使用 calc() 函数
css.container { position: relative; height: 400px; } .content { position: absolute; top: calc(50% - 50px); /* 垂直居中 */ }
宏任务和微任务的关系
宏任务(Macro Task)和微任务(Micro Task)是 JavaScript 中处理异步操作的两种不同类型。
- 宏任务(Macro Task):通常代表一些较大的任务,比如 setTimeout、setInterval、I/O 操作等。当执行完一个宏任务后,JavaScript 引擎会检查是否有微任务需要执行,然后再执行微任务队列中的任务。
常见的宏任务包括整体代码(Script)执行、setTimeout、setInterval、I/O 操作、UI 渲染等。
- 微任务(Micro Task):微任务通常是在当前任务执行结束后立即执行的任务,它们相对于宏任务来说执行顺序更早。
常见的微任务包括 Promise 的 then 方法、MutationObserver、process.nextTick 等。
JavaScript 中执行异步操作时,宏任务和微任务的执行顺序如下:
- 执行一个宏任务(例如执行整体代码、定时器等)。
- 当宏任务执行完毕后,在宏任务执行栈清空之前,执行所有微任务队列中的任务。
- 当前宏任务执行栈清空后,检查是否有渲染任务,如果有则执行渲染。
- 执行下一个宏任务(如果有)。
总的来说,微任务优先级比较高,会在下一个宏任务之前执行完毕,而宏任务则相对较慢,会在当前宏任务执行完毕后执行。
闭包
是什么 当一个函数中的内部函数被拿到函数外部调用,又因为在js中内层作用域总是能访问外层作用域的,那么内部函数存在对外部函数中变量的引用,这些变量的集合称之为闭包
使用场景
创建私有变量 (全局变量不易维护) 延长变量的生命周期 实现柯里化(颗粒)
React18新特性
升级
- React18 不再支持IE浏览器
- 新项目直接使用 npm 或者 yarn 安装最新版依赖即可
- 改变根节点的挂在方式: 使用新的API
creatRoot
, 使用旧的API仍然兼容, 只用使用了createRoot
之后才会有React18的新特性
tsx
ReactDOM.createRoot(document.getElementById('root')!).render(
<React.StrictMode>
<Provider store={store}>
<App/>
</Provider>
</React.StrictMode>,
)
在上面的示例中,我们使用了ReactDOM.createRoot
方法创建了一个根节点,并使用 render
方法将组件渲染到根节点中。这样可以让React应用更快地响应用户操作,提高用户体验。
setState异步同步
异步更新(默认行为)
在 React 18 中,默认情况下,
setState
方法会以异步方式进行更新。这意味着它会将多个状态更新批量处理,并在适当的时机进行合并和应用,以优化性能。这样做可以减少不必要的重渲染,并提高应用程序的响应性。同步更新(使用
flushSync
)尽管
setState
默认以异步方式进行更新,但在某些情况下,您可能需要立即获取更新后的状态。为了实现此目的,React 18 提供了flushSync
方法,可以强制执行同步更新。
tsx
import { flushSync } from 'react-dom';
// 同步更新
flushSync(() => {
this.setState({ count: this.state.count + 1 });
});
新增API
startTransition
startTransition
是一个新的 React API,旨在帮助开发者优化应用程序的性能和用户体验。这个函数可以告诉 React 在下次重新渲染组件时,应该延迟更新状态。这样,一些较慢的操作(例如异步请求等)就可以在后台执行,不会影响应用程序的交互性能。useTransition
useTransition
是startTransition
的 hook 版本。它可以在函数组件中使用,从而让开发者更方便地控制异步操作的状态。createRoot
createRoot
是一个新的入口函数,用于创建根React组件。它可以替代原先的ReactDOM.render
方法,使得开发者可以将多个根节点渲染到一个页面上。useDeferredValue
useDeferredValue
是一个新的 hook,可以将某个状态值的更新延迟一段时间后再执行,从而提高应用程序的性能和用户体验。类似于防抖tsxconst deferredSearchTerm = useDeferredValue(searchTerm, { timeoutMs: 1000 });
useMutableSource
useMutableSource
允许开发者访问可变的数据源,并在多个组件之间共享状态。这对于高性能的数据订阅和共享非常有用。
严格模式
React 严格模式(Strict Mode)是一个开发模式,可以帮助开发者发现一些潜在的问题,以提高应用程序的质量。启用严格模式后,React 会执行额外的检查和警告,以帮助开发者发现一些常见问题,并尽早地解决它们。
React 严格模式只在开发环境下工作,不会影响生产环境下的应用程序。
tsx
import React from 'react';
import ReactDOM from 'react-dom';
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('root')
);
React 严格模式主要包含以下几个方面的检查和提示:
识别不安全的生命周期方法,提示开发者修改,这些方法可能会导致意外的副作用或错误。
检测意外的副作用,例如:多余的重新渲染、不符合预期的函数调用等。
检测某些过时的 API 使用,提供更好的替代方案。
检测警告信息,使其更加明显和易于发现。
在应用程序启动时禁用严格模式
在一些情况下,移除 React.StrictMode 组件可能不太方便,例如:在大型项目中或已经存在大量的 console.log 调用等代码片段。此时,可以在应用程序启动时禁用严格模式。
在应用程序启动文件中,我们可以使用 React 的 unstable_disableDevMode()
函数来禁用严格模式
tsx
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
React.unstable_disableDevMode();
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('root')
);
并发模式
React 并发模式(React Concurrent Mode)是 React 的一项新功能,旨在改善在复杂应用程序中的用户体验和性能。在传统的 React 中,更新组件树时会阻塞用户界面的响应,可能导致卡顿和延迟。
而并发模式通过将任务分解为多个小步骤,让 React 在执行渲染和布局时可以中断和恢复任务,从而提供更平滑和响应式的用户体验。
在 React 并发模式中,引入了两个主要概念:任务调度和优先级。任务调度器负责决定哪些任务执行、何时执行以及中断和恢复任务。优先级允许 React 根据任务的紧迫性来安排任务的执行顺序,确保响应度更高的任务能够优先执行。
利用并发模式,React 可以将渲染过程分解为多个小任务,并根据优先级来动态调整任务执行的顺序。这样,在浏览器空闲时间或网络请求等异步操作期间,React 可以暂停当前任务,执行其它具有更高优先级的任务,以实现更爽快的用户交互体验。
总而言之,React 并发模式通过任务调度和优先级机制,提供了更好的用户体验和性能,使得 React 应用程序能够更加平滑地响应用户操作。
tsx
import React, {
useState,
useEffect,
unstable_ConcurrentMode as ConcurrentMode
} from 'react';
const App = ():React.FC => {
const [count, setCount] = useState<number>(0);
useEffect(() => {
const timer = setInterval(() => {
setCount((prevCount) => prevCount + 1);
}, 1000);
return () => {
clearInterval(timer);
};
}, []);
return (
<ConcurrentMode>
<div>
<h1>计数器</h1>
<p>{count}</p>
</div>
</ConcurrentMode>
);
}
export default App;