前端面试基础部分

HTML基础

文章目录

1. HTML 文件中的 DOCTYPE 是什么作用?

  • 告诉浏览器的解析器要使用哪种HTML规范或XHTML规范来解析页面

2. HTML、XML、XHTML 之间有什么区别?

  • 都属于标记语言

  • HTML4 和 XML同时存在

    • HTML4 先用后制定规范,规范不兼容(需要使用规定标签)
    • XML:主要用于数据存储(可以自定义标签(可扩展性))
  • XHTML:解决HTML混乱问题而生,语法方面与XML一样严格(w3c闭门造车)

  • HTML5 :HTML基础上扩展,用于页面呈现

4. 谈谈你对 HTML 语义化的理解?

  • 有利于SEO,可阅读性好

5. HTML5新特性

  • 统一的文件类型声明 <!DOCTYPE html>

  • 新增标签元素

    • section,nav,footer,header,main
    • video,canvas,
  • input新的类型值

    • date,email,url
  • 新的标签属性

    • charset(meta标签),async(script标签)
  • 全域属性

    • contenteditable: div内容变成可编辑(原本只有是input标签可编辑)
    • draggleable:可拖拽(draggleable:true)

6. meta标签用法

  • 设置网页关键词
  • 设置视口
  • 设置http响应头,Content-Type网页内容类型(字符集)
<meta http-equiv="content-type" content="text/html;charset=utf-8">
<!-- 设置字符集可简写为 -->
<meta charset="utf-8">

7. img的srcset


<!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>
</head>
<body>

  <!-- 1. 如果仅仅是对于 dpr 进行响应式处理, 可以用 srcset 
          针对于不同 dpr 的设备, 使用不同的图片显示
  -->
  <!-- <img style="width: 320px; height: 320px;" srcset="320.png 1x, 640.png 2x" alt=""> -->

  <!-- 2. 希望能够在不同的尺寸下, 设置不同的img src (通过js也可以实现) -->
  <!-- 
    srcset: 提供了备选项, 可以用的图片路径 (1元, 5元, 10元, 到底用哪个, 根据符合的条件)
    sizes: 响应式的配置 img 的宽度
      (max-width: 320px) 100vw  样式生效的最大宽度, <=320生效, 100vw, 一个屏幕的宽度
      (max-width: 360px) 320px  320~360范围, 图片的宽度, 设置成 320px
      (max-width: 480px) 360px  360~480范围, 图片的宽度, 设置成 360px
      ...

    如果已经加载了高清图片, 再切换到小屏幕, 没有必要换成小图, 因为已经加载了
    如果要测试, 
      1. 先切换到小屏幕(浏览器宽度小) 
      2. 清除缓存
   -->
  <img alt="img元素srcset属性浅析"
    srcset="
      320.png 320w, 
      480.png 480w, 
      640.png 640w"
    sizes="
      (max-width: 320px) 100vw, 
      (max-width: 360px) 320px,
      (max-width: 480px) 360px,
      (max-width: 640px) 480px,
      640px"
    src="640.png"
  />
  
</body>
</html>

8. script的async和defer

  • 都是异步加载脚本,同步执行脚本
  • async加载完后立即执行(同步)
  • defer等dom渲染完后加载(同步)

async使用场景

  • js脚本之间没有依赖关系

defer

  • js脚本之间有依赖关系,等上面的defer脚本执行再执行(保证顺序)(onload)

9 web存储

  • indexedDB:异步,不会阻塞页面(即使容量很大)
  • cookie:js-cookie :处理cookie插件

10 sticky吸顶

<style>
* {
margin: 0;
padding: 0;
}
.header {
width: 100%;
height: 100px;
background-color: orange;
}
.nav {
width: 100%;
height: 200px;
background-color: pink;
position: sticky;
top: 0px;
}
.main {
width: 100%;
height: 100px;
background-color: skyblue;
}
</style>
<div class="header">我是头部</div>
<div class="nav">我是导航</div>
<div class="container">
<div class="main">我是主体部分1</div>
<div class="main">我是主体部分2</div>
<div class="main">我是主体部分3</div>
<div class="main">我是主体部分4</div>
<div class="main">我是主体部分5</div>
<div class="main">我是主体部分6</div>
<div class="main">我是主体部分7</div>
<div class="main">我是主体部分8</div>
</div>
  • 说明:即.nav盒子距离顶部距离为0时开始吸顶(即滚动距离到nav盒子时开始吸顶)

11. z-index

  • 前提:有定位
  • z-index的小坑, 如果父辈元素有定位, 且配置了z-index, 优先按照父辈元素的定位的z-index进行比较层级
<style>
.father {
width: 100%;
height: 200px;
position: relative;
background-color: skyblue;
z-index: 1;
}
.son {
position: absolute;
width: 100px;
height: 100px;
background-color: red;
left: 0;
top: 0;
z-index: 999;
}
.box2 {
position: absolute;
width: 100px;
    height: 100px;
background-color: blue;
left: 0;
top: 0;
z-index: 100;
}
</style>
<div class="father">
<div class="son"></div>
</div>
<div class="box2"></div>
  • 蓝色盒子最上层(100>1)
  • father:1 son:999,蓝色盒子:100
    • 999被父亲限制了

12. 清除浮动

.clearfix::after{

	content:"";
	height:0;
	line-height:0;
	display:none;
	visibility:hidden;
	clear:both;
}

.clearfix{
	zoom:1;
}

13 左右两边定宽,中间自适应

  • 左盒子left
  • 右盒子right
  • 中间盒子overflow:hidden

原理

  • 3个bfc,互相不影响(不影响其他人)

14.标准盒模型和怪异盒子模型

  • content-box :标准盒模型:盒子的height和width即为内容的实际宽度,(盒子大小加上border和padding)
  • border-box:怪异盒模型:盒子的实际宽度和高度即为,css设置的属性:width和height

15 js的垃圾回收机制

  • 判断内存是否不在使用了

  • 引用计数法:

let o1={
    a:1,
    b:2
}

// o1引用 1


let p=o1

// 引用2

p=1

// 引用=2-1=1

// 

p=null // 引用1-1=0 ,回收


  • 弊端,循环引用
// o1 和 o2相互引用

// 使用完后一直保持引用数为1

let o1={}  //1
let o2={}  //1

o1.a=o2   // 2
o2.a=o1	  // 2

// o1,o2不再使用,

o1.a和o2.a的内存块相互引用


仍有引用数1
标记清除法
  • 从window对象出发,看是否能访问到那块内存空间

16. 作用域链

  • 全局作用域和局部作用域
  • 局部作用域访问其他外部作用域找到变量,找不到继续往外部作用域找,形成了作用域链
vue data节点原理
data(){
    return {
        obj:{1,2,3}
    }
}

// 一个组件初始化时
a.vue
aObj=data()

// 另外一个组件初始化时
b.vue
bObj=data()


// data()函数每次执行,都会返回的对象{obj:{}} 但是多次调用,地址不同

// 相当于
// 每次执行返回的obj地址不同
data(){
    let obj={
        xxx
    }
    
    return obj
}

17 闭包

  • 函数+该函数内可访问函数外的变量
  • 作用:实现数据私有(有点像java的私有变量,提供一个方法修改变量)
function fn(){
    
    let count=0
    
    return add(){
        count++
        console.log('count:'+count)
    }
}

let result=fn()
  • 实现for循环中定时器顺序打印问题
for(var i=0;i<5;i++){
    
    // 立即执行函数,函数套函数,形成引用
    (function(){
        setTimeout(()=>{
            
            console.log(i)
        })
    })(i)
}

18 new构造函数执行过程

  • 创建一个新的对象
  • 构造函数的this指向这个对象
  • 执行构造函数
  • 返回实例

19 转数字的一种方式

  • +数据类型(+“0” +[]…)

20 原型链的理解

  • 为什么要有原型链
// 以构造函数为例,我们实例化两个对象p1,p2

// 共同调用构造函数中的方法
// 就会出现问题,p1.method()  与p2.method()  不相同,而执行逻辑却是一样的,但是这多开辟了一块空间存放method

function Person(){
    this.sayHi=function(){
        console.log('aaa')
    }
}

let p1=new Person()
let p2=new Person()
p1.sayHi()
p2.sayHi()
  • 解决,构造函数的原型上把这个方法挂载上去
Person.prototype.sayHi=function(){
    console.log('aaa')
}
let p1=new Person()
let p2=new Person()
// 这样内存空间不会重复开辟
p1.sayHi()
p2.sayHi()

  • 原型链

实例对象访问属性或者方法时,首先在自己的原型上找(__proto__)

如果找不到,则访问原型的原型

p1.__proto__===Person.prototype

一些辅助方法(实例使用)
  • hasOwnProperty(‘属性名’),判断属性是否是自己的

21. 继承

  • 为什么要有继承

构造函数之间的关系,代码复用

1. 原型继承
  • 子类的prototype=父类的实例对象(原型链实现继承)
  • 为什么不直接这样继承(Student.prototype=Person.prototype)
    • 这样的话学生添加新方法会影响到基类的方法
function Person(name){
    this.name=name
    ...
}
    
function Student(){
    ...
}    
    
Student.prototype=new Person()
  • 原型链:Student.prototype--->p1--->p1.__proto__(Person.prototype)
注意点
  • 只能继承方法
2. 组合继承
  • 为了解决属性没有继承的问题(把父类的构造函数执行一次)
  • 原型继承+借用构造函数call
function Person(name){
    this.name=name
    ...
}
    
function Student(name,id){
    ...
    // call 实现属性的继承
    Person.call(this.name)
    this.id=id
}    
    
Student.prototype=new Person()
3. 寄生组合继承
  • 优化原型继承(new Person() 作为原型其中的属性不是必要的)
  • 希望原型是一个空的对象,不过这个对象的__proto__为Person.prototype, 或者复制一下Person.prototype, 让我的原型指向它
function Person(name){
    this.name=name
    ...
}
    
function Student(name,id){
    ...
    // call 实现属性的继承
    Person.call(this.name)
    this.id=id
}    
    
Student.prototype=Object.create(Person.prototype)
  • Object.create(参数对象)
    • 生成一个新对象
    • 新对象的__proto__—>参数对象
4. class继承
class Person {
  constructor (name, age) {
    this.name = name
    this.age = age
  }
    
    // 即Person.prototype.jump
  jump () {
    console.log('会跳')
  }
}

22 判断是否为数组

object.prototype.toString.call(arr)

Array.isArray(arr)

23 this指向

  • 默认绑定(window,global)
  • 隐式绑定(函数调用者)
  • 上下文绑定(call,apply,bind)

24 宏任务

  • 主线程要执行的代码,定时器
  • 微任务:promise,then.catch

网络相关

1. HTTPS

  • HTTPS为什么要出现

    • HTTP传输数据是明文的,https对传输数据进行加密
  • HTTPS

    • 对称加密+非对称加密

    非对称加密什么:对称加密的密钥

    对称加密密钥传输成功后,双方都使用对称的密钥进行数据通信

    • 为什么这样做

    非对称加密大型数据是需要性能支撑

2. 数字证书

  • 为什么要出现数字证书(场景)

一开始,客户端和服务器都不认识,它们准备使用安全信道进行通信

  1. 客户端请求服务器,得到服务器公开的公钥
  2. 服务器响应被别人拦截(篡改的公钥),那么你以后的通信就是用的别人的公钥,那别人是不是肯定有私有,那是不是你说的话它都知道
  • 不直接响应公钥,响应证书(包含公钥),(来证明这个网站的连接是安全的),这里并没有根源上解决问题,只是提示了网站不安全(你最终是不是还没拿到可靠的公钥)

3. 数字签名

  • 为了保证证书不被篡改

对证书hash生成唯一标识,唯一标识通过ca私钥加密发给接收方,接收方对网站发过来的证书同样hash(1),ca发过来的进行ca公钥解密(2)

比对1,2

4. HTTP2的优势

  • 二进制传输数据,解析更高效
  • 头部压缩:请求头重复的部分记录下来
  • 服务器推送
  • 多路复用
    • 一个tcp连接承载多个数量的双向通信

5. HTTP缓存

  • web服务缓存:数据库缓存,服务端缓存(代理服务器缓存),浏览器缓存
  • 浏览器缓存:HTTP缓存,本地存储(cookie,localstorage,indexFb)
5.1 HTTP缓存(加快页面加载效率)
  • 强缓存:食品过期时间(进行判断,是否资源过期,如果未过期,直接使用缓存)
    • Expired:绝对过期时间
      • 问题:服务器时间和浏览器时间不一致,出现cache-control
      • 时间服务器发过来,判断却与浏览器时间比对
    • cache-control:相对过期时间(优先级大)
      • 以浏览器时间为准
  • 协商缓存:未命中强缓存(找服务器协商)
    • 一定要发请求询问服务器
    • 两种情况
      • 304:继续读缓存
      • 200:重新发请求
    • 过程
      • 第一个请求资源是,服务器会返回最后修改时间Last-modify
      • 进行协商缓存请求时,请求头包含if-modify-since(值为未修改之前的最后修改时间),服务器收到后根据现在资源的最后修改时间与if-modify-since比对,进行反馈
    • ETag/if-none-Match(优先级大于last-modify)
      • 为了解决修改日期问题:一秒内修改多次,时间上无差别,认为没有修改
      • 而Etag这是文件校验码

了解专业术语

  • 缓存命中率:多少请求是从缓存中读取的

6. HTTP请求分类

  • get/delete:数据拼接在请求头
  • post/put/patch:数据通过请求体传输

6.1 get与post请求的区别

  • 数据传输:get:地址栏,post:请求体
  • 数据类型:get:ascall码,post:任何
  • 功能特性:get:幂等:多次请求的结果和一次请求结果相同
    • post:多次请求的结果不相同

6.2 报文结构

  • 请求/响应/行
  • 请求/响应/头
  • 空行
  • 请求/响应/体

请求行

GET xxx.com HTTP/1.1

响应行

HTTP/1.1 200 ok

6.3 HTTP 长连接

  • HTTP/1.1加入
  • connection:keep-alive\
  • 连接限制:Keep-alive:timeout=5,max=100
    • 超时时间
    • 请求次数

7. TCP

  • 面向连接的,可靠服务
  • 只支持一对一
  • 确认重传机制保证可靠通信
  • TCP是面向字节的,累积确认保证顺序
  • TCP使用滑动窗口实现流量控制
7.1 一次完整的HTTP请求
  1. 在浏览器输入要访问的网址,DNS对域名进行解析获取IP
  2. 根据IP找到对应服务器,建立TCP连接(三次握手)
  3. 建立HTTP连接
  4. 服务器响应HTTP连接,浏览器得到HTML代码,进行渲染
  5. 浏览器解析过程遇到需要的资源再次发起请求获取
  6. 服务器关闭TCP连接(四次握手)
7.2 要点
  • DNS域名解析
    • 递归查询:以DNS服务器身份去查询ip
    • 迭代查询:本地服务器迭代其他域名服务器
    • 查询过程:浏览器缓存–>本地缓存(hosts)–>本地域名服务器–>根域名服务器—>顶级(可能找到)–>权限域名服务器(可能找到)
  • HTML渲染
    • html—>dom
    • css—>渲染树
    • 边解析边下载(浏览器)
    • js单线程(会阻塞资源下载),为了防止DOM结构被js修改

7.3 TCP三次握手

  • 服务器方被动打开pcb控制块,等待客户的一方发起连接请求
  • 客户端发起请求后(SYN=1,seq=x)
  • 服务器收到并确认后(SYN=1,ACK=1,seq=y,ack=x+1)
  • 客户端发确认(ACK=1,ack=y+1)

为什么是三次,防止第二次的确认迟到,建立错误的连接

8. UDP

  • 无连接,不可靠
  • 支持一对多
  • 速率快,额外开销少

9. 前端如何实现即时通讯

  • 为什么不能实现

HTTP协议只能客户端发起请求,服务器响应,而服务器主动推送做不到

  • 实现方式
    • 短轮询
    • Comet
    • SSE
    • WebSocket
短轮询
  • 客户端定时发送请求,获取服务器最新数据
    • 实现简单,浏览器兼容
    • 资源消耗大
Comet-ajax长轮询
  • 客户端通过xhr对象发起HTTP请求,如果服务器没有更新数据,请求会一直阻塞

    • 结果:服务器更新数据,返回结果,再次长轮询
      • 服务器不更新数据,请求超时,再次长轮询
  • 优缺点

    • 浏览器兼容性好
    • 服务器压力大,请求在服务器端不处理
SSE
  • 服务端推送,基于HTTP,HTML5中的流数据传输
    • 浏览器发送请求,服务器声明此次发送的数据为流数据,之后服务器一直向客户端发送数据
  • 优缺点
    • 不是严格意义上的双向通信,
    • 兼容性不好,
WebSocket

DOM

1. 浏览器如何解析CSS选择器

  • 从右往左解析

为什么不是从左往右

因为从左往右需要遍历整课DOM树,例如.mode-nav h3 span

  1. 遍历整棵树,找到.mode-nav
  2. 把.mode-nav 作为根,继续遍历后续 h3
  3. h3 作为根,找到span

从右往左比较节省性能

先找到span,遍历整棵树

span找到根html没找到就结束了

span找到了h3 ,h3 找.mode-nav,节点树比往下找是少的

  • 原因还是孩子太多了,父亲少

2. 浏览器如何进行页面渲染

  1. 获取HTML文件并解析生成DOM树
  2. 同时解析CSS文件生成样式规则树(style rule)
  3. 根据DOM树和样式规则树生成渲染树(render tree)
  4. 进行布局(重排),即为每一个节点分配在屏幕的位置
  5. 进行重绘,遍历渲染树节点,调用GPU将元素呈现出来

3. 重绘和重排

重排
  • 重新生成布局,重新排列元素
  • 发生阶段(布局发生改变)
    • DOM的增删
    • 元素位置,尺寸变化
    • 内容变化
    • 页面初始化渲染
    • 浏览器窗口大小变化
重绘
  • 元素的外观发生改变,需要重新绘制
  • 发生阶段
    • 元素样式发生改变
    • 发生了重排

重绘不一定发生重排,重排一定发生重绘

4. 浏览器对重绘和重排的优化

  • 不会发生过渡效果!!!

浏览器在渲染是,把多次重排和重绘放入一个队列中,当队列的长度到达某个数值时,才进行一次重排和重绘

等队列中的操作到了一定的数量或者到了一定的时间间隔,浏览器就会flush队列,进行一个批处理

这样就会让多次的重排、重绘变成了一次重排重绘。

虽然有了浏览器的优化,但有时候我们写的一些代码可能会强制浏览器提前flush队列,这样浏览器的优化可能起不到作用了。

比如当你请求向浏览器获取一些样式信息的时候(保证获取结果的准确性),就会让浏览器flush队列

  1. offsetTop, offsetLeft, offsetWidth, offsetHeight
  2. scrollTop/Left/Width/Height
  3. clientTop/Left/Width/Height
  4. 请求了getComputedStyle()

5. 避免重绘和重排的方法

  1. 集中处理样式
  2. 不使用offsetTop等系列获取,会flush队列
  3. 使用transform实现动画效果,不使用left,top
    • transform只是视觉效果上的变化,元素只会发生重绘,原有的位置不发生改变
  4. 使用documentFragment(文档碎片)

GIT

1. git开发流程

  • 有一个dev分支,写新功能,在dev分支上新开分支,书写新的功能
  • 功能完成后,合并到dev分支
  • dev分支完成后,合并到release分支,release分支经过bug修复后,合并到master分支和dev分支
  • master分支如果要紧急修复,开辟hotfix分支
  • 循环第一步

Vue

1. 生命周期

  1. 开始创建:beforeCreate,created
  2. 初始化数据:beforeMount,mounted
  3. 编译模板
  4. 挂载DOM:mounted
  5. 渲染、更新数据:beforeUpdate,Updated
  6. 卸载:beforeDestroy,destoryed

5.3 $children $parent $refs

(1) $children

父组件中, $children 返回的是一个组件集合,如果你能清楚的知道子组件的顺序,你也可以使用下标来操作

// 父组件中
<template>
  <div class="hello_world">
    <com-a></com-a>
    <com-b></com-b>
  </div>
</template>

this.$children[0] => <com-a></com-a>

this.$children[1] => <com-b></com-b>

(2) $parent

子组件中, this.$parent 指向父组件

this.$parent.xxx = 200

this.$parent.fn()

(3) $refs

通过添加 ref 和 $refs 配合, 也可以很方便的获取子组件, 访问调用子组件的属性或方法

// 父组件中
<template>
  <div class="hello_world">
    <com-a ref="coma"></com-a>  // this.$refs.coma.count = 200
    <com-b ref="comb"></com-b>  // this.$refs.comb.addFn()
  </div>
</template>

this.$refs.coma => <com-a></com-a>

this.$refs.comb => <com-b></com-b>

5.4 provide inject

**成对出现:**provide和inject是成对出现的

作用:用于父组件向子孙组件传递数据

使用方法:

  • provide在父组件中, 返回要传给下级的数据
  • inject在需要使用这个数据的子孙组件中注入数据。(不论组件层次有多深)

父组件

export default {
	provide () {
        return {
            value: this.value // 共享给子孙组件的数据
        }
    },
    data () {
        return {
            value: '父组件的数据',
            money: 100
        }
    }
}

子孙组件

export default {
    inject: ['value'],
    props: {
        ...
    }
}

5.5 $attrs $listeners

在 Vue 2.4 版本中加⼊的 $attrs$listeners 可以用来作为跨级组件之间的通信机制。 (父传孙)

父组件

<template>
  <div>
    <my-child1 :money="100" desc='你好哇' @test1="fn1" @test2="fn2"></my-child1>
  </div>
</template>

子组件

<template>
  <div class="my-child1">
    <!-- $attrs => { "money": 100, "desc": "你好哇" } -->
    <div>{{ $attrs }}</div>
    <my-child2 v-bind="$attrs" v-on="$listeners" ></my-child2>
  </div>
</template>

<script>
import MyChild2 from './my-child2'
export default {
  created () {
    console.log(this.$listeners)
  },
  components: {
    MyChild2
  }
}
</script>

image-20210309011422081

孙组件

<template>
  <div>
    我是child2 - {{ money }} - {{ desc }}
    <button @click="clickFn">按钮</button>
  </div>
</template>

<script>
export default {
  props: ['money', 'desc'],
  methods: {
    clickFn () {
      this.$emit('test1', '嘎嘎')
      this.$emit('test2', '嘿嘿')
    }
  }
}
</script>

image-20210309122823432

7. Vue双向数据绑定原理

  • definedProperty(vue2)
    • 监听单个属性
    • 只支持get,set
    • 兼容性IE9
  • Proxy(vue3)
    • 监听对象,数组的变化
    • 支持多种数据变化的劫持(get,set,deleteProperty)

7.1 M V VM设计模式

Modal层:数据模型层
  • ajax请求得到的数据
View层:视图模板层
ViewModal层:视图模型层
  • 暴露数据给View层,进行数据般的,指令声明,进行业务逻辑实现

核心

  • 数据驱动视图
  • 双向数据绑定

7.2 computed与watch的区别

  • computed
    • 必须有返回值
    • 依赖的属性发生变化,计算属性的值重新计算
    • 可以缓存
  • watch
    • 监视数据的变化
    • 没有返回值,而是数据变化后进行一系列的逻辑操作

7.3 vue响应式系统的基本原理

  • 通过Object.defineProperty完成对数据的劫持,通过观察者模式完成对于节点的数据更新
观察者模式
  • 定义对象间一种一对多的依赖关系,当一个对象的状态发生改变时,就通知所有依赖于它的对象

一句话概括
  • vue采用观察者模式,劫持需要变化的数据,当数据发生变化时,会通知到依赖收集dep,观察者watcher(计算属性,侦听器,渲染)会订阅dep,dep得到数据更新的情况后会通知watcher,watcher处理后进行视图的更新渲染

7.4 Vue key的作用

  • 给虚拟dom添加标识,便于新旧dom的比较

为什么需要加标识

  • 默认比较算法diff:同层元素之间按下标比较,0–0,1–1

  • 场景:如果新旧dom其他差别不大,只是新dom前插了一个元素,那么下标比较是不是全错,性能就低了

  • 加上key:就可以实现相同key的比较
    • 以空间换时间

7.5 router传参

  • query传参

    • 拼接在地址栏
    • 可以path,也可以命名路由
    this.$router.push({
        path:'/home',
        query:{
            
        }
    })
    
    this.$router.push({
        name:'home',
        query:{
            
        }
    })
    
    • 刷新参数不丢失
  • params传参

    • 地址栏不显示
    • 只能是命名路由
    • 刷新参数丢失
  1. 可以配合 localStorage 使用

    (1) A 跳转路由到 B, 通过 params 传值

    (2) B 页面中, 立刻通过 this.$route.params 获取参数

    ​ (获取参数的逻辑, 优先从$route中拿, 如果拿不到(说明刷新了), 从本地取即可)

    (3) 拿到参数后, 立刻存到本地 (保证刷新丢失后, 还能从本地拿)

    (4) 实现功能…

B页面的逻辑

created () {
    let username = this.$route.params.username
    if (username) {
        // 刚跳过来, 有参数, 立刻存起来
        localStorage.setItem('myParams', JSON.stringify(this.$route.params))
    } else {
        // 没有, 说明用户刷新了, 丢失了params, username参数, 本地拿
        username = JSON.parse(localStorage.getItem('myParams')).username
    }
}

7.6 vue的SEO优化

服务端渲染SSR

  • 单页面的vue,网络爬虫只能看到div根标签(其他内容由js渲染),内容为空
  • 服务端渲染就是把html结构在服务端生成,发给浏览器,爬虫爬取到的就是完整的(这里需要后端为nodejs)

静态化

  • nuxt.js实现静态化打包(打包时生成html的静态结构)
  • 不支持路径参数路由:/user/:id

插件预渲染

  • 少数页面进行SEO
  • 速度慢

Phantomjs

  • 针对爬虫(机器)用户,SEO排名多由爬虫用户决定
    默认比较算法diff:同层元素之间按下标比较,0–0,1–1

  • 场景:如果新旧dom其他差别不大,只是新dom前插了一个元素,那么下标比较是不是全错,性能就低了

[外链图片转存中…(img-eTxE591M-1678501561689)]

  • 加上key:就可以实现相同key的比较
    • 以空间换时间

7.5 router传参

  • query传参

    • 拼接在地址栏
    • 可以path,也可以命名路由
    this.$router.push({
        path:'/home',
        query:{
            
        }
    })
    
    this.$router.push({
        name:'home',
        query:{
            
        }
    })
    
    • 刷新参数不丢失
  • params传参

    • 地址栏不显示
    • 只能是命名路由
    • 刷新参数丢失
  1. 可以配合 localStorage 使用

    (1) A 跳转路由到 B, 通过 params 传值

    (2) B 页面中, 立刻通过 this.$route.params 获取参数

    ​ (获取参数的逻辑, 优先从$route中拿, 如果拿不到(说明刷新了), 从本地取即可)

    (3) 拿到参数后, 立刻存到本地 (保证刷新丢失后, 还能从本地拿)

    (4) 实现功能…

B页面的逻辑

created () {
    let username = this.$route.params.username
    if (username) {
        // 刚跳过来, 有参数, 立刻存起来
        localStorage.setItem('myParams', JSON.stringify(this.$route.params))
    } else {
        // 没有, 说明用户刷新了, 丢失了params, username参数, 本地拿
        username = JSON.parse(localStorage.getItem('myParams')).username
    }
}

7.6 vue的SEO优化

服务端渲染SSR

  • 单页面的vue,网络爬虫只能看到div根标签(其他内容由js渲染),内容为空
  • 服务端渲染就是把html结构在服务端生成,发给浏览器,爬虫爬取到的就是完整的(这里需要后端为nodejs)

静态化

  • nuxt.js实现静态化打包(打包时生成html的静态结构)
  • 不支持路径参数路由:/user/:id

插件预渲染

  • 少数页面进行SEO
  • 速度慢

Phantomjs

  • 针对爬虫(机器)用户,SEO排名多由爬虫用户决定
  • 判断是否为爬虫,是的话调用后台node.js环境生成html静态结构
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值