先自我介绍一下,小编浙江大学毕业,去过华为、字节跳动等大厂,目前阿里P7
深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年最新Web前端全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上前端开发知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新
如果你需要这些资料,可以添加V获取:vip1024c (备注前端)
正文
Vue 实现一个高阶组件
高阶组件就是一个函数,且该函数接受一个组件作为参数,并返回一个新的组件。在不改变对象自身的前提下在程序运行期间动态的给对象添加一些额外的属性或行为。
// 高阶组件(HOC)接收到的 props 应该透传给被包装组件即直接将原组件prop传给包装组件
// 高阶组件完全可以添加、删除、修改 props
export default function Console(BaseComponent) {
return {
props: BaseComponent.props,
mounted() {
console.log(“高阶组件”);
},
render(h) {
console.log(this);
// 将 this.$slots 格式化为数组,因为 h 函数第三个参数是子节点,是一个数组
const slots = Object.keys(this.$slots)
.reduce((arr, key) => arr.concat(this.$slots[key]), [])
.map((vnode) => {
vnode.context = this._self; // 绑定到高阶组件上,vm:解决具名插槽被作为默认插槽进行渲染
return vnode;
});
// 透传props、透传事件、透传slots
return h(
BaseComponent,
{
on: this.$listeners,
attrs: this.$attrs, // attrs 指的是那些没有被声明为 props 的属性
props: this.$props,
},
slots
);
},
};
}
Vue.component()、Vue.use()、this.$xxx()
Vue.component()方法注册全局组件。
-
第一个参数是自定义元素名称,也就是将来在别的组件中使用这个组件的标签名称。
-
第二个参数是将要注册的Vue组件。
import Vue from ‘vue’;
// 引入loading组件
import Loading from ‘./loading.vue’;
// 将loading注册为全局组件,在别的组件中通过标签使用Loading组件
Vue.component(‘loading’, Loading);
Vue.use注册插件,这接收一个参数。这个参数必须具有install方法。Vue.use函数内部会调用参数的install方法。
-
如果插件没有被注册过,那么注册成功之后会给插件添加一个installed的属性值为true。Vue.use方法内部会检测插件的installed属性,从而避免重复注册插件。
-
插件的install方法将接收两个参数,第一个是参数是Vue,第二个参数是配置项options。
-
在install方法内部可以添加全局方法或者属性
import Vue from ‘vue’;
// 这个插件必须具有install方法
const plugin = {
install (Vue, options) {
// 添加全局方法或者属性
Vue.myGlobMethod = function () {};
// 添加全局指令
Vue.directive();
// 添加混入
Vue.mixin();
// 添加实例方法
Vue.prototype.$xxx = function () {};
// 注册全局组件
Vue.component()
}
}
// Vue.use内部会调用plugin的install方法
Vue.use(plugin);
将Hello方法挂载到Vue的prototype上.
import Vue from ‘vue’;
import Hello from ‘./hello.js’;
Vue.prototype.$hello = Hello;
vue组件中就可以this.$hello(‘hello world’)
Vue父组件传递props数据,子组件修改参数
-
父子组件传值时,父组件传递的参数,数组和对象,子组件接受之后可以直接进行修改,并且父组件相应的值也会修改。控制台中发出警告。
-
如果传递的值是字符串,直接修改会报错。单向数据流,每次父级组件发生更新时,子组件中所有的 prop 都将会刷新为最新的值。
如果子组件想修改prop中数据:
-
定义一个局部变量,使用prop的值赋值
-
定义一个计算属性,处理prop的值并返回
Vue父子组件生命周期执行顺序
加载渲染过程
父beforeCreate -> 父created -> 父beforeMount-> 子beforeCreate -> 子created -> 子beforeMount -> 子mounted -> 父mounted
子组件更新过程
父beforeUpdate -> 子beforeUpdate -> 子updated -> 父updated
父组件更新过程
父beforeUpdate -> 父updated
销毁过程
父beforeDestroy -> 子beforeDestroy -> 子destroyed -> 父destroyed
Vue 自定义指令
自定义指令提供了几个钩子函数:bind
:指令第一次绑定到元素时调用inserted
:被绑定元素插入父节点时调用update
:所在组件的 VNode 更新时调用
使用slot后可以在子组件内显示插入的新标签
webpack 及工程化
============
webpack的生命周期,及钩子
compiler(整个生命周期 [kəmˈpaɪlər]) 钩子 https://webpack.docschina.org/api/compiler-hooks/compilation(编译 [ˌkɑːmpɪˈleɪʃn]) 钩子
compiler
对象包含了Webpack 环境所有的的配置信息。这个对象在启动 webpack 时被一次性建立,并配置好所有可操作的设置,包括 options,loader 和 plugin。当在 webpack 环境中应用一个插件时,插件将收到此 compiler 对象的引用。可以使用它来访问 webpack 的主环境。
compilation
对象包含了当前的模块资源、编译生成资源、变化的文件等。当运行webpack 开发环境中间件时,每当检测到一个文件变化,就会创建一个新的 compilation,从而生成一组新的编译资源。compilation 对象也提供了很多关键时机的回调,以供插件做自定义处理时选择使用。
compiler
代表了整个webpack
从启动到关闭的生命周期
,而compilation
只是代表了一次新的编译过程
webpack 编译过程
Webpack 的编译流程是一个串行的过程,从启动到结束会依次执行以下流程:
-
初始化参数:从配置文件和 Shell 语句中读取与合并参数,得出最终的参数;
-
开始编译:用上一步得到的参数初始化
Compiler
对象,加载所有配置的插件,执行对象的run
方法开始执行编译; -
确定入口:根据配置中的
entry
找出所有的入口文件; -
编译模块:从入口文件出发,调用所有配置的
Loader
对模块进行翻译,再找出该模块依赖的模块,再递归本步骤直到所有入口依赖的文件都经过了本步骤的处理; -
完成模块编译:在经过第4步使用
Loader
翻译完所有模块后,得到了每个模块被翻译后的最终内容以及它们之间的依赖关系; -
输出资源:根据入口和模块之间的依赖关系,组装成一个个包含多个模块的
Chunk
,再把每个Chunk
转换成一个单独的文件加入到输出列表,这步是可以修改输出内容的最后机会; -
输出完成:在确定好输出内容后,根据配置确定输出的路径和文件名,把文件内容写入到文件系统。
优化项目的webpack打包编译过程
1.构建打点:构建过程中,每一个Loader
和 Plugin
的执行时长,在编译 JS、CSS 的 Loader 以及对这两类代码执行压缩操作的 Plugin上消耗时长 。一款工具:speed-measure-webpack-plugin
2.缓存:大部分 Loader 都提供了cache
配置项。cache-loader
,将 loader 的编译结果写入硬盘缓存
3.多核编译,happypack
项目接入多核编译,理解为happypack
将编译工作灌满所有线程
4.抽离,webpack-dll-plugin
将这些静态依赖从每一次的构建逻辑中抽离出去,静态依赖单独打包,Externals
将不需要打包的静态资源从构建逻辑中剔除出去,使用CDN 引用
5.tree-shaking
,虽然依赖了某个模块,但其实只使用其中的某些功能。通过 tree-shaking
,将没有使用的模块剔除,来达到删除无用代码的目的。
首屏加载优化
路由懒加载:改为用import
引用,以函数的形式动态引入,可以把各自的路由文件分别打包,只有在解析给定的路由时,才会下载路由组件;
element-ui
按需加载:引用实际上用到的组件 ;
组件重复打包:CommonsChunkPlugin
配置来拆包,把使用2次及以上的包抽离出来,放进公共依赖文件,首页也有复用的组件,也会下载这个公共依赖文件;
gzip: 拆完包之后,再用gzip
做一下压缩,关闭sourcemap。
UglifyJsPlugin: 生产环境,压缩混淆代码,移除console代码
CDN部署静态资源:静态请求打在nginx时,将获取静态资源的地址进行重定向CDN内容分发网络
移动端首屏加载可以使用骨架屏,自定义loading,首页单独做服务端渲染。
如何进行前端性能优化(21种优化+7种定位方式)
webpack 热更新机制
热更新流程总结:
-
启动本地
server
,让浏览器可以请求本地的静态资源 -
页面首次打开后,服务端与客户端通过 websocket建立通信渠道,把下一次的 hash 返回前端
-
客户端获取到hash,这个hash将作为下一次请求服务端 hot-update.js 和 hot-update.json的hash
-
修改页面代码后,Webpack 监听到文件修改后,开始编译,编译完成后,发送 build 消息给客户端
-
客户端获取到hash,成功后客户端构造hot-update.js script链接,然后插入主文档
-
hot-update.js 插入成功后,执行hotAPI 的 createRecord 和 reload方法,获取到 Vue 组件的 render方法,重新 render 组件, 继而实现 UI 无刷新更新。
webpack的 loader和plugin介绍,css-loader,style-loader的区别
loader 它就是一个转换器,将A文件进行编译形成B文件,
plugin ,它就是一个扩展器,来操作的是文件,针对是loader结束后,webpack打包的整个过程,它并不直接操作文件,会监听webpack打包过程中的某些节点(run, build-module, program)
Babel 能把ES6/ES7的代码转化成指定浏览器能支持的代码。
css-loader
的作用是把 css文件进行转码style-loader
: 使用<style>
将css-loader
内部样式注入到我们的HTML页面
先使用 css-loader
转码,然后再使用 style-loader
插入到文件
如何编写一个webpack的plugin?
https://segmentfault.com/a/1190000037513682
webpack 插件的组成:
-
一个 JS 命名函数或一个类(可以想下我们平时使用插件就是
new XXXPlugin()
的方式) -
在插件类/函数的 (prototype) 上定义一个 apply 方法。
-
通过 apply 函数中传入 compiler 并插入指定的事件钩子,在钩子回调中取到 compilation 对象
-
通过 compilation 处理 webpack 内部特定的实例数据
-
如果是插件是异步的,在插件的逻辑编写完后调用 webpack 提供的 callback
为什么 Vite 启动这么快
Webpack 会先打包
,然后启动开发服务器,请求服务器时直接给予打包结果。
而 Vite 是直接启动
开发服务器,请求哪个模块再对该模块进行实时编译
。
Vite 将开发环境下的模块文件,就作为浏览器要执行的文件,而不是像 Webpack 那样进行打包合并
。
由于 Vite 在启动的时候不需要打包
,也就意味着不需要分析模块的依赖
、不需要编译
。因此启动速度非常快。当浏览器请求某个模块时,再根据需要对模块内容进行编译。
你的脚手架是怎么做的
使用 download-git-repo
下载仓库代码democommander
:完整的 node.js
命令行解决方案。声明program
,使用.option()
方法来定义选项Inquirer.js
:命令行用户界面的集合。
前端监控
前端监控通常包括行为监控(PV/UV,埋点接口统计)、异常监控、性能监控。
一个监控系统,大致可以分为四个阶段:日志采集、日志存储、统计与分析、报告和警告。
错误监控
Vue专门的错误警告的方法 Vue.config.errorHandler
,(Vue提供只能捕获其页面生命周期内的函数,比如created,mounted)
Vue.config.errorHandler = function (err) {
console.error(‘Vue.error’,err.stack)
// 逻辑处理
};
框架:betterjs,fundebug(收费) 捕获错误的脚本要放置在最前面,确保可以收集到错误信息 方法:
-
window.onerror()
当有js运行时错误触发时,onerror可以接受多个参数(message, source, lineno, colno, error)。 -
window.addEventListener('error'), function(e) {}, true
会比window.onerror先触发,不能阻止默认事件处理函数的执行,但可以全局捕获资源加载异常的错误
前端JS错误捕获–sourceMap
如何监控网页崩溃?**崩溃和卡顿有何差别?**监控错误
-
Service Worker 有自己独立的工作线程,与网页区分开,网页崩溃了,Service Worker 一般情况下不会崩溃;
-
Service Worker 生命周期一般要比网页还要长,可以用来监控网页的状态;
卡顿:加载中,渲染遇到阻塞
性能监控 && 性能优化
性能指标:
-
FP
(首次绘制) -
FCP
(首次内容绘制 First contentful paint) -
LCP
(最大内容绘制时间 Largest contentful paint) -
FPS
(每秒传输帧数) -
TTI
(页面可交互时间 Time to Interactive) -
HTTP
请求响应时间 -
DNS
解析时间 -
TCP
连接时间
性能数据采集需要使用 window.performance API
, JS库 web-vitals
:import {getLCP} from 'web-vitals'
;
// 重定向耗时
redirect: timing.redirectEnd - timing.redirectStart,
// DOM 渲染耗时
dom: timing.domComplete - timing.domLoading,
// 页面加载耗时
load: timing.loadEventEnd - timing.navigationStart,
// 页面卸载耗时
unload: timing.unloadEventEnd - timing.unloadEventStart,
// 请求耗时
request: timing.responseEnd - timing.requestStart,
// 获取性能信息时当前时间
time: new Date().getTime(),
// DNS查询耗时
domainLookupEnd - domainLookupStart
// TCP链接耗时
connectEnd - connectStart
// request请求耗时
responseEnd - responseStart
// 解析dom树耗时
domComplete - domInteractive
// 白屏时间
domloadng - fetchStart
// onload时间
loadEventEnd - fetchStart
性能优化常用手段:缓存技术、 预加载技术、 渲染方案。
-
缓存 :主要有 cdn、浏览器缓存、本地缓存以及应用离线包
-
预加载 :资源预拉取(prefetch)则是另一种性能优化的技术。通过预拉取可以告诉浏览器用户在未来可能用到哪些资源。
- prefetch支持预拉取图片、脚本或者任何可以被浏览器缓存的资源。
在head里 添加 <linkrel="prefetch"href="image.png">
-
prerender是一个重量级的选项,它可以让浏览器提前加载指定页面的所有资源。
-
subresource可以用来指定资源是最高优先级的。当前页面需要,或者马上就会用到时。
- 渲染方案:
-
静态渲染(SR)
-
前端渲染(CSR)
-
服务端渲染(SSR)
-
客户端渲染(NSR):NSR 数据请求,首屏数据请求和数据线上与 webview 的一个初始化和框架 JS 初始化并行了起来,大大缩短了首屏时间。
640.png
常见的六种设计模式以及应用场景
https://www.cnblogs.com/whu-2017/p/9471670.html
观察者模式的概念
观察者模式模式,属于行为型模式的一种,它定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主体对象在状态变化时,会通知所有的观察者对象。
发布订阅者模式的概念
发布-订阅模式,消息的发送方,叫做发布者(publishers),消息不会直接发送给特定的接收者,叫做订阅者。意思就是发布者和订阅者不知道对方的存在。需要一个第三方组件,叫做信息中介,它将订阅者和发布者串联起来,它过滤和分配所有输入的消息。换句话说,发布-订阅模式用来处理不同系统组件的信息交流,即使这些组件不知道对方的存在。
需要一个第三方组件,叫做信息中介,它将订阅者和发布者串联起来
工厂模式 主要是为创建对象提供了接口。场景:在编码时不能预见需要创建哪种类的实例。
代理模式 命令模式
单例模式
保证一个类仅有一个实例,并提供一个访问它的全局访问点。(window)
Http 及浏览器相关
===========
七层网络模型
应用层、表示层、会话层、传输层、网络层、数据链路层、物理层
TCP:面向连接、传输可靠(保证数据正确性,保证数据顺序)、用于传输大量数据(流模式)、速度慢,建立连接需要开销较多(时间,系统资源) 。(应用场景:HTP,HTTP,邮件)
UDP:面向非连接、传输不可靠、用于传输少量数据(数据包模式)、速度快 ,可能丢包(应用场景:即时通讯)
是否连接 面向连接 面向非连接
传输可靠性 可靠 不可靠
应用场合 少量数据 传输大量数据
https
客户端先向服务器端索要公钥,然后用公钥加密信息,服务器收到密文后,用自己的私钥解密。服务器公钥放在数字证书中。
url到加载渲染全过程
-
DNS域名解析。
-
TCP三次握手,建立接连。
-
发送HTTP请求报文。
-
服务器处理请求返回响应报文。
-
浏览器解析渲染页面。
-
四次挥手,断开连接。
DNS 协议提供通过域名查找 IP地址
,或逆向从 IP地址反查域名
的服务。DNS 是一个网络服务器,我们的域名解析简单来说就是在 DNS 上记录一条信息记录。
TCP 三次握手,四次挥手:握手挥手都是客户端发起,客户端结束。三次握手与四次挥手详解
负载均衡:请求在进入到真正的应用服务器前,可能还会先经过负责负载均衡的机器,它的作用是将请求合理地分配到多个服务器上
,转发HTTP请求;同时具备具备防攻击等功能。可分为DNS负载均衡,HTTP负载均衡,IP负载均衡,链路层负载均衡等。
Web Server:请求经过前面的负载均衡后,将进入到对应服务器上的 Web Server,比如 Apache
、Tomcat
反向代理是工作在 HTTP 上的,一般都是 Nginx
。全国各地访问baidu.com就肯定要通过代理访问,不可能都访问百度的那台服务器。 (VPN正向代理,代理客户端)
浏览器解析渲染过程:返回的html传递到浏览器后,如果有gzip会先解压,找出文件编码格式,外链资源的加载 html从上往下解析,遇到js,css停止解析渲染,直到js执行完成。解析HTML,构建DOM树 解析CSS,生成CSS规则树 合并DOM树和CSS规则,生成render树去渲染
不会引起DOM树变化,页面布局变化,改变元素样式的行为叫重绘
引起DOM树结构变化,页面布局变化的行为叫回流
GUI渲染线程
负责渲染浏览器界面HTML元素,当界面需要 重绘(Repaint)
或由于某种操作引发 回流(reflow)
时,该线程就会执行。在Javascript引擎运行脚本期间,GUI渲染线程都是处于挂起状态的,也就是说被”冻结”了. 直到JS程序执行完成,才会接着执行。因此如果JS执行的时间过长,这样就会造成页面的渲染不连贯,导致页面渲染加载阻塞的感觉。JavaScript是可操纵DOM的,如果在修改这些元素属性同时渲染界面,渲染前后元素数据可能不一致
GPU绘制多进程的浏览器:主控进程,插件进程,GPU,tab页(浏览器内核)多线程的浏览器内核:每一个tab页面可以看作是浏览器内核进程,然后这个进程是多线程的。
它有几大类子线程:
-
GUI线程
-
JS引擎线程
-
事件触发线程
-
定时器线程
-
HTTP请求线程
http1 跟HTTP2
http2
多路复用:相同域名多个请求,共享同一个TCP连接,降低了延迟
请求优先级:给每个request设置优先级
二进制传输;之前是用纯文本传输
数据流:数据包不是按顺序发送,对数据包做标记。每个请求或回应的所有数据包成为一个数据流,
服务端推送:可以主动向客户端发送消息。
头部压缩:减少包的大小跟数量
HTTP/1.1 中的管道( pipeline)传输中如果有一个请求阻塞
了,那么队列后请求也统统被阻塞住了 HTTP/2 多请求复用一个TCP连接,一旦发生丢包,就会阻塞住所有的 HTTP 请求。HTTP/3 把 HTTP 下层的 TCP 协议改成了 UDP!http1 keep alive 串行传输
http 中的 keep-alive 有什么作用
响应头中设置 keep-alive
可以在一个 TCP 连接上发送多个 http 请求
浏览器缓存策略
强缓存:cache-control;no-cache max-age=<10000000>;expires;其中Cache-Conctrol的优先级比Expires高;
控制强制缓存的字段分别是Expires和Cache-Control,如果客户端的时间小于Expires的值时,直接使用缓存结果。
协商缓存:Last-Modified / If-Modified-Since和Etag / If-None-Match,其中Etag / If-None-Match的优先级比Last-Modified / 首次请求,服务器会在返回的响应头中加上Last-Modified字段,表示资源最后修改的时间。
浏览器再次请求时,请求头中会带上If-Modified-Since字段,比较两个字段,一样则证明资源未修改,返回304,否则重新返回资源,状态码为200;
垃圾回收机制:
标记清除
:进入执行环境的变量都被标记,然后执行完,清除这些标记跟变量。查看变量是否被引用。
引用计数
:会记录每个值被引用的次数,当引用次数变成0后,就会被释放掉。
前端安全
同源策略:如果两个 URL 的协议、域名和端口都相同,我们就称这两个 URL 同源。因为浏览器有cookies
。
-
XSS:跨站脚本攻击(Cross Site Scripting) input, textarea等所有可能输入文本信息的区域,输入
<script src="http://恶意网站"></script>
等,提交后信息会存在服务器中 。 -
CSRF:跨站请求伪造 。引诱用户打开黑客的网站,在黑客的网站中,利用用户的登录状态发起的跨站请求。
A
站点img
的src=B
站点的请求接口,可以访问;解决:referer
携带请求来源
访问该页面后,表单自动提交, 模拟完成了一次POST操作,发送post请求
解决:后端注入一个随机串
到Cookie
,前端请求取出随机串添加传给后端。
-
http 劫持:电信运营商劫持
-
SQL注入
-
点击劫持:诱使用户点击看似无害的按钮(实则点击了透明
iframe
中的按钮) ,解决后端请求头加一个字段X-Frame-Options
-
文件上传漏洞 :服务器未校验上传的文件
CSS 及 HTML
==========
什么是BFC(块级格式化上下文)、IFC(内联格式化上下文 )、FFC(弹性盒模型)
BFC(Block formatting context)
,即块级格式化上下文
,它作为HTML页面上的一个独立渲染区域
,只有区域内元素参与渲染,且不会影响其外部元素。简单来说,可以将 BFC 看做是一个“围城”,外面的元素进不来,里面的元素出不去(互不干扰)。
一个决定如何渲染元素的容器 ,渲染规则 :
-
1、内部的块级元素会在垂直方向,一个接一个地放置。
-
2、块级元素垂直方向的距离由margin决定。属于同一个BFC的两个相邻块级元素的margin会发生重叠。
-
3、对于从左往右的格式化,每个元素(块级元素与行内元素)的左边缘,与包含块的左边缘相接触,(对于从右往左的格式化则相反)。即使包含块中的元素存在浮动也是如此,除非其中元素再生成一个BFC。
-
4、BFC的区域不会与浮动元素重叠。
-
5、BFC是一个隔离的独立容器,容器里面的子元素和外面的元素互不影响。
-
6、计算BFC容器的高度时,浮动元素也参与计算。
形成BFC的条件:
1、浮动元素,float 除 none 以外的值;
2、定位元素,position(absolute,fixed);
3、display 为以下其中之一的值 inline-block,table-cell,table-caption;
4、overflow 除了 visible 以外的值(hidden,auto,scroll);
BFC 一般用来解决以下几个问题
-
边距重叠问题
-
消除浮动问题
-
自适应布局问题
flex: 0 1 auto;
是什么意思?
元素会根据自身宽高设置尺寸。它会缩短自身以适应 flex
容器,但不会伸长并吸收 flex
容器中的额外自由空间来适应 flex
容器 。水平的主轴(main axis
)和垂直的交叉轴(cross axis
)几个属性决定按哪个轴的排列方向
-
flex-grow
:0
一个无单位数(): 它会被当作<flex-grow>的值。
-
flex-shrink
:1
一个有效的**宽度(width)**值: 它会被当作<flex-basis>的值。
-
flex-basis
:auto
关键字none
,auto
或initial
.
放大比例、缩小比例、分配多余空间之前占据的主轴空间。
避免CSS全局污染
-
scoped 属性
-
css in js
const styles = {
bar: {
backgroundColor: ‘#000’
}
}
const example = (props)=>{
}
-
CSS Modules
-
使用less,尽量少使用全局对选择器
// 选择器上>要记得写,免得污染所有ul下面的li
ul{
>li{
color:red;
}
}
CSS Modules
阮一峰 CSS Modules
CSS Modules是一种构建步骤中的一个进程。通过构建工具来使指定class
达到scope
的过程。
CSS Modules
允许使用::global(.className)
的语法,声明一个全局规则。凡是这样声明的class
,都不会被编译成哈希字符串
。:local(className)
: 做 localIdentName 规则处理,编译唯一哈希类名。
CSS Modules使用特点:
-
不使用选择器,只使用 class 名来定义样式
-
不层叠多个 class,只使用一个 class 把所有样式定义好
-
不嵌套class
盒子模型和 box-sizing
属性
width: 160px; padding: 20px; border: 8px solid orange;
标准 box-sizing: content-box;
元素的总宽度 = 160 + 20_2 + 8_2; IE的 border-box
:总宽度160
margin/padding
取百分比的值时 ,基于父元素的宽度和高度的。
css绘制三角形
- 通过border 处理
// border 处理
.class {
width: 0;
height: 0;
border-left: 50px solid transparent;
border-right: 50px solid transparent;
border-bottom: 100px solid red;
}
// 宽高+border
div {
width: 50px;
height: 50px;
border: 2px solid orange;
}
- clip-path裁剪获得
div{
clip-path: polygon(0 100%, 50% 0, 100% 100%);
}
- 渐变linear-gradient 实现
div {
width: 200px;
height: 200px;
background:linear-gradient(to bottom right, #fff 0%, #fff 49.9%, rgba(148,88,255,1) 50%,rgba(185,88,255,1) 100%);
}
CSS实现了三角形后如何给三角形添加阴影
???
CSS两列布局的N种实现
两列布局分为两种,一种是左侧定宽、右侧自适应,另一种是两列都自适应(即左侧宽度由子元素决定,右侧补齐剩余空间)。
- 左侧定宽、右侧自适应如何实现
// 两个元素都设置dislpay:inline-block
.left {
display: inline-block;
width: 100px;
height: 200px;
background-color: red;
vertical-align: top;
}
.right {
display: inline-block;
width: calc(100% - 100px);
height: 400px;
background-color: blue;
vertical-align: top;
}
// 两个元素设置浮动,右侧自适应元素宽度使用calc函数计算
.left{
float: left;
width: 100px;
height: 200px;
background-color: red;
}
.right{
float: left;
width: calc(100% - 100px);
height: 400px;
background-color: blue;
}
// 父元素设置display:flex,自适应元素设置flex:1
.box{
height: 600px;
width: 100%;
display: flex;
}
.left{
width: 100px;
height: 200px;
background-color: red;
}
.right{
flex: 1;
height: 400px;
background-color: blue;
}
// 父元素相对定位,左侧元素绝对定位,右侧自适应元素设置margin-left的值大于定宽元素的宽度
.left{
position: absolute;
width: 100px;
height: 200px;
background-color: red;
}
.right{
margin-left: 100px;
height: 400px;
background-color: blue;
}
- 左右两侧元素都自适应
// flex布局 同上
// 父元素设置display:grid; grid-template-columns:auto 1fr;(这个属性定义列宽,auto关键字表示由浏览器自己决定长度。fr是一个相对尺寸单位,表示剩余空间做等分)grid-gap:20px(行间距)
.parent{
display:grid;
grid-template-columns:auto 1fr;
grid-gap:20px
}
.left{
background-color: red;
height: 200px;
}
.right{
height:300px;
background-color: blue;
}
// 浮动+BFC 父元素设置overflow:hidden,左侧定宽元素浮动,右侧自适应元素设置overflow:auto创建BFC
.box{
height: 600px;
width: 100%;
overflow: hidden;
}
.left{
float: left;
width: 100px;
height: 200px;
background-color: red;
}
.right{
overflow: auto;
height: 400px;
background-color: blue;
}
CSS三列布局
-
float布局:左边左浮动,右边右浮动,中间margin:0 100px;
-
Position布局: 左边left:0; 右边right:0; 中间left: 100px; right: 100px;
-
table布局: 父元素 display: table; 左右 width: 100px; 三个元素display: table-cell;
-
弹性(flex)布局:父元素 display: flex; 左右 width: 100px;
-
网格(gird)布局:
// gird提供了 gird-template-columns、grid-template-rows属性让我们设置行和列的高、宽
.div{
width: 100%;
display: grid;
grid-template-rows: 100px;
grid-template-columns: 300px auto 300px;
}
常见场景及问题
=======
app与H5 如何通讯交互的?
// 兼容IOS和安卓
callMobile(parameters,messageHandlerName) {
//handlerInterface由iOS addScriptMessageHandler与andorid addJavascriptInterface 代码注入而来。
if (/(iPhone|iPad|iPod|iOS)/i.test(navigator.userAgent)) {
// alert(‘ios’)
window.webkit.messageHandlers[messageHandlerName].postMessage(JSON.stringify(parameters))
} else {
// alert(‘安卓’)
//安卓传输不了js json对象,只能传输string
window.webkitmessageHandlerName
}
}
由app将原生方法注入到window上供js调用
messageHandlerName
约定的通信方法parameters
需要传入的参数
移动端适配方案
rem
是相对于HTML的根元素em
相对于父级元素的字体大小。VW,VH
屏幕宽度高度的高分比
//按照宽度375图算, 1rem = 100px;
(function (win, doc) {
function changeSize() {
doc.documentElement.style.fontSize = doc.documentElement.clientWidth / 3.75 + ‘px’;
console.log(100 * doc.documentElement.clientWidht / 3.75)
}
changeSize();
win.addEventListener(‘resize’, changeSize, false);
})(window, document);
代码编程相关
======
实现发布订阅
/* Pubsub */
function Pubsub(){
//存放事件和对应的处理方法
this.handles = {};
}
Pubsub.prototype = {
//传入事件类型type和事件处理handle
on: function (type, handle) {
if(!this.handles[type]){
this.handles[type] = [];
}
this.handles[type].push(handle);
},
emit: function () {
//通过传入参数获取事件类型
//将arguments转为真数组
var type = Array.prototype.shift.call(arguments);
if(!this.handles[type]){
return false;
}
for (var i = 0; i < this.handles[type].length; i++) {
var handle = this.handles[type][i];
//执行事件
handle.apply(this, arguments);
}
},
off: function (type, handle) {
handles = this.handles[type];
if(handles){
if(!handle){
handles.length = 0;//清空数组
}else{
for (var i = 0; i < handles.length; i++) {
var _handle = handles[i];
if(_handle === handle){
//从数组中删除
handles.splice(i,1);
}
}
}
}
}
promise怎么实现链式调用跟返回不同的状态
// MyPromise.js
// 先定义三个常量表示状态
const PENDING = ‘pending’;
const FULFILLED = ‘fulfilled’;
const REJECTED = ‘rejected’;
// 新建 MyPromise 类
class MyPromise {
constructor(executor){
// executor 是一个执行器,进入会立即执行
// 并传入resolve和reject方法
executor(this.resolve, this.reject)
}
// 储存状态的变量,初始值是 pending
status = PENDING;
// resolve和reject为什么要用箭头函数?
// 如果直接调用的话,普通函数this指向的是window或者undefined
// 用箭头函数就可以让this指向当前实例对象
// 成功之后的值
value = null;
// 失败之后的原因
reason = null;
// 更改成功后的状态
resolve = (value) => {
// 只有状态是等待,才执行状态修改
if (this.status === PENDING) {
// 状态修改为成功
this.status = FULFILLED;
// 保存成功之后的值
this.value = value;
}
}
// 更改失败后的状态
reject = (reason) => {
// 只有状态是等待,才执行状态修改
if (this.status === PENDING) {
// 状态成功为失败
this.status = REJECTED;
// 保存失败后的原因
this.reason = reason;
}
}
then(onFulfilled, onRejected) {
// 判断状态
if (this.status === FULFILLED) {
// 调用成功回调,并且把值返回
onFulfilled(this.value);
} else if (this.status === REJECTED) {
// 调用失败回调,并且把原因返回
onRejected(this.reason);
}
}
}
实现Promise.all
// Promise.all
function all(promises) {
let len = promises.length, res = []
if (len) {
return new Promise(function (resolve, reject) {
for(let i=0; i < len; i++){
let promise = promises[i];
promise.then(response => {
res[i] = response
// 当返回结果为最后一个时
if (res.length === len) {
resolve(res)
}
}, error => {
reject(error)
})
}
})
}
对象数组转换成tree数组
将entries 按照 level 转换成 result 数据结构
const entries = [
{
“province”: “浙江”, “city”: “杭州”, “name”: “西湖”
}, {
“province”: “四川”, “city”: “成都”, “name”: “锦里”
}, {
“province”: “四川”, “city”: “成都”, “name”: “方所”
}, {
“province”: “四川”, “city”: “阿坝”, “name”: “九寨沟”
}
];
const level = [“province”, “city”, “name”];
const result = [
{
value:‘浙江’,
children:[
{
value:‘杭州’,
children:[
{
value:‘西湖’
}
]
}
]
},
{
value:‘四川’,
children:[
{
value:‘成都’,
children:[
{
value:‘锦里’
},
{
value:‘方所’
}
]
},
{
value:‘阿坝’,
children:[
{
value:‘九寨沟’
}
]
}
]
},
]
思路:涉及到树形数组,采用递归遍历的方式
function transfrom(list, level) {
const res = [];
list.forEach(item => {
pushItem(res, item, 0);
});
性能优化
1.webpack打包文件体积过大?(最终打包为一个js文件)
2.如何优化webpack构建的性能
3.移动端的性能优化
4.Vue的SPA 如何优化加载速度
5.移动端300ms延迟
6.页面的重构
所有的知识点都有详细的解答,我整理成了280页PDF《前端校招面试真题精编解析》。
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
需要这份系统化的资料的朋友,可以添加V获取:vip1024c (备注前端)
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
D) {
// 调用失败回调,并且把原因返回
onRejected(this.reason);
}
}
}
实现Promise.all
// Promise.all
function all(promises) {
let len = promises.length, res = []
if (len) {
return new Promise(function (resolve, reject) {
for(let i=0; i < len; i++){
let promise = promises[i];
promise.then(response => {
res[i] = response
// 当返回结果为最后一个时
if (res.length === len) {
resolve(res)
}
}, error => {
reject(error)
})
}
})
}
对象数组转换成tree数组
将entries 按照 level 转换成 result 数据结构
const entries = [
{
“province”: “浙江”, “city”: “杭州”, “name”: “西湖”
}, {
“province”: “四川”, “city”: “成都”, “name”: “锦里”
}, {
“province”: “四川”, “city”: “成都”, “name”: “方所”
}, {
“province”: “四川”, “city”: “阿坝”, “name”: “九寨沟”
}
];
const level = [“province”, “city”, “name”];
const result = [
{
value:‘浙江’,
children:[
{
value:‘杭州’,
children:[
{
value:‘西湖’
}
]
}
]
},
{
value:‘四川’,
children:[
{
value:‘成都’,
children:[
{
value:‘锦里’
},
{
value:‘方所’
}
]
},
{
value:‘阿坝’,
children:[
{
value:‘九寨沟’
}
]
}
]
},
]
思路:涉及到树形数组,采用递归遍历的方式
function transfrom(list, level) {
const res = [];
list.forEach(item => {
pushItem(res, item, 0);
});
性能优化
1.webpack打包文件体积过大?(最终打包为一个js文件)
2.如何优化webpack构建的性能
3.移动端的性能优化
4.Vue的SPA 如何优化加载速度
5.移动端300ms延迟
6.页面的重构
所有的知识点都有详细的解答,我整理成了280页PDF《前端校招面试真题精编解析》。
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
需要这份系统化的资料的朋友,可以添加V获取:vip1024c (备注前端)
[外链图片转存中…(img-vuyb7DvF-1713629994804)]
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!