CSS实现三列等高布局
- flex
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
.wrap {
display: flex;
}
.item {
flex: 1;
width: 0;
background-color: aquamarine;
}
</style>
</head>
<body>
<div class="wrap">
<div class="left">left</div>
<div class="item">
<p>center</p>
<p>center</p>
<p>center</p>
<p>center</p>
<p>center</p>
<p>center</p>
<p>center</p>
</div>
<div class="right">right</div>
</div>
</body>
</html>
- grid
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
.wrap {
display: grid;
grid-template-columns: 33.3% 33.3% 33.3%;
grid-auto-flow: column;
grid-gap: 10px;
background-color: azure;
}
.item {
background-color: aquamarine;
}
</style>
</head>
<body>
<div class="wrap">
<div class="item">left</div>
<div class="item">
<p>center</p>
<p>center</p>
<p>center</p>
<p>center</p>
<p>center</p>
<p>center</p>
<p>center</p>
</div>
<div class="item">right</div>
</div>
</body>
</html>
css中的position: sticky?
设置了sticky的元素在屏幕范围时该元素的位置不会受到定位影响,当该元素将要移除偏移范围时定位会变成fixed,再根据left、top进行定位。设置了该属性的元素不会脱离文档流,元素固定的相对偏移位置是相对于离他最近的具有滚动框的祖先元素,如果祖先元素不滚动,则相对视图窗口定位。可用于固定菜单用途。
flex:1的完整内容?
flex:1 可以实现不同内容div平分空间,flex的属性有flex-grow、flex-shrink、flex-basis,默认值为0,1,auto。flex-grow定义项目的放大比例,默认为0,flex-shrink定义项目的缩小比例,默认为1,flex-basis则是给上面两个属性分配多余空间之前计算是否还有多余空间,默认为auto,即项目本身大小。flex:1 完整的写法就是上面上个属性的值分别为1、1、0%;
flex布局的属性有哪些?
- display:flex,定义一个flex容器
- flex-direction: row 默认值水平从左到右,column垂直从上到下,row-reverse水平右到左,coloum-reverse垂直下到上;
- flex-wrap: 定义如何换行,默认nowrap不换行,wrap换行,wrap-reverse反向换行;
- flex-flow: direction与wrap的简写,默认是row、nowrap;
- justify-content: 设置元素在X轴方向的对齐方式,flex-start默认值起始位置对齐,flex-end结束位置对齐,center居中位置对齐,space-between平均分布对齐,space-around平均分布对齐两边保留子元素与子元素之间间隙大小的一半;
- align-items: 设置元素在Y轴方向的对齐方式,flex-start默认值起始位置对齐,flex-end结束位置对齐,center居中位置对齐,baseline元素的行内轴与侧轴同一条则与flex-start等效否则与基线对齐,stretch如果指定侧轴大小属性为auto则位置元素距离盒子尺寸尽可能接近所在行的尺寸。
- align-content: 设置元素堆叠伸缩行行为的对齐方式默认stretch,与aling-items类型,但它适用于多行flex容器,区别align-items中间会产生间隙,它不会。 https://www.runoob.com/cssref/css3-pr-align-content.html
BFC是什么?
BFC是格式化上下文,是web页面中盒子模型布局的css渲染模式,指的是一个独立的渲染区域或者一个隔离的独立容器。形成BFC的条件:浮动元素(none除外),定位元素(绝对、fixed),display(inline-block、table-cell、table-caption),overflow(visible除外);特性:内部的box会垂直放置、垂直方向距离margin决定会重叠、bfc区域不会与float box重叠、计算bfc的高度时浮动元素也参与计算;
less的好处:可以使用变量、函数、嵌套、可复用等
防抖和节流?
防抖:在事件被触发n秒后开始执行,如果在n秒内又被触发则重新计时。适用场景:提交按钮点击,搜索框联想搜索;
节流:在一个单位时间内,只触发一次函数执行,如果这个时间内多次触发相同函数,只执行一次。适用场景:拖拽、缩放;
闭包的概念?原理?为什么要用?场景?
概念:函数A执行返回一个内部函数B并被外部变量引用,B函数中用了A函数中的变量,则形成闭包;
好处:可以在B中访问A的函数作用域即可以读取A的变量;可以将函数中的变量存在内存保护变量不会污染;把变量保存在了独立的作用域作为私有成员;
坏处:变量被保存在了内存中,导致无法回收消耗内存;不需要时及时设置为null进行释放;
原理:函数执行分为预编译与执行阶段。在预编译阶段如果发现内部函数使用了外部函数的变量,则在内存中创建一个闭包对象进行变量值保存,如果已经存在则增加对应的属性值;执行完成后函数执行上下文被销毁,A函数对闭包对象的引用也被销毁,但B函数内部还在使用该闭包的引用,所以B可继续使用A的变量。利用了函数作用域链的特性,一个函数内部定义的函数将包含外部函数的活动对象添加到了它的作用域中,函数执行完毕其执行作用域链销毁,但是内部函数的作用域链中仍在引用这个活动对象,因此这个活动对象不会销毁,直到内部函数销毁才销毁。
应用场景:循环中创建闭包,避免拿到相同值。https://www.cnblogs.com/gg-qq/p/11399152.html
事件循环机制event loop?
js的任务执行分为同步和异步。同步任务直接放在主线程上排队依次执行;异步任务则放在任务队列进行排队调用,任务队列下一步将会进入调用栈然后主线程执行调用栈中的任务。js是单线程每次在主线程只能执行一个任务,在检查调用栈是否为空以及将某个任务添加到调用栈的过程就是事件循环。
浏览器事件循环中异步队列有微任务、宏任务。常见的宏任务:setTimeout、setInterval、script、IO操作、UI渲染等;常见的微任务:promise.then;
事件循环过程:1、检查宏任务队列是否为空,非空则执行一个宏任务,空则检查微任务队列是否为空,空则执行视图更新,非空则调用微任务执行,执行完成后继续检查微任务队列;
promis的特性?优缺点?内部实现?
基本特性:
- 三种状态:pending、fulfilled、rejected;
- 接受一个回掉函数(resolve,reject);
- then、catch方法返回一个新的promise实例;
- finally方法不管状态都会执行;
- promise.all将多个promise实例包装返回的每个成员都是promise实例;
- promise.race同all差不多参数中的实例只要有一个率先改变状态则会将该实例的状态返回给race并将返回值作为race方法产生的实例的返回值;
优点:统一了异步API;链式调用、一次性调用;解决回调地狱;错误处理;
缺点:一旦建立中途无法取消,throw进行跳转catch中断;pending状态无法得知请求进展;
微任务与宏任务
宏任务:当前调用栈中执行的代码为宏任务;宏任务中的事件在回调队列中,由事件触发线程维护;
微任务:当前宏任务执行完在下一个宏任务开始执行之前需要执行的任务。微任务的事件放在微任务队列中,由js引擎线程维护;
区分微任务和宏任务是为了将异步任务划分优先级,其实就是为了插队执行。
react中的项目性能优化?
分包策略减少资源大小加快加载;ssr;利用profiler分析组件进行分析;减少不必要要的渲染;使用purecomponent;不在render中进行数据处理;减少使用不必要的标签;react.memo进行组件缓存;
React组件通信方式?
- 父组件向子组件传递props;
- 子组件向父组件,通过回调函数传递参数的方式;
- 跨级组件,通过context传递;
- 不关联组件,使用状态管理、eventBus等
- 兄弟组件:通过父组件统一进行回调;
react事件绑定的原理?
在document中监听所有支持的事件,通过事件冒泡进行获取交给合成事件进行处理,如果不想使用时间冒泡则通过preventDefault。
- 事件注册
- 组件装载/更新,通过lastProps、nextProps判断是否新增、删除事件分别调用事件注册、卸载方法;
- 调用eventPluginHub的enqueuePutListener进行事件存储;
- 获取document对象,根据事件名称判断捕获还是冒泡;
- 判读事件兼容性,正常addEventListener,ie则attachevent;
- 给document注册原生事件回调统一进行事件分发;
- 事件存储
- EventPluginHub负责管理react合成事件的callback,将callback存储在了listenerBank中,还存储了合成事件的plugin;
- EventListenerHub的putListener方法将向存储器增加一个listener;
- 获取到事件绑定的唯一标识key;
- 将callback根据事件类型、元素的唯一标识存储在listenerBank中;
- listenerBank是一个map结构;
- 事件执行
- 触发document注册原生事件的回调函数进行事件分发;
- 获取到触发这个事件的最深一层的元素;
- 遍历这个元素的所有父亲元素,依次对每一级进行处理;
- 构造合成事件;
- 将每一级的合成事件存取在事件队列,遍历事件队列;
- 通过isPropagationStopped判断当前事件是否执行了阻止冒泡方法;
- 如果有阻止则停止遍历,否则通过executeDispatch执行合成事件;
- 执行完成则释放;
- 合成事件
- 调用EventPluginHub中的extractEvents方法;
- 循环所有类型的eventPlugin,处理不同事件的一个工具;
- 每个eventPlugin根据不同的事件类型返回不同的事件迟;
- 在事件池中取出合成事件,没有事件池则会创建;
- 根据唯一标识和事件类型取出回调函数;
- 返回带有合成事件参数的回调函数
react设计思路与理念
- 编写简单直观的代码
- 简化可复用的组件
- 虚拟dom
- 函数式编程
哪些方法会触发react的重新渲染?重新渲染会做些什么?
- setState进行状态更新时,但是传递null就不会触发;
- 父组件重新渲染也会触发子组件的重新渲染;
- 渲染过程中还会进行新旧vNode对比即domDiff,将两个虚拟dom进行深度优先遍历进行标记,再次对比就会根据标记进行查找,遍历到了差异对象后根据对应规则进行更新;
react的优缺点?使用过程中遇到的问题?
- react速度快,因为vDom与diff算法;
- 单向数据流;
- 可以ssr;
- 模块化,独立的组件;
- 生态圈好,大公司维护;
- 并不是一个完整的mvc框架,重点在view层;
- setState伪异步的方式导致有时数据渲染更新问题;
- 首屏加载事件长;
- 父节点更新导致子节点也更新;
react中事件代理?原理?
react中其实是基于vdom实现了合成事件进行了事件的封装,通过事件委派和自动绑定进行实现。事件委派是指react把事件绑定到结构的最外层,使用了统一的事件管理方式然后通过事件监听器维持组件内部的事件监听和回调函数; react组件中每个方法的上下文都会指向该组件的实例,即自动绑定this为当前的组件。
对虚拟dom的理解?
本质来说,其实就是一个JavaScript对象,通过对象的方式表示DOM结构,将页面的状态抽象为js对象,配合不同的渲染方式实现跨平台渲染,再通过事务处理机制,将多次修改dom的结果一次更新,有效的减少了页面渲染次数,减少了dom的重绘重排提高了渲染性能。
使用虚拟dom的原因:
- 保证性能下限,再不是手动优化的情况下,提供过的去的性能,因为dom渲染不可避免大量的dom渲染始终会有性能问题,所以说提供过的去的性能;
- 可以跨平台,因为转换为了js对象,则在任何可以运行js的地方都可以使用,也可以实现ssr进行服务端渲染;
- 首次渲染因为多了一层虚拟dom的处理,会比innerHMTL慢;
pureComponent与Component的区别?
p与c除了在shouldComUpdate的方法上的实现外几乎一样,pure中代替我们通过props和state的浅对比实现了should;
p的优缺点:不需要开发者自己去写should,可以通过内部自己判断实现一定的性能提升,因为用的是浅对比,所以深层的数据可能会产生错误的判断;
react hook的理解?
Hook是16.8新增的特性,可以通过函数的方式直接写一个组件,并提供了useXXX相关的API进行状态的变化更新;
主要是为了解决共享状态逻辑复用,hook中没有生命周期的概念。具体的API:useState、useEffect、useContext、useReducer((state, action) => newState的reducer,并返回与dispatch方法配对的当前状态)、useCallback、useMemo、useRef、useMutationEffect、useLayoutEffect(dom改变后同步触发,使用它来从dom读取布局并同步重新渲染)
react中props改变后在哪些生命周期中处理?
- getDerivedStateFromProps返回一个对象用于更新state,返回null则不更新;
- shouldComponentUpdate根据返回值判断组件是否受props影响;
- getSnapshotBeforeUpdate在最近一次渲染输出之前调用;
- componentDidUpdate对比props变化;
react 有状态组件和无状态组件的区别?
- 有状态组件
- 一个类组件,有继承,可以使用this,可以使用生命周期,内部使用state维护自身状态的变化,有状态组件根据外部组件传入的props和自身的state进行渲染;
- 使用场景:需要用到状态的,需要使用状态操作组件的
- 无状态组件
- 不依赖状态,可以是类组件、函数组件,更高的性能,组件内不维护state;
- 简化代码专注render,无生命周期性能更好,无副作用渲染只取决于props,视图与数据分离;
- 无法使用ref;无生命周期等;
mobx与redux区别?
- 共同点:为了解决状态管理,统一维护管理应用状态,将store层与react组件链接;
- 区别:
- redux:action、reducer方式,通过action更新state
- mobx:action,store进行集中管理;观察者模式;
react setState原理?
react的类组件是通过state管理内部状态,可以通过setState和$forceUpdate进行更新,setState其实最终还是走的forceUpdate。每个类组件都有一个updater对象进行管理state的变化,当调用setState传入partialState时,会将partialState存入updater中的pendingState中,此时updater又会调用emitUpdate来决定当前是否立即更新,判断条件是是否有nextProps,或者updateQueue的isPending是否开启。当这些方法执行完毕则更新update,调用update的componentUpdate,判断should的生命周期其实也是判断forceUpdate是否执行。
react diff算法?
virtual dom策略:Web UI中dom节点跨层级的移动较少可以忽略不计;拥有相同类的两个组件将会形成相似的树形结构,拥有不同类的两个组件也会生成不同的树形结构;对于同一层级的一组子节点,可以通过唯一id进行区分。
基于以上的策略,react分别对tree diff、component diff、element diff进行了算法优化;
- tree diff:对树进行了分层比较,两棵树只会对同一层级的节点进行比较,react通过updateDepth 对虚拟dom进行层级控制,只会对同一个父节点下所有子节点进行比较,当发现节点不存在,则该节点与子节点会被完全删除,不会进行进一步比较。
- component diff:同一类型组件则按照原策略比较vdom,如果不是则判断该组件是否为dirty component,从而替换整个组件下的所有子节点;对于同类型组件,则可能不变化则不进行对比;
- element diff:当节点处于同一层级时,diff则进行三种节点操作,插入、移动、删除。
webpack优化?
- 使用高版本的webpack:v8带来的优化;自己内部算法;ast直接在loader传递;字符串方法代替正则;
- 使用thread-loader、多线程打包;缩小打包区域include;noParse属性对不需要解析的库进行忽略;合理使用alias;cache-loader缓存;content hash方式命名;
- 动态索引链接dll plugin进行分包;terser-webpack-plugin开启parallel多线程打包,进行代码压缩;
- 使用CDN;mini-css进行css拆分;splitChunksPlugin进行js公共代码拆分;
- 进行图片压缩,image-webpack-plugin; analyse分析包大小;speed-measure分析打包时间;
webpack压缩、打包实现原理?
- 压缩原理:去掉注释,去掉不必要的换行、空格,规范变量名,简化变量名;
- 打包原理:根据entry入口,找到各自依赖模块,进行loader解析编译,转换ast,处理bundle输出;
开发环境中热更新优化?
关闭文件hash功能;关闭压缩;使用source-map:eval、eval-cheap;多线程,开启缓存;
webpack持久化缓存?
打包依赖和运行时依赖打包到不同的chunk,即拆分chunks;使用动态引入进行延迟加载;保证hash稳定,可设置打包文件名称为content-hash;
webpack打包时的hash值产生?
- hash:代表每次打包生成新的hash值,设置了该项则打包的文件名称的hash值相同;
- chunkhash:基于入口文件及其关联的chunk生成,某个文件改的则只会影响与其关联的文件重新打包产生新的hsah值,不会影响不关联的;
- contenthash:根据文件内容创建hash值,文件内容不变则hash值不改变;
webpack热更新原理?
- 概念
- webpack complier 将js编译为bundle;
- bundle server 提供文件在浏览器访问的服务器;
- HMR server 将热更新文件输出给hmr runtime;
- hmr runtime 会被注入到bundle.js中,与hmr server建立一个socket通信,接收文件变化进行响应;
- 原理
- 启动阶段:启动devserver时也会启动一个hrm server以及bundle server,compiler将打包文件发送给bundle server,浏览器通过bundle server获取到bundle.js;
- 文件发生变化,complier 重新编译发送给hrm server,hrm server接收文件判断哪些文件发生了变化,将变化通知给hrm runtime,hrm runtime进行代码更新;
webpack plugin实现原理?
webpack本质是一种事件流机制,核心模块有tabable钩子函数+complier编译+compilation 创建bundles;webpack 在编译代码过程中,会触发一系列 Tapable 钩子事件,插件所做的,就是找到相应的钩子,往上面挂上自己的任务,也就是注册事件,这样,当 webpack 构建的时候,插件注册的事件就会随着钩子的触发而执行了。
complier对象代表了完整的webpack环境配置,loader和plugin内部都需要用到,这个对象在启动webpack时就会被创建,包括了options、loader、plugin。https://segmentfault.com/a/1190000021593923
webpack打包流程?以及生命周期?
- 初始化参数:将命令行参数与
webpack 配置文件
合并、解析得到参数对象。参数对象传给 webpack 执行得到Compiler
对象。 - 开始编译:执行
Compiler
的run
方法开始编译。每次执行run
编译都会生成一个Compilation
对象。 - 确定入口:触发
Compiler
的make
方法分析入口文件, - 编译模块:调用
compilation
的buildModule
方法创建主模块对象。 - 完成编译:生成入口文件
AST(抽象语法树)
,通过AST
分析和递归加载依赖模块。 - 输出资源:所有模块分析完成后,执行
compilation
的seal
方法对每个chunk
进行整理、优化、封装。 - 输出文件:最后执行
Compiler
的emitAssets
方法把生成的文件输出到output
的目录中。
按需加载组件是怎么配置的?
babel-plugin-import,在babel配置文件中配置;
webpack中css与style loader区别?
css loader处理css文件,如果在JS中导入了css,那么就需要使用 css-loader 来识别这个模块,通过特定的语法规则进行转换内容最后导出,css-loader会处理 import
/ require
() @import
/ url
引入的内容
style loader把js中import导入的样式文件代码打包到js中,运行js是自动插入到style标签,style-loader是不能单独使用的,应为它并不负责解析 css 之前的依赖关系,每个loader的功能都是单一的,各自拆分独立
webpack中file与url loader区别?
url-loader和file-loader作用相似,不同之处在于处理不同大小图片时的方式:file-loader在处理任何大小文件时,都会返回publicPath;url-loader可以设置一个阈值,文件大于阈值时,与file-loader一样返回publicPath,小于阈值时,返回文件base64形式编码;
常用的loader与plugin?
- loader:file、url、image、babel、css、style、postcss、thread、cache、eslint、less、scss、html等;
- plugin:ingnore、terser-webpack、mini-css-extract、clean、copy、speed-measure、html-webpack、hotmodule、dllPlugin、optimize-css-asstets、webpack-bundle-analuzer、compression压缩gzip、happyPack、friendly、DefinePlugin等;
tree-shaking?
是一种通过清除多余代码的方式优化项目打包体积的技术。Tree-shaking的本质是消除无用的js代码。无用代码消除在广泛存在于传统的编程语言编译器中,编译器可以判断出某些代码根本不影响输出,然后消除这些代码,这个称之为DCE(dead code elimination),Tree-shaking 是 DCE 的一种新的实现,Javascript同传统的编程语言不同的是,javascript绝大多数情况需要通过网络进行加载,然后执行,加载的文件大小越小,整体执行时间更短,所以去除无用代码以减少文件体积,对javascript来说更有意义。
Dead Code 一般具有以下几个特征:代码不会被执行,不可到达;代码执行的结果不会被用到;代码只会影响死变量(只写不读);
tree-shaking的消除原理是依赖于ES6的模块特性,ES6模块依赖关系是确定的,和运行时的状态无关,可以进行可靠的静态分析,这就是tree-shaking的基础。tree-shaking不支持动态导入,只支持纯静态导入;
ES6 module 特点:
- 只能作为模块顶层的语句出现
- import 的模块名只能是字符串常量
- import binding 是 immutable的
模块化标准的理解?
- commonjs:
- 通过require方式同步加载模块,通过exports 或者mpdule.exports导出模块需要暴露的接口;每个文件就是一个模块有自己独立的作用域、文件内的变量,属性函数,不可被外界访问;node中常用;在导出时属于值的拷贝;加载的直接是整个模块;
- 会缓存引用值,二次使用会读取缓存;运行时加载;
- 主要用于服务端、运行时加载、this指向当前模块;
- esmodule:
- 模块通过import方式导入,通过export default导出,采用了实时绑定的方式,导入导出的值都指向内存地址;可以单独加载某个方法、变量;
- 动态引用,没有缓存值;编译时加载输出;
- 主要用于浏览器端、编译时加载、异步加载、按需加载,执行时获取值;
前端性能提升哪些方面?
- 静态资源优化:减少静态资源体积;
- 接口访问优化:http持久链接connection:keep-alive,后端接口统一,前端持久化缓存;
- 页面渲染优化:减少dom操作,优先css渲染,虚拟dom,减少页面重绘、重排;