在HTML页面中的所有元素都可以看成是一个盒子
盒子的组成:内容content、内边距padding、边框border、外边距margin
盒模型的类型:
标准盒模型
margin + border + padding + content
IE盒模型
margin + content(border + padding)
控制盒模型的模式:box-sizing:content-box(默认值,标准盒模型)、border-box(IE盒模型);
CSS的特性:继承性、层叠性、优先级
优先级:写CSS样式的时候,会给同一个元素添加多个样式,此时谁的权重高就显示谁的样式
标签、类/伪类/属性、全局选择器、行内样式、id、!important
!important > 行内样式 > id > 类/伪类/属性 > 标签 > 全局选择器
display:none;
元素在页面上消失,不占据空间
opacity:0;
设置了元素的透明度为0,元素不可见,占据空间位置
visibility:hidden;
让元素消失,占据空间位置,一种不可见的状态
position:absolute;
将元素移出页面
clip-path
剪切
px是像素,显示器上给我们呈现画面的像素,每个像素的大小是一样,绝对单位长度
rem,相对单位,相对于html根节点的font-size的值,直接给html节点的font-size:62.5%;
1rem = 10px; (16px*62.5%=10px)
重排(回流):布局引擎会根据所有的样式计算出盒模型在页面上的位置和大小。删除/添加DOM元素、修改元素大小位置、内容改变会触发。
重绘:计算好盒模型的位置、大小和其他一些属性之后,浏览器就会根据每个盒模型的特性进行绘制。改变颜色、文本、阴影触发。
浏览器的渲染机制
对DOM的大小、位置进行修改后,浏览器需要重新计算元素的这些几何属性,就叫重排
对DOM的样式进行修改,比如color和background-color,浏览器不需要重新计算几何属性的时候,直接绘制了该元素的新样式,那么这里就只触发了重绘
(1)定位+margin
margin:auto;
(2)定位+transform
top:50%;
left:50%;
transform:translate(-50%,-50%);
(3)flex布局
.father{
display:flex;
justify-content:center;
align-items:center;
}
子类只需要写基础样式即可
(4)grid布局
(5)table布局
CSS的三大特性:继承、层叠、优先级
子元素可以继承父类元素的样式:
1.字体的一些属性:font
2.文本的一些属性:line-height、text-align、color
3.元素的可见性:visibility:hidden
4.表格布局的属性:border-spacing
5.列表的属性:list-style
6.页面样式属性:page
7.声音的样式属性
预处理语言增加了变量、函数、混入等强大的功能
SASS LESS
ECMAScript:JS的核心内容,描述了语言的基础语法,比如var,for,数据类型(数组、字符串),
文档对象模型(DOM):DOM把整个HTML页面规划为元素构成的文档
浏览器对象模型(BOM):对浏览器窗口进行访问和操作
String Boolean Number Array Object Function Math Date RegExp...
Math
abs() sqrt() max() min()
Date
new Date () getYear()
Array
String
concat() length() slice() split()
push():向数组末尾添加一个或多个元素。
pop():从数组末尾删除一个元素并返回被删除的元素。
shift():从数组头部删除一个元素并返回被删除的元素。
unshift():向数组头部添加一个或多个元素。
concat():将两个或多个数组合并为一个新数组。
slice():返回数组的一部分,不会修改原始数组。
splice():从指定位置删除或添加元素,并返回被删除的元素。
sort() unshift() shift() reverse() join() map() filter()
every() some() reduce() isArray() findIndex()
哪些方法会改变原数组?
push() pop() unshift() shift() sort() reverse() splice()
①typeof():对于基本数据类型没问题,遇到引用数据类型就不管用
②instanceof():只能判断引用数据类型,不能判断基本数据类型
③constructor:几乎可以判断基本数据类型和引用数据类型,如果声明了一个构造函数,并把它的原型指向了Array,就无法判断
(‘aaa’).constructor === String //true
④Object.prototype.toString.call()
var opt = Object.prototype.toString
opt.call(‘aaa’)
1怎么理解闭包?
闭包=内层函数+外层函数的变量
2.闭包的作用?
封闭数据,实现数据私有,外部也可以访问函数内部的变量
闭包很有用,因为它允
许将函数与其所操作的某些数据(环境)关联起来
3.闭包可能引起的问题?
内存泄漏 P44
JS里已经分配内存地址的对象,但是由于长时间没有释放或者没办法清除,造成长期占用内存的现象,会让内存资源大幅浪费,最终导致运行速度慢,甚至崩溃的情况。
垃圾回收机制
因素:一些为生命直接赋值的变量;一些未清空的定时器;过度的闭包;一些引用元素没有被清除。
又叫事件代理,原理就是利用了事件冒泡的机制来实现,也就是说把子元素的事件绑定到了父元素的身上
如果子元素组织了事件冒泡,那么委托也就不成立
组织事件冒泡:event.stopPropagation()
addEventListener('click',函数名,true/false) 默认是false(事件冒泡),true(事件捕获)
好处:提高性能,减少事件的绑定,也就减少了内存的占用。
基本数据类型:String Number Boolean undefined null
基本数据类型保存在栈内存当中,保存的就是一个具体的值
引用数据类型(复杂数据类型):Object Function Array
保存在堆内存当中,声明一个引用类型的变量,它保存的是引用类型数据的地址
假如声明两个引用类型同时指向了一个地址的时候,修改其中一个那么另外一个也会改变
原型就是一个普通对象,它是为构造函数的实例共享属性和方法;所有实例中引用的原型都是同一个对象
使用prototype可以把方法挂在原型上,内存只保存一份
__proto__可以理解为指针,实例对象中的属性,指向了构造函数的原型(prototype)
一个实例对象在调用属性和方法的时候,会依次从实例本身-构造函数原型-原型的原型上去查找
1.先创建一个空对象
2.把空对象和构造函数通过原型链进行链接
3.把构造函数的this绑定到新的空对象身上
4.根据构建函数返回的类型判断,如果是值类型,则返回对象,如果是引用类型,就要返回这个引用类型
1.原型链继承
2.借用构造函数继承
3.组合式继承
4.ES6的class类继承
JS引擎 运行上下文 调用栈 事件循环 回调
·JS引擎是JavaScript的解释器,它可以将JavaScript代码转换成可执行的机器代码。不同的浏览器有自己的JS引擎,如Chrome的V8引擎、Firefox的SpiderMonkey引擎等。
·运行上下文是JavaScript中执行代码的上下文环境,每个函数都有一个运行上下文。当函数执行时,它会创建一个新的运行上下文,并执行其中的代码。运行上下文包括全局变量、函数、对象等,当函数执行完毕后,运行上下文将被销毁。
·调用栈是一种数据结构,它记录了当前正在执行的函数以及它们之间的调用关系。当一个函数被调用时,它会被压入调用栈,当它执行完毕后,它会被弹出调用栈。调用栈的深度有限制,如果调用的函数层数太多,会导致栈溢出。
·事件循环是指JavaScript中的事件循环机制,它负责处理异步操作和事件回调。当JavaScript代码执行时,会进入一个事件循环,等待异步操作和事件回调的处理。当异步操作完成或事件触发时,事件循环会将对应的回调函数放入任务队列中,等待执行。事件循环会不断循环执行任务队列中的任务,直到没有任务可执行。(先微任务,后宏任务)
·回调是指将一个函数作为参数传递给另一个函数,并在另一个函数中执行该函数。回调函数通常用于异步操作和事件处理中,可以避免阻塞主线程,提高程序的响应速度。
1.可以在浏览器上直接运行:JavaScript是一种嵌入在HTML文件中的脚本语言,可以直接在浏览器中运行,无需借助服务器端程序。这种设计使得JavaScript非常适合用于快速开发、部署和调试Web应用程序。
2.单线程模式:JavaScript采用单线程模式,即在一个时间段内只能执行一个任务。如果需要执行多个任务,
需要按照一定的顺序排队等待执行。这种设计可以简化语言本身的实现,同时也方便开发者进行调试和优化。
3.弱类型语言:JavaScript是一种弱类型语言,这意味着它不会强制要求变量必须具有特定的数据类型。这种
设计使得JavaScript更加灵活,同时也需要开发者自行处理类型转换和错误处理。
4.事件驱动模型:JavaScript采用事件驱动模型,即通过触发特定的事件来执行相应的代码。这种设计可以实
现异步处理和多线程执行,同时也方便开发者进行模块化和组件化开发。
5.对象模型:JavaScript采用基于对象的语言模型,支持封装、继承和多态等特性。这种设计可以方便开发者进行面向对象编程和组件化开发。
6.垃圾回收机制:JavaScript采用垃圾回收机制,即自动回收不再使用的内存空间,以避免内存泄漏问题。这
种设计可以提高程序的稳定性和性能。
(1)全局对象中的this指向
指向的是window
(2)全局作用域或者普通函数中的this
this永远指向最后调用它的那个对象
严格模式(use strict)下函数内部this指向undefined
在不是箭头函数的情况下
(3)new 关键词改变了this的指向
(4)apply,call,bind
可以改变this指向,不是箭头函数
(5)箭头函数中的this
它的指向在定义的时候就已经确定了
箭头函数它没有this,看外层是否有函数,有就是外层函数的this,没有就是window
基于原型的面向对象(构造函数、原型对象)也不推荐使用箭头函数,因为this无法指向实例对象,this.name = name无法赋值
不适用:构造函数、原型函数、字面量对象中函数(匿名函数)、dom事件函数
适用:需要使用上层this的地方
(6)匿名函数中的this
永远指向了window,匿名函数的执行环境具有全局性,因此this指向window
当没有async和defer这两个属性的时候,
浏览器会立刻加载并执行指定的脚本
有async
加载和渲染后面元素的过程将和script的加载和执行并行进行(异步)
有defer
加载和渲染后面元素的过程将和script的加载并行进行(异步),但是它的执行事件要等
所有元素解析完成之后才会执行
HTML5规定的内容:
setTimeout最小执行时间是4ms
setInterval最小执行时间是10ms
JS的组成:ECMAScript BOM DOM
ES5:ECMAScript5,2009年ECMAScript的第五次修订,ECMAScript2009
ES6:ECMAScript6,2015年ECMAScript的第六次修订,ECMAScript2015,是JS的下一个版本标准
1.新增块级作用域(let,const)
不存在变量提升
存在暂时性死区的问题
块级作用域的内容
不能在同一个作用域内重复声明
2.新增了定义类的语法糖(class)
3.新增了一种基本数据类型(symbol)
4.新增了解构赋值
从数组或者对象中取值,然后给变量赋值
5.新增了函数参数的默认值
6.给数组新增了API
7.对象和数组新增了扩展运算符
8.Promise
解决回调地狱的问题。
自身有all,reject,resolve,race方法
原型上有then,catch
把异步操作队列化
三种状态:pending初始状态,fulfilled操作成功,rejected操作失败
状态:pending -> fulfilled;pending -> rejected 一旦发生,状态就会凝固,不会再变
async await
同步代码做异步的操作,两者必须搭配使用
async表明函数内有异步操作,调用函数会返回promise
await是组成async的表达式,结果是取决于它等待的内容,如果是promise那就是promise的结果,如果是普通函数就进行链式调用
await后的promise如果是reject状态,那么整个async函数都会中断,后面的代码不执行
9.新增了模块化(import,export)
10.新增了set和map数据结构
set就是不重复
map的key的类型不受限制
11.新增了generator
12.新增了箭头函数
不能作为构造函数使用,不能用new
箭头函数就没有原型
箭头函数没有arguments
箭头函数不能用call,apply,bind去改变this的执行
this指向外层第一个函数的this
相同点:
都可以改变函数内部的this指向.
区别点:
call和apply会调用函数,并且改变函数内部this指向
call和apply传递的参数不一样,call传递参数aru1aru2…形式apply必须数组形 式[arg] bind 不会调用函数,可以改变函数内部this指向.
主要应用场景:
call调用函数并且可以传递参数
apply经常跟数组有关系.比如借助于数学对象实现数组最大值最小值 bind 不调用函数,但是还想改变this指向.比如改变定时器内部的this指向.
如果一个函数内可以调用函数本身,那么这个就是递归函数
函数内部调用自己
特别注意:写递归必须要有退出条件return
深拷贝和浅拷贝都只针对引用类型
简单数据类型拷贝值,引用数据类型拷贝的是地址(简单理解:如果是单层对象,没问题。多层对象,即对象里面还有对象就有问题)
·浅拷贝和直接赋值区别:
直接赋值的方法,只要是对象,都会相互影响,因为是直接拷贝对象栈里面的地址。
浅拷贝如果是一层对象,不相互影响,如果出现多层对象拷贝还会相互影响。
·常见方法
拷贝对象:
①Object.assgin(o,object) // 拷贝一个新的object,名为o
②展开运算符 const o = {…object}
拷贝数组:
①Array.prototype.concat()
②[…arr]
拷贝的是对象,不是地址
·常见方法
①通过递归实现深拷贝
②lodash/cloneDeep
③通过JSON.stringify()、JSON.parse()实现
const o = JSON.parse(JSON.stringify(obj))
详:
①通过递归实现深拷贝
普通拷贝直接赋值,遇到数组再次调用这个递归函数,遇到对象再次调用递归,先Array,后Object,顺序不能把变,因为数组也属于对象。
const obj = {
uname: 'pink',
age: 18,
hobbby: ['乒乓球', '足球']
}
const o = {}
// 拷贝函数
function deepCopy(newObj, oldObj) {
for (let k in oldObj) {
// 处理数组的问题
if (oldObj[k] instanceof Array) {
newObj[k] = []
// newObj[k] 是 []
// oldObj[k] 是 ['乒乓球', '足球']
deepCopy(newObj[k] = oldObj[k])
} else if (oldObj[k] instanceof Object) {
//数组和对象不能换位置
newObj[k] = {}
deepCopy(newObj[k] = oldObj[k])
} else {
// k 属性名 uname age oldObj[k] 属性值 18
// newObj[k] === o.uname 给新对象添加属性
newObj[k] = oldObj[k]
}
}
}
deepCopy(o, obj) // 函数调用 两个参数 o 新对象 obj 旧对象
②lodash/cloneDeep
<script sc = "./lodash.min.js"></script>
<script>
const obj = {
uname: 'pink',
age: 18,
hobbby: ['乒乓球', '足球']
}
const o = _.cloneDeep(obj)
</script >
JS是一个单线程的脚本语言
主线程 执行栈 任务队列 宏任务 微任务
主线程先执行同步任务,然后才去执行任务队列里的任务,如果在执行宏任务之前有微任务,那么要先执行微任务
全部执行完之后等待主线程的调用,调用完之后再去任务队列中查看是否有异步任务,这样一个循环往复的过程就是事件循环!
创建交互式网页应用的网页开发技术
在不重新加载整个网页的前提下,与服务器交换数据并更新部分内容
通过XmlHttpRequest对象向服务器发送异步请求,然后从服务器拿到数据,最后通过JS操作DOM更新页面
1.创建XmlHttpRequest对象 xmh
2.通过xmh对象里的open()方法和服务器建立连接
3.构建请求所需的数据,并通过xmh对象的send()发送给服务器
4.通过xmh对象的onreadystate chansge事件监听服务器和你的通信状态
5.接收并处理服务器响应的数据结果
6.把处理的数据更新到HTML页面上
1.get一般是获取数据,post一般是提交数据
2.get参数会放在url上,所以安全性比较差,post是放在body中
3.get请求刷新服务器或退回是没有影响的,post请求退回时会重新提交数据
4.get请求时会被缓存,post请求不会被缓存
5.get请求会被保存在浏览器历史记录中,post不会
6.get请求只能进行url编码,post请求支持很多种
Promise对象,封装了一个异步操作并且还可以获取成功或失败的结果
Promise主要就是解决回调地狱的问题,之前如果异步任务比较多,同时他们之间有相互依赖的关系,
就只能使用回调函数处理,这样就容易形成回调地狱,代码的可读性差,可维护性也很差
有三种状态:pending初始状态 fulfilled成功状态 rejected失败状态
状态改变只会有两种情况,
pending -> fulfilled; pending -> rejected 一旦发生,状态就会凝固,不会再变
首先就是我们无法取消promise,一旦创建它就会立即执行,不能中途取消
如果不设置回调,promise内部抛出的测u哦呜就无法反馈到外面
若当前处于pending状态时,无法得知目前在哪个阶段。
原理:
构造一个Promise实例,实例需要传递函数的参数,这个函数有两个形参,分别都是函数类型,一个是resolve一个是reject
promise上还有then方法,这个方法就是来指定状态改变时的确定操作,resolve是执行第一个函数,reject是执行第二个函数
1.都是处理异步请求的方式
2.promise是ES6,async await 是ES7的语法
3.async await是基于promise实现的,他和promise都是非阻塞性的
优缺点:
1.promise是返回对象我们要用then,catch方法去处理和捕获异常,并且书写方式是链式,容易造成代码重叠,不好维护,async await 是通过tra catch进行捕获异常
2.async await最大的优点就是能让代码看起来像同步一样,只要遇到await就会立刻返回结果,然后再执行后面的操作
promise.then()的方式返回,会出现请求还没返回,就执行了后面的操作
1.cookies
H5标准前的本地存储方式
兼容性好,请求头自带cookie
存储量小,资源浪费,使用麻烦(封装)
2.localstorage
H5加入的以键值对为标准的方式
操作方便,永久存储,兼容性较好
保存值的类型被限定,浏览器在隐私模式下不可读取,不能被爬虫
3.sessionstorage
当前页面关闭后就会立刻清理,会话级别的存储方式
4.indexedDB
H5标准的存储方式,,他是以键值对进行存储,可以快速读取,适合WEB场景
token:验证身份的令牌,一般就是用户通过账号密码登录后,服务端把这些凭证通过加密等一系列操作后得到的字符串
1.存loaclstorage里,后期每次请求接口都需要把它当作一个字段传给后台
2.存cookie中,会自动发送,缺点就是不能跨域
如果存在localstorage中,容易被XSS攻击,但是如果做好了对应的措施,那么是利大于弊
如果存在cookie中会有CSRF攻击
1.客户端用账号密码请求登录
2.服务端收到请求后,需要去验证账号密码
3.验证成功之后,服务端会签发一个token,把这个token发送给客户端
4.客户端收到token后保存起来,可以放在cookie也可以是localstorage
5.客户端每次向服务端发送请求资源的时候,都需要携带这个token
6.服务端收到请求,接着去验证客户端里的token,验证成功才会返回客户端请求的数据
DNS解析
建立TCP连接
发送HTTP请求
服务器处理请求
渲染页面
浏览器会获取HTML和CSS的资源,然后把HTML解析成DOM树
再把CSS解析成CSSOM
把DOM和CSSOM合并为渲染树
布局
把渲染树的每个节点渲染到屏幕上(绘制)
断开TCP连接
DOM树是和HTML标签一一对应的,包括head和隐藏元素
渲染树是不包含head和隐藏元素
精灵图:把多张小图整合到一张大图上,利用定位的一些属性把小图显示在页面上,当访问页面可以减少请求,提高加载速度
base64:传输8Bit字节代码的编码方式,把原本二进制形式转为64个字符的单位,最后组成字符串
base64是会和html css一起下载到浏览器中,减少请求,减少跨域问题,但是一些低版本不支持,若base64体积比原图片大,不利于css的加载。
基于XML语法格式的图像格式,可缩放矢量图,其他图像是基于像素的,SVG是属于对图像形状的描述,本质是文本文件,体积小,并且不管放大多少倍都不会失真
1.SVG可直接插入页面中,成为DOM一部分,然后用JS或CSS进行操作
2.SVG可作为文件被引入
3.SVG可以转为base64引入页面
JSON Web Token 通过JSON形式作为在web应用中的令牌,可以在各方之间安全的把信息作为JSON对象传输
信息传输、授权
JWT的认证流程
1.前端把账号密码发送给后端的接口
2.后端核对账号密码成功后,把用户id等其他信息作为JWT 负载,把它和头部分别进行base64编码拼接后签名,形成一个JWT(token)。
3.前端每日请求时都会把JWT放在HTTP请求头的Authorization字段内
4.后端检查是否存在,如果存在就验证JWT的有效性(签名是否正确,token是否过期)
5.验证通过后后端使用JWT中包含的用户信息进行其他的操作,并返回对应结果
简洁、包含性、因为Token是JSON加密的形式保存在客户端,所以JWT是跨语言的,原则上是任何web形式都支持。
node package manager,node的包管理和分发工具,已经成为分发node模块的标准,是JS的运行环境
npm的组成:网站、注册表、命令行工具
1.请求头信息:
Accept:浏览器告诉服务器所支持的数据类型
Host:浏览器告诉服务器我想访问服务器的哪台主机
Referer:浏览器告诉服务器我是从哪里来的(防盗链)
User-Agent:浏览器类型、版本信息
Date:浏览器告诉服务器我是什么时候访问的
Connection:连接方式
Cookie
X-Request-With:请求方式
2.响应头信息:
Location:这个就是告诉浏览器你要去找谁
Server:告诉浏览器服务器的类型
Content-Type:告诉浏览器返回的数据类型
Refresh:控制了的定时刷新
强缓存(本地缓存)、协商缓存(弱缓存)
强缓:不发起请求,直接使用缓存里的内容,浏览器把JS,CSS,image等存到内存中,下次用户访问直接从内存中取,提高性能
协缓:需要像后台发请求,通过判断来决定是否使用协商缓存,如果请求内容没有变化,则返回304,浏览器就用缓存里的内容
强缓存的触发:
HTTP1.0:时间戳响应标头
HTTP1.1:Cache-Control响应标头
协商缓存触发:
HTTP1.0:请求头:if-modified-since 响应头:last-modified
HTTP1.1:请求头:if-none-match 响应头:Etag
http:// www. aaa.com:8080/index/vue.js
协议 子域名 主域名 端口号 资源
同源策略是浏览器的核心,如果没有这个策略就会遭受网络攻击
主要指的就是协议+域名+端口号三者一致,若其中一个不一样则不是同源,会产生跨域
三个允许跨域加载资源的标签:img link script
跨域是可以发送请求,后端也会正常返回结果,只不过这个结果被浏览器拦截了!
JSONP
CORS
websocket
反向代理
都是应对页面中频繁触发事件的优化方案
防抖:避免事件重复触发
【单位时间内,频繁触发事件,只执行最后一次】
使用场景:1.频繁和服务端交互 2.输入框搜索输入、手机号、邮箱验证输入检测
方法:
·lodash库:_.debounce(fn, 等待时间ms)
·手写防抖函数
4、声明定时器变量
5、每次鼠标移动(事件触发)的时候都要先判断是否有定时器,如果有先 【清除】以前的定时器
6、如果没有定时器,则开启定时器,存入到定时器变量里面
定时器里面写函数调用
节流:把频繁触发的事件减少,每隔一段时间执行
【单位时间内,频繁触发事件,只执行一次】
使用场景:滚动条滚动scroll、鼠标移动mousemove、页面尺寸缩放resize
方法:
·lodash库:_.throttle(fn, 时间间隔ms)
·手写节流函数
1、声明定时器变量
2、每次鼠标移动(事件触发)的时候都要先判断是否有定时器,如果有先 【不开启】新定时器
3、如果没有定时器,则开启定时器,存入到定时器变量里面
JSON是一种纯字符串形式的数据,它本身不提供任何方法,适合在网络中进行传输
JSON数据存储在.json文件中,也可以把JSON数据以字符串的形式保存在数据库、Cookise中
JS提供了JSON.parse() JSON.stringify()
什么时候使用json:定义接口;序列化;生成token;配置文件package.json
可以在渲染数据的地方给一些默认的值
if判断语句
1.在相应其中拦截,判断token返回过期后,调用刷新token的接口
2.后端返回过期时间,前端判断token的过期时间,去调用刷新token的接口
3.写定时器,定时刷新token接口
流程:
1.登录成功后保存token 和 refresh_token
2.在响应拦截器中对401状态码引入刷新token的api方法调用
3.替换保存本地新的token
4.把错误对象里的token替换
5.再次发送未完成的请求
6.如果refresh_token过期了,判断是否过期,过期了就清楚所有token重新登录
分片上传:
1.把需要上传的文件按照一定的规则,分割成相同大小的数据块
2.初始化一个分片上传任务,返回本次分片上传的唯一标识
3.按照一定的规则把各个数据块上传
4.发送完成后,服务端会判断数据上传的完整性,如果完整,那么就会把数据库合并成原始文件
断点续传:
服务端返回,从哪里开始 浏览器自己处理
document.write()
element.innerHTML
document.createElement()
区别:
1.document.write 是直接将内容写入页面的内容流,但是文档流执行完毕,则它会导致页面全部重绘
2.innerHTML是将内容写入某个DOM节点,不会导致页面全部重绘
3.innerHTML 创建多个元素效率更高(不要拼接字符串,采取数组形式拼接),结构稍微复杂
4.createElement()创建多个元素效率稍低一点点,但是结构更清晰
总结:不同浏览器下,innerHTML 效率要比 creatElement 高
当鼠标移动到元素上时就会触发mouseenter事件。
类似mouseover,它们两者之间的差别是
mouseover鼠标经过自身盒子会触发,经过子盒子还会触发。
mouseenter只会经过自身盒子触发。
之所以这样,就是因为mouseenter不会冒泡。
跟mouseenter搭配,鼠标离开mouseleave 同样不会冒泡。
①DOM对象:用原生js获取过来的对象就是DOM对象
②jQuery对象:用iquery方式获取过来的对象是iQuery对象。本质:通过 把 D O M 元素进行了包装③ j Q u e r y 对象只能使用 j Q u e r y 方法, D O M 对象则使用原生的 J a v a S c i r p t 属性和方法 D O M 对象与 j Q u e r y 对象之间是可以相互转换的。因为原生 i s 比 i O u e r v 更大,原生的一些属性和方法 i O u e r v 没有给我们封装,要想使用这些属性和方法需要把 j Q u e r y 对象转换为 D O M 对象才能使用。 1. D O M 对象转换为 j Q u e r y 对象 : 把DOM元素进行了包装 ③jQuery 对象只能使用jQuery方法,DOM 对象则使用原生的 JavaScirpt属性和方法 DOM对象与jQuery对象之间是可以相互转换的。 因为原生is比iOuerv更大,原生的一些属性和方法iOuerv没有给我们封装,要想使用这些属性和方法需要把 jQuery对象转换为DOM对象才能使用。 1.DOM对象转换为jQuery对象: 把DOM元素进行了包装③jQuery对象只能使用jQuery方法,DOM对象则使用原生的JavaScirpt属性和方法DOM对象与jQuery对象之间是可以相互转换的。因为原生is比iOuerv更大,原生的一些属性和方法iOuerv没有给我们封装,要想使用这些属性和方法需要把jQuery对象转换为DOM对象才能使用。1.DOM对象转换为jQuery对象:(DOM对象)
$(div’)
2.jQuery对象转换为DOM对象(两种方式)
$(‘div’) [index] index是索引号
$(‘div’).get(index)index是索引号
遍历内部DOM元素(伪数组形式存储)的过程就叫做隐式选代。
简单理解:jQuery给匹配到的所有元素进行循环遍历,执行相应的方法,而不用我们再进行循环,简化我们的操作,方便我们调用。
作用域链本质上是底层的变量查找机制。
在函数被执行时,会优先在当前函数作用域中查找变量。如果当前作用域查找不到则会依次逐级查找腹肌作用域知道全局作用域。
总结:
·嵌套关系的作用域串联起来形成了作用域链
·相同作用域链中按着从小到大的规则查找变量
·子作用域能够访问父作用域,父级作用域无法访问子级作用域
堆栈空间分配区别:
-栈(操作系统):由操作系统自动分配释放函数的参数值、局部变量等,基本数据类型放到栈里面。
-堆(操作系统):一般由程序员分配释放,若程序员不释放,由垃圾回收机制回收。复杂数据类型放到堆里面。
两种常见的浏览器垃圾回收算法:引用计数法 和标记清除法
·引用计数(现在不太用了)
IE采用的引用计数算法,定义“内存不再使用”,就是看一个对象是否有指向它的引用,没有引用了就回收对象算法:
·变量提升
1.用哪个关键字声明变量会有变量提升? var
2.变量提升是什么流程?
先把var变量提升到当前作用域于最前面。只提升变量声明,不提升变量赋值。然后依次执行代码。我们不建议使用var声明变量
·函数提升
函数提升和变量提升类似,是指函数在声明之前即可被调用。
1、函数提升能使函数的声明调用更加灵活
2、函数表达式不存在提升的现象
3、函数提升出现在相同作用域中
·函数参数(动态参数、剩余参数)
动态参数
1.当不确定传递多少个实参的时候,我们怎么办? arguments动态参数
2.arguments是什么? 伪数组、它只存在函数中
剩余参数(提倡)
getSum(…arr)、getSum(a, b, …arr)
使用场景:不确定函数参数的个数时
1、…是语法符号,置于最末函数形参之前,用于获取多余的实参
2、借助…获取的剩余实参,是个真数组
3、使用时不需要加…
动态参数和剩余参数区别:arguments(动态参数)是伪数组,剩余参数是真数组。
区分:扩展运算符(…)
1、扩展运算符可以在函数外部使用,数组展开;剩余参数在函数参数中使用,得到真数组
2、使用场景:
求数组最大、最小值 Math.max(…arr) 因为数组没有求最大值的方法
合并数组 const arr = […arr1, …arr2]
·语法:
1.箭头函数属于表达式函数,因此不存在函数提升
2.箭头函数只有一个参数时可以省略圆括号()
3.箭头函数函数体只有一行代码时可以省略花括号{},并自动做为返回值被返回
4、加括号的函数体返回对象字面量表达式 const fn = (uname) => ({ uname: uname })
·参数
没有arguments动态参数,有剩余参数
·this
箭头函数不会创建自己的this,它只会从自己的作用域链的上一层沿用this。DOM 事件调函数不推荐使用箭头函数,因为事件回调函数使用箭头函数时,this为全局的window
1.length用来获取字符串的度长(重点)
2.split(‘分隔符’)用来将字符串拆分成数组(重点)
3.substring(需要截取的第一个字符的索引[结束的索引号])用于字符串截取(重点)
4.startsWith(检测字符串[,检测位置索引号])检测是否以某字符开头(重点)
5.includes(搜索的字符串[,检测位置索引号])判断一个字符串是否包含在另一个字符串中,根据情况返回 true或false(重点)
6.toUpperCase用于将字母转换成大写
7.toLowerCase月用于将就转换成小写
8.indexof检测是否包含某字符
9.endsWith 检测是否以某字符结尾
10.replace用于替换字符串,支持正则匹配
11.match用于查找字符串,支持正则匹配
1join:将数组元素连接成一个字符串,可以指定连接符。
2.push:将一个或多个元素添加到数组的末尾,并返回新的长度。
A生成
3.pop0:删除并返回数组的最后一个元素。
4.shift:删除并返回数组的第一个元素。
5.unshift:将一个或多个元素添加到数组的开头,并返回新的长度。
6.slice:返回一个新的数组,包含从给定开始索引到结束索引之间的数组元素。
7.splice:通过删除、替换或添加元素来修改数组,并返回被删除的元素。
8.sort:对数组元素进行排序,并返回数组。
9.reverse:反转数组的元素顺序,并返回数组。
10.indexOf:返回给定元素在数组中首次出现的索引,如果没有找到则返回-1。
11.lastndexOf:返回给定元素在数组中最后一次出现的索引,如果没有找到则返回-1。12.forEach:对数组的每个元素执行一次给定的函数。
13.map:返回一个新的数组,每个元素都是给定函数处理后的结果。
14.filter:返回一个新的数组,包含通过给定函数实现的测试的所有元素。
15.reduce:将数组中的元素从左到右合并,以便将其减少为单个值。
16.every:检查所有元素是否都符合条件。
17.some:检查是否有元素符合条件。
18.find:返回符合测试函数的第一个元素值。
19.findIndex:返回符合测试函数的第一个元素索引。
20.includes:判断一个数组是否包含一个指定的值。
(1)与原型对象的关系
对象原型__proto__指向该构造函数的原型对象
(2)原型继承
子类的原型 = new 父类
Woman.prototype new Person()
(3)原型链
重要的两句话:
①所有的对象里面都有__proto__对象原型,指向原型对象
②所有的原型对象里面有constructor,指向创造该原型对象的构造函数
基于原型对象的继承使得不同构造函数的原型对象关联在一起,并且这种关联的关系是一种链状的结构,我们将原型对象的链状结构关系称为原型链。
查找原则:
①当访问一个对象的属性(包括方法)时,首先查找这个对象自身有没有该属性。
②如果没有就查找它的原型(也就是_proto_指向的prototype原型对象)
③如果还没有就查找原型对象的原型(Object的原型对象)
④依此类推一直找到Object为止(null)
⑤__proto__对象原型的意义就在于为对象成员查找机制提供一个方向,或者说一条路线
可以使用instanceof运算符用于检测构造函数的prototype属性是否出现在某个实例对象的原型链上
深拷贝和浅拷贝都只针对引用类型
(1)浅拷贝:简单数据类型拷贝值,引用数据类型拷贝的是地址(简单理解:如果是单层对象,没问题。多层对象,即对象里面还有对象就有问题)
·浅拷贝和直接赋值区别:
直接赋值的方法,只要是对象,都会相互影响,因为是直接拷贝对象栈里面的地址。
浅拷贝如果是一层对象,不相互影响,如果出现多层对象拷贝还会相互影响。
·常见方法
拷贝对象:
①Object.assgin(o, object) // 拷贝一个新的object,名为o
②展开运算符 const o = {…object}
拷贝数组:
①Array.prototype.concat()
②[…arr]
(2)深拷贝
拷贝的是对象,不是地址
·常见方法
①通过递归实现深拷贝
②lodash/cloneDeep
③通过JSON.stringify()实现
const o = JSON.parse(JSON.stringify(obj))
详:
①通过递归实现深拷贝
普通拷贝直接赋值,遇到数组再次调用这个递归函数,遇到对象再次调用递归,先Array,后Object,顺序不能把变,因为数组也属于对象。
const obj = {
uname: ‘pink’,
age: 18,
hobbby: [‘乒乓球’, ‘足球’]
}
const o = {}
// 拷贝函数
function deepCopy(newObj, oldObj) {
for (let k in oldObj) {
// 处理数组的问题
if (oldObj[k] instanceof Array) {
newObj[k] = []
// newObj[k] 是 []
// oldObj[k] 是 [‘乒乓球’, ‘足球’]
deepCopy(newObj[k] = oldObj[k])
} else if (oldObj[k] instanceof Object) {
//数组和对象不能换位置
newObj[k] = {}
deepCopy(newObj[k] = oldObj[k])
} else {
// k 属性名 uname age oldObj[k] 属性值 18
// newObj[k] === o.uname 给新对象添加属性
newObj[k] = oldObj[k]
}
}
}
deepCopy(o, obj) // 函数调用 两个参数 o 新对象 obj 旧对象
②lodash/cloneDeep
在写HTML页面结构时所用的标签有意义
头部用head 主体用main 底部用foot...
怎么判断页面是否语义化了?
把CSS去掉,如果能够清晰的看出来页面结构,显示内容较为正常
为什么要选择语义化?
1.让HTML结构更加清晰明了
2.方便团队协作,利于开发
3.有利于爬虫和SEO
4.能够让浏览器更好的去解析代码
5.给用户带来良好的体验
H5的新特性:
1.语义化的标签
2.新增音频视频
3.画布canvas
4.数据存储localstorage sessionstorage
5.增加了表单控件 email url search...
6.拖拽释放API
CSS3的新特性:
1.新增选择器:属性选择器、伪类选择器、伪元素选择器
2.增加了媒体查询
3.文字阴影
4.边框
5.盒子模型box-sizing
6.渐变
7.过度
8.自定义动画
9.背景的属性
10.2D和3D
rem是相对长度,相对于根元素(html)的font-size属性来计算大小,通常来做
移动端的适配
rem是根据根元素font-size计算值的倍数
比如html上的font-size:16px,给div设置宽为1.5rem,1.2rem = 16px*1.2 = 19.2px.
(1)当设置样式overflow:scroll/auto时,IOS上的华东会卡顿
-webkit-overflow-scrolling:touch;
(2)在安卓环境下placeholder文字设置行高时会偏上
input有placeholder属性的时候不要设置行高
(3)移动端字体小于12px时异常显示
应该先把在整体放大一倍,然后再用transform进行缩小
(4)ios下input按钮设置了disabled属性为true显示异常
input[typy=button]{
opcity:1
}
(5)安卓手机下取消语音输入按钮
input::-webkit-input-speech-button{
display:none
}
(6)IOS下取消input输入框在输入引文首字母默认大写
(7)禁用IOS和安卓用户选中文字
添加全局CSS样式:-webkit-user-select:none
(8)禁止IOS弹出各种窗口
-webkit-touch-callout:none
(9)禁止IOS识别长串数字为电话
添加meta属性
都可以控制元素的显示和隐藏
1.v-show时控制元素的display值来让元素显示和隐藏;v-if显示隐藏时把DOM元素整个添加和删除
2.v-if有一个局部编译/卸载的过程,切换这个过程中会适当的销毁和重建内部的事件监听和子组件;v-show只是简单的css切换
3.v-if才是真正的条件渲染;v-show从false变成true的时候不会触发组件的声明周期,v-if会触发声明周期
4.v-if的切换效率比较低 v-show的效率比较高
是Model-View-ViewModel的缩写。前端开发的架构模式
M:模型,对应的就是data的数据
V:视图,用户界面,DOM
VM:视图模型:Vue的实例对象,连接View和Model的桥梁
核心是提供对View和ViewModel的双向数据绑定,当数据改变的时候,ViewModel能监听到数据的变化,自动更新视图,当用户操作视图的时候,ViewModel也可以监听到视图的变化,然后通知数据进行改动,这就实现了双向数据绑定
ViewModel通过双向绑定把View和Model连接起来,他们之间的同步是自动的,不需要认为干涉,所以我们只需要关注业务逻辑即可,不需要操作DOM,同时也不需要关注数据的状态问题,因为她是由MVVM统一管理
key属性是DOM元素的唯一标识
作用:
1.提高虚拟DOM的更新
2.若不设置key,可能会触发一些bug
3.为了触发过度效果
组件从创建到销毁的过程就是它的生命周期
创建
beforeCreat
在这个阶段属性和方法都不能使用
created
这里时实例创建完成之后,在这里完成了数据监测,可以使用数据,修改数据,不会触发updated,也不会更新视图
挂载
beforeMount
完成了模板的编译,虚拟DOM也完成创建,即将渲染,修改数据,不会触发updated
Mounted
把编译好的模板挂载到页面,这里可以发送异步请求也可以访问DOM节点
更新
beforeUpdate
组件数据更新之前使用,数据是新的,页面上的数据时旧的,组件即将更新,准备渲染,可以改数据
updated
render重新做了渲染,这时数据和页面都是新的,避免在此更新数据
销毁
beforeDestroy
实例销毁前,在这里实例还可以用,可以清楚定时器等等
destroyed
组件已经被销毁了,全部都销毁
使用了keep-alive时多出两个周期:
activited
组件激活时
deactivited
组件被销毁时
created:在渲染前调用,通常先初始化属性,然后做渲染
mounted:在模板渲染完成后,一般都是初始化页面后,在对元素节点进行操作
在这里请求数据可能会出现闪屏的问题,created里不会
一般用created比较多
请求的数据对DOM有影响,那么使用created
如果请求的数据对DOM无关,可以放在mounted
1.事件修饰符
.stop 组织冒泡
.prevent 组织默认行为
.capture 内部元素触发的事件先在次处理
.self 只有在event.target是当前元素时触发
.once 事件只会触发一次
.passive 立即触发默认行为
.native 把当前元素作为原生标签看待
2.按键修饰符
.keyup 键盘抬起
.keydown 键盘按下
3.系统修饰符
.ctrl
.alt
.meta
4.鼠标修饰符
.left 鼠标左键
.right 鼠标右键
.middle 鼠标中键
5.表单修饰符
.lazy 等输入完之后再显示
.trim 删除内容前后的空格
.number 输入是数字或转为数字
1.在表单中加rules属性,然后再data里写校验规则
2.内部添加规则
3.自定义函数校验
(1)父传子
props
父组件使用自定义属性,然后子组件使用props
$ref
引用信息会注册在父组件的$refs对象上
(2)子传父
$emit
子组件绑定自定义事件,触发执行后,传给父组件,父组件需要用事件监听来接收参数
(3)兄弟传
new一个新的vue实例,用on和emit来对数据进行传输
(4)vuex传值
Vue的一个内置组件,包裹组件的时候,会缓存不活跃的组件实例,并不是销毁他们
作用:把组件切换的状态保存在内存里,防止重复渲染DOM节点,减少加载时间和性能消耗,提高用户体验
下载 创建实例 接着封装请求响应拦截器 抛出 最后封装接口
params传参
this.$router.push({name:'index',params:{id:item.id}})
this.$route.params.id
路由属性传参
this.$router.push({name:'/index/${item.id}'})
路由配置 { path:'/index:id' }
query传参(可以解决页面刷新参数丢失的问题)
this.$router.push({
name:'index',
query:{id:item.id}
})
(1)hash的路由地址上有#号,history模式没有
(2)在做回车刷新的时候,hash模式会加载对应页面,history会报错404
(3)hash模式支持低版本浏览器,history不支持,因为是H5新增的API
(4)hash不会重新加载页面,单页面应用必备
(5)history有历史记录,H5新增了pushState和replaceState()去修改历史记录,并不会立刻发送请求
(6)history需要后台配置
路由拦截 axios拦截
需要在路由配置中添加一个字段,它是用于判断路由是否需要拦截
{
name:'index',
path:'/index',
component:Index,
meta:{
requirtAuth:true
}
}
router.beforeEach((to,from,next) => {
if(to.meta.requirtAuth){
if( store.satte.token ){
next()
}else{
}
}
})
要在路由配置里设置meat属性,扩展权限相关的字段,在路由导航守卫里通过判断这个权限标识,实现路由的动态增加和跳转
根据用户登录的账号,返回用户角色
前端再根据角色,跟路由表的meta.role进行匹配
把匹配搭配的路由形成可访问的路由
1.window.location.reload()
2.matcher
const router = createRouter()
export function resetRouter(){
const newRouter = creatRouter()
router.matcher = newRouter.matcher
}
vuex肯定会重新获取数据,页面也会丢失数据
1.把数据直接保存在浏览器缓存里(cookie localstorage sessionstorage)
2.页面刷新的时候,再次请求数据,达到可以动态更新的方法
监听浏览器的刷新书简,在刷新前把数据保存到sessionstorage里,刷新后请求数据,请求到了用vuex,如果没有那就用sessionstorage里的数据
1.computed是计算属性,watch是监听,监听的是data中数据的变化
2.computed是支持缓存,依赖的属性值发生变化,计算属性才会重新计算,否则用缓存;watch不支持缓存
3.computed不支持异步,watch是可以异步操作
4.computed是第一次加载就监听,watch是不监听
5.computed函数中必须有return watch不用
state 存储变量
getters state的计算属性
mutations 提交更新数据的方法
actions 和mutations差不多,他是提交mutations来修改数据,可以包括异步操作
modules 模块化vuex
使用场景:
用户的个人信息、购物车模块、订单模块
通过数据劫持和发布订阅者模式来实现,同时利用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联系起来,最终达到数据更新视图更新,视图更新数据更新的效果
虚拟DOM,描述元素和元素之间的关系,创建一个JS对象
如果组件内有响应的数据,数据发生改变的时候,render函数会生成一个新的虚拟DOM,这个新的虚拟DOM会和旧的虚拟DOM进行比对,找到需要修改的虚拟DOM内容,然后去对应的真实DOM中修改
diff算法就是虚拟DOM的比对时用的,返回一个patch对象,这个对象的作用就是存储两个节点不同的地方,最后用patch里记录的信息进行更新真实DOM
步骤:
1.JS对象表示真实的DOM结构,要生成一个虚拟DOM,再用虚拟DOM构建一个真实DOM树,渲染到页面
2.状态改变生成新的虚拟DOM,跟就得虚拟DOM进行比对,这个比对的过程就是DIFF算法,利用patch记录差异
3.把记录的差异用在第一个虚拟DOM生成的真实DOM上,视图就更新了。
1.原理不同
vue就是数据绑定;jq是先获取dom再处理
2.着重点不同
vue是数据驱动,jq是着重于页面
3.操作不同
4.未来发展不同
vuex是vue的状态管理工具
vue中可以直接触发methods中的方法,vuex是不可以的。未来处理异步,当触发事件的时候,会通过dispatch来访问actions中的方法,actions中的commit会触发mutations中的方法从而修改state里的值,通过getter把数据更新到视图
Vue.use(vuex),调用install方法,通过applyMixin(vue)在任意组件内执行this.$store就可以访问到store对象。
vuex的state是响应式的,借助的就是vue的data,把state存到vue实例组件的data中
(1)普通遍历,对象.forEach()
arr.forEach(function(item,index,arr){
console.log(item,index)
})
(2)对元素统一操作 对象.map()
var newarr = arr.map(function(item){
return item+1
})
(3)查找符合条件的元素 对象.filter()
arr.filter(function(item){
if(item > 2){
return false
}else{
return true
}
})
(4)查询符合条件的元素,返回索引 对象.findindex()
arr.finindex(function(item){
if(item>1){
return true
}else{
return false
}
})
对象.evening() 遇到不符合的对象会停止
对象.some() 找到符合条件的元素就停止
下载:node cnpm webpack vue-cli
创建项目:
1.找到对应的文件,然后利用node指令创建(cmd)
2.vue init webpack xxxx
3.回车项目描述
4.作者回车
5.选择vue build
6.回车
7.输入n
8.不按照yarn
9.输入npm run dev
1.使用Vue.extend()创建一个组件
2.使用Vue.components()方法注册组件
3.如果子组件需要数据,可以在props中接收定义
4.子组件修改好数据,要把数据传递给父组件,可以用emit()方法
原则:
把功能拆开
尽量让组件原子化,一个组件做一件事情
容器组件管数据,展示组件管视图
1.低耦合,组件之间的依赖越小越好
2.最好从父级传入信息,不要在公共组件中请求数据
3.传入的数据要进行校验
4.处理事件的方法写在父组件中
vue的特性,用来对文本进行格式化处理
使用它的两个地方,一个是插值表达式,一个是v-bind
分类:
1.全局过滤器
Vue.filter('add',function(v){
return v < 10 ? '0' + v : v
})
{{33 | add}}
2.本地过滤器
和methods同级
filter:{
add:function(v){
return v < 10 ? '0' + v : v
}
}
1.localtion.reload()
2.this.$router.go(0)
3.provide和inject
1.双向数据绑定的原理不同
2.是否支持碎片
3.API不同
4.定义数据变量方法不同
5.生命周期的不同
6.传值不同
7.指令和插槽不同
8.main.js不同
1.编码优化
不要把所有数据都放在data中
v-for时给每个元素绑定事件用事件代理
keep-alive缓存组件
尽可能拆分组件,提高复用性、维护性
key值要保证唯一
合理使用路由懒加载,异步组件
数据持久化存储的使用尽量用防抖、节流优化
2.加载优化
按需加载
内容懒加载
图片懒加载
3.用户体验
骨架屏
4.SEO优化
预渲染
服务端渲染ssr
5.打包优化
CDN形式加载第三方模块
多线程打包
抽离公共文件
6.缓存和压缩
客户端缓存、服务端缓存
服务端Gzip压缩
1.使用路由懒加载
2.非首屏组件使用异步组件
3.首屏不中要的组件延迟加载
4.静态资源放在CDN上
5.减少首屏上JS、CSS等资源文件的大小
6.使用服务端渲染
7.简历减少DOM的数量和层级
8.使用精灵图请求
9.做一些loading
10.开启Gzip压缩
11.图片懒加载
1.diff算法的优化
2.静态提升
3.事件侦听缓存
1.proxy可以代理整个对象,defineproperty只代理对象上的某个属性
2.proxy对代理对象的监听更加丰富
3.proxy代理对象会生成新的对象,不会修改被代理对象本身
4.proxy补兼容ie浏览器
可以重复使用的vue实例,独一无二的组件名称
可以抽离单独的公共模块
提高代码的复用率
public
图标、index.html、img
src
api
assets
components
按分类再次划分子目录
plugins
router
static
styles
utils
views
App.vue
main.js
package.json
vue.config.js
是基于vue的应用框架,关注的是渲染,可以开发服务端渲染应用的配置
SSR:服务端渲染
好处:
SSR生成的是有内容的HTML页面,有利于搜索引擎的搜索
优化了首屏加载时间
SEO:优化搜索引擎
SPA的应用不利于搜索引擎SEO的操作
1.SSR
2.预渲染 prerender-spa-plugin
title标题组件 show text link
toolbox工具栏 导出图片 数据视图 切换 缩放 show orient feature
tooltip tigger 触发类型
markPoint标注点
markLine图标的标线
1.uni-app有没有做过分包?
优化小程序的下载和启动速度
小程序启动默认下载主包并启动页面,当用户进入分包时,才会下载对应的分包,下载完进行展示
1.运行效率
2.对基础的支持不够
webpack会把js css image看作一个模块,用import/require引入
找到入口文件,通过入口文件找到关联的依赖文件,把他们打包到一起
把bundle文件,拆分成多个小的文件,异步按需加载所需要的文件
如果一个被多个文件引用,打包时只会生成一个文件
如果引用的文件没有调用,不会打包,如果引入的变量和方法没有调用也不会打包
对于多个入口文件,加入引入了相同的代码,可以用插件把他抽离到公共文件中
拉取代码 git pull '仓库地址'
查看状态 git sattus
提交到本地缓存区 git add .
提交本地仓库 git commit -m '修改描述'
提交到远程仓库 git push '仓库地址' master
创建分支 git branch -b xxx
合并分支 git merge '合并分支的名字'
1.两个分支中修改了同一个文件
2.两个分支中修改了同一个文件的名字
1.解决:当前分支上,直接修改代码 add commit
2.解决:在本地当前分支上,修改冲突代码 add commit push
疫情 社保 薪资问题 个人发展 技术提升 家庭因素
1.不要回答,没有问题
2.不要说一些常见的简单的问题,比如:数据请求不过来、渲染页面时出现了问题、跳转路由不会...
首先应该时自行去查找资料寻求解决办法,然后再去请教同时或者组长
1.尽量不要暴露自己的缺点
2.不要过度美化自己
1.开发前会开个会议,最后形成一个开发文档
2.利用工具保证项目的正常进度,规范化