HTML基础
文章目录
- HTML基础
- 网络相关
- DOM
- GIT
- Vue
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. 数字证书
- 为什么要出现数字证书(场景)
一开始,客户端和服务器都不认识,它们准备使用安全信道进行通信
- 客户端请求服务器,得到服务器公开的公钥
- 服务器响应被别人拦截(篡改的公钥),那么你以后的通信就是用的别人的公钥,那别人是不是肯定有私有,那是不是你说的话它都知道
- 不直接响应公钥,响应证书(包含公钥),(来证明这个网站的连接是安全的),这里并没有根源上解决问题,只是提示了网站不安全(你最终是不是还没拿到可靠的公钥)
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:相对过期时间(优先级大)
- 以浏览器时间为准
- Expired:绝对过期时间
- 协商缓存:未命中强缓存(找服务器协商)
- 一定要发请求询问服务器
- 两种情况
- 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请求
- 在浏览器输入要访问的网址,DNS对域名进行解析获取IP
- 根据IP找到对应服务器,建立TCP连接(三次握手)
- 建立HTTP连接
- 服务器响应HTTP连接,浏览器得到HTML代码,进行渲染
- 浏览器解析过程遇到需要的资源再次发起请求获取
- 服务器关闭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
- 遍历整棵树,找到.mode-nav
- 把.mode-nav 作为根,继续遍历后续 h3
- h3 作为根,找到span
从右往左比较节省性能
先找到span,遍历整棵树
span找到根html没找到就结束了
span找到了h3 ,h3 找.mode-nav,节点树比往下找是少的
- 原因还是孩子太多了,父亲少
2. 浏览器如何进行页面渲染
- 获取HTML文件并解析生成DOM树
- 同时解析CSS文件生成样式规则树(style rule)
- 根据DOM树和样式规则树生成渲染树(render tree)
- 进行布局(重排),即为每一个节点分配在屏幕的位置
- 进行重绘,遍历渲染树节点,调用GPU将元素呈现出来
3. 重绘和重排
重排
- 重新生成布局,重新排列元素
- 发生阶段(布局发生改变)
- DOM的增删
- 元素位置,尺寸变化
- 内容变化
- 页面初始化渲染
- 浏览器窗口大小变化
重绘
- 元素的外观发生改变,需要重新绘制
- 发生阶段
- 元素样式发生改变
- 发生了重排
重绘不一定发生重排,重排一定发生重绘
4. 浏览器对重绘和重排的优化
- 不会发生过渡效果!!!
浏览器在渲染是,把多次重排和重绘放入一个队列中,当队列的长度到达某个数值时,才进行一次重排和重绘
等队列中的操作到了一定的数量或者到了一定的时间间隔,浏览器就会flush队列,进行一个批处理
。
这样就会让多次的重排、重绘变成了一次重排重绘。
虽然有了浏览器的优化,但有时候我们写的一些代码可能会强制浏览器提前flush队列,这样浏览器的优化可能起不到作用了。
比如当你请求向浏览器获取一些样式信息的时候(保证获取结果的准确性),就会让浏览器flush队列
- offsetTop, offsetLeft, offsetWidth, offsetHeight
- scrollTop/Left/Width/Height
- clientTop/Left/Width/Height
- 请求了getComputedStyle()
5. 避免重绘和重排的方法
- 集中处理样式
- 不使用offsetTop等系列获取,会flush队列
- 使用transform实现动画效果,不使用left,top
- transform只是视觉效果上的变化,元素只会发生重绘,原有的位置不发生改变
- 使用documentFragment(文档碎片)
GIT
1. git开发流程
- 有一个dev分支,写新功能,在dev分支上新开分支,书写新的功能
- 功能完成后,合并到dev分支
- dev分支完成后,合并到release分支,release分支经过bug修复后,合并到master分支和dev分支
- master分支如果要紧急修复,开辟hotfix分支
- 循环第一步
Vue
1. 生命周期
- 开始创建:beforeCreate,created
- 初始化数据:beforeMount,mounted
- 编译模板
- 挂载DOM:mounted
- 渲染、更新数据:beforeUpdate,Updated
- 卸载: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>
孙组件
<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>
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传参
- 地址栏不显示
- 只能是命名路由
- 刷新参数丢失
-
可以配合 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传参
- 地址栏不显示
- 只能是命名路由
- 刷新参数丢失
-
可以配合 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静态结构