Html
1.H5新增了那些标签?
语义化标签:`<header>`:头部标签
`<nav>`:导航标签
`<section>`:块级标签 注释*
`<article>`:内容标签 1.需要把它们转化为块级元素 display:block
`<aside>`:侧边栏标签 2.主要用于移动端
`<footer>`:尾部标签
多媒体标签:`<video>`视频标签 `<audio>`音频标签
图形标签:<canvas>
本地离线存储(分为cookie和webStorage,而webStorage又分为localStorage和[sessionStorage]
localStorage sessionStorage cookie
input: number date time email url search
C3新增了那些属性?(圆角、阴影、动画等等)
1.处理盒子塌陷?
1、给父盒子添加`overflow:auto;`或者`overflow:hidden;`。
2、父盒子里最下方引入清除浮动块 <div style="clear:both"></div>
3、为外部盒子添加after伪类,设置clear属性清除浮动(主流)
父盒子::after {
content: "";
/* 清除两边的浮动 */
clear: both;
/* 也可以使用display:table; */
display: block;
/* 兼容IE浏览器 */
zoom: 1;
}
2.元素的水平居中、垂直居中方式?
1、 text-align:center line-height:元素高度
2、 盒子模型
3、 定位
4、 flex布局
3.BFC?
1、概述:块级格式化上下文。你可以把BFC看做一个容器,容器里边的元素不会影响到容器外部的元素。
2、特性:1. BFC是一个块级元素在垂直方向上依次排列。
2. BFC是一个独立的容器,内部元素不会影响容器外部的元素。
3. 属于同一个BFC的两个盒子,margin会发生重叠,并且取最大外边距。
3、 创建BFC?
**给父级元素添加以下任意样式**
1. overflow: hidden;
2. display: flex;
3. display: inline-flex;
4. display: inline-block;
5. position: absolute;
6. position: fixed;
4、 作用?
1、解决当父级元素没有高度时,子级元素浮动会使父级元素高度塌陷的问题(清除浮动)
2、解决子级元素外边距会使父级元素塌陷的问题(清除塌陷)
4.回流(重排)和重绘
回流:布局发生改变
重绘:样式发生改变
区别:回流必定会引起重绘,重绘一定不会引起回流,回流会导致页面重排,影响性能
5.css中有哪些方式可以隐藏页面元素?区别是什么?
display: none脱离文档流 无法响应事件 回流重绘visibility: hidden占据文档流 无法响应事件 重绘opacity: 0占据文档流 响应事件 重绘 || 不重绘position: absolute脱离文档流 无法响应事件 回流重绘clip-path: circle(0%)占据文档流 无法响应事件 重绘
6.px、em、rem、vw 和 vh 是用来表示长度单位的,区别是什么?:
px(像素):px是绝对单位,表示屏幕上的实际像素(元素大小不会随着视口的改变而改变)。em:em是相对单位,它相对于其父元素的字体大小来计算(如果父元素的字体大小是16px,那么1em就 等于16px)rem:rem是相对单位,它相对于根元素(html元素)的字体大小来计算vw和vh:vw表示视口宽度的百分比,100vw等于视口的宽度,vh表示视口高度的百分比,100vh等于视口的高度
总结:
-
使用
px可以精确控制元素的大小,但不利于响应式设计。 -
使用
em和rem可以根据父元素或根元素的字体大小来调整元素的大小,适合用于相对大小的设计。 -
使用
vw和vh可以根据视口大小来设置元素的大小,适合用于响应式设计。
js方面
let const 区别
- 都是块级作用域、不能重复声明
- let存在暂时性死区问题 const声明必须赋值,且这个值不能改变,当属性值为对象是可以改变
"暂时性死区"(Temporal Dead Zone,简称 TDZ)是指在 JavaScript 中使用 let 或 const 声明变量时,
该变量在声明之前无法被访问的现象。在变量声明之前对其进行访问会导致 ReferenceError 错误。
//举个例子来说明暂时性死区
console.log(myVar); // ReferenceError: Cannot access 'myVar' before initialization
let myVar = 10;
ES6常用的方法有哪些?
- Promise
`Promise 是异步编程的一种解决方案
`Promise`对象代表一个异步操作,有三种状态:`pending`(进行中)、`fulfilled`(已成功)和`rejected`(已失败)`
一旦状态改变,就不会再变,一旦新建它就会立即执行,无法中途取消,`Promise`对象的状态改变,只有两种可能:
从`pending`变为`fulfilled`或者从`pending`变为`rejected`。
`Promise`构造函数接受一个函数作为参数,该函数的两个参数分别是resolve和reject
`resolve:(pending--->fulfilled)`
`reject:(pending--->rejected)`。
//异步加载图片举例:
function loadImageAsync(url) {
return new Promise(function(resolve, reject) {
const image = new Image();
image.onload = function() {
resolve(image);
};
image.onerror = function() {
reject(new Error('Could not load image at ' + url));
};
image.src = url;
});
}
Promise其他的一些常用的方法:
`Promise.all()` 方法是一个用于处理多个 Promise 实例的方法,它接收一个 Promise 对象数组作为参数,
并返回一个新的 Promise 对象。这个新的 Promise 对象在传入的所有 Promise 对象都成功(resolved)时才会变
为成功状态,如果其中有任何一个 Promise 对象失败(rejected),那么这个新 Promise 对象就会立即变为失败状态。
const promise1 = new Promise((resolve, reject) => {
setTimeout(() => { resolve('Promise 1 resolved')}, 1000);
});
const promise2 = new Promise((resolve, reject) => {
setTimeout(() => { resolve('Promise 2 resolved')}, 2000)
});
const promise3 = new Promise((resolve, reject) => {
setTimeout(() => { resolve('Promise 3 resolved')}, 1500)
});
Promise.all([promise1, promise2, promise3]) .then((results) => {
console.log('All promises resolved:', results);
}) .catch((error) => {
console.error('At least one promise rejected:', error);
});
`Promise.allSettled()`方法与Promise.all很相似,但不同的是
Promise.all传入的所有 Promise 对象都成功(resolved)时才会变为成功状态(fulfilled),
Promise.allSettled是传入的所有 Promise 对象只有等到参数数组的所有 Promise 对象都发生状态变更
(不管是`fulfilled`还是`rejected`),返回的 Promise 对象才会发生状态变更
`Promise.race()和Promise.any()`
Promise.any:只要参数实例有一个变成`fulfilled`状态,包装实例就会变成`fulfilled`状态;
如果所有参数实例都变成`rejected`状态,包装实例就会变成`rejected`状态。
Promise.race:任何一个 Promise 对象的状态发生变化(无论是成功还是失败)时,
就会采用该 Promise 对象的状态作为返回的新 Promise 对象的状态。
- 闭包
闭包:内部函数调用外部函数的参数和变量
闭包的主要用途包括:
1. 保护变量:通过闭包,可以创建私有变量,只有内部函数可以访问和修改这些变量,外部代码无法直接访问,从而提供了一定程度的数据封装和保护。
2. 延续局部变量的生命周期:内部函数可以引用外部函数的变量,即使外部函数已经执行完毕,这些变量依然存在于内部函数的作用域中,从而延续了变量的生命周期。
3. 实现柯里化和偏函数应用:通过闭包,可以将多参数的函数转化为接受部分参数的函数,从而方便地实现柯里化和偏函数应用。
闭包可能会导致内存泄露
解决:使用完时候消费掉
举例:
function createCounter() {
let count = 0; return function increment() {
count++; console.log(count);
if (count >= 10) {
count = null; // 及时释放引用
}
};
}
const counter = createCounter(); // 当不再需要计数器时,手动将 count 设置为 null 释放对其的引用
- 原型、原型链
每个对象都有一个__proto__属性,指向构造函数的prototype。
原型、构造函数、实例、原型链的关系如何?
构造函数(Constructor):构造函数是用来创建对象的函数。当使用 new 关键字调用构造函数时,
会创建一个新的对象,并且该对象会继承构造函数的属性和方法。
原型(Prototype):每个 JavaScript 对象都有一个原型(prototype),原型是对象与其他对象的链接。
通过原型,对象可以继承另一个对象的属性和方法。
实例(Instance):实例是通过构造函数创建的具体对象。每个实例都拥有自己的属性和方法,
同时也可以访问构造函数原型中定义的属性和方法。
原型链(Prototype Chain):当需要访问一个对象的属性或方法时,JavaScript 引擎会先查找对象本身是否拥有
这个属性或方法,如果没有,就会沿着原型链向上查找。原型链是由对象的原型指向构成的链式结构,
直到最顶层的 Object.prototype。
-
箭头函数(箭头函数与普通函数的区别)
- 简洁的语法:箭头函数使用
(参数) => { 函数体 }的形式来定义,相比传统的函数声明方式更为简洁。 - 隐式的返回值:当函数体只有一条语句时,箭头函数会隐式返回该语句的结果,无需使用
return关键字。 - 没有自己的
this:箭头函数没有自己的this值,它会继承外层作用域的this。这意味着在箭头函数内部,无法使用this来引用函数本身,而是继承了外部作用域的this。 - 不能作为构造函数:箭头函数不能通过
new关键字调用,因此不能用作构造函数来创建对象实例。 - 不能绑定
arguments对象:箭头函数没有自己的arguments对象,它会继承外层作用域的arguments对象。
- 简洁的语法:箭头函数使用
-
模板字符串
-
解构赋值
-
Es6数组新增了哪些方法?(扩展运算符、Array.form、fond和findIndex、includes、flat等等)
-
阮一峰老师(es6.ruanyifeng.com/)
防抖、节流函数
防抖:防抖是触发高频事件后n秒内函数只会执行一次,如果n秒内高频事件再次被触发,则重新计算时间。适用于可以多次触发但触发只生效最后一次的场景。(最后一次执行)
/**防抖*/
function handleFd(fn,delay=500){
let timer
return function(){
const args = arguments
if(timer){
clearTimeout(timer)
}
timer = setTimeout(()=>{
fn.call(this,args)
},delay)
}
}
节流:节流是高频事件触发,但在n秒内只会执行一次,如果n秒内触发多次函数,只有一次生效,节流会稀释函数的执行频率。(每隔一段时间执行一次)
/**节流*/
function handleJl(fn,delay=500){
let timer = true
return function(){
const args = arguments
if(timer){
return
}
timer = flase
timer = setTimeout(()=>{
fn.call(this,args)
timer = true
},delay)
}
}
深浅拷贝
/**
*深拷贝:将一个对象从内存中完全拷贝出来,在内存中开辟一个新的空间存放这个对象,两者互不影响
*实现方式:1、JSON.parse(JSON.stringify(obj)) 缺点:
*如果obj里有RegExp、Error对象,则序列化的结果将只得到空对象;
*如果obj里有函数,undefined,则序列化的结果会把函数或 undefined丢失
*2、通过递归实现深拷贝(代码如下)
*/
function deepClone(source){
const targetObj = source.constructor === Array ? [] : {}; // 判断复制的目标是数组还是对象
for(let keys in source){ // 遍历目标
if(source.hasOwnProperty(keys)){
if(source[keys] && typeof source[keys] === 'object'){ // 如果值是对象,就递归一下
targetObj[keys] = source[keys].constructor === Array ? [] : {};
targetObj[keys] = deepClone(source[keys]);
}else{ // 如果不是,就直接赋值
targetObj[keys] = source[keys];
}
}
}
return targetObj;
}
/**浅拷贝:创建一个新的对象,将这个对象的原始属性完全拷贝一份,如果是基本类型,就拷贝基本类型的值,
如果是引用数据类型,拷贝的就是内存里的值,如果其中一个引用类型的值发生了改变,就会影响另一个值*/
//object.assign({},obj)
//扩展运算符、concat
apply、call、bind的区别?
相同点:都可以改变this的指向,第一个参数都是this要指向的对象
不同点:apply与call方法相似,不同之处在于传参的形式不一样,apply是以数组的形式传参
apply与call方法在改变this指向是会立即执行,而bind是稍后执行,而是返回改变this
后的新方法
事件循环{主线程>微任务(promise)>宏任务(定时器函数)}
事件循环:JS是单线程的,意味着同一时间内只能做一件事,但是这并不意味着单线程就是阻塞,而实现单线程非阻塞的方法就是事件循环机制。在JS中把任务分为同步和异步,同步任务和异步任务的执行环境不同,同步任务会进入主线程,异步任务会进入EventQueue(事件队列),主线程中的任务执行完毕后,回去EventQueue中读取对应的任务,并推到主线程中执行,不断重复过程,称为EventLoop(事件循环机制) 理解这里很重要!
<script>
console.log('同步任务1')
setTimeOut(()=>{
console.log('setTimeOut是个宏任务')
},0)
new Promise((reslove,reject)=>{
console.log('遇到new,Promise立即执行')
reslove()
}).then(()=>{
console.log('Promise.then是个微任务')
})
console.log('同步任务2')
</script>
//打印结果:同步任务1 遇到new,Promise立即执行 同步任务2 Promise.then是个微任务 setTimeOut是个宏任务
常见的微任务有
- Promise.then
- Proxy对象替代
- process.nextTick
- MutaionObserver
常见的宏任务
- 整个script
- setTimeout/setInterval
- UI rendering/UI事件
- setImmediate、I/O
当点击 button 时,浏览器的事件流是怎样触发的 ?
在浏览器中,当用户点击一个按钮时,事件流描述了事件(如点击事件)在DOM树中传播的顺序。事件流分为两个主要的模型:冒泡事件流和捕获事件流。
以下是一个简化的说明,描述了从点击按钮到事件处理函数被调用的整个过程:
-
事件捕获阶段:
- 事件首先从文档的根元素(
document对象)开始,然后逐级向下传播到目标元素。 - 在这个阶段,浏览器检查是否有在捕获阶段注册的事件监听器,如果有,这些监听器将被调用。
- 事件首先从文档的根元素(
-
目标阶段:
- 事件到达目标元素(在这个例子中是按钮元素)。
- 在目标元素上注册的所有事件监听器(无论它们是在捕获阶段、冒泡阶段还是两者都有)都会按照注册的顺序被调用。
-
事件冒泡阶段:
- 事件从目标元素开始,逐级向上传播回文档的根元素。
- 在这个阶段,浏览器检查是否有在冒泡阶段注册的事件监听器,如果有,这些监听器将被调用。
关闭Windows.open()弹出的窗口后,如何刷新父页面?
//在关闭弹窗的按钮上添加一下代码?
const flag = window.open(url)
const loop = setTimeOut(()=>{
if(flag.closed){
clearTimeOut(loop)
parent.location.reload()
}
},500)
Vue面试题
1. vue双向数据绑定原理?
是采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty() 来劫持 各个属性的setter,getter,在数据变动时发布消息给订阅者,触发相应的监听回调从而达到数据和视图同步。
2. diff算法
diff 算法是一种通过同层的树节点进行比较的高效算法,比较方式:diff整体策略为:深度优先,同层比较 diff算法 当data发生改变 会根据新的数据生成一个新的虚拟dom ,新的虚拟dom和旧的虚拟dom进行对比, 这个对比的过程就是diff算法,会找到不同地方,只去渲染不同的地方,总的来说就是减少DOM,重绘和回流。
3.虚拟dom
虚拟dom 是一个 JavaScript 对象,通过对象的方式来表示 DOM 结构。将页面的状态抽象为 JS 对象的形式,配合不同的渲染工具,使跨平台渲染成为可能。通过事务处理机制,将多次 DOM 修改的结果一次性更新到页面上,从而有效的减少页面渲染的次数,减少修改DOM的重绘重排次数,提高渲染性能。
4. vue的响应式原理?
get 和 set 方法,data 中声明的属性都被添加了访问器属性,当读取 data 中的数据时自动调用 get 方法,当修改 data 中的数据时,自动调用 set 方法,检测到数据的变化,会通知观察者 Wacher,观察者 Wacher自动触发重新render 当前组件(子组件不会重新渲染),生成新的虚拟 DOM 树,Vue 框架会遍历并对比新虚拟 DOM 树和旧虚拟 DOM 树中每个节点的差别,并记录下来, 最后,加载操作,将所有记录的不同点,局部修改到真实 DOM 树上
5.vue生命周期
-
beforeCreate 创建前,这个时候data中的数据,还未定义,所以不能使用
-
created创建后 最早开始使用 data和methods中数据的钩子函数
-
beforeMount 挂载前 指令已经解析完毕内存中已经生成dom树,但是尚未挂载到页面中去,此时页面还是旧的。
-
mounted 挂载后 dom已经渲染完毕,此时页面和内存中都是最新的数据,最早可以操作DOM元素钩子函数
-
beforeUpdate 更新前 当视图层的数据发生改变会执行这个钩子 内存更新,但是DOM节点还未更新,数据没有与页面同步
-
updated() 更新后 数据更新完成以后触发的方法,DOM节点已经更新
-
beforeDestroy 即将销毁 data和methods中的数据此时还是可以使用的,可以做一些释放内存的操作
-
destroyed 销毁完毕 组件已经全部销毁,Vue实例已经被销毁,Vue中的任何数据都不可用
-
activated 被 keep-alive 缓存的组件激活时调用。
-
deactivated 被 keep-alive 缓存的组件停用时调用。
| Vue2生命周期钩子函数 | Vue3选项式API | Vue3组合式API | 描述 |
|---|---|---|---|
beforeCreate | beforeCreate | setup() | 创建前,此时data和methods还没有初始化 |
created | created | setup() | 创建后,data中有值,尚未挂载,可以进行一些Ajax请求 |
beforeMount | beforeMount | onBeforeMount() | 挂载前,会找到虚拟DOM,编译成Render |
mounted | mounted | onMounted() | 挂载后,DOM已创建,可用于获取访问数据和DOM元素 |
beforeUpdate | beforeUpdate | onBeforeUpdate() | 更新前,内存更新,但是DOM节点还未更新,数据没有与页面同步 |
updated | updated | onUpdated() | 更新后,数据更新完成以后触发的方法,DOM节点已经更新,所有状态已是最新 |
beforeDestroy | beforeUnmount | onBeforeUnmount() | 销毁前,即将销毁 data和methods中的数据此时还是可以使用的,可以做一些释放内存的操作,可用于一些定时器或订阅的取消 |
destroyed | unmounted | onUnmounted() | 销毁后,可用于一些定时器或订阅的取消 |
activated | activated | onActivated() | keep-alive缓存的组件激活时 |
deactivated | deactivated | onDeactivated() | keep-alive缓存的组件停用时 |
| --- | renderTracked | onRenderTracked() | 调试钩子,响应式依赖被收集时调用 |
| --- | renderTriggered | onRenderTriggered() | 调试钩子,响应式依赖被触发时调用 |
| --- | serverPrefetch | onServerPrefetch() | 组件实例在服务器上被渲染前调用 |
6.created和mount的区别?
- created 是最早修改data的最早时机
- mounted 是最早改变dom的最早时机
7.vue父子组件生命周期执行顺序
- 加载渲染过程:父beforeCreate->父created->父beforeMount->子beforeCreate->子created->子beforeMount->子mounted->父mounted
- 子组件更新过程:父beforeUpdate->子beforeUpdate->子updated->父updated
- 父组件更新过程:父beforeUpdate->父updated
- 销毁过程:父beforeDestroy->子beforeDestroy->子destroyed->父destroyed
补充:第一次页面加载时会触发 beforeCreate, created, beforeMount, mounted 这几个钩子
8.$nextTick的作用
nextTick中的回调是在下次 DOM 更新循环结束之后执行的延迟回调。在修改数据之后立即使用这个 方法,获取更新后的DOM。使用场景:可以在created钩子函数中拿到dom节点
9.组件间的通信方式
- 父到子(props)
- 子到父($emit)
- 兄弟间传值(eventBus)
- $ref
- Vuex
10.Vue组件中data为什么是一个函数?为什么写一个返回值?
为了保证函数独立性和复用性,data是一个函数,组件实例化的时候这个函数将会被调用,返回一个 对象使用return包裹后数据中的变量只在当前组件中生效,不会影响其他组件,不使用return包裹的数据 在项目中全局可见,会造成数据污染。
11.Vue中key值的作用?
使用key来给每一个节点添加一个唯一标识,可以根据key,更准确, 更快的找到对应的vnode节点, 更高效的对比虚拟DOM中每个节点是否是相同节点,相同就复用,不相同就删除旧的创建新的 主要作用:高效的更新虚拟DOM
12.用自定义指令做过那些事情?
1.输入框的自动聚焦
<el-input v-focus v-model="item.name" @blur="() => (item.isEdit = false)" autofocus />
directives: {
//自定义输入框每次出现都聚焦的指令
focus: {
inserted: function (el) {
el.focus()
}
}
}
2.Vue自定义指令实现按钮级权限
<a href="https://blog.csdn.net/qq_45710388/article/details/123143610">
13.Vue事件修饰符?
.stop阻止事件冒泡 (阻止传播:stopPropagation()).prevent阻止默认行为 (取消默认事件行为:preventDefault()).capture捕获事件.self仅绑定自身元素.once只执行一次点击
14.v-model 的修饰符?
.lazy通过这个修饰符,转变为在 change 事件再同步.number自动将用户输入值转化为数值类型.trim自动过滤用户输入的收尾空格
15.router的区别?
- $route是“路由信息对象”,包括
path,params,hash,query,fullPath,matched,name等路由信息参数。 - $router是“路由实例” 对象包括了
路由的跳转方法,钩子函数等
跳转路由的方式:1、this.router.go(-1) 3、router-link
16.vue-router的两种模式?
-
hash模式:
location.hash的值实际就是URL#后面的东西,特点:hash虽然出URL中,但不会被包含 在HTTP请求中,对后端完全没有影响,因此改变hash不会重新加载页面 -
history模式:
利用了HTML5 Histoty Interface中新增的pushState()和replaceState()方法特点:前端的url和后端发起请求的url需要一致(否则会报404的错误),需要和后端进⾏配合
17.params和query的区别?
- 属性名不同:query一般使用path,params使用name
- 传参不同:query类似 get,跳转之后页面 url后面会拼接参数,类似?id=1。params类似 post,跳转之后页面 url后面不会拼接参数
- 取参不同:this.route.params.xxx
18.GET和POST的区别?
get参数通过url传递,post放在请求体中get请求在url中传递的参数是有长度限制的,而post没有post比get更安全,因为get参数都暴露在url中get请求只能进行url编码,而post支持多种编码格式
19.Computed和Watch的区别?
- computed 计算属性 : 依赖其它属性值,并且
computed 的值有缓存,只有它依赖的 属性值发生改 变,下一次获取 computed 的值时才会重新计算 computed 的值。使用场景:购物车 - watch 侦听器 : 更多的是观察的作用,无缓存性,类似于某些数据的
监听回调,每当监听的数据变化 时都会执行回调进行后续操作。使用场景:输入框
20.怎样理解 Vue 的单项数据流?
数据总是从父组件传到子组件,子组件没有权利修改父组件传过来的数据,只能请求父组件对原始数 据进行修改。这样会防止从子组件意外改变父组件的状态,从而导致你的应用的数据流向难以理解。
21.vue性能优化
- 尽量减少data中的数据,data中的数据都会增加getter和setter,会收集对应的watcher
- v-if和v-for不能连用
- 如果需要使用v-for给每项元素绑定事件时使用事件代理
- SPA 页面采用keep-alive缓存组件
- 在更多的情况下,使用v-if替代v-show
- key保证唯一
- 使用路由懒加载、异步组件
- 防抖、节流
- 第三方模块按需导入
- 长列表滚动到可视区域动态加载
- 图片懒加载
22.Vue 中强制更新视图的几种方式
方法一:Vue.set() 方法(this.$set())
Vue.set( target, key, value ) 中有三个参数
target:要更改的数据源(可以是对象或者数组)
key:要更改的具体数据 如果是数组 就是索引值
value :重新赋的值
例:this.$set(this.student,"age", 24)
方法二:this.$forceUpdate();
23.怎么解决Vue.js初始化闪屏问题
<div v-cloak>{{ title }}</div>
[v-cloak]{ display:none; }
24.什么是SPA?
SPA(Single Page Application:单页面应用)是一种 Web 应用程序的架构模式,它通过动态加载页面内容,实现在单个页面中提供整个应用程序所需的功能和交互体验,而无需每次加载新页面。这种应用程序通常以 JavaScript、HTML 和 CSS构建,并利用 AJAX 技术从服务器异步请求数据
SPA 的一些特点和优势:
- 无需刷新页面:SPA 在加载初始页面后,通过 AJAX 技术动态获取数据并更新页面内容,实现无需刷新整个页面的交互体验,用户可以流畅地浏览应用。
- 快速响应:由于 SPA 只需要加载一次页面,后续的页面内容更新都是通过 AJAX 请求实现,因此可以实现快速的页面切换和响应,提高用户体验。
- 前后端分离:SPA 通常采用前后端分离的架构,前端负责 UI 展示和交互逻辑,后端提供 API 数据接口,使得开发和维护更加灵活和高效。
- 路由管理:SPA 使用客户端路由管理,通过 URL 的 hash 或 HTML5 History API 实现页面间的切换和导航,同时可以实现页面状态的保存和回溯。
- 缓存和性能优化:SPA 可以通过缓存技术将部分数据或页面缓存到客户端,减少重复请求和提升性能,同时也可以实现按需加载资源,减小首次加载时的资源体积。
- 交互体验:由于 SPA 可以实现动态更新页面内容,因此可以实现丰富的交互效果和动画,提升用户体验和吸引力。
SPA 的一些劣势:对 SEO 不友好、 首次加载时间较长、内存管理等问题需要考虑和解决
解决方法:
- 服务器端渲染(SSR) :使用服务器端渲染可以改善对 SEO 的支持,因为搜索引擎可以更轻松地索引页面内容。通过在服务器端生成页面内容,可以减少客户端加载时间,并提高首屏加载速度。
- 代码分割:将应用程序拆分为多个较小的模块,按需加载,可以减少首次加载时间。这样可以确保用户只下载当前页面所需的代码,而不是整个应用程序。
- 图片和资源优化:优化图片和其他资源的大小和格式,以减少页面加载时间。使用适当的压缩技术和格式可以帮助提高页面性能。
- 懒加载(Lazy Loading) :延迟加载页面中的某些内容,如图片、视频或其他资源,直到用户需要访问它们。这可以减少初始加载时间,提高页面响应速度。
- 内存管理:确保及时释放不再需要的资源和内存,避免内存泄漏。定期检查代码,优化内存使用,尤其是在大型应用程序中。
- 缓存策略:合理设置缓存策略,利用浏览器缓存和服务端缓存来减少重复加载资源的次数,提高页面加载速度。
- 性能监控:使用工具监控应用程序的性能表现,识别潜在的性能瓶颈,并进行相应的优化和改进。
- 移动优化:确保应用程序在移动设备上的性能和用户体验良好。优化移动端页面布局、图片大小等,以提高移动设备上的加载速度和用户体验。
Vuex
1.vuex是什么?
vue框架中状态管理。
2.vuex有哪几种属性?
有五种,State、 Getter、Mutation 、Action、 Module
state: 基本数据(数据源存放地)
getters: 从基本数据派生出来的数据
mutations : 提交更改数据的方法,同步!(更改state中状态的唯一方法) this.store.commit()
actions : 像一个装饰器,包裹mutations,使之可以异步。this.store.dispatch()
modules : 模块化Vuex
Http
1.http常见的状态码
200:请求成功。一般用于GET与POST请求
300:重定向
400:客户端请求的语法错误,服务器无法理解
401:请求要求用户的身份认证
403:服务器理解请求客户端的请求,但是拒绝执行此请求(没有权限)
404:服务器无法根据客户端的请求找到资源(网页)
500:服务器内部错误,无法完成请求
2.http和https的区别?
1、端口:https的端口是443,而http的端口是80,当然两者的连接方式也是不太一样的。
2、传输数据:http传输是明文的,而https是用ssl进行加密的。https具有安全性
3、申请证书:https传输一般是需要申请证书,申请证书可能会需要一定的费用。而http不需要
3.强缓存和协商缓存?
强缓存:浏览器不会像服务器发送任何的请求,直接从本次存储中读取文件并返回Status Code:200 ok
强缓存就是本地缓存,浏览器首次请求资源后,需要再次请求时,浏览器首先获取该资源缓存的header信息,然后根据
Cache-Control和expires来判断该资源在本地缓存中是否过期,若没有过期则直接从本地缓存中获取资源信息,浏览
器就不再向服务器重新请求资源,如过期需要重新发送请求,重新缓存资源,更新缓存的时间
协商缓存:是服务区用来确定缓存资源是否可用过期
向服务器发送请求,服务器会根据这个请求的request header的一些参数来判断是否命中协商缓存,如果命中,则返
回304状态码并带上新的response header通知浏览器从缓存中读取资源
总结:
- 强制缓存和协商缓存都针对静态资源,动态资源实现缓存方法参考上方伪代码。
- 强制缓存在前,协商缓存在后。
- 资源未过期触发强制缓存,资源过期后再触发协商缓存。
- 判断过期的方法expires(绝对时间)、cache-control(相对时间)
- 判断资源是否有更新(Last-Modified 和 ETag)
4.说一下用户输入完Url按下回车,看到网页的过程发生了什么?
1、URL解析
2、DNS域名解析
3、建立tcp连接(三次握手)
4、发送http请求
5、服务器处理请求并返回Http报文
6、浏览器解析渲染页面
5.浏览器渲染页面过程?
1. 解析html代码,生成DOM tree
2. 解析css代码,生成CSSOM tree
3. 通过DOM tree 和 CSSOM tree 生成 Render tree
4. Layout(布局),计算Render tree中各个节点的位置及精确大小
5. Painting(绘制),将render tree渲染到页面上