一、事件循环
进程:(类比房屋)一块内存空间,用于隔离应用,相互独立,如需通信需要双方同意
线程:(类比人)每个进程至少有一个线程-主线程
**浏览器的进程:**多进程、多线程的模型。包括浏览器进程、网络进程、渲染进程等
**渲染进程:**每个浏览器标签页都会开辟新的渲染进程,渲染主线程(html、c s s、j s、布局、图层、f p s画面绘制等),只有一个!最开始渲染主线程会无限循环看任务队列是否有新消息,有就依次执行,其他线程来的新任务会添加在任务队列最后,这就是事件循环。
**同步:**事件无法立即执行。需要排队等待任务一个解决完后再解决下一个,会造成事件拥堵、浏览器卡死。
**异步:**j s是一门单线程语言,运行在渲染主线程中,主线程只取事件队列里的任务,如遇到setTimeOut、x h r、addEventLisener事件时,主线程立刻结束此任务的执行,将此任务交给其他线程去处理,自己则处理下一个任务队列中的任务,渲染主线程永不阻塞!
**任务优先级:**任务没有优先级,在消息队列中先进先出
**消息队列优先级:**消息队列有优先级,每个任务都有一个类型,同一类型的任务都必须在一个队列,不同类型的任务可以在不同队列。微队列优先级最高(必须先执行完),其次交互队列、其次延时队列(定时器);如 Promise.resolve.then(()⇒{代码直接进入微队列!!})
二、浏览器渲染原理
网络进程拿到html的文档(字符串)后—给到网络线程,生成一个渲染任务,并把这个渲染任务加入到渲染主线程的消息队列。
渲染进程在事件循环机制的作用下,渲染主线程拿到渲染任务,执行渲染。
渲染流程:
1.解析html(得到dom和cssom)——样式计算(得到样式的最终值,颜色会变成r g ba,em变成p x)——布局(得到布局树,每个元素的大小、位置,隐藏元素除外,所以do m树和布局树不会一一对应)——分层——绘制(主线程形成指令集,接下来的操作交给合成线程)|||||—分块(合成线程分块)—光栅化(根据分块,计算每块的像素点颜色,此过程会用到GPU加速)—画(合成线程计算每块在屏幕上的位置,交给GPU和显卡进行最终呈现),上一个阶段的输出成为下一个阶段的输入。
2.parse Html 成dom树和cssom树,开一个预解析线程率先下载c s s和解析c s s,提高解析效率,所以c s s不会阻塞html的解析。
3.解析是从上往下进行,遇到j s暂停一切行为,因为要启动v8引擎执行j s,j s有可能改变dom,所以j s会阻塞html的解析。
相关面试题:
1.重排:影响元素几何信息都会造成,重新计算布局以及后续所有操作,j s应该尽可能把这些操作合并计算,reflow是异步完成的,这就是j s在获取属性时,可能无法正确获取到最新的值的原因。当获取属性时应该立即reflow。
2.重绘:影响元素外观属性,比如颜色、背景、边框等。不会重新计算布局,重排一定会引起重绘!
3.为什么transform效率高:因为它经过样式计算后直接到最后一步画,不会经过中间的一系列步骤。
4.如果优化重排,使用tranform,使用will-change创建分层,避免使用table布局、合并操作样式,尽可能使用className来替换样式不使用style。
三、VUE
1.数据响应式与双向绑定
数据响应式:
当数据改变时会自动运行一些相关函数。(1.函数中读取到的数据,2.该数据是响应式对象的某个属性;3.函数是被监控的是函数,vue2:被watcher监控 vue3:被effect监控 常见的有render、watch、watch Effect、computed;)必须是数据和函数的关联
双向绑定:
依托于响应式系统,
VUE2:
1.数据劫持,在组件初始化阶段render函数会通过Object.defineProperty**给每一个属性添加get和set方法,从而能监听属性值的变化**
2.依赖收集,当属性值被读取的时候,触发get函数,收集到哪些组件依赖了此属性。
3.发布订阅,当属性值被设置的时候,触发set函数,通知依赖此属性的所有组件去更新
VUE3:
1.在数据劫持的步骤做出了优化,通过**reactive用Object.proxy来代理对象本身,而不是某个属性。其他的都差不多。
2. VUE2 defineProperty和VUE3 proxy的差异:
vue2中创建一个observer观察器用来观察对象的属性,采用递归遍历每一个对象的每一个属性进行Object.defineProperty进行get(依赖收集)和set(派发更新);缺点1是效率低因为要遍历,2是只能观察到已有的属性,新增属性遗漏,3.需要对数组的方法进行重写;
vue3中创建一个reactive用proxy来代理对象本身,不需要深度遍历读取每个属性,只有当读到某个属性为对象时才会递归,且可以监听到对象的任何操作,新增删除属性;对象深层监听、对数组的自然观察。
3.插槽:
本质上是一个个的对象,每个对象的名字就是插槽的名字,也就是具名插槽。
默认插槽的名字叫default;对象的值是一个函数,里面可以传递参数,也就是作用域插槽;函数返回一个虚拟节点。
4.diff算法与虚拟DOM
虚拟DOM: 本质上是js对象_vnode描述页面的结构,把dom数据化。每一个组件render函数都会创建虚拟dom树。因为直接操作真实dom的创建、更新、插入,会很影响性能,重绘重排。
diff算法:智能高效性能优化的关键技术,首先会根据真实DOM生成虚拟VDOM,使用patch方法比较(循环两边向中间收拢)。当虚拟VDOM的数据发生改变时,会生成新Vnode,使用新的Vnode和oldVnode相比较,发现有不同就直接修改在真实DOM上(打补丁),然后使oldVnode=Vnode,实现一边比较一边打补丁,并且新旧节点为同级比较,如果第一层不一样就直接替换,否则逐层比较。
流程为:当数据改变时、set方法会调用dep.notify通知所有订阅者watcher,订阅者调用patch函数给真实dom打补丁。
5.路由模式
hash:获取不到链接不会发请求,不会给后端带来困扰。可以配一个404页面。且地址栏中带有#。打包后可以看到内容。window.onhashChange监听
history:找不到链接也会发请求。地址栏有/。打包后看不到内容,利用HTML的history API 监听,比如:history.pushState replaceState.
6.vue2和vue3的升级-能说出几个
(1)引入了组合式api
(2)传送门:允许将模版代码渲染到任意节点上,跨层级。
(3)Fragments:片段,允许多个根元素使用的时候进行包裹
(4)suspense异步组件:异步组件加载状态显示占位内容
(5)proxy取代defineProperty
(6)天然t s支持和tree shaking(未引入不打包进去)
(7)静态节点提升:将静态节点、纯文本等提升到渲染函数外,避免重复渲染
(8)v-model增强:支持多个v-model,且可以自定义修饰符,definModel的增加
(9)生命周期调整:由setup代替beforCreate和created.
(10)父子组件的生命周期:
开始——父beforCreate/onBeforeMount——子mounted/onMounted
更新——父beforeUpdate——子beforeUpdate updated——父updated
销毁——父beforeDestory/onBeforeUnmount——子beforeDestory destoryed——父destoryed/onUnmounted
7.vue3 setup函数
语法糖:不需要return,最终语法糖中的代码都会写成setup函数的形式,defineExpose宏可以暴露成员,
script 函数中:需要return,expose可以暴露return中的成员,接受两个参数props和context上下文(attires\slots\emit\expose)
8.vue传值与通信
vue2:事件总线、props、$emit、provide\inject、vuex
vue3:mi t t、 props、emit、 provide\inject、pinia
9.pinia和vuex的区别和使用
**vuex:**有modules可以管理多个模块,commit提交mutations,actions提交mutations,diapatch分发actions,适用于vue2。
pinia: 简化状态管理器的模块只保留state\getter\actions,同步异步都可在actions中操作;可以定义多个store,每个store就是一个模块,用ID划分;可以批量修改数据。适用于vue3。
仓库持久化:在页面离开前保存仓库数据到localStorage,在页面渲染时取出来替换store的值,都有插件可用。
10.$nextTick作用
在下次DOM更新循环结束后,执行延迟回掉,在修改数据之后立即使用这个方法,获取更新后的DOM
11.v-model的使用
(1)vue2:v-model
一个组件上的 v-model 默认会利用名为 value的 属性 和名为 input 的事件
(1)
父组件//////////
子组件////////
<select :value="value" @change="change">
北京...
// 当在组件上使用v-model时,这里的变量名必须是 value
props:['value'],
methods: {
change(e){
// 当在组件上使用v-model时,这里自定义事件的名字必须是 input
this.$emit('input', e.target.value)
}
}
(2)
在表单元素上,v-model 在内部为不同的输入元素使用不同的property 并抛出不同的事件
可以用.sync 修饰符实现自定义属性的传值
父组件////////////
子组件///////////
<select :value="homeId" @change="change">
山东...
props:['homeId'],
methods: {
change(e){
this.$emit('update:homeId', e.target.value)
}
}
(2)vue3:dinfineModel
v-model默认使用 modelValue属性 和 update:modelValue事件
12.SSR和SSG的理解
SSR:更快的首屏加载、更好的SEO、统一的语言开发;服务负载高、部署繁杂、开发限制
SSG:适用于静态数据页面的首屏加载、
四、项目构建
1.绝对路径和相对路径:一种书写方式.
指的是url地址,和文件夹毫无关系。发请求一定是完整的url地址,可以用绝对路径和相对路径的书写方式!
绝对路径:完整url地址;可以省略协议(://www.baidu.com/c.js),避免协议不… 上线后可以用当前网站的补全)
相对路径:./(找的是path部分最后的一个/) ; ../(找的是path部分倒数第二个/)
2.技术选型
项目因素:如果是门户网站,选择好用的的方便的框架;如果是需要很好的SEO,可能会考虑nuxt.js;如果需要跨端,可能会选择uni-app\flutter
技术因素:根据自身的技术栈、技术栈的生态系统、可扩展和可维护性。
框架-vue
构建工具-webpack\vite\rspack等
css-less\sass,考虑全局基础样式管理
状态管理-vuex\pinia
路由-vue-router
API-axios
功能模块目录设计---工具类、组件类、api类、样式类、页面类、插件类等等
测试-自测、单元测试、整体测试
打包和性能优化--减少体积、懒加载;
部署与上线--测试
3.npm和pnpm — 幻影依赖问题
npm:安装依赖后有很多其他的依赖出现在node_modules中,并没有出现在dependences中,但在项目中可以正常使用,可能导致部署后找不到报错,且升级某个依赖后,依赖他的依赖可能导致版本不兼容。
pnpm:使用一个仓库存放所有依赖,node_modules里面的依赖都是快捷方式,只有package.json中有的才会放到node_modules中。总仓库在.pnpm中
五、j s知识点
1.箭头函数的作用:
消除函数的二义性(js设计不规范fuc和class不分),和面向对象无关、没有this指向、不能用new、没有原型。
2.前端开发中常见的设计模式
MVC:模型-处理视图逻辑、视图-展示、控制器-处理用户输入
MVVM:模型-、视图-、视图模型-实现视图和模型的双向数据绑定
单例模式:只有一个实例,并提供一个全局访问点,如vue项目中的vue实例
观察者模式:一对多的依赖关系,当一个对象状态改变时,所有依赖的对象都将得到通知,如btn.addEventLisener('click',()),btn和关联,addEventLisener直接关联(没有媒介)
发布订阅模式:一对多的依赖关系,当一个对象状态改变时,所有依赖的对象都将得到通知(有媒介),如eventBus.on('name',()),eventBus就是媒介
工厂模式:用一个函数创建实例,返回一个new 创建的实例,如jq的$函数
3.命令式编程、声明式编程、函数式编程
命令式编程:需要明确地告诉计算机如何一步步地完成任务,强调任务的步骤,是具体明确的操作,比如jq,原生j s
声明式编程:需要告诉计算机想要达到的目标,而不关注具体如何实现,比如vue的双向绑定
函数式编程:声明式编程的子集,强调通过编写函数来实现目标。
4.promise和async await
都是处理异步操作的形式
promise:
promise一旦开始执行就不可逆,它有三种状态pending、fulfilled、rejected,他只会从pending--fulfilled或者从pending--rejected.
new promise((resolve,reject)=>{
执行异步事件,
最后通过resolve(输出成功),
reject(输出失败)}).then((res)=>{
输出异步事件的成功结果
}).catch((err)=>{
输出异步事件的错误结果,捕获异常
}).finally(()=>{
最后都会执行这一步
})
promise.race:接受一个包含多个promise的可迭代对象(数组、map、set),并返回第一个解决或拒绝的promise结果
promise.all:接受一个包含多个promise的可迭代对象(数组、map、set),等所有的promise都执行完毕后,返回一个新的promise,在then中处理成功结果,在catch中处理异常结果,只要有一个异常就立即返回失败的原因。
**async await:**是promise的语法糖,通过try/catch捕获异常
async function fetchData() {
try {
const response = await fetch('https://api.example.com/data');
const data = await response.json();
console.log(data);
} catch (error) {
console.error('Fetching data failed:', error);
}
}
5.深拷贝和浅拷贝
深拷贝:
新开辟一个内存空间存放拷贝的数据,不会影响原数据
最好的办法是写一个deepClone的公共方法,传入需要克隆的树,判断数据类型,如果是对象,新建一个对象构造函数new obj.constructor,循环对象再给新对象复制,再次递归。
1.JSON.stringify();(深拷贝普通对象时推荐使用)
2.递归
// 递归拷贝 (类型判断)
function deepClone(value,hash = new WeakMap){ // 弱引用,不用map,weakMap更合适一点
// null 和 undefiend 是不需要拷贝的
if(value == null){ return value;}
if(value instanceof RegExp) { return new RegExp(value) }
if(value instanceof Date) { return new Date(value) }
// 函数是不需要拷贝
if(typeof value != 'object') return value;
let obj = new value.constructor(); // [] {}
// 说明是一个对象类型
if(hash.get(value)){
return hash.get(value)
}
hash.set(value,obj);
for(let key in value){ // in 会遍历当前对象上的属性 和 __proto__指代的属性
// 补拷贝 对象的__proto__上的属性
if(value.hasOwnProperty(key)){
// 如果值还有可能是对象 就继续拷贝
obj[key] = deepClone(value[key],hash);
}
}
return obj
// 区分对象和数组 Object.prototype.toString.call
}
3.第三方库lodash的cloneDeep()方法
浅拷贝:
直接复制,会指向同一个地址,修改一个会影响另一个
6.数组的方法
Array.form():可以把类数组对象转化为数组
Array.of():将一组值转化为数组Array.of(1,2,3) =[1,2,3]
Array.copyWithin():将指定位置的成员复制到其他位置(会覆盖原有成员)
Array.includes():数组是否包含某一个元素,返回true/false
Array.flat(层级数):数组拍扁
Array.reduce(正序)/reduceRight(倒序)
将数组累计:Array.reduce((sum,currentItem,index,arr)=>{ return sum+=currentItem},0初始值)
7.原型链和原型
1.对象是new函数 出来的
2.函数是一个双胞胎,每个函数除了本身还会有一个原型对象prototype
3.这个对象的隐式原型指向prototype,最终形成一个三角关系
最终函数也是一个对象:是通过new function来的
最终prototype是Object出来的,Object的prototype 指向null
一层一层往上找prototype 就形成原型链
8.set、map、object的区别
set:
无序性、唯一性、可以存任何类型的值(无健),可用来去重new Set([...[1,2,3],...[2,3]]) == [1,2,3]
let arr = new Set()
arr.add(1)== {1}. arr.add(2)==={1,2} arr.add(2) == {1,2}
arr.has(1)==true
arr.delete(2)=={2}
arr.clear()=={}
let brr = new Set([1,2,3)]
遍历方法:
brr.values()== 值的集合
brr.keys()== 值的集合
brr.entries() == 值集合对应11 22 33
brr.forEach((value)=>{}) == 遍历set中的每个值
map:
Map 存储的是键值对、有序性、Map 的键可以是任意类型、在频繁增删情况下性能更好、避免原型链污染;
实现了iterator接口,可以使用for...of或.forEach循环。使用 .keys()、.values()、.entries() 获取迭代器。
const map = new Map();
map.set('num',111). map.set(1,'hello'). map.set({id:1},111)
map.has(key) map.get(key). map.delete(key) map.clear()
遍历方法:
map.keys() == 健的迭代器
map.values() == 值的迭代器
map.entries() == 健值对迭代器-默认迭代器
map.forEach((value,key)=>{}) == 遍历map中的每个健值对
object:
存储的是键值对、无序性、键只能为字符串或symbol、Map和Set只能通过new 来创建;
可以继承原型上的方法,比如toString()\constructor
对象本身不可直接迭代,但可以先遍历其键或值的集合,在迭代。通过for...in循环,再使用Object.keys()、Object.values()、Object.entries等方法获取键、值或键值对。
10.call、apply、bind
作用:都适用于改变this的指向,
call:立即执行,多个参数
func.call(作用域,参数1,参数2,...)
apply:立即执行,参数是数组
func.apply(作用域,[参数1,参数2,...])
bind: 不会立即执行。多个参数
func.bind(作用域,参数1,参数2,...)
11.let、const和var
let\const:
都是块级作用域(暂时性死区),只能在代码块中使用,不存在变量提升
在同一代码块中,不允许重复声明
const生命的是一个只读常量
var:
生命的变量会挂在window上
存在变量提升,在声明之前访问不报错
12.typeof和instanceof的区别
**typeof:**用于检测一个变量的基本数据类型。它返回一个表示数据类型的字符串,可能的返回值包括:"number"、"string"、"boolean"、"function"、"object"、"undefined"、"symbol"、"bigint"。对于null、数组和对象,typeof会返回"object"
**instanceof:**用于判断一个对象是否是某个构造函数的实例。返回true/false
13.内存泄露和闭包
垃圾:不用了的数据
内存泄漏:垃圾未被回收
垃圾回收:浏览器把访问不到的数据给标记清除,腾出内存空间
闭包:
闭包是指有权访问另一个函数作用域的变量的函数,闭包可以通过函数嵌套和变量引用实现。
1.如果一个本应该被销毁的函数没有回收,那么他里面的词法环境也无法被回收,可能导致内存泄漏
2.共享词法环境中的无用函数,也无法被销毁
防治措施:
变量不用了及时销毁
减少打印和闭包的使用
14.for in和for of
for in适合遍历对象,for in遍历的是数组的索引,对象的属性,以及原型链上的属性。
for of适合遍历数组。
六、网络问题
1.跨域解决方案
原因:浏览器同源策略-由于请求发出--服务器响应-但浏览器校验未通过,目标都是保持生产环境和开发环境一致!
代理:(前端)
webpack或者vite的devServer中配置proxy,如果生产环境是不跨域的,那么前端必须使用代理
CORS方案:(后端)
保证服务器是自己的,让服务器明确表示这个请求是通过的。浏览器收到服务器同意通过,那么允许跨域。
简单请求是在请求时的origin源头上带上访问地址,服务端同意,会在响应头加上Access-Control-Allow-Origin:*(全部通过)或者 访问地址;
预检请求第一步浏览器在Options中带着访问地址、请求方法、参数等去询问服务器,服务器需要明确告知同意允许访问地址、请求方法、参数。第二步再发送真实请求和简单请求一致。
2.简单请求和预检请求
**简单请求:**不动header、请求方式为get\head\post、content-type为text/plain或者multipart/form-data或者application/x-www-form-urlencoded
**预检请求:**凡是不满足简单请求的都是预检请求,比如axios请求传参,他的content-type为application/json
3.http和https的区别
**http:**端口号默认80;明文传输不需要证书;
https: 端口号默认443;使用SSL/TLS对数据进行加密和安全认证,需要CA证书;浏览器发起https请求,服务器会把配置好的公钥证书给到浏览器,浏览器去验证证书的有效性生成对称密钥,然后加密发给服务端,服务端使用私钥解密得到对称密钥,双方得到相同的对称密钥。请求和响应双方都要使用此对称密钥加密和解密。防止冒充、篡改、安全性更高,但更消耗服务器资源。
TCP 三次握手和四次挥手:
三次握手:客户端发起syn询问服务端(你ok吗)---服务端收到回复ack并且询问syn同时进行(我OK,你OK吗)---ke客户端收到回复ack(我也OK),最终建立链接
四次挥手:客户端发起fin告知服务端(我要结束了)---服务端收到回复ack(我知道了)---服务器处理完最后的事情告知客户端fin(我也要结束了)-客户端收到回复ack(我知道了),随后断开连接
4.JWT- json web token 身份验证
原理就是服务端利用一个 密钥+用户端传过来的信息 进行签名计算,再把结果返回到前端,前端获取到签名后存起来,每次请求带过去,后端使用密钥+前端传过来的信息计算签名与带过去的签名比较。确保信息不被篡改。
JWT把格式做了一个标准化,header+payload计算签名signature
5.单点登录SSO
用于用户在多个相关但独立的系统中,只需登陆一次就可以访问所有系统的场景。
提高生产力和用户体验、降低密码管理复杂度、简化用户信息维护等
(1)同域名下的单点登录:
sessionID+cookie模式:强控制力、认证中心服务器压力大
服务器抽离一个SSO登录系统专门管理用户登录权限
前端1登录后拿到服务器返回的凭证sessionID存到cookie,同域名下cookie共享,前端2拿到cookie直接登录
(2)不同域名下的单点登录:
双token模式-jwt:详见刷新token无感章节,无强控制力,服务器压力小
6.web3.0理解
特点:高薪、远程、低门槛、英语、风险高(岗位少、公司存活时间短)
区块链-分布式存储系统
用户数据的主动权,由平台向用户自身转变
法律风险(加密货币)
去中心化,每个模块自己管理自己,无需传统机构代理
技术:技术就是普通的一些前端技术
7.websocket与传统http的作用和区别
1.当客户端想要用websocket来进行即时通讯里,**握手阶段**是采用http/https完成的一次特殊请求。
请求地址为:ws://XXXX. wss://XXX
请求头:connection:upgrade,upgrade:webscoket,版本号、websocket-key
响应:消息码**101** 切换协议、connection:upgrade,upgrade:webscoket,版本号、websocket-key
2.区别:
都是基于TCP的协议(全双工)
websocket:(全双工)
持久高效通信帧传递、无需处理跨域问题、支持文本和二进制、与http兼容;增加服务器资源消耗、兼容性、发送的数据包不能超过2GB
http/https:(半双工)
3.socket和websocket:
socket:在传输层,将两个设备之间搭建一个通道,可以允许通信,提供一个接口功能,技术比较麻烦,但能处理更多难度的通信需求。
websocket:在网络层,主要是让网页里的双向实时通信变得简单的协议,容易上手。
8.如何取消a xi o s请求
请求实际上是不可以取消,取消的是发送端的响应接收。必须删除操作是不可以的,删除接口发送后,后端已经删除了,前端却不知道。
实际上是调用XHR的abort方法
对于axios来说,内部的cancelToken方法可以取消请求,请求重复取消接下来的请求,可以让每一个请求都创建一个唯一key保存,每次请求判断是否存在重复。
9.刷新token无感
1.登录时会返回一个长token和一个短token,长token用来请求新的短token,短token是用来请求资源的时候Authorization加上的;axios拦截请求保存两个长短对应token到localstorage。
2.请求接口当拦截到不是刷新token的请求响应401了,重新用长token去请求刷新短token,保存新的短token重新请求接口axiosServer.request(res.config)
3.当请求刷新短token的响应401了,代表长token也失效了,退出登录
10.浏览器SEO
1.网页title设置、meta标签 网站描述和关键字
2.语义化代码如head、footer、article
3.图片加上alt属性
4.重要的内容放在最前面,不用js输出
5.使用text-indent将H1标签内缩隐藏增加关键字,一般加载logo里
6.少用iframe,搜索引擎不会抓取里面的内容
7.友情链接i标签,链接和自己网站差不多内容差不多并且质量高的网站
11.大屏适配解决方案(vue3-scale-box)
1.保持16:9的比例
以1920*1080的设计图来计算,获取根节点大小,当window进行resize的时候,计算浏览器宽高innerWidth\innerHeight与设计图宽高的对应比例,找到最小的比例用来缩放
2.计算(浏览器的宽高-设计图的宽高*缩放比例)/2的值进行top和left的定位
transform:translate(left top) scale(最小值)
3,可以把变形做一个过渡动画
4.可以把窗口的改变做一个防抖
12.如何解决页面大规模请求接口
背景:大屏接口过多、数据采集平台接口多
方法:
1.滑动窗口逻辑---队列的形式
封装函数参数为(任务列表,并发数),返回一个promise,里面包含并发数任务依次执行,当前任务执行完后运行下一个已有任务,当任务执行完并后resolve。
2.防抖、节流
防抖:取短时间内的最后一次
节流:取规定时间间隔上的那些次,限制频率
3.分页加载和无限滚动
13.如何处理页面白屏
具体情况具体分析,
performance---summery看文件执行的时间长短(js\render\还是网络造成)
1.使用v-show代替v-if、静态资源压缩、异步加载方式、减少请求数量、提前渲染关键内容。
2.使用延迟装载(defer),按帧requestAnimateFrame渲染,可以使用户先看到视口内容。
3.link资源网络请求可以进行强缓存,通过和后端上了开启强缓存
4.dns域名解析提前,提前找到所有域名,通过link rel=dns-prefetch进行提前解析
5.骨架屏、使用预加载link rel=prefetch 或者 link rel=preload
6.tree shaking去除未使用代码
7.compression 压缩 资源处理首屏优化,vite主要通过Gzip压缩、代码分割和资源预加载等策略实现
七.css问题
1.清除浮动
浮动元素会脱离文档流,不占据空间,可以左右移动直到碰到父元素或者其他浮动元素。浮动元素必须有宽度,具有行内块元素的特性。紧挨浮动元素间不会有缝隙。
解决浮动元素引起父元素高度塌陷的方法:
为父元素设置高度和overflow:hidden,为最后一个子元素设置clear:borh.
2.link和@import的区别
1.link:
是XHTML的标签,不存在兼容问题,
link引入css,是同步加载,在页面引入时同时加载,还可以加载其他文件
link标签是DOM元素,支持使用js控制DOM和修改样式
2.@import:
不支持低版本浏览器,存在兼容问题
只能加载css文件
引入css,是异步加载,需要等页面完全载入后再加载css
@import是一种方式,不支持使用js控制DOM和修改样式
3.水平垂直居中
1.父元素相对定位+子元素绝对定位;子元素上下左右:0,margin:0
2.父元素相对定位+子元素绝对定位;子元素top,left设置50%,transform:translate(-50%,-50%)
3.flex布局:display:flex;justify-content:center;align-items:center;
4.grid布局:display:grid;justify-items:center;align-content:center;
4.绝对定位和浮动的区别
1.都可以让元素脱离文档流,获得块级属性,可以设置宽高
2.float仍然会占位置,绝对定位不会占位置,但会遮盖其他元素
5.文字超宽显示省略号…
a:{
width:200px;
overflow:hidden;
text-overflow:ellipsis;
white-space:nowrap
}
6.css的属性继承
当一个元素的每一个css属性没有计算出确定的值时,这时才需要继承属性。顺序是先看设置的值、再看层叠(有冲突的样式比较重要性-确定最终值)、再看继承、最后才是浏览器默认值。
可继承:字体相关、文本相关、visibility
7.盒模型
盒子的组成=content+padding+border+margin(可以除外)
浏览器属性box-sizing:content-box(默认,width和height为内容尺寸)和border-box(width和height为边框以内的尺寸)
八、其他--待补充(微前端、低代码、electron可能会放到下一篇)