1. react 和 vue的区别 还有jquery?
(1) jquery 和 vue、react 的区别:
vue 和 react : 数据和视图分离 以数据驱动视图,只关心数据变化 dom 操作被封装(数据驱动)
jquery:依靠 dom 操作去组合业务逻辑(事件驱动)
(2)React 和 Vue 变化(都是基于js前端框架)
两者本质区别:
1. vue 本质是 MVVM 框架,由MVC发展而来;
2.React本质是前端组件化框架,由后端组件化发展而来
模版的区别:
1. Vue-使用模版(最初由Angular提出)
2. React-使用JSX
3. 模版语法上更倾向于JSX
4. 模版分离上更倾向于Vue (React 模版与JS混在一起,未分离)
组件化的区别:
1. React 本身就是组件化,没有组件化就不是 React
2. Vue 也支持组件化,不过是在MVVM上扩展
3. 对于组件化,更倾向于 React, 做的彻底而清新
相同点:
1. 都支持组件化;
2. 都是数据驱动视图;
2. TS 和 JS 的区别? TS的好处?
TypeScript 是 JavaScript 类型超集,支持 ES6 语法,支持面向对象编程的概念,如类、接口、基础 和 泛型等。
TypeScript 特性:
- 类型批注和编译时类型检测:在编译时批注变量类型
- 类型推断:ts 中没有批注变量类型会自动推断变量的类型
- 类型擦除:在编译过程中批注内容和接口会在运行时利用工具擦除
- 接口:ts 中用接口来定义对象类型
- 枚举:用于取值被限定在一定范围内的场景
- Mixin:可以接受任意类型的值
- 泛型编程:写代码时使用一些以后才指定的类型
- 名字空间:名字只在该区域内有效,其他区域可重复使用该名字而不冲突
- 元组:元组合并了不同类型的对象,相当于一个可以装不同类型数据的数组
3. TS 一些常用的类型?
typescript 数据类型:
- boolean (布尔类型)
- number (数字类型)
- string (字符串类型)
- array (数组类型)
- tuple (元组类型)
- enum (枚举类型)
- any (任意类型)
- null 和 undefined 类型
- void 类型
- nerver 类型
- object 类型
面经一
(1)对低代码的理解
低代码 是借助低代码工具的情况下,开发人员编写少量代码快速开发出企业级应用系统,并帮助企业团队进行数字化转型。低码开发平台借助一整套功能组件,功能分类包括:数据表、工作流、自动化、自定义API、图表视图、脚本、拓展包、权限设置等内容。开发人员可利用这些内置功能高效开发出新的流程和系统软件。低代码开发平台还有一个显著特征就是利用“拖拉拽”的可视化、图形化的开发环境,高效实现系统开发。
(2)对路由守卫的理解,有哪些,怎么设置,作用是什么
路由守卫钩子函数执行输出顺序:
- 全局前置守卫: beforeEach
- 路由独享守卫: beforeEnter
- 组件路由守卫: beforeRouterEnter(此时this并不指向该组件实例)
- 全局解析守卫: beforeResolve
- 全局后置守卫: afterEach
- 组件生命周期: beforeCreate – create – beforeMount – mounted
- 组件路由守卫: beforeRouterEnter 的 next 回调
vue的路由守卫包括:
全局路由守卫: 前置路由守卫、全局路由守卫 钩子函数顺序:beforeEach、beforeResolve、afterEach
组件路由守卫:beforeRouteEnter、beforeRouteUpdate、beforeRouteLeave
路由独享守卫
export default new VueRouter({
routes: [
{
path: '/',
name: 'home',
component: 'Home',
beforeEnter: (to, from, next) => {
// ...
}
}
]
})
(3)权限的操作;动态路由
(4)你觉得公司开发一个项目和大学课程上有什么区别
(5)组件之间通信
vue 组件之前通信:
- 父子组件之间的通信、
- 兄弟组件之间的通信
- 祖孙与后代组件之间的通信
- 非关系组件间之间的通信
组件间通信的方案:
- 通过 props 传递
- 通过 $emit 触发自定义事件
- 使用 ref
- EventBus 中央事件总线
- parent 或 root
- attrs 与 listeners
- Provide 与 Inject
- Vuex
react 组件之间通信:
- 父组件向子组件传递
- 子组件向父组件传递
- 兄弟组件之间的通信
- 父组件向后代组件传递
- 非关系组件传递
(6)父子传值和vuex的区别和应用场景
父子传值:通过props 属性来实现,父组件通过props将数据传递给子组件,子组件接收并使用这些数据。
vuex 全局状态管理 适用于大型复杂应用程序中共享和管理状态
(7)100张图片需要加载,怎么优化?(图片懒加载)
1.延迟加载:初始页面加载时,只加载可是区域内的图片,其余图片暂不加载。
2.监听页面滚动:监听用户滚动事件,当用户滚动到一个图片的位置时,再加载该图片。
3.设置占位符:在图片未加载时 使用一个占位符(比如一个小的loading动画或者灰色方框)代替
4.图片懒加载属性:将图片的`src`属性替换成一个自定义属性(比如`data-src`),并将实际图片地址存储在该属性中。
Lazy Loading Images
.image-container {
display: flex;
flex-wrap: wrap;
}
.image-item {
width: 200px;
height: 200px;
margin: 10px;
border: 1px solid #ccc;
}
document.addEventListener("DOMContentLoaded", function() {
const lazyImages = document.querySelectorAll('.lazy-image');
function lazyLoad() {
lazyImages.forEach(image => {
if (image.offsetTop < (window.innerHeight + window.pageYOffset)) {
image.src = image.dataset.src;
image.classList.remove('lazy-image');
}
});
}
lazyLoad();
document.addEventListener("scroll", lazyLoad);
window.addEventListener("resize", lazyLoad);
});
图片懒加载的实现方式:
(8)怎么获取图片是不是在可视区域内?有哪些方法?
(9)创建一个对象的原理?如果返回的不是对象而是一个数字呢?
(10)xss攻击
XSS 跨站脚本攻击 :存储型 反射型 DOM型
CSRF 跨域请求伪造
SQL 注入攻击
存储型
- 攻击者将恶意代码提交到目标网站的数据库中
- 用户打开目标网站时,网站服务端将恶意代码从数据库取出,拼接在 HTML 中返回给浏览器
- 用户浏览器接收到响应后解析执行,混在其中的恶意代码也被执行
- 恶意代码窃取用户数据并发送到攻击者的网站,或者冒充用户的行为,调用目标网站接口执行攻击者指定的操作
反射型
- 攻击者构造出特殊的 URL,其中包含恶意代码
- 用户打开带有恶意代码的 URL 时,网站服务端将恶意代码从 URL 中取出,拼接在 HTML 中返回给浏览器
- 用户浏览器接收到响应后解析执行,混在其中的恶意代码也被执行
- 恶意代码窃取用户数据并发送到攻击者的网站,或者冒充用户的行为,调用目标网站接口执行攻击者指定的操作
DOM型
- 攻击者构造出特殊的 URL,其中包含恶意代码
- 用户打开带有恶意代码的 URL
- 用户浏览器接收到响应后解析执行,前端 JavaScript 取出 URL 中的恶意代码并执行
- 恶意代码窃取用户数据并发送到攻击者的网站,或者冒充用户的行为,调用目标网站接口执行攻击者指定的操作
CSRF 跨站请求伪造:攻击者诱导受害者进入第三方网站,在第三方网站中,向被攻击网站发送跨站请求。
- 阻止不明外域的访问
- 同源检测
- Samesite Cookie
- 提交时要求附加本域才能获取的信息
- CSRF Token
- 双重Cookie验证
(11)事件代理和proxy,为什么要有事件代理
事件代理:把一个元素响应事件(click、keydown …….)的函数委托到另一个元素
事件流都会经过三个阶段:捕获阶段 -> 目标阶段 -> 冒泡阶段,而事件委托就是在冒泡阶段完成
事件委托:会把一个或者一组元素的事件委托到它的父层或者更外层元素上,真正绑定事件是外层元素,而不是目标元素。
当事件响应到目标元素上时,会通过时间冒泡机制从而触发它的外层元素绑定事件,然后在外层元素上去执行函数。
(12)为什么选前端,为什么不选后端或者算法?
(13)有没有实习过?主要做什么工作?
vuex 全局事件总线
- state 用来存放共享变量的地方
- getter (state 中的计算属性) 用来获得共享变量的值
- mutation 用来存放修改 state 的值
- action 用来存放修改 state 的方法,但是 action 是在 mutations 的基础上进行的。
面经二
金山效率真的高,两天前一面,昨天通知二面
(1)自我介绍
(2)项目相关
(3)学过ts吗,用过ts吗
(4)学过Vue3吗
(5)讲讲Vue2和Vue3的区别
1.vue2和vue3的双向数据绑定原理发生了改变。
vue2 双向数据绑定是利用ES5中的一个API Object.definePropert()对数据进行劫持 结合 发布订阅模式的方式来实现的。
(vue2的双向数据绑定原理通过object.defineProperty中的set方法来实现数据劫持,但是无法监听数组内部的数据变化)
vue3 使用ES6语法的proxy对象来实现双向数据绑定的,可以检测到数组内部数据的变化。
Proxy用于修改某些操作的默认行为,相当于在目标对象之前架设一层拦截,外部所有的访问都必须先通过这层拦截,因此提供了一种机制,可以对外部的访问进行过滤和修改。
2. vue3支持碎片化(Fragments)
// vue2
{{ title }}
// vue3
{{ title }}
3. Composition API
Vue2 与vue3 最大的区别是vue2使用选项类型api,对比vue3合成型api。
旧得选项型api在代码里分割了不同得属性:data,computed,methods等;
4. 建立数据data
vue2-把数据放入data属性中
export default {
props:{
title: String
},
data(){
return {
username: '',
password: ''
}
}
}
在Vue3.0 需要使用一个新的setup() 方法,次方法在组件初始化构造时触发。
(6)vue 的双向绑定
Vue 是双向数据绑定的框架,双向数据绑定由三个重要部分构成:
- 数据层(Model):应用的数据及业务逻辑
- 视图层(View):应用的展示效果,各类UI组件
- 业务逻辑层(ViewModel):框架封装的核心,它负责将数据与视图关联起来
1. new Vue() 首先执行初始化,对 data 执行响应函处理,这个过程发送Observe中
2. 同时对模版执行编译,找到其中动态绑定的数据,从 data 中获取并初始化视图,这个过程发生在 Compile 中
3. 同时定义一个更新函数和 Watcher,将来对应数据变化时 Watcher 会调用更新函数
4. 由于 data 的某个 key 在一个视图中可能出现多次,所以每个 key 都需要一个管家 Dep 来管理多个 watcher
5. 将来data中数据一旦发生变化,会首先找到对应的 dep,通知所有 Watcher 执行更新函数
(7)了解哪些设计模式
- 单例模式
- 工厂模式
- 策略模式
- 代理模式
- 中介者模式
- 装饰者模式
(8)观察者模式和发布订阅模式的区别是什么
观察者模式:定义了对象间一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都将得到通知,并自动更新。
发布订阅模式:是一种消息方式,消息的发送者(发布者)不会将消息直接发送给特定的接受者(订阅者)。而是将发布的消息分为不同的类别,无需了解哪些订阅者(如果有的话)可能存在。
同样的,订阅者可以表达对一个或者多个类别的兴趣,只接收感兴趣的消息,无需了解哪些发布者存在。
(9)html渲染的过程
- 解析HTML,生成DOM树,解析CSS,生成CSSOM
- 将DOM树和CSSOM树结合,生成渲染树(Render Tree)
- Layout(回流):根据生成树的渲染树,进行回流(Layout),得到节点的几何信息(位置、大小)
- Painting(重绘):根据渲染器以及回流得到的集合信息,得到节点的绝对像素
- Display:将像素发送GPU,展示在页面上
(10)Dom树中的所有结构都会在渲染树中显示吗
Dom 树
(11)实习过程中遇到的协作上的问题有哪些
(12)为什么选择前端
(13)如何评判一个前端项目的好坏
(14)前端性能的衡量指标
vue 的性能优化:
1.编译优化:
不要把所有数据都放在data中
v-for 时给每个元素绑定事件用事件代理
keep-alive 缓存组件
尽可能拆分组件,提高复用性、维护性
key 值保证唯一
合理使用路由懒加载,异步组件
数据持久化存储的使用尽量用防抖、节流优化
2.加载优化:
按需加载
内容懒加载
图片懒加载
3.用户体验:
骨架屏
4.SEO优化:
预渲染
服务端 ssr
5. 打包优化:
CDN 形式加载第三方模块
多线程打包
抽离公共文件
6. 缓存和压缩:
客户端缓存、服务端缓存
服务端 Gzip 压缩
(15)
面经三
(1)水平垂直居中,分别都说出两种
(2)block和inline的区别
block:块级元素
inline:行内元素
block
特点:
- 独占一行
- 可以设置height,width,padding,margin
- 一般情况下可以包含其他内联元素或者块级元素
- 宽度缺省时,默认为100%,占满和整个父级元素的宽度
inline
特点:
- 不会换行,连续排列
- width 和 height 属性将不起作用。
- 垂直方向的内边距padding、外边距margin以及边框border会被应用但是不会把其他处于 inline 状态的盒子推开。
- 水平方向的内边距padding、外边距margin以及边框border会被应用而且也会把其他处于 inline 状态的盒子推开。
- 行内元素只能包含数据和其他行内元素
- 默认为基线对齐,即text-align = baseline
inline-block
特点:
- width,height,margin,padding,border都起作用,但是不会换行
- 是上述两种类型的综合
内联块级元素标签: img、input、td、select、textarea、label,button
(3)选择器的优先级
- 全局选择器(通配符*)
- 标签选择器(body, div, p, ul, li)
- 类选择器(.)
! important > 行内样式 > ID选择器 > Class选择器 > 标签选择器 > 通配符
(4)BFC讲一下:创建条件,作用
BFC 块级格式化上下文
- 内部的盒子会在垂直方向上一个接一个的放置
- 对于同一个BFC的俩个相邻的盒子的margin会发生重叠,与方向无关
- 每个元素的外边距与包含块的左边界相接触(从左到右),即使浮动元素也是如此
- BFC的区域不会与float的元素区域重叠
- 计算BFC的高度时,浮动子元素也参与计算
- BFC就是页面上的一个沟里的独立容器,容器里面的子元素不会影响到外面的元素。
触发 BFC 的条件包含不限于:
- 根元素,即HTML元素
- 浮动元素:float 值为left、right
- overflow值 不为 visible,为 auto、scroll、hidden
- display的值 inline-block、inltable-cell、table-caption、table、inline-table、flex、inline-flex、grid、inline-grid
- position 的值为 absolute或fixed
(5)relative和absolute的区别
position 的属性值:
1. Absolute:绝对定位,是相对于最近的且不是static定位的父元素来定位
2. Fixed:绝对定位,是相对于浏览器窗口来定位,是固定的,不会根屏幕一起滚动
3. Relative:相对定位,是相对于其原本的位置来定位的
4. Static:默认值,没有定位。
5. Inherit:继承父元素position值。
(6)判断js数据类型哪些方法
(7)防抖节流:手撕
防抖:把触发非常频繁的时间合并成一次去执行。
节流:事件,按照一段时间的间隔来进行触发。
(8)读代码输出题:关于this指向的,还有settimeout,async等同步任务、微任务执行顺序之类的
(9)localstorage和sessionstorage的区别
(10)同源策略以及跨域解决方案
(11)cora跨域是在后端还是前端设置
(12)项目中使用过什么跨域方法
(13)CSRF攻击说一下,还有什么其他的攻击?
(14)TCP三次握手和四次挥手,为什么是三次握手而不是两次,为什么是四次挥手而不是三次
(15)为什么项目不用vue3做
(16)webpack了解嘛?描述一下
(17)vue的生命周期,以及ajax请求在哪个周期发送
面经四
(1)有没有听说过事件循环,并简述事件循环的作用和机制
(2)有没有听说过跨域,跨域是如何产生的,如何解决
(3)有没有听说过闭包,以及闭包的作用和应用场景
(4)简述一下原型链和原型的概念以及作用
(5)简述一下浏览器从输入url到显示页面的过程
(6)简述三次握手的过程
(7)有没有听说过回流与重绘(重排与重绘),什么时候会触发回流或重绘
(8)有哪些比较印象深刻的项目(答的实习项目和社团内部的一个项目)
(9)在社团项目中是如何参与工作的以及做了哪些工作
(10)简述一下实习中为什么要对项目进行重构
(11)在重构项目前进行了哪些工作
(12)在项目中如何判断设备类型
(13)如何根据设备类型去进行适配(用的rem方案)
(14)为什么使用vue进行重构,有哪些考量
(15)重构时使用的是vue2还是vue3
(16)有没有了解过vue的diff算法,简述一下
(17)vue-router的hashRouter和historyRouter有什么区别
(18)如何理解MVVM框架
- 数据层(Model):应用的数据及业务逻辑
- 视图层(View):应用的展示效果,各类UI组件
- 业务逻辑层(ViewModel):框架封装的核心,它负责将数据与视图关联起来
(19)react有哪些生命周期
(20)react的优化过程中如何对重复渲染进行处理(答的用useMemo)
(21)react的class组件中如何优化重复渲染
(22)有没有了解过react fiber
(23)如何去理解虚拟dom
(24)如何理解webpack中的loader和plugin,这两个的作用是什么
(25)对于react和vue两个框架优缺点的个人理解
面经五
(1)css的flex布局属性有哪些?
css 设置为 flex 布局以后,子元素的float、clear和vertical-align 属性将失效。
容器的属性有6个,分别是:
flex-direction flex-wrap flex-flow justify-content align-items align-content
①flex-direcion属性:
作用:控制主轴的方向 默认值:row
flex-direction: row | row-reverse | column | column-reverse;
② flex-wrap属性:
作用:默认情况下,项目都排在一条线(又称”轴线”)上。flex-wrap属性定义,如果一条轴线排不下,如何换行。 默认值:nowrap
flex-wrap: nowrap | wrap | wrap-reverse;
③ flex-flow属性:
作用:该属性是flex-direction属性和flex-wrap属性的简写形式
默认值:r服务器托管网ow nowrap
④ justify-content属性:
作用:定义项目在主轴上的对齐方式
justify-content: flex-start | flex-end | center | space-between | space-around;
默认值:flex-start
⑤ align-items属性:
作用:定义项目在交叉轴上如何对齐。
align-items:flex-start | flex-end | center | baseline | stretch
默认值:flex-start
(2)6个卡片,每行3个,flex如何实现?
Card 1
Card 2
Card 3
Card 4
Card 5
Card 6
.card-container {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
}
.card {
width: 30%;
margin-bottom: 10px;
background-color: #f0f0f0;
padding: 10px;
}
-
.card-container
是一个容器,它被设置为flex容器,允许子元素进行弹性布局。 -
flex-wrap: wrap;
允许子元素在需要时换行,确保在小屏幕上也能正常显示。 -
justify-content: space-between;
将卡片在容器内水平分布,两端对齐。
(3)60个卡片呢? 你刚刚方法可能不行,换60个呢?
(4)伪类的了解?
伪类是css中的一种选择器,它允许在特定的状态或条件下选择元素并为其应用样式。伪类通常以冒号(:) 开头,用于对元素的特定状态或行为进行定位和样式化。
选择器 | 描述 |
:hover | 鼠标悬停时应用样式。常用于链接和交互元素。 |
:active | 元素被激活(例如按钮被点击)时应用样式。 |
:focus | 元素获得焦点时应用样式(通常用于表单元素)。 |
:visited | 已访问链接的样式。 |
:nth-child(n) | 选择父元素下的第n个子元素。 |
:nth-of-type(n) | 选择特定类型的父元素下的第n个子元素。 |
:not(selector) | 排除特定选择器的元素。 |
:first-child | 选择父元素下的第一个子元素。 |
:last-child | 选择父元素下的最后一个子元素。 |
:first-of-type | 选择父元素下特定类型的第一个子元素。 |
(5)浏览器输入URL整个过程
- 查询该域名的ip地址 下载浏览器本地缓存,如果浏览器有本地缓存,如果浏览器由本地缓存且未过期则返回结果; 否则向上一级 DNS 服务器(域名系统)查询,直到DNS根服务器;
- 浏览器和服务器建立 TCP 连接;
- 浏览器发送 HTTP 请求(三次握手);
- 服务器通过 HTTP 响应把首页的html文件发送给浏览器;
- TCP释放连接(四次挥手);
- 浏览器首页解析 html 文件 并展示给用户;
(6)http2.0,1.1,1.0,3.0有啥区别吗?
(7)https加密过程
1. 浏览器请求 URL,找到服务器,向服务器发送请求。服务器将自己的整数(包含服务器公钥)、对称加密算法种类以及其他相关信息返回给浏览器。
2. 浏览器检测CA证书是否可依赖,确认证书有效。
3. 如果不是,给服务器发警告,询问是否可以继续使用。
4. 如果是,浏览器使用公钥加密一个随机对称秘钥,包含加密的 URL 一起发送给服务器。
5. 服务器用自己的密钥解密浏览器发送的钥匙,然后用这把对称加密的钥匙给浏览器请求的 URL 连接解密。
6. 服务器用浏览器发送的对称钥匙给请求的网页加密,浏览器使用相同的钥匙就可以解密网页。
(8)页面渲染有重绘 重排,这俩有了解吗?
(9)强缓存和协商缓存
(10)http的Keep-Alive?
(11)JS原型链
(12)你对前端工程化的了解?
(13)webpack的一些原理?
(14)babel的了解?
(15)poltill,babel的 词语不知道怎么拼
(16)webpack的tree-Dom的了解?
(17)网络安全的xss,csrf?
(18)https为了防御什么攻击?
(19)前端js排序底层是哪一种排序?
(20)js 中 sort 函数的底层实现机制
js中的sort()方法用于对数组元素进行排序,V8 引擎 sort 函数只给出了两种排序 InsertionSort 和 QuickSort,数组长度小于等于 22 的用插入排序 InsertionSort,比22大的数组则使用快速排序 QuickSort。
(21)文档中有敏感词怎么办?
(22)你的项目经验有web,react,vue哪个用得熟一点?
(23)有了解vue的原理吗?
(24)说一下数据的双向绑定?
通过数据劫持和发布订阅者模式来实现,同时利用 Object.defineProperty() 劫持各个属性的 setter 和 getter,在数据发生改变的时候发布消息给订阅者,触发对应的监听回调渲染视图,也就是说数据和视图时同步的,数据发生改变,视图跟着发生改变,视图改变,数据也会发生改变。
第一步:需要 observer 的数据对象进行递归遍历,包括子属性对象的属性,都加上 setter
和 getter。
第二步:compile 模板解析指令,把模板中的变量替换成数据,然后初始化渲染视图,同时
把每个指令对应的节点绑定上更新函数,添加订阅者,如果数据变化,收到通知,更新视图
第三步:Watcher 订阅者是 Observer 和 Compile 之间的通信桥梁,作用:
1.在自身实例化的时候,在订阅器内添加自身
2.自身要有一个 update()方法
3.等待属性变动时,调用自身的 update 方法,触发 compile 这种的回调
第四步:MVVM 作为数据绑定的入口,整合了 observer、compile 和 watcher 三者,通
过 observer 来监听自己的数据变化,通过 compile 解析模板指令,最后利用 watcher 把
observer 和 compile 联系起来,最终达到数据更新视图更新,视图更新数据更新的效果。
(25)vue2 or vue3?
(26)vue3对2来说 架构上做的什么变化?
(27)状态管理这块的理解?或者某个状态管理的理解,用来解决什么问题?
(28)学习或者项目中遇到比较难的问题,自己怎么解决的?
(29)为啥不用socket这种方式呢?
(30)还有什么其他比较难得问题吗?
(31)数据有嵌套怎么办呢?
使用ES6进行对象解构。
最基本的结构在对象中提取某服务器托管网个字段
const user = {
id: 123,
name: 'hehe'
};
const {name} = user;
console.log(name); //prints: hehe
解构并使用别名有时接口定义的字段往往带有下划线,但我们的前端更便好于驼峰式命名,那么可以使用别名(rename):
const user = {
id: 123,
nick_name: 'hehe'
};
const {nick_name: nickName} = user;
console.log(nickName); //prints: hehe
解构嵌套对象
const user = {
id: 123,
name: 'hehe',
education: {
degree: 'Masters'
}
};
const {education: {degree}} = user;
console.log(degree); //prints: Masters
(32)数据比较多渲染成table,比较卡顿,有没有遇到这种问题?
(33)前端如何做大数据量展示的优化?
前端如何进行性能优化?
1. 编码优化
不要把所有数据都放在 data 中
v-for 时给每个元素绑定事件用事件代理
keep-alive 缓存组件
尽可能拆分组件,提高复用性、维护性
key 值要保证唯一
合理使用路由懒加载,异步组件
数据持久化存储的使用尽量用防抖、节流优化
2. 加载优化
按需加载
内容懒加载
图片懒加载
3. 用户体验
骨架屏
4. SEO 优化
预渲染
服务端渲染 ssr
5. 打包优化
CDN 形式加载第三方模块
多线程打包
抽离公共文件
6. 缓存和压缩
客户端缓存、服务端缓存
服务端 Gzip 压缩
(34)问,问了base、技术栈、产品
面经六
(1)讲一下闭包?
(2)怎么封装一个轮播图组件?
1.基本组件拆分和布局
2.自动轮播
3.悬停控制启动和停止
4.手动控制切换
5.销毁定时器
6.抽取相关的参数
解决(项目中)
问题一:轮播图实现
① 获取轮播图数据:虽然找到接口了,但是由于XHR请求在浏览器端会有跨域的限制,不能直接请求QQ官网的接口地址,需要做一层Proxy代理:
获取响应数据:
获取轮播图数据,使用BetterScroll的基本配置项,监听slideWillChange事件
onMounted(() => {
const sliderVal = slider.value = new BScroll(wrapperRef.value, {
click: true,
scrollX: true,
scrollY: false,
momentum: false,
bounce: false,
probeType: 2,
slide: true
})
sliderVal.on('slideWillChange', (page) => {
currentPageIndex.value = page.pageX
})
})
掘金方法:
1.数据驱动动画 :首先把轮播图播放动画当中能用到的状态变量进行初始化。
// main.vue
data(){
return {
reversing:false,//控制动画播放到首尾时无缝跳转的开关
swiperItemCount:0,// 初始化传入的轮播图个数
index:0 // 控制轮播图当前位置的索引
}
},
computed:{
scrollItemCount(){ // 内容实际存在的图片个数
return this.swiperItemCount+2 // 组件初始化以后需要复制传进来的首尾两张图片到指定位置,所以这里需要加上2
}
}
2. 通过更改index索引值以驱动图片的位置移动,这样就有了视觉上动画的效果。
watch: {
index(newIndex, oldIndex) {
const endIndex = this.scrollItemCount - 1
if (newIndex === endIndex && newIndex > oldIndex) {
setTimeout(() => {
this.reversing = true
this.index = 1
setTimeout(() => {
this.reversing = false
}, 100)
}, this.duration)
} else if (newIndex === 0 && newIndex {
this.reversing = true
this.index = endIndex - 1
setTimeout(() => {
this.reversing = false
}, 100)
}, this.duration)
}
},
}
这里通过观测动画播放的当前位置这个变量,我们在相应的时机更改它的值来达到整个包装容器的瞬间移动,这样也就产生了图片播放连续的动画效果了。
(3)场景提:一个长列表通过滚动加载更多内容,怎么优化整个过程?
分页加载:
- 将列表分成多个页面,每次只加载当前页面的内容,当用户滚动到底部时再加载下一页的内容。这样可以减轻一次性加载大量数据的压力。
虚拟列表:
- 只渲染用户可见区域内的列表项,对于不在视口中的项,只在需要时才进行渲染。这可以显著减少DOM元素的数量,提升性能。
节流和防抖:
- 使用节流和防抖技术来控制滚动事件的频率,避免在短时间内触发大量的数据加载请求。
异步加载:
- 使用异步加载来确保页面在加载数据时不会被阻塞。可以使用
async/await
或者Promise
来管理异步操作。懒加载:
- 对于非必要的资源(如图片等),可以采用懒加载技术,只在用户接近可见区域时才加载。
缓存:
- 如果数据是静态的或者相对稳定的,可以考虑将部分数据进行缓存,减少重复请求。
分块加载:
- 将数据分成多块进行加载,而不是一次性加载全部内容。这可以减少单次请求的数据量,提升加载速度。
减少不必要的重绘和回流:
- 在操作DOM时,尽量批量处理,避免频繁的对DOM进行修改,以减少浏览器的重绘和回流。
优化图片和媒体资源:
- 使用适当的图片格式和大小,以及懒加载技术来优化图片的加载。
使用Web Workers:
- 将一些计算密集型的任务放到Web Workers中进行处理,以保持主线程的流畅性。
监测性能指标:
- 使用工具监测页面性能,及时发现和解决性能瓶颈。
利用浏览器缓存:
- 使用合适的HTTP缓存策略,确保重复请求的数据可以从缓存中获取。
综合使用以上策略,可以有效地优化长列表的滚动加载过程,提升页面的性能和用户体验。根据具体的场景和需求,可以选择合适的优化方法。
如何实现呢?
1.实现一个监听器Observer,用来劫持并监听所有属性,如果有变动的,就通知订阅者。
2.实现一个订阅者Watcher,每一个Watcher都绑定一个更新函数,watcher可以收到属性的变化通知并执行相应的函数,从而更新视图。
3.实现一个解析器Compile,可以扫描和解析每个节点的相关指令(v-model,v-on等指令),如果节点存在v-model,v-on等指令,则解析器Compile初始化这类节点的模板数据,使之可以显示在视图上,然后初始化相应的订阅者(Watcher)。
设置use-pull-up-load 进行下拉框加载
onMounted(() => {
const scrollVal = scroll.value = new BScroll(rootRef.value, {
pullUpLoad: true,
observeDOM: true,
click: true
})
scrollVal.on('pullingUp', pullingUpHandler)
async function pullingUpHandler() {
if (preventPullUpLoad.value) {
scrollVal.finishPullUp()
return
}
isPullUpLoad.value = true
await requestData()
scrollVal.finishPullUp()
scrollVal.refresh()
isPullUpLoad.value = false
}
(4)如何实现图片懒加载?
① 图片懒加载的实现原理:
实现过程中注意优化的点:
- 避免重复设置 src。
- 滚动事件监听添加节流。
- 加载图片的时间点可以适当提前。
- 避免出现布局抖动。
- 响应式图片要额外处理。
- seo 不友好的问题。
vue-lazy是基于vue下的图片懒加载库
-
② 图片懒加载的实现方法:
原理:在没有可视区域的图片暂时不加载图片,等进入可视区域后再加载图片,这样可以减少初始页面加载
方案一:img的loading属性设为“lazy”。lazy 告诉用户代理推迟图片加载直到浏览器认为其需要立即加载时才去加载。
方案二:通过offsetTop来计算是否在可视区域内。
方案三:通过 getBoundingClientRect 来计算是否在可是区域内。
把获取图片元素 offsetTop 改成 getBoundingClientRect 方法获取离可视区顶端的距离。
方案四:通过IntersectionObserver来判断是否在可视区域内。
(5)webpack 的操作流程
从启动到结束会依次执行以下三大步骤:
- 初始化流程:从配置文件和
Shell
语句中读取与合并参数,并初始化需要使用的插件和配置插件等执行环境所需要的参数; - 编译构建流程:从 Entry 发出,针对每个 Module 串行调用对应的 Loader 去翻译文件内容,再找到该 Module 依赖的 Module,递归地进行编译处理;
- 输出流程:对编译后的 Module 组合成 Chunk,把 Chunk 转换成文件,输出到文件系统;
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
let htmlWebpackPlugin = new HtmlWebpackPlugin({
// 虚拟的html文件名 index.html
filename: 'index.html',
// 虚拟html的模板为 src下的index.html
template: path.resolve(__dirname, './src/index.html')
});
module.exports = {
// 开发模式
mode: 'development',
// 配置入口文件
entry: './src/index.tsx',
// 出口文件目录为根目录下dist, 输出的文件名为main
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'main.js'
},
// 配置开发服务器, 并配置自动刷新
devServer: {
// 自动压缩代码
compress: true,
// 服务端口为1208
port: 1208,
// 自动打开浏览器
open: true,
// 根目录下dist为基本目录
static: path.join(__dirname, 'dist'),
},
// 装载虚拟目录插件
plugins: [htmlWebpackPlugin],
module: {
// 根据文件后缀匹配规则
rules: [
// 配置js/jsx语法解析
{
test: /.(js|ts|jsx|tsx)$/,
use: [
{
loader: 'esbuild-loader',
options: {
loader: 'tsx',
target: 'es2015',
},
}
]
},
{
test: /.scss$/,
use: [
"style-loader", // creates style nodes from JS strings
"css-loader", // translates CSS into CommonJS
"sass-loader" // compiles Sass to CSS
]
},
{
test: /.(png|svg|jpg|jpeg|gif)$/i,
type: 'asset/resource',
},
{
test: /.(woff|woff2|eot|ttf|otf)$/i,
type: 'asset/resource',
},
{
test: /.css$/,
use: [
// 将 JS 字符串生成为 style 节点
'style-loader',
// 将 CSS 转化成 CommonJS 模块
'css-loader',
],
},
]
},
resolve: {
extensions: ['.js', '.jsx', '.ts', '.tsx'],
},
}
(6)loader和plugin区别
- loader 是文件加载器,能够加载资源文件,并对这些文件进行一些处理,诸如编译、压缩等,最终一起打包到指定的文件中。(运行在打包文件之前)
- plugin 赋予了 webpack 各种灵活的功能,例如打包优化、资源管理、环境变量注入等,目的是解决 loader 无法实现的其他事。(在整个编译周期都起作用)
(7)用的什么路由模式
(8)hash模式的特点
hash
模式是一种把前端路由的路径用井号#
拼接在真实url
后面的模式。当井号#
后面的路径发生变化时,浏览器并不会重新发起请求,而是会触发onhashchange
事件。
hash模式和history模式的区别:1.hash 的路由地址上有#号,history 模式没有2.在做回车刷新的时候,hash 模式会加载对应页面,history 会报错 4043.hash 模式支持低版本浏览器,history 不支持,因为是 H5 新增的 API4.hash 不会重新加载页面,单页面应用必备5.history 有历史记录,H5 新增了 pushState 和 replaceState()去修改历史记录,并不会立刻发送请求6.history 需要后台配置
(9)了解过栅栏布局吗(grid网格)
设置 display:grid/inline-grid 的元素就是网格布局容器,这样就能发出浏览器渲染引擎的网格布局算法。
display属性:
-
display:grid 则该容器是一个块级元素
-
display: inline-grid 则容器元素为行内元素
grid-template-colums 属性,grid-template-rows属性
grid-template-columns
属性设置列宽,grid-template-rows
属性设置行高
(10)ES6新特性
(11)内存泄漏
(12)怎么在一个盒子中加入一模一样的上千个子元素,怎么优化速度?
(13)TCP三次握手
服务器托管,北京服务器托管,服务器租用 http://www.fwqtg.net