1、绝对定位方法:
(1)不确定当前div的宽度和高度,采用 transform: translate(-50%,-50%); 当前div的父级添加相对定位(position: relative;)
(2)确定了当前div的宽度,margin值为当前div宽度一半的负值
(3)绝对定位下top left right bottom 都设置0
(4)calc() 函数动态计算实现水平垂直居中
2、flex布局方法
当前div的父级添加flex css样式
3、table-cell实现水平垂直居中
table-cell middle center组合使用
display: table-cell;
vertical-align: middle;
text-align: center;
回答完后会继续问
2、当里面div的框高不固定时,怎么水平垂直居中
1、水平居中
父容器container加css属性 text-align:center;
子容器center加css属性display:inline-block;
.center{_display:inline;} 为针对ie6的hack
2、垂直居中
父容器vc的css属性 display:table;overflow:hidden;
子容器vci的css属性 vertical-align:middle;display:table-cell;
针对ie6的hack,vci容器的 _position:absolute;_top:50%; 和content容器的 _position:relative; _top:-50%;
如果不需要水平居中的话,需要注释掉vci容器的text-align:center;_left:50%;以及content的display:inline-block;_left:-50%;
3、宽度高度固定的div垂直居中和水平居中
父容器要用相对定位position:relative;否则的话子元素会相对于浏览器窗口进行绝对定位。
子容器绝对定位,top:50%;left:50%;margin-top,margin-left的值取该容器高度,宽度的一半的负值。
Doctype声明于文档最前面,告诉浏览器以何种方式来渲染页面,这里有两种模式,严格模式和混杂模式。
严格模式的排版和JS 运作模式是 以该浏览器支持的最高标准运行。
混杂模式,向后兼容,模拟老式浏览器,防止浏览器无法兼容页面。
link属于html标签,而@import是css提供的
页面被加载时,link会同时被加载,而@import引用的css会等到页面加载结束后加载。
link是html标签,因此没有兼容性,而@import只有IE5以上才能识别。
link方式样式的权重高于@import的。
(1)多个新的表单
Input 输入类型,如:color,url,date等
autoplay: autoplay 如果出现该属性,则视频在就绪后马上播放。
controls: controls 如果出现该属性,则向用户显示控件,比如播放按钮。
height pixels 设置视频播放器的高度。
loop: loop 如果出现该属性,则当媒介文件完成播放后再次开始播放。
muted: muted 规定视频的音频输出应该被静音。
poster URL 规定视频下载时显示的图像,或者在用户点击播放按钮前显示的图像。
preload:
如果出现该属性,则视频在页面加载时进行加载,并预备播放。如果使用 “autoplay”,则忽略该属性。
src url 要播放的视频的 URL。
width pixels 设置视频播放器的宽度。
var c=document.getElementById(“myCanvas”);
var cxt=c.getContext(“2d”);//获取2d作图对象
cxt.moveTo(10,10);//画线的的起始点
cxt.lineTo(150,50);//画线
cxt.lineTo(10,50);
cxt.stroke();//线
cxt.fillStyle="#FF0000";//填充颜色
cxt.beginPath();//开始路径
cxt.arc(70,18,15,0,Math.PI*2,true);//画圆
cxt.closePath();//结束路径
cxt.fill();//填充
cxt.drawImage(img,0,0);//画布填充图片
cxt.createLinearGradient(0,0,175,50); //画布填充渐变
SVG绘图
地理定位 ***
百度地图引入和使用
拖放API ***
draggable=“true”
setData()
drag ondrag 当拖动元素或选中的文本时触发。
dragend ondragend 当拖拽操作结束时触发 (比如松开鼠标按键或敲“Esc”键). (见结束拖拽)
dragenter ondragenter 当拖动元素或选中的文本到一个可释放目标时触发(见 指定释放目标)。
dragexit ondragexit 当元素变得不再是拖动操作的选中目标时触发。
dragleave ondragleave 当拖动元素或选中的文本离开一个可释放目标时触发。
dragover ondragover 当元素或选中的文本被拖到一个可释放目标上时触发(每100毫秒触发一次)。
dragstart ondragstart 当用户开始拖动一个元素或选中的文本时触发(见开始拖动操作)。
drop ondrop 当元素或选中的文本在可释放目标上被释放时触发(见执行释放)。
特性
Cookie 一般由服务器生成,可设置失效时间,(设置过期时间是小于当前时间)。
如果在浏览器端生成Cookie,默认是关闭浏览器后失效;大小 4K左右
每次都会携带在HTTP头中,如果使用cookie保存过多数据会带来性能问题 需要程序员自己封装,源生的Cookie接口不友好
localStorage 除非被清除,否则永久保存 大小 5M 仅在客户端(即浏览器)中保存,不参与和服务器的通信
源生接口可以接受,亦可再次封装来对Object和Array有更好的支持
sessionStorage 仅在当前会话下有效,关闭页面或浏览器后被清除 大小 5M 仅在客户端(即浏览器)中保存,不参与和服务器的通信
源生接口可以接受,亦可再次封装来对Object和Array有更好的支持
COOKIE是如何工作的 *
Cookie可用于客户端数据的存储,在没有其它存储办法时,使用这种方式是可行的,但随着现在浏览器开始支持各种各样
的存储方式而逐渐被废弃。 由于服务器指定Cookie以后浏览器的每次请求都会携带Cookie数据,这会带来额外的性能负
担(尤其是在移动环境下)。 新的浏览器API已经允许开发者直接在本地存储数据,如可以使用Web storage API (本地
存储和会话存储)和IndexedDB(索引数据库)。
COOKIE主要用在以下三个方面:
会话状态管理(如用户登录状态、购物车)
个性化设置(如用户自定义设置)
浏览器行为跟踪(如跟踪分析用户行为)
COOKIE的缺陷
每个 HTTP 请求中都包含 Cookies,从而导致传输相同的数据减缓我们的 Web 应用程序。
每个 HTTP 请求中都包含 Cookies,从而导致发送未加密的数据到互联网上,可能会导致数据泄露,虽然进行过加密,但是攻击者拿到cookie后仍然可以登录,因为难以识别是否为同一个用户在登陆。
Cookies 只能存储有限的 4KB 数据,对于复杂的存储需求来说是不够用的。
sessionStroage有哪些应用场景?
答: 在不需要和服务器交互的场所,用来存储用户数据之类的,可以在路由页跳转的时候取出更改储存,减少调用接口的次数,减轻服务器压力。
用storage怎么来判断用户是否需要再登陆?
答:可以用加密的方法存储,每次用户访问的时候可以取出调用服务器接口作为参数发送进行对比,存在账号密码就直接跳过登录页。
localStorage是否可以在同源窗口共享?
答:同一浏览器的相同域名和端口的不同页面间可以共享相同的 localStorage,但是不同页面间无法共享sessionStorage的信息。
详情指路
盒子的大小:
默认情况下width和height属性只是设置content(内容)部分的宽和高
盒子的宽度 = 内容宽度 + 左填充 + 右填充 + 左边框 + 右边框 + 左边距 + 右边距
盒子的高度 = 内容高度 + 上填充 + 下填充 + 上边框 + 下边框 + 上边距 + 下边距
当box-sizing:content-box时,这种盒子模型成为标准盒子模型,当box-sizing: border-box时,这种盒子模型称为IE盒子模型。
区别:从下图中我们可以看出,这两种盒子模型最主要的区别就是width的包含范围,
在 标准的盒子模型 中,width指content部分的宽度,
在 IE盒子模型 中,width表示content+padding+border这三个部分的宽度,故这使得在计算整个盒子的宽度时存在着差异:
标准盒子模型的盒子宽度:左右border+左右padding+width
IE盒子模型的盒子宽度:width
标准盒子模型(W3C盒子模型):
IE盒子模型:
CSS3指定盒子模型种类
box-sizing
属性允许您以特定的方式定义匹配某个区域的特定元素。
box-sizing: content-box;
//宽度和高度分别应用到元素的内容框。在宽度和高度之外绘制元素的内边距和边框
box-sizing: inherit
; // 规定应从父元素继承 box-sizing 属性的值。
即box-sizing
属性可以指定盒子模型种类,content-box指定盒子模型为W3C(标准盒模型),border-box为IE盒子模型(怪异盒模型)。
解决两种模式下的兼容性问题
建议不要给元素添加具有指定宽度的内边距,而是尝试将内边距或外边距添加到元素的父元素和子元素
弹性布局:使用 百分比、rem 、flex 自适应布局
浮动布局:使用 float clear
table布局:一般用于后台显示
自适应布局和响应式布局:一般需要用到media媒体查询完成,需要根据屏幕宽度的不同,写多个css样式文件
水平:justify-content:center;
垂直:align-content:center;
justify-content:对其方式,水平主轴对齐方式
flex-direction:决定主轴的方向(即子item的排列方法)
flex-wrap:决定换行规则
flex:1 的值是110%,
【父控件有剩余空间占1份放大,父控件空间不足按1缩小,自身的空间大小是0%】 ***
flex属性 是 flex-grow、flex-shrink、flex-basis三个属性的缩写。
推荐使用此简写属性,而不是单独写这三个属性。
flex-grow:定义项目的的 放大 比例;
默认为0,即 即使存在剩余空间,也不会放大;
所有项目的flex-grow为1:等分剩余空间(自动放大占位);
flex-grow为n的项目,占据的空间(放大的比例)是flex-grow为1的n倍。
flex-shrink:定义项目的 缩小 比例;
默认为1,即 如果空间不足,该项目将缩小;
所有项目的flex-shrink为1:当空间不足时,缩小的比例相同;
flex-shrink为0:空间不足时,该项目不会缩小;
flex-shrink为n的项目,空间不足时缩小的比例是flex-shrink为1的n倍。
flex-basis: 定义在分配多余空间之前,项目占据的主轴空间(main size),浏览器根据此属性计算主轴是否有多余空间,
默认值为auto,即 项目原本大小;
设置后项目将占据固定空间。
所以flex属性的默认值为:0 1 auto (不放大会缩小)
flex为none:0 0 auto (不放大也不缩小)
flex为auto:1 1 auto (放大且缩小)
css3选择器
新属性 | 描述 |
---|---|
border-radius | |
border-image | |
background-size | |
background-size | |
background-origin | |
background-clip | 规定背景的绘制区域。 |
linear-gradient() | 线性渐变。 |
radial-gradient() | 径向渐变 |
word-break | 定义如何换行 |
word-wrap | 允许长的内容可以自动换行 |
text-overflow | 指定当文本溢出包含它的元素,应该发生什么 |
text-shadow | 文字阴影 |
transform-style | 指定嵌套元素是怎样在三维空间中呈现 |
rotate(angle) | 定义 2D 旋转,在参数中规定角度 |
translate(x,y) | 指定元素在二维空间中的位移。X轴方向向右,Y轴方向向下 |
scale(n) | 定义 2D 缩放转换 |
matrix(a,b,c,d,e,f) | 定义 2D 转换,使用六个值的矩阵 |
skew(x-angle,y-angle) | 定义沿着 X 和 Y 轴的 2D 倾斜转换 |
perspective(n) | 为 3D 转换元素定义透视视图 |
translate | 指定元素在的位移 |
matrix3d(n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n) | 定义 3D 转换,使用 16 个值的 4x4 矩阵 |
transition | 设置元素当过渡效果,四个简写属性为 ***** |
animation | 为元素添加动画,是一个简写属性 |
css新增的一些伪类
新增伪类 | 描述 |
---|---|
p:first-of-type | 选择器匹配属于其父元素的特定类型的首个子元素的每个元素 |
p:last-of-type | 选择器匹配属于其父元素的特定类型的最后一个子元素的每个元素 |
p:only-of-type | 选择器匹配属于其父元素的特定类型的唯一子元素的每个元素 |
p:only-child | 选择器匹配属于其父元素的唯一子元素的每个元素 |
p:nth-child(2) | 选择器匹配属于其父元素的第 N 个子元素,不论元素的类型。n 可以是数字、关键词或公式 |
:enabled :disabled | 表单控件的禁用状态 |
:checked:checked | 选择器匹配每个选中的输入元素(仅适用于单选按钮或复选框) |
Flex弹性布局 *****
媒体查询 media *
!important(在样式属性后不加“;”,在!important后加分号)>行内样式>ID选择器>Class选择器>标签>通配符
相同级别:
(1)同一级别中后写的会覆盖先写的样式
(2)选择器约分
CSS优先级:是由四个级别和各级别出现次数决定的
四个级别:行内样式,ID选择器,Class选择器,标签
每个规则对应一个初始值0,0,0,0
若是 行内选择符,则加1、0、0、0
若是 ID选择符,则加0、1、0、0
若是 类选择符/属性选择符/伪类选择符,则分别加0、0、1、0
若是 元素选择符/伪元素选择符,则分别加0、0、0、1
算法:将每条规则中,选择符对应的数相加后得到的”四位数“,从左到右进行比较,大的优先级越高。
注意:
①、!important
的优先级是最高的,但出现冲突时则需比较”四位数“;
②、优先级相同时,则采用就近原则,选择最后出现的样式;
③、继承得来的属性,其优先级最低;
!important > 行内样式>ID选择器 > 类选择器 > 标签 > 通配符 > 继承 > 浏览器默认属性
css选择器使用强烈建议采用低权重原则,利于充分发挥css的继承性,复用性,模块化、组件化。
1、使用带clear属性的空元素
clear{clear:both;}
2、使用CSS的overflow属性
给浮动元素的容器添加 overflow:hidden;
或 overflow:auto;
另外在 IE6 中还需要触发 hasLayout ,例如为父元素设置容器宽高或设置 zoom:1。
在添加overflow属性后,浮动元素又回到了容器层,把容器高度撑起,达到了清理浮动的效果。
3、 给浮动的元素的容器添加浮动
4、使用邻接元素处理
直接给浮动元素后面的元素添加clear属性
5、使用CSS的 :after
伪元素
结合:after 伪元素(注意这不是伪类,而是伪元素,代表一个元素之后最近的元素)和 IEhack ,可以完美兼容当前主流的各大浏览器,这里的 IEhack 指的是触发 hasLayout。
固定定位fixed:
元素的位置相对于浏览器窗口是固定位置,即使窗口是滚动的它也不会移动。Fixed定位使元素的位置与文档流无关,因此不占据空间。 Fixed定位的元素和其他元素重叠。
相对定位relative:
如果对一个元素进行相对定位,它将出现在它所在的位置上。然后,可以通过设置垂直或水平位置,让这个元素“相对于”它的起点进行移动。 在使用相对定位时,无论是否进行移动,元素仍然占据原来的空间。因此,移动元素会导致它覆盖其它框。
绝对定位absolute:
绝对定位的元素的位置相对于最近的已定位父元素,如果元素没有已定位的父元素,那么它的位置相对于。 absolute 定位使元素的位置与文档流无关,因此不占据空间。 absolute 定位的元素和其他元素重叠。
粘性定位sticky:
元素先按照普通文档流定位,然后相对于该元素在流中的flow root(BFC)和 containing block(最近的块级祖先元素)定位。而后,元素定位表现为在跨越特定阈值前为相对定位,之后为固定定位。
默认定位Static:
默认值。没有定位,元素出现在正常的流中(忽略top, bottom, left, right 或者 z-index 声明)。
inherit:
规定应该从父元素继承position 属性的值。
1、采用meta viewport的方式
2、采用border-image的方式
3、采用transform: scale()的方式
this永远指向函数运行时所在的对象,而不是函数被创建时所在的对象。匿名函数或不处于任何对象中的函数指向window 。
1.如果是call,apply,with,指定的this是谁,就是谁。
2.普通的函数调用,函数被谁调用,this就是谁。
js中的异步以及事件轮询 (event loop) 机制
js 宏任务和微任务
详解JavaScript中的Event Loop(事件循环)机制
async await 和promise对象的区别:
同:async和promise都是异步方法,
异:区别是async生成的结果是promise对象, async是promise的终结版。
await只能在async中使用,await是阻塞的意思,就是暂停,你一起调用2个接口,第一个执行完,不输出结果,要等最第二个接口执行完,才返回这两个的结果。
是属于将异步操作转化为同步操作的做法
async await和generator:
async是Generator的语法糖 ,也就是说,async是对generator的实现,而generator代码更复杂。
generator 除了能解决回调地域问题,还可以作为迭代器使用。generator 语法一般用于redux-saga
redux-saga 一般在umi或dva框架中使用
会引出 堆 和 栈
简单点来说,就是假设B复制了A,当修改A时,看B是否会发生变化,如果B也跟着变了,说明这是浅拷贝,拿人手短,如果B没变,那就是深拷贝,自食其力。
1、区别: 浅拷贝/深度拷贝
判断: 拷贝是否产生了新的数据还是拷贝的是数据的引用
知识点:对象数据存放的是对象在栈内存的引用,直接赋值的是对象的引用
2、常用的拷贝技术
2.1 数组的一层深浅拷贝
可以使用 循环赋值、slice、concate完成
2.2 对象的一层深拷贝
可以使用 循环赋值、assign完成
2.3 多层深拷贝
可以使用 序列化和反序列化
可以使用 jquery 的$.extend 进行深拷贝
可以使用 自己封装的深拷贝函数
1.1、js数组的slice方法
var arr1 = [“前端”,“安卓”,“苹果”];
var arr2 = arr1.slice(0); // var arr2 = arr1; //浅拷贝, 直接赋值 log的两个结果一样,都赋了新值
arr2[0] = “后端”;
console.log(“原始值:” + arr1 );//前端,安卓,苹果
console.log(“新值:” + arr2);//后端,安卓,苹果
理解:通过JS的slice方法,改变拷贝出来的数组的某项值后,对原来数组没有任何影响。
缺点:适用于对不包含引用对象的一维数组的深拷贝
1.2、js数组的concat方法
var arr1 = [“前端”,“安卓”,“苹果”];
var arr2 = arr1.concat();
arr2[0] = “后端”;
console.log(“原始值:” + arr1 );//前端,安卓,苹果
console.log(“新值:” + arr2);//后端,安卓,苹果
理解:concat方法,原数组和新数组修改某值后,不会改变。
缺点:适用于对不包含引用对象的一维数组的深拷贝
1.3 js遍历数组
var arr1 = ["前端","安卓","苹果"];;//原来数组
var arr2 = [];//新数组
function deepCopy(arry1, arry2){
var length = arry1.length;
for(var i = 0;i<length;i++){
arry2[i] = arry1[i];
}
}
deepCopy(arr1, arr2);
arr2[0] = "后端";
console.log(arr1);
console.log(arr2);
理解:通过对数组个元素进行遍历,然后赋值到新数组,改变原数组或者新数组,不会影响新数组或原数组。
缺点:如果包含二维数组,要进行单独处理,方法重写。
重写理解:通过循环遍历数组个元素,并且判断各元素下是否包含下级,来进行遍历。 改变拷贝出来的数组的某项值后,对原来数组没有任何影响
1)arr.concat(): 数组深拷贝
2). arr.slice(): 数组深拷贝
3).Object.assign()对象深拷贝
4). JSON.parse(JSON.stringify(arr/obj)): 数组或对象深拷贝, 但不能处理函数数据
5). 浅拷贝包含函数数据的对象/数组
6). 深拷贝包含函数数据的对象/数组
对于多层对象和数组:可以使用 递归调用、JSON.parse(JSON.stringify(arr/obj))、jquery的extend方法来实现深拷贝
变量根据作用域的不同分为两种:全局变量和局部变量。
闭包就是能够读取其他函数内部变量的函数。例如在javascript中,只有函数内部的子函数才能读取局部变量,所以闭包可以理解成“定义在一个函数内部的函数“。在本质上,闭包是将函数内部和函数外部连接起来的桥梁。
简单来说就是 函数嵌套函数
作用:延伸变量的作用范围。
可以扩展函数中的局部变量的作用域范围
可以减少定义 全局变量,避免全局污染 , 封装插件 封装组件的时候经常使用闭包
缺点: 将 函数的局部变量转为 全局变量,导致 全局变量永驻内容,会产生内存泄漏
输出索引号、定时器、函数防抖节流、私有变量封装…
1、setTimeout
原生的setTimeout传递的第一个函数不能带参数,通过闭包可以实现传参效果。
function f1(a) {
function f2() {
console.log(a);
}
return f2;
}
var fun = f1(1);
setTimeout(fun,1000);//一秒之后打印出1
2、 回调
定义行为,然后把它关联到某个用户事件上(点击或者按键)。代码通常会作为一个回调(事件触发时调用的函数)绑定到事件。
3.函数防抖 ***
在事件被触发n秒后再执行回调,如果在这n秒内又被触发,则重新计时。
实现的关键就在于setTimeOut这个函数,由于还需要一个变量来保存计时,考虑维护全局纯净,可以借助闭包来实现。
// fn [function] 需要防抖的函数
// delay [number] 毫秒,防抖期限值
function debounce(fn,delay){
let timer = null
//借助闭包
return function() {
if(timer){
clearTimeout(timer) //进入该分支语句,说明当前正在一个计时过程中,并且又触发了相同事件。所以要取消当前的计时,重新开始计时
timer = setTimeOut(fn,delay)
}else{
timer = setTimeOut(fn,delay) // 进入该分支说明当前并没有在计时,那么就开始一个计时
}
}
}
4.封装私有变量
如下面代码:用js创建一个计数器
function f1() {
var sum = 0;
var obj = {
inc:function () {
sum++;
return sum;
}
};
return obj;
}
let result = f1();
console.log(result.inc());//1
console.log(result.inc());//2
console.log(result.inc());//3
所有js数据类型都拥有valueOf和toString这两个方法,null除外valueOf()方法:返回指定对象的原始值。
toString()方法:返回对象的字符串表示。在数值运算中,优先调用了valueOf,字符串运算中,优先调用toString. sum+’ '是一个字符串类型的数据
原型:既构造函数的prototype
.每个构造函数都有一个prototype
属性指向生成这个函数的原型对象,简称原型;
prototype
可以对构造函数进行扩展,既添加构造函数的属性和方法
原型链:每个对象都有一个__proto__
属性, 指向生成改对象的原型对象,这样,我们就可以找到是哪个对象生成了改对象,
原型链一般用于 继承
原型链的核心就是依赖对象的_proto_
的指向,当自身不存在的属性时,就一层层的扒出创建对象的构造函数,直至到Object时,就没有_proto_
指向了。
因为_proto_
实质找的是prototype
,所以我们只要找这个链条上的构造函数的prototype
。其中Object.prototype
是没有_proto_
属性的,它==null
。
继承方式:
this指向,箭头函数的this指向
this的指向在函数定义的时候是确定不了的,只有函数执行的时候才能确定this到底指向谁,实际上this的最终指向的是那个调用它的对象
this的指向在函数定义的时候是确定不了的,只有函数执行的时候才能确定this到底指向谁,实际上this的最终指向的是那个调用它的对象
命令 | 描述 |
---|---|
git init | 初始化 ***** |
git clone | 克隆代码库 ***** |
git config | 配置 |
git add | 增加文件到暂存区 ***** |
git commit | 提交暂存区到仓库 ***** |
git branch | 名称 新建分支 ***** |
git checkout | 切换分支 ***** |
git merge | 合并分支 ***** |
git branch -d | 删除分支 ***** |
git tag | 打tag 包 ***** |
git status | 查看状态 ***** |
git log | 查看日志 **** |
git diff | 查看暂存区和工作区差异 |
git fetch | 下载远程仓库的变动 ***** |
git pull | 取回远程仓库变化,并与本地分支合并 ***** |
git push | 上传本地指定分支到远程仓库 ***** |
因为前端有同源保护政策,所以,不同源或者说不同的域名和ip之间不能进行访问。
1.jsonp jsonp有什么问题?只能是get方式不能是post方式 jsonp原理:script标签的src属性可以跨域
2.proxy代理 只能是打包前使用,打包后需要后台配置跨域 nginx反向代理
3.后台头部设置 Access-Control-Allow-Origin ,cors
4.其他 方式:
a. document.domain + iframe (只有在主域相同的时候才能使用该方法)
b. location.hash + iframe
c. window.name + iframe
d. postMessage(HTML5中的XMLHttpRequest Level 2中的API)
e. web socket
web sockets是一种浏览器的API,它的目标是在一个单独的持久连接上提供全双工、双向通信。
1.支持客户/服务器模式。
2.简单快速
3.灵活
4.无连接
5.无状态
请求方法(所有方法全为大写)有多种,各个方法的解释如下:
GET 请求获取Request-URI所标识的资源
POST 在Request-URI所标识的资源后附加新的数据
HEAD 请求获取由Request-URI所标识的资源的响应消息报头
PUT 请求服务器存储一个资源,并用Request-URI作为其标识
DELETE 请求服务器删除Request-URI所标识的资源
TRACE 请求服务器回送收到的请求信息,主要用于测试或诊断
CONNECT 保留将来使用
OPTIONS 请求查询服务器的性能,或者查询与资源相关的选项和需求
3xx:重定向–要完成请求必须进行更进一步的操作
4xx:客户端错误–请求有语法错误或请求无法实现
5xx:服务器端错误–服务器未能实现合法的请求
301 永久移动,请求的资源被永久的移动到新url,返回信息会包括新的url。浏览器会自动定向到新url
302 临时移动,资源只是临时被移动,客户端赢继续使用原有url
304 未修改,所请求的资源未修改,服务器返回此状态码是=时,不会返回任何资源,客户端通常会缓存访问过的资源,通过提供一个头信息指出客户端希望只返回在指定日期之后修改的资源
400 Bad Request //客户端请求有语法错误,不能被服务器所理解,解决方法:修改请求的参数及语法
401 Unauthorized //请求未经授权,这个状态代码必须和WWW-Authenticate报头域一起使用 ,
解决方式:即没有启用任何认证方式,只需要在IIS Manager里面启用需要的认证方式即可。
即被Authorization Rule阻挡,则需要分析这个authorization rule是否是否必须来决定对他的更改。
403 Forbidden //服务器收到请求,但是拒绝提供服务
1、你的IP被列入黑名单。
2、你在一定时间内过多地访问此网站(一般是用采集程序),被防火墙拒绝访问了。
3、网站域名解析到了空间,但空间未绑定此域名。
4、你的网页脚本文件在当前目录下没有执行权限。
6、以http方式访问需要ssl连接的网址。
7、浏览器不支持SSL 128时访问SSL 128的连接。
8、在身份验证的过程中输入了错误的密码。
解决方式: 1、重建dns缓存
对于一些常规的403 forbidden错误,马海祥建议大家首先要尝试的就是重建dns缓存,在运行中输入cmd,然后输入ipconfig /flushdns即可。如果不行的话,就需要在hosts文件里把主页解析一下了。
2、修改文件夹安全属性
3、关于apache导致的403 forbidden错误,需设置Apache的配置文件。
4、关于HawkHost空间出现403 Forbidden错误需设置htaccess文件。
404 Not Found //请求资源不存在,eg:输入了错误的URL 解决办法:输入正确的url地址
405 请求方式不对 ,比如原本需要post方式请求的,你写了get方式请求
流程:
(1)创建XMLHttpRequest对象,也就是创建一个异步调用对象.
(2)创建一个新的HTTP请求,并指定该HTTP请求的方法、URL及验证信息
(3)设置响应HTTP请求状态变化的函数.
(4)发送HTTP请求 .(send)
(5)获取异步调用返回的数据.(onreadystatechange)
(6)使用JavaScript和DOM实现局部刷新.
let、 const
let
:声明的变量只在所在的块级有用,不存在变量提升
**注意:**使用let关键字声明的变量才具有块级作用域,使用var声明的变量不具备块级作用域特性。
const
:声明常量,常量就是值(内存地址)不能变化的量,具有块级作用域,必须赋值,值不能修改
() => {} //():代表是函数; =>:必须要的符号,指向哪一个代码块;{}:函数体
const fn = () => {}//代表把一个函数赋值给fn
(1)数组的扩展
Array.from方法用于将两类对象转为真正的数组:类似数组的对象(array-like object)和可遍历(iterable)的对象(包括ES6新增的数据结构Set和Map)。
Array.of方法用于将一组值,转换为数组。
Array.prototype.copyWithin(target, start = 0, end = this.length)数组实例的copyWithin方法,在当前数组内部,将指定位置的成员复制到其他位置(会覆盖原有成员),然后返回当前数组。也就是说,使用这个方法,会修改当前数组。
数组实例的find方法,用于找出第一个符合条件的数组成员。它的参数是一个回调函数,所有数组成员依次执行该回调函数,直到找出第一个返回值为true的成员,然后返回该成员。如果没有符合条件的成员,则返回undefined。
fill方法使用给定值,填充一个数组。
entries(),keys()和values()——用于遍历数组。它们都返回一个遍历器对象(详见《Iterator》一章),可以用for...of循环进行遍历,唯一的区别是keys()是对键名的遍历、values()是对键值的遍历,entries()是对键值对的遍历。
Array.prototype.includes方法返回一个布尔值,表示某个数组是否包含给定的值,与字符串的includes方法类似。该方法属于ES7,但Babel转码器已经支持。
(2)函数的扩展
函数参数的默认值
与解构赋值默认值结合使用
函数的 length 属性
指定了默认值以后,函数的length属性,将返回没有指定默认值的参数个数。也就是说,指定了默认值后,length属性将失真
ES6 引入 rest 参数(形式为“...变量名”),用于获取函数的多余参数,这样就不需要使用arguments对象了。rest 参数搭配的变量是一个数组,该变量将多余的参数放入数组中。
扩展运算符 ... *****
替代数组的apply方法
// ES5的写法
Math.max.apply(null, [14, 3, 77])
// ES6的写法
Math.max(...[14, 3, 77])
// 等同于
Math.max(14, 3, 77);
扩展运算符的应用:合并数组 与解构赋值结合 函数的返回值 字符串 实现了Iterator接口的对象 Map和Set结构,Generator函数
/************/
严格模式 'use strict';
重点掌握,重点重点
箭头函数 ES6允许使用“箭头”(=>)定义函数。 箭头函数可以保留this的指向 *****
箭头函数注意点:
(1)函数体内的this对象,就是定义时所在的对象,而不是使用时所在的对象。
(2)不可以当作构造函数,也就是说,不可以使用new命令,否则会抛出一个错误。
(3)不可以使用arguments对象,该对象在函数体内不存在。如果要用,可以用Rest参数代替。
(4)不可以使用yield命令,因此箭头函数不能用作Generator函数。
(3)数组的扩展
let text='abcdefg';
for (let i of text) {
console.log(i);
}
includes():返回布尔值,表示是否找到了参数字符串。
startsWith():返回布尔值,表示参数字符串是否在源字符串的头部。
endsWith():返回布尔值,表示参数字符串是否在源字符串的尾部。
repeat方法返回一个新字符串,表示将原字符串重复n次。
padStart()用于头部补全,padEnd()用于尾部补全。
模板字符串 `aaa{$test}`
(4)对象的扩展
Object.is() 比较两个值是否相等
Object.assign方法用于对象的合并,将源对象(source)的所有可枚举属性,复制到目标对象(target)。
属性的遍历
ES6一共有5种方法可以遍历对象的属性。
(1)for...in
for...in循环遍历对象自身的和继承的可枚举属性(不含Symbol属性)。
(2)Object.keys(obj)
Object.keys返回一个数组,包括对象自身的(不含继承的)所有可枚举属性(不含Symbol属性)。
(3)Object.getOwnPropertyNames(obj)
Object.getOwnPropertyNames返回一个数组,包含对象自身的所有属性(不含Symbol属性,但是包括不可枚举属性)。
(4)Object.getOwnPropertySymbols(obj)
Object.getOwnPropertySymbols返回一个数组,包含对象自身的所有Symbol属性。
(5)Reflect.ownKeys(obj)
Reflect.ownKeys返回一个数组,包含对象自身的所有属性,不管是属性名是Symbol或字符串,也不管是否可枚举。
Object.setPrototypeOf方法的作用与__proto__相同,用来设置一个对象的prototype对象,返回参数对象本身。它是 ES6 正式推荐的设置原型对象的方法。
该方法与Object.setPrototypeOf方法配套,用于读取一个对象的原型对象。
Object.keys()引入了Object.keys方法,返回一个数组,成员是参数对象自身的(不含继承的)所有可遍历(enumerable)属性的键名。
Object.values方法返回一个数组,成员是参数对象自身的(不含继承的)所有可遍历(enumerable)属性的键值。
Object.entries方法返回一个数组,成员是参数对象自身的(不含继承的)所有可遍历(enumerable)属性的键值对数组。
set 和map 数据类型
proxy
Proxy 可以理解成,在目标对象之前架设一层“拦截”,外界对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写。Proxy 这个词的原意是代理,用在这里表示由它来“代理”某些操作,可以译为“代理器”
var obj = new Proxy({}, {
get: function (target, key, receiver) {
console.log(`getting ${key}!`);
return Reflect.get(target, key, receiver);
},
set: function (target, key, value, receiver) {
console.log(`setting ${key}!`);
return Reflect.set(target, key, value, receiver);
}
});
vue双向绑定原理的Object.defineProperty 更改为了 Proxy,性能有所优化
peomise
解决异步回调地狱问题
var promise = new Promise(function(resolve, reject) {
// ... some code
if (/* 异步操作成功 */){
resolve(value);
} else {
reject(error);
}
});
.then() Promise实例添加状态改变时的回调函数。
.catch() 用于指定发生错误时的回调函数。
Promise.all方法用于将多个Promise实例,包装成一个新的Promise实例。
all中的内容是两个异步操作,只有等到它们的结果都返回了,才会触发pickTopRecommentations这个回调函数。
Promise.race方法同样是将多个Promise实例,包装成一个新的Promise实例。
Promise.resolve()有时需要将现有对象转为Promise对象,Promise.resolve方法就起到这个作用。
Promise.reject(reason)方法也会返回一个新的 Promise 实例,该实例的状态为rejected。
.done()Promise对象的回调链,不管以then方法或catch方法结尾,要是最后一个方法抛出错误,都有可能无法捕捉到
.finally方法用于指定不管Promise对象最后状态如何,都会执行的操作。它与done方法的最大区别,它接受一个普通的回调函数作为参数,该函数不管怎样都必须执行。
Generator 函数的语法
迭代器或解决异步调用回调地狱
function* gen() {
yield 123 + 456;
}
redux-saga中使用了该语法
async await : 解决异步回调地域问题,一般和promise一起用
新引进了 类 class :需要使用 function做为构造函数来使用的问题,简化了继承
module: import export
数组
方法 | 描述 |
---|---|
join(‘分隔符’) | 把数组所有元素转换为一个字符串 |
toString() | 把数组转换为字符串,逗号分隔 |
concat() | 连接两个数组,不影响数组 |
slice(begin, end) | 截取数组片段,生成新数组 |
split(begin, num) | 数组删除元素,会影响原数组 |
indexOf() | 数组中查找给定元素的第一个索引 |
lastIndexOf() | 数组中查找给定元素的最后一个索引v |
sort() | 排序 |
reverse() | 倒序 |
push() | 数组末尾添加元素 |
pop() | 删除数组最后一个元素 |
unshift() | 向数组开头添加元素 |
shift() | 删除数组第一个元素 |
forEach() | 对数组进行遍历循环,对数组中的每一项运行给定函数 |
filter() | “过滤”功能,数组中的每一项运行给定函数,返回满足过滤条件组成的数组 |
map() | 指“映射”,对数组中的每一项运行给定函数,返回每次函数调用的结果组成的数组 |
some() | 判断数组中是否存在满足条件的项,只要有一项满足条件,就会返回true |
every() | 判断数组中每一项都是否满足条件,只有所有项都满足条件,才会返回true |
字符串
方法 | 描述 |
---|---|
charAt() | 返回指定索引位置的字符 |
charCodeAt() | 返回指定索引位置字符的 Unicode 值 |
concat() | 连接两个或多个字符串,返回连接后的字符串 |
fromCharCode() | 将 Unicode 转换为字符串 |
indexOf() | 返回字符串中检索指定字符第一次出现的位置 |
lastIndexOf() | 返回字符串中检索指定字符最后一次出现的位置 |
localeCompare() | 用本地特定的顺序来比较两个字符串 |
match() | 找到一个或多个正则表达式的匹配 |
replace() | 替换与正则表达式匹配的子串 |
search() | 检索与正则表达式相匹配的值 |
slice() | 提取字符串的片断,并在新的字符串中返回被提取的部分 |
split() | 把字符串分割为子字符串数组 |
substr() | 从起始索引号提取字符串中指定数目的字符 |
substring() | 提取字符串中两个指定的索引号之间的字符 |
toLocaleLowerCase() | 根据主机的语言环境把字符串转换为小写,只有几种语言(如土耳其语)具有地方特有的大小写映射 |
toLocaleUpperCase() | 根据主机的语言环境把字符串转换为大写,只有几种语言(如土耳其语)具有地方特有的大小写映射 |
toLowerCase() | 把字符串转换为小写 |
toString() | 返回字符串对象值 |
toUpperCase() | 把字符串转换为大写 |
trim() | 移除字符串首尾空白 |
valueOf() | 返回某个字符串对象的原始值 |
对象
Object.assign() 对象合并
1、instanceof
A instanceof B // true or false
[] instanceof Array // true
{} instanceof Array //false
2、 typeof
在typeof上进行enhancement, typeof数组和对象返回都是object, 但是数组的长度为0及0以上的整数,object的长度为undefined.
typeof arr && !isNaN(arr.length) // true
typeof obj && !isNaN(obj.length) // false
3、Object.prototype.toString.call()
Object.prototype.toString.call(arr) // [Object Array]
Object.prototype.toString.call(obj) // [Object Object]
4、Array.isArray()
Array.isArray(arr) // true
Array.isArray(obj) //false
5、constructor属性
arr.constructor // f Array() { [native code] }
obj.constructor // f Object() { [native code] }
new Promise(
function (resolve, reject) {// 一段耗时的异步操作
resolve(‘成功’) // 数据处理完成
// reject(‘失败’) // 数据处理出错
}).then((res) => {console.log(res)}, /*成功*/ (err) => {console.log(err)} /*失败*/ )
/******************/
const promiseClick =()=>{
console.log(‘点击方法被调用’)
let p = new Promise(function(resolve, reject){//做一些异步操作
setTimeout(function(){
console.log(‘执行完成Promise’);
resolve(‘要返回的数据可以任何数据例如接口返回数据’);}, 2000);
});
return p
}
promiseClick().then(()=>{},()=>{}); //then的参数:1、成功的回调 2、失败的回调
new Promise(function(resolve,reject){
//返回resolve还是reject
}).then(function(){}, function(){}) //1、接收的成功回调 2、接收失败回调
Promise.all(iterable) 方法返回一个 Promise 实例,此实例在 iterable 参数内所有的 promise 都“完成(resolved)”或
参数中不包含 promise 时回调完成(resolve);如果参数中 promise 有一个失败(rejected),此实例回调失败(reject),
失败的原因是第一个失败 promise 的结果。
它通常在启动多个异步任务并发运行并为其结果创建承诺之后使用,以便人们可以等待所有任务完成。
通俗的说法:解决promise的同步调用问题,可以将多个异步操作转为同步操作,缺点:只要有一个promise返回错误,那么后面的promise都不会再执行
const promise1 = Promise.resolve(3);
const promise2 = 42;
const promise3 = new Promise((resolve, reject) => {
setTimeout(resolve, 100, 'foo');
});
Promise.all([promise1, promise2, promise3]).then((values) => {
console.log(values);
});
promise.allsettled
从输入URL到页面加载的主干流程如下:
1、浏览器构建HTTP Request请求
2、网络传输
3、服务器构建HTTP Response 响应
4、网络传输
5、浏览器渲染页面
域名解析 --> 发起TCP的3次握手 --> 建立TCP连接后发起http请求 --> 服务器响应http请求,浏览器得到html代码 –> 浏览器解析html代码,并请求html代码中的资源(如js、css、图片等) --> 浏览器对页面进行渲染呈现给用户
详情指路
函数节流是指一定时间内js方法只跑一次。
函数防抖是指频繁触发的情况下,只有足够的空闲时间,才执行代码一次
函数节流应用的实际场景,多数在监听页面元素滚动事件的时候会用到。因为滚动事件,是一个高频触发的事件
// 函数节流
var canRun = true;
document.getElementById("throttle").onscroll = function(){
if(!canRun){ // 判断是否已空闲,如果在执行中,则直接return
return;
}
canRun = false;
setTimeout(function(){
console.log("函数节流");
canRun = true;
}, 300);
};
函数节流的要点是,声明一个变量当标志位,记录当前代码是否在执行
如果空闲,则可以正常触发方法执行。
如果代码正在执行,则取消这次方法执行,直接return。
函数防抖的应用场景,最常见的就是用户注册时候的手机号码验证和邮箱验证了。只有等用户输入完毕后,前端才需要检查格式是否正确,如果不正确,再弹出提示语。
// 函数防抖
var timer = false;
document.getElementById("debounce").onscroll = function(){
clearTimeout(timer); // 清除未执行的代码,重置回初始化状态
timer = setTimeout(function(){
console.log("函数防抖");
}, 300);
};
函数节流的要点,也是需要一个setTimeout来辅助实现。延迟执行需要跑的代码。
如果方法多次触发,则把上次记录的延迟执行代码用clearTimeout清掉,重新开始。
如果计时完毕,没有方法进来访问触发,则执行代码。
浏览器渲染原理
浏览器向服务器请求到了HTML文档后便开始解析,产物是DOM(文档对象模型),如果有css,会根据css生成CSSOM(CSS对象模型),然后再由DOM和CSSOM合并产生渲染树,有了渲染树,知道了所有节点的样式,便根据这些节点以及样式计算它们在浏览器中确切的大小和位置,这就是布局。最后把节点绘制到浏览器上。
创建DOM树—创建CSSOM树—执行脚本—生成渲染树—生成布局—绘制
重绘
当页面元素样式改变不影响元素在文档流中的位置时(如background-color,border-color,visibility),浏览器只会将新样式赋予元素并进行重新绘制操作。
回流
当改变的操作响应文档内容或者结构,或者元素位置时,就会触发回流。有以下几种情况:
DOM操作(对元素的增删改、顺序变化等)
内容变化,包括表单区域内的文本变化
css属性的更改或者重新计算
增删样式表内容
修改class属性
浏览器窗口变化(滚动或缩放)
伪类样式激活(:hover等)
浏览器优化渲染
浏览器本身能够进行优化,尽可能减少重绘和回流。
一个position为absolute或fixed的元素更改,只会影响本身及子元素,而static元素则会影响后面所有元素。
JavaScript执行时,浏览器会缓存所有变化,然后一次性全部绘制。(读取元素属性会引起强制回流)。
我们可以进行的优化:
样式表放在head标签中,脚本放在body结束前。
简化并优化css选择器。(选择器是从右到左匹配)
DOM节点保存在一个变量中,避免重复获取。
修改元素样式时,更改其class属性更好。
DOM的事件模型主要包含:
0级事件处理程序:事件冒泡,阻止事件冒泡
2级事件处理程序: addEventListener()和removeEventListener()
cookie | localstorage | sessionStorage | |
---|---|---|---|
数据有效期 | 可设置失效时间,否则默认为关闭浏览器后失效 | 除非被手动清除,否则永久保存 | 仅在当前网页会话下有效,关闭页面或浏览器后就会被清除 |
存放数据 | 不能超过4K | 可以达到5M或更大 | 可以达到5M或更大 |
http请求 | 每次都会携带在http头中,即cookie在浏览器和服务器间来回传递 | 仅在客户端即浏览器中保存,不参与和服务器的通信 | 仅在客户端即浏览器中保存,不参与和服务器的通信 |
如果使用cookie保存过多数据会带来性能问题
1、降低请求量:合并资源,减少HTTP 请求数,minify / gzip 压缩,webP,lazyLoad。
2、加快请求速度:预解析DNS,减少域名数,并行加载,CDN 分发。
3、缓存:HTTP 协议缓存请求,离线缓存 manifest,离线数据缓存localStorage。
4、渲染:JS/CSS优化,加载顺序,服务端渲染,pipeline。
阻止冒泡
w3c方法是ev.stopPropagation()
IE中方法是window.event.cancelBubble = true
阻止默认事件
ev.preventDefault()
return false;//写在函数的最后一句
1、js数据类型
基础类型(原始值):Undefined、 Null、 String、 Number、 Boolean、 Symbol (es6新出的)
复杂类型(对象值): 对象
2、三种隐式转换类型
1、将值转为原始值,ToPrimitive()。
2、将值转为数字,ToNumber()。
3、将值转为字符串,ToString()。
运算符: + & ==
/* +运算符 */
[]+{} //"[object Object]"
{}+[]
"a"+[] //"a"
"a"+{} //"a[object Object]"
1+[] // "1"
1+{} //"1[object Object]"
0
1+'0' //"10"
null+1 //1
null+"q" //"nullq"
undefined+1 //NaN
undefined+"b" //"undefinedb"
NaN+1 //NaN
NaN+"c" //"NaNc"
==
不同于 ===
undefined == null //true
null == 1 //false
null == 0 //false
undefined == 1 //false
undefined == 0 //false
[1] == 1 //true
var a = {1:1} //undefined
a==1 //false
. . / 这些运算符只会针对number类型,故转换的结果只能是转换成number类型,比较简单。
更多指路
可以是数字,object对应的key没有限制,只是如果是数字,取值的时候就不能用英文句号(.),只能用[]的方式取值
工厂模式是一种设计模式,目的是为了创建对象,它通常在类或类的静态方法中实现,
有以下目的:当创建相似对象是执行重复操作
当编译时,不知道具体类型的情况下,为工厂客户提供一个创建对象的接口
//使用工厂方式创建一个对象
function createPerson(name,sex){
//1.原料
var obj = new Object();
//2.加工 -- 对属性进行赋值
obj.name = name;
obj.sex = sex;
//3.方法
obj.showName = function(){
console.log("人物名称:"+this.name);
}
obj.showSex = function(){
console.log("人物的性别:"+this.sex);
}
//4.加工结束,--输出返回
return obj;
}
//工厂模式的使用
var person1 = createPerson("如花","男");
//调用工厂里的方法
person1.showName();
person1.showSex();
var person2 = createPerson("凤姐","女");
//调用工厂里的方法
person2.showName();
person2.showSex();
/*
工厂模式:
优点: 写好了工厂方法后,只要原料足够,我们可以无限次的创建新的对象
缺点: 1.没有使用 new ,2.每个对象都有自己的函数,浪费资源
接触过哪些设计模式: 工厂模式 、单例模式(数据库连接)、观察者模式(双向绑定原理)、订阅模式、mvc模式、mvvm模式
单例模式:在它的核心结构中值包含一个被称为单例的特殊类。一个类只有一个实例,即一个类只有一个对象实例。
工厂模式:在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。
发布订阅模式:在软件架构中,发布订阅是一种消息范式,消息的发送者(称为发布者)不会将消息直接发送给特定的接收者(称为订阅者)。而是将发布的消息分为不同的类别,无需了解哪些订阅者(如果有的话)可能存在。同样的,订阅者可以表达对一个或多个类别的兴趣,只接收感兴趣的消息,无需了解哪些发布者(如果有的话)存在。
图片上传后台有三种格式:
内存泄漏 : 即为变量内容持续占用内存空间,不释放,垃圾回收机制也没有将该内存回收的情况
可能产生内存泄漏的情况:
死循环
定时器没有清除
绑定的事件没有解除
递归调用没有结束条件
主要存在内存泄漏的问题点:
BOM DOM对象泄漏
scipt中存在对BOM DOM对象的引用
javaScript对象泄漏
闭包函数导致的泄漏
主要关注的代码点:
DOM中的addEventLisner 函数及派生的事件监听, 比如Jquery 中的on 函数, vue 组件实例的 $on 函数,第三方库中的初始化函数
BOM对象的事件监听,比如webSocket的监听事件
避免不必要的函数引用
如果是要render函数,避免在html标签中DOM BOM事件
1、安装node
2、安装http镜像文件
npm install http-server -g(windows下)
sudo npm install http-server -g(linux和mac下)
3、在本地创建文件夹(要切换到创建的路径)
cd 文件夹的名字
4、执行服务
http-server
然后会显示8080端口本地服务器
for(var i = 1; i <= 5; i++){
setTimeout(function () {
console.log(i);
}, 1000);
}
打印结果为5个6;
原因是:js是单线程,有任务队列,任务队列分为两种,同步任务和异步任务。
同步任务指的是,在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务;
异步任务指的是,不进入主线程、而进入"任务队列"(task queue)的任务,只有"任务队列"通知主线程,某个异步任务可以执行了,该任务才会进入主线程执行。
所以循环是同步任务先执行,当执行完之后,当setTimeout的异步操作准备好后,通知主线程,主线程将其从异步队列中取出来,再执行,所以当循环完成时,i的值位6,setTimeout再执行,打印5个6
所有同步任务都在主线程上执行,形成一个执行栈(execution context stack)。
主线程之外,还存在一个"任务队列"(task queue)。只要异步任务有了运行结果,就在"任务队列"之中放置一个事件。
一旦"执行栈"中的所有同步任务执行完毕,系统就会读取"任务队列",看看里面有哪些事件。那些对应的异步任务,于是结束等待状态,进入执行栈,开始执行。
主线程不断重复上面的第三步。
只要主线程空了,就会去读取"任务队列",这就是JavaScript的运行机制。这个过程会不断重复。
“任务队列"中的事件,除了IO设备的事件以外,还包括一些用户产生的事件(比如鼠标点击、页面滚动等等)。只要指定过回调函数,这些事件发生时就会进入"任务队列”,等待主线程读取。
事件循环(event loop)
主线程从"任务队列"中读取事件,这个过程是循环不断的,所以整个的这种运行机制又称为Event Loop(事件循环)。
TCP与UDP区别总结:
1、TCP面向连接(如打电话要先拨号建立连接);UDP是无连接的,即发送数据之前不需要建立连接
2、TCP提供可靠的服务。也就是说,通过TCP连接传送的数据,无差错,不丢失,不重复,且按序到达;UDP尽最大努力交付,即不保证可靠交付
3、TCP面向字节流,实际上是TCP把数据看成一连串无结构的字节流;UDP是面向报文的
UDP没有拥塞控制,因此网络出现拥塞不会使源主机的发送速率降低(对实时应用很有用,如IP电话,实时视频会议等)
4、每一条TCP连接只能是点到点的;UDP支持一对一,一对多,多对一和多对多的交互通信
5、TCP首部开销20字节;UDP的首部开销小,只有8个字节6、TCP的逻辑通信信道是全双工的可靠信道,UDP则是不可靠信道
指路
1、localStorage 的基本方法:
定义:localStorage.setItem('key','value')
获取:localStorage.getItem('key')
删除:localStorage.removeItem('key')
清空:localStorage.clear()
2、……
主要区别:document.write是直接将内容写入页面的内容流,会导致页面全部重绘,innerHTML将内容写入某个DOM节点,不会导致页面全部重绘
##40.display:none和visibility:hidden的区别是: *
1.display:none是彻底消失,不在文档流中占位,浏览器也不会解析该元素;visibility:hidden是视觉上消失了,可以理解为透明度为0的效果,在文档流中占位,浏览器会解析该元素;
2.使用visibility:hidden比display:none性能上要好,display:none切换显示时visibility,页面产生回流(当页面中的一部分元素需要改变规模尺寸、布局、显示隐藏等,页面重新构建,此时就是回流。所有页面第一次加载时需要产生一次回流),而visibility切换是否显示时则不会引起回流。
所以我使用visibility:hidden,在页面渲染时第二个tab页中的轮播图就可以获取宽度做自适应了。
(1)什么是WebSocket?
WebSocket是HTML5中的协议,支持持久连续,http协议不支持持久性连接。Http1.0和HTTP1.1都不支持持久性的链接,HTTP1.1中的keep-alive,将多个http请求合并为1个
(2)WebSocket是什么样的协议,具体有什么优点?
HTTP的生命周期通过Request来界定,也就是Request一个Response,那么在Http1.0协议中,这次Http请求就结束了。在Http1.1中进行了改进,是的有一个connection:Keep-alive,也就是说,在一个Http连接中,可以发送多个Request,接收多个Response。但是必须记住,在Http中一个Request只能对应有一个Response,而且这个Response是被动的,不能主动发起。
WebSocket是基于Http协议的,或者说借用了Http协议来完成一部分握手,在握手阶段与Http是相同的。我们来看一个websocket握手协议的实现,基本是2个属性,upgrade,connection。
基本请求如下:
GET /chat HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==
Sec-WebSocket-Protocol: chat, superchat
Sec-WebSocket-Version: 13
Origin: http://example.com
多了下面2个属性:
Upgrade:webSocket
Connection:Upgrade
告诉服务器发送的是websocket
Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==
Sec-WebSocket-Protocol: chat, superchat
Sec-WebSocket-Version: 13
CSRF:跨站请求伪造,可以理解为攻击者盗用了用户的身份,以用户的名义发送了恶意请求,比如用户登录了一个网站后,立刻在另一个tab页面访问量攻击者用来制造攻击的网站,这个网站要求访问刚刚登陆的网站,并发送了一个恶意请求,这时候CSRF就产生了,比如这个制造攻击的网站使用一张图片,但是这种图片的链接却是可以修改数据库的,这时候攻击者就可以以用户的名义操作这个数据库
防御方式的话:使用验证码,检查https头部的refer,使用token
XSS:跨站脚本攻击,是说攻击者通过注入恶意的脚本,在用户浏览网页的时候进行攻击,比如获取cookie,或者其他用户身份信息,可以分为存储型和反射型,存储型是攻击者输入一些数据并且存储到了数据库中,其他浏览者看到的时候进行攻击,反射型的话不存储在数据库中,往往表现为将攻击代码放在url地址的请求参数中,
防御的话为cookie设置httpOnly属性,对用户的输入进行检查,进行特殊字符过滤
XSS防御的总体思路是:对输入(和URL参数)进行过滤,对输出进行编码。也就是对提交的所有内容进行过滤,对url中的参数进行过滤,过滤掉会导致脚本执行的相关内容;然后对动态输出到页面的内容进行html编码,使脚本无法在浏览器中执行。虽然对输入过滤可以被绕过,但是也还是会拦截很大一部分的XSS攻击。
必要性:由于字符串、对象和数组没有固定大小,所有当他们的大小已知时,才能对他们进行动态的存储分配。JavaScript程序每次创建字符串、数组或对象时,解释器都必须分配内存来存储那个实体。只要像这样动态地分配了内存,最终都要释放这些内存以便他们能够被再用,否则,JavaScript的解释器将会消耗完系统中所有可用的内存,造成系统崩溃。
这段话解释了为什么需要系统需要垃圾回收,JS不像C/C++,他有自己的一套垃圾回收机制(Garbage Collection)。JavaScript的解释器可以检测到何时程序不再使用一个对象了,当他确定了一个对象是无用的时候,他就知道不再需要这个对象,可以把它所占用的内存释放掉了。
var a="hello world";
var b="world";
var a=b; //这时,会释放掉"hello world",释放内存以便再引用
垃圾回收的方法:标记清除、计数引用。
标记清除
这是最常见的垃圾回收方式,当变量进入环境时,就标记这个变量为”进入环境“,从逻辑上讲,永远不能释放进入环境的变量所占的内存,永远不能释放进入环境变量所占用的内存,只要执行流程进入相应的环境,就可能用到他们。当离开环境时,就标记为离开环境。
垃圾回收器在运行的时候会给存储在内存中的变量都加上标记(所有都加),然后去掉环境变量中的变量,以及被环境变量中的变量所引用的变量(条件性去除标记),删除所有被标记的变量,删除的变量无法在环境变量中被访问所以会被删除,最后垃圾回收器,完成了内存的清除工作,并回收他们所占用的内存。
引用计数法
另一种不太常见的方法就是引用计数法,引用计数法的意思就是每个值没引用的次数,当声明了一个变量,并用一个引用类型的值赋值给改变量,则这个值的引用次数为1,;相反的,如果包含了对这个值引用的变量又取得了另外一个值,则原先的引用值引用次数就减1,当这个值的引用次数为0的时候,说明没有办法再访问这个值了,因此就把所占的内存给回收进来,这样垃圾收集器再次运行的时候,就会释放引用次数为0的这些值。
事件委托是利用冒泡阶段的运行机制来实现的,就是把一个元素响应事件的函数委托到另一个元素,一般是把一组元素的事件委托到他的父元素上,委托的优点是
减少内存消耗,节约效率
动态绑定事件
事件冒泡,就是元素自身的事件被触发后,如果父元素有相同的事件,如onclick事件,那么元素本身的触发状态就会传递,也就是冒到父元素,父元素的相同事件也会一级一级根据嵌套关系向外触发,直到document/window,冒泡过程结束。
在HTTP/1.0中默认使用短连接。也就是说,客户端和服务器每进行一次HTTP操作,就建立一次连接,任务结束就中断连接。
当客户端浏览器访问的某个HTML或其他类型的Web页中包含有其他的Web资源(如JavaScript文件、图像文件、CSS文件等),
每遇到这样一个Web资源,浏览器就会重新建立一个HTTP会话。
而从HTTP/1.1起,默认使用长连接,用以保持连接特性。使用长连接的HTTP协议,会在响应头加入这行代码:
Connection:keep-alive
在使用长连接的情况下,当一个网页打开完成后,客户端和服务器之间用于传输HTTP数据的TCP连接不会关闭,客户端再次访问这个服务器时
,会继续使用这一条已经建立的连接。Keep-Alive不会永久保持连接,它有一个保持时间,可以在不同的服务器软件(如Apache)中设定这个
时间。实现长连接需要客户端和服务端都支持长连接。
Sourcemaps
&改善了选择器
改善了if()函数
高级操作列表
新的list-separator()函数
支持Maps
改善了@for循环
@at-root规则
新字符串操作函数
新的@import功能
sass和less区别:
1.sass和less主要区别在于实现方式: less是基于JavaScript的在客户端处理 所以安装的时候用npm,sass是基于ruby所以在服务器处理。
2.sass与less的安装
sass基于Ruby语言开发而成,因此安装sass前需要安装Ruby。
less 在服务器端最容易的安装方式就是通过 npm(node.js 的包管理器)。less 在客户端使用【.less】(LESS源文件),只需要在官网载一个javascript脚本文件主【less.js】,然后在HTML中引入即可。
3.变量
sass 是以 开 头 定 义 的 变 量 , 如 : 开头定义的变量,如: 开头定义的变量,如:mainColor: #963;
less 是以@开头定义的变量,如 @mainColor: #963;
4.作用域
sass 没有全局变量,满足就近原则,但是实际中可以将需要定义的全局属性放在base.scss 文件中。注意变量名重复; less 中的作用域和其他程序语言中的作用域非常的相同,他首先会查找局部定义的变量,如果没有找到,会像冒泡一样,一级一级往下查找,直到根为止。
1、算法,一个数组【000000000111111111111】这样,你怎么找出第一个1,最底层的js原生写法, 列如第一个数与第二个数作比较,当第二个大于第一个元素的时候就找出了第一个1,那还有没有更效率的写法
使用循环或递归来实现
2、移动端的1ps线虚掉怎么解决
https://www.cnblogs.com/lunarorbitx/p/5287309.html
3、点击事件在移动端或有300ms的延迟,为什么,怎么解决
原因:
移动端浏览器的默认显示宽度是980px(不同机型各异,但相差不大),而不是屏幕的宽度(320px或其他)。为了对早期普通网页更好的体验,iphone设计了双击放大显示的功能–这就是300ms延迟的来源:如果用户一次点击后300ms内没有其他操作,则认为是个单击行为;否则为双击放大行为
解决方法:
1.设置不能缩放:user-scalable=no。 不能缩放就不会有双击缩放操作,因此click事件也就没了300ms延迟,这个是Chrome首先在Android中提出的。
2.设置显示宽度:width=device-width。Chrome 开发团队不久前宣布,在 Chrome 32 这一版中,他们将在包含 width=device-width 或者置为比 viewport 值更小的页面上禁用双击缩放。当然,没有双击缩放就没有 300
毫秒点击延迟。
3.IE的指针事件 (Pointer Events):设置touch-action:none,根据规范,touch-action 属性决定 “是否触摸操作会触发用户代理的默认行为。这包括但不限于双指缩放等行为”。
从实际应用的角度来看,touch-action决定了用户在点击了目标元素之后,是否能够进行双指缩放或者双击缩放。因此,这也相当完美地解决了300 毫秒点击延迟的问题。
鉴于上述的3种解决方案,现在较为通用的meta设置为:
插件
cnpm install fastclick --save
全局引入 main.js
import fastClick from 'fastclick'
配置ok
fastClick.attach(document.body)
4、移动端的小刘海怎么解决
https://blog.csdn.net/weixin_46034375/article/details/107823692
移动:
1.onclick事件的点穿点透 使用 ontap替换
2.移动端点击事件300ms延时 在头部的viewport 设置禁止缩放
3.iphone手机的小刘海,iphone手机的home键 https://blog.csdn.net/C__Two/article/details/106627613
https://imweb.io/topic/5baa38c279ddc80f36592efb
5、网页显示页面卡顿甚至崩溃,说出可能的原因和解决方法
http://www.manongjc.com/article/54132.html
https://www.cnblogs.com/jing-tian/p/11266796.html
publicPath: './', //基本路径
outputDir: 'dist', //输出文件目录
assetsDir:"static", // 放置静态资源的目录
indexPath:"index.html" // html的输出路径
开发生产共同配置
resolve: {
alias: {
'@': path.resolve(__dirname, './src'),
'@c': path.resolve(__dirname, './src/components'),
'@p': path.resolve(__dirname, './src/pages')
} 别名配置
css配置
css: {
extract: true, // 是否使用css分离插件 ExtractTextPlugin
sourceMap: false, // 开启 CSS source maps?
loaderOptions: {
css: {}, // 这里的选项会传递给 css-loader
postcss: {} // 这里的选项会传递给 postcss-loader
}, // css预设器配置项 详见https://cli.vuejs.org/zh/config/#css-loaderoptions
modules: false // 启用 CSS modules for all css / pre-processor files.
},
// proxy 跨域的配置
devServer: {
open: process.platform === 'darwin',
host: '0.0.0.0', // 允许外部ip访问
port: 8022, // 端口
https: false, // 启用https
overlay: {
warnings: true,
errors: true
}, // 错误、警告在页面弹出
proxy: {
'/api': {
target: 'http://www.baidu.com/api',
changeOrigin: true, // 允许websockets跨域
// ws: true,
pathRewrite: {
'^/api': '' // 请求数据路径别名,这里是注意将static/mock放入public文件夹
}
}
} // 代理转发配置,用于调试环境
},
1.babel-plugin-component ,减少js包的大小,将插件(如element-ui)和自己写的js分开打包,按需加载
2.路由懒加载:使用import(/webpackChunkName:“group-foo”/’./Foo.vue’)
可以完成按需加载页面,避免首页加载内容过多而导致的白屏问题
3.使用 UglifyPlugin (webpack.optimize.UglifyJsPlugin)对代码进行压缩
4.使用该插件image-webpack-loader 进行图片压缩
1: 引入:
require("image-webpack-loader")
2:配置:
module: {
rules: [
...(config.dev.useEslint ? [createLintingRule()] : []),
{
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
loader: 'url-loader',
options: {
loader: 'image-webpack-loader',
options: {
bypassOnDebug: true,
}
}
},
5.由于webpack打包后的js过大,以至于在加载资源时间过长。所以将文件打包成多个js文件,在需要的时候按需加载
new commonsChunkPlugin({
name:'charts',
chunks:['commons']
minChunks:function(module){
return (
module.resource &&
/\.js$/.test(module.resource) &&
module.resource.indexOf(
path.join(__dirname, '../node_modules')
) === 0 && ['jquery.js', 'highcharts.js','echarts'].indexOf( module.resource.substr(module.resource.lastIndexOf('/')+1).toLowerCase() ) != -1
)
}
})
}
Vue 项目性能优化方案
(1)map文件的处理
编辑/config/index.js
文件,找到其中的
productionSourceMap: true,
改为:
productionSourceMap: false,
(2)将项目打包到子目录
一般打包时,是将文件打包为根目录访问的,也就是说,必须在 dist 文件夹下面启动一个服务,才能把项目跑起来。但是我们开发的大多数项目,可能是必须跑在二级目录,甚至更深层次的目录的
编辑/config/index.js
文件,找到的
assetsPublicPath: '/',
//修改为
assetsPublicPath: '/dist/',
把 ‘/’ 修改为你要放的子目录的路径就行了
vue3.0新特性:
1、更快: 虚拟dom重写,优化slots的生成,静态树提升,静态属性提升,基于Proxy的响应式系统
2、更小: 通过摇树优化核心体积
3、更容易维护: ts + 模块化
4、更友好: 跨平台->编译器核心和运行时核心与平台无关,是的vue更容易与任何平台一起使用(web、安卓、ios)
5、更容易使用:改进的ts支持,编译器能提供强有力的类型检查和错误及警告
6、更好的调试支持
7、独立的响应画模块
8、Composition API
vuex 流程
1.在组件中使用dispatch 将状态值分发action;
2.在actions中将 状态值commit提交到 mutations;
3.在mutations中修改store中的状态值;
4.当状态值发生变化时,自动触发render重新渲染页面。
vuex 属性 state action mutation module getter
vuex action mutation 区别 :action 可以异步, 大数据量的操作;mutation 可以直接更改store中的数据值
vuex getters 作用 相当于vue组件中的计算属性
vuex辅助函数 mapState mapAction mapMutation mapGetter
vuex与缓存区别
vuex刷新后数据就没有了,localStorage刷新后值还存在
vuex是响应式的,localStorage不是响应式的
vuex数据持久化 :vuex-persist
(1)轻量级框架:只关注视图层,是一个构建数据的视图集合,大小只有几十kb;
(2)简单易学:国人开发,中文文档,不存在语言障碍 ,易于理解和学习;
(3)双向数据绑定:保留了angular的特点,在数据操作方面更为简单;
(4)组件化:保留了react的优点,实现了html的封装和重用,在构建单页面应用方面有着独特的优势;
(5)视图,数据,结构分离:使数据的更改更为简单,不需要进行逻辑代码的修改,只需要操作数据就能完成相关操作;
虚拟DOM:dom操作是非常耗费性能的, 不再使用原生的dom操作节点,极大解放dom操作,但具体操作的还是dom不过是换了另一种方式;
(6)运行速度更快:相比较与react而言,同样是操作虚拟dom,就性能而言,vue存在很大的优势。
1.什么是 vue 生命周期?有什么作用?
答:每个 Vue 实例在被创建时都要经过一系列的初始化过程——例如,需要设置数据监听、编译模板、将实例挂载到 DOM 并在数据变化时更新 DOM 等。同时在这个过程中也会运行一些叫做 生命周期钩子 的函数,这给了用户在不同阶段添加自己的代码的机会。(ps:生命周期钩子就是生命周期函数)例如,如果要通过某些插件操作DOM节点,如想在页面渲染完后弹出广告窗, 那我们最早可在mounted 中进行。
2.第一次页面加载会触发哪几个钩子?
答:beforeCreate, created, beforeMount, mounted
3.简述每个周期具体适合哪些场景
答:beforeCreate:在new一个vue实例后,只有一些默认的生命周期钩子和默认事件,其他的东西都还没创建。在beforeCreate生命周期执行的时候,data和methods中的数据都还没有初始化。不能在这个阶段使用data中的数据和methods中的方法
create:data 和 methods都已经被初始化好了,如果要调用 methods 中的方法,或者操作 data 中的数据,最早可以在这个阶段中操作
beforeMount:执行到这个钩子的时候,在内存中已经编译好了模板了,但是还没有挂载到页面中,此时,页面还是旧的
mounted:执行到这个钩子的时候,就表示Vue实例已经初始化完成了。此时组件脱离了创建阶段,进入到了运行阶段。 如果我们想要通过插件操作页面上的DOM节点,最早可以在和这个阶段中进行
beforeUpdate: 当执行这个钩子时,页面中的显示的数据还是旧的,data中的数据是更新后的, 页面还没有和最新的数据保持同步
updated:页面显示的数据和data中的数据已经保持同步了,都是最新的
beforeDestory:Vue实例从运行阶段进入到了销毁阶段,这个时候上所有的 data 和 methods , 指令, 过滤器 ……都是处于可用状态。还没有真正被销毁
destroyed: 这个时候上所有的 data 和 methods , 指令, 过滤器 ……都是处于不可用状态。组件已经被销毁了。
4.created和mounted的区别
答:created:在模板渲染成html前调用,即通常初始化某些属性值,然后再渲染成视图。
mounted:在模板渲染成html后调用,通常是初始化页面完成后,再对html的dom节点进行一些需要的操作。
5.vue获取数据在哪个周期函数
答:一般 created/beforeMount/mounted 皆可.
比如如果你要操作 DOM , 那肯定 mounted 时候才能操作.
6.请详细说下你对vue生命周期的理解?
答:总共分为8个阶段创建前/后,载入前/后,更新前/后,销毁前/后。
创建前/后: 在beforeCreated阶段,vue实例的挂载元素 e l 和 ∗ ∗ 数 据 对 象 ∗ ∗ d a t a 都 为 u n d e f i n e d , 还 未 初 始 化 。 在 c r e a t e d 阶 段 , v u e 实 例 的 数 据 对 象 d a t a 有 了 , el和**数据对象**data都为undefined,还未初始化。在created阶段,vue实例的数据对象data有了, el和∗∗数据对象∗∗data都为undefined,还未初始化。在created阶段,vue实例的数据对象data有了,el还没有。
载入前/后:在beforeMount阶段,vue实例的$el和data都初始化了,但还是挂载之前为虚拟的dom节点,data.message还未替换。在mounted阶段,vue实例挂载完成,data.message成功渲染。
更新前/后:当data变化时,会触发beforeUpdate和updated方法。
销毁前/后:在执行destroy方法后,对data的改变不会再触发周期函数,说明此时vue实例已经解除了事件监听以及和dom的绑定,但是dom结构依然存在。
*** Vue 的父组件和子组件生命周期钩子函数执行顺序可以归类为以下 4 部分:
加载渲染过程
父 beforeCreate -> 父 created -> 父 beforeMount -> 子 beforeCreate -> 子 created -> 子 beforeMount -> 子 mounted -> 父 mounted
子组件更新过程
父 beforeUpdate -> 子 beforeUpdate -> 子 updated -> 父 updated
父组件更新过程
父 beforeUpdate -> 父 updated
销毁过程
父 beforeDestroy -> 子 beforeDestroy -> 子 destroyed -> 父 destroyed
vue.js 则是采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的setter,getter,在数据变动时发布消息给订阅者,触发相应的监听回调。
整体思路
核心:通过Object.defineProperty()来实现对属性的劫持,达到监听数据变动的目的
要实现mvvm的双向绑定,就必须要实现以下几点:
1、实现一个数据监听器Observer,能够对数据对象的所有属性进行监听,如有变动可拿到最新值并通知订阅者
2、实现一个指令解析器Compile,对每个元素节点的指令进行扫描和解析,根据指令模板替换数据,以及绑定相应的更新函数
3、实现一个Watcher,作为连接Observer和Compile的桥梁,能够订阅并收到每个属性变动的通知,执行指令绑定的相应回调函数,从而更新视图
4、mvvm入口函数,整合以上三者
vue数据双向绑定是通过数据劫持结合发布者-订阅者模式
的方式来实现的。
我们已经知道实现数据的双向绑定,首先要对数据进行劫持监听,所以我们需要设置一个监听器Observer,用来监听所有属性。如果属性发上变化了,就需要告诉订阅者Watcher看是否需要更新。因为订阅者是有很多个,所以我们需要有一个消息订阅器Dep来专门收集这些订阅者,然后在监听器Observer和订阅者Watcher之间进行统一管理的。接着,我们还需要有一个指令解析器Compile,对每个节点元素进行扫描和解析,将相关指令(如v-model,v-on)对应初始化成一个订阅者Watcher,并替换模板数据或者绑定相应的函数,此时当订阅者Watcher接收到相应属性的变化,就会执行对应的更新函数,从而更新视图。因此接下去我们执行以下3个步骤,实现数据的双向绑定:
1.实现一个监听器Observer,用来劫持并监听所有属性,如果有变动的,就通知订阅者。
2.实现一个订阅者Watcher,每一个Watcher都绑定一个更新函数,watcher可以收到属性的变化通知并执行相应的函数,从而更新视图。
3.实现一个解析器Compile,可以扫描和解析每个节点的相关指令(v-model,v-on等指令),如果节点存在v-model,v-on等指令,则解析器Compile初始化这类节点的模板数据,使之可以显示在视图上,然后初始化相应的订阅者(Watcher)。
3.0:
Vue3.x是用ES6的语法 Proxy对象来实现的,这个玩意儿也可以实现数据的劫持
相比于vue2.x,使用proxy的优势如下
1 defineProperty只能监听某个属性,不能对全对象监听
2 可以省去for in、闭包等内容来提升效率(直接绑定整个对象即可)
3 可以监听数组,不用再去单独的对数组做特异性操作
vue3.x可以检测到数组内部数据的变化
vue2.0与vue3.0 双向数据绑定原理 区别
第一种:vue异步组件技术 ==== 异步加载,vue-router配置路由 , 使用vue的异步组件技术 , 可以实现按需加载 .但是,这种情况下一个组件生成一个js文件。
第二种:路由懒加载(使用import)。
第三种:webpack提供的require.ensure(),vue-router配置路由,使用webpack的require.ensure技术,也可以实现按需加载。这种情况下,多个路由指定相同的chunkName,会合并打包成一个js文件。
计算属性 watch ,计算属性就是当其依赖属性的值发生变化时,这个属性的值会自动更新,与之相关的DOM部分也会同步自动更新。
计算属性有缓存,计算属性的函数会自动调用。普通函数需要手动触发
计算属性和watch ,异步操作或大数据量操作使用watch
methods: 不存在缓存,执行一次运行一次,执行n次,运行n次
1.watch擅长处理的场景:一个数据影响多个数据
2.computed擅长处理的场景:一个数据受多个数据影响
computed & watch的区别
因为JavaScript的特性所导致,在component中,data必须以函数的形式存在,不可以是对象。
组建中的data写成一个函数,数据以函数返回值的形式定义,这样每次复用组件的时候,都会返回一份新的data,相当于每个组件实例都有自己私有的数据空间,它们只负责各自维护的数据,不会造成混乱。而单纯的写成对象形式,就是所有的组件实例共用了一个data,这样改一个全都改了。
.stop:等同于JavaScript中的event.stopPropagation(),防止事件冒泡;
.prevent:等同于JavaScript中的event.preventDefault(),防止执行预设的行为(如果事件可取消,则取消该事件,而不停止事件的进一步传播);
.capture:与事件冒泡的方向相反,事件捕获由外到内;
.self:只会触发自己范围内的事件,不包含子元素;
.once:只会触发一次。
父传子 : props接收
子传父: $emit 手动触发自定义事件 (因为 vue组件间传递数据时单向的)
兄弟: bus vuex(我)
https://blog.csdn.net/kangkang_90/article/details/92798296
http://www.mamicode.com/info-detail-3057151.html
props/
$emit
$children/ $parent
provide
/ inject
provide
/ inject
是vue2.2.0
新增的api, 简单来说就是父组件中通过provide
来提供变量, 然后再子组件中通过inject
来注入变量。
注意: 这里不论子组件嵌套有多深, 只要调用了
inject
那么就可以注入provide
中的数据,而不局限于只能从当前父组件的props属性中回去数据
4.ref
/ refs
5.eventBus
6.Vuex
7.localStorage
/ sessionStorage
8.$attrs
与 $listeners
在vue2.4
中,为了解决该需求,引入了$attrs
和$listeners
, 新增了inheritAttrs
选项。 在版本2.4以前,默认情况下,父作用域中不作为 prop 被识别 (且获取) 的特性绑定 (class 和 style 除外),将会“回退”且作为普通的HTML特性应用在子组件的根元素上
需要在@click后面加上.native,官方对于native的解释为:
.native -——监听组件根元素的原生事件
由于 JavaScript 的限制,Vue 不能检测数组和对象的变化。尽管如此我们还是有一些办法来回避这些限制并保证它们的响应性。
对于对象:
Vue 无法检测 property 的添加或移除
Vue 不能检测以下数组的变动:
当你利用索引直接设置一个数组项时,例如:vm.items[indexOfItem] = newValue
当你修改数组的长度时,例如:vm.items.length = newLength
当页面上的值不发生变化时,可以使用 $.set
对象还可以使用 :assign
数组还可以使用:splice
Vue 将被侦听的数组的变更方法进行了包裹,所以它们也将会触发视图更新。push() pop() shift() unshift() splice() sort() reverse()
也有非变更方法,例如 filter()、concat() 和 slice()。它们不会变更原始数组,而总是返回一个新数组
1、vue页面第一次渲染执行的几个钩子函数
beforeCreate created beforeMounte mounted
2、vue页面跳转时执行那几个钩子
beforeCreate created beforeMounte mounted beforeDestory destoryed
v-model用于表单数据的双向绑定,其实它就是一个语法糖,这个背后就做了两个操作:
v-bind绑定一个value属性;
v-on指令给当前元素绑定input事件。
当你修改了data的值然后马上获取这个dom元素的值,是不能获取到更新后的值,
你需要使用$nextTick这个回调,让修改后的data值渲染更新到dom元素之后在获取,才能成功。
虚拟dom是在内存生成一个虚拟的dom对象,来记录该节点的属性和方法,这样避免了直接操作真实dom节点,增加性能
在父组件调用子组件时,写在子组件标签中间的的内容,可以传递到子组件的slot标签的相应位置;
使用场景:类似于element-ui里面的组件封装,对组件的扩展,
匿名插槽:没名字
具名插槽:有名字
作用域插槽:所以作用域插槽是一种子传父传参的方式,解决了普通slot在parent中无法访问child数据的去问题
例如:暴露了width、title、确定按钮、取消按钮的事件函数、弹窗的内容,
我是模态框的主体内容
路由创建 路由跳转 路由传参
1、全局钩子 beforeEach(全局前置守卫,如果你的项目中有一个以上的功能需要守卫建议使用 这个) afterEach beforeResolve (解析守卫)
2、某个路由的钩子 beforeEnter
3、组件内钩子
beforeRouteEnter
beforeRouteUpdate (2.2 新增)
beforeRouteLeave
参数:from to next
路由懒加载
子路由
$route 当前页面路由
$router 全局的路由
$route为当前router跳转对象里面可以获取name、path、query、params等
r o u t e r 为 V u e R o u t e r 实 例 , 想 要 导 航 到 不 同 U R L , 则 使 用 router为VueRouter实例,想要导航到不同URL,则使用 router为VueRouter实例,想要导航到不同URL,则使用router.push方法
axios 请求拦截 ,验证token ,防攻击
全局路由守卫,除了登录页面,其他页面都需要守卫
token有过期时间,在后台管理,如果过期了,会跳转到登录页,再重新获取token,token 保存到缓存
hash —— 即地址栏 URL 中的 # 符号(history没有)
history —— 利用了 HTML5 History Interface 中新增的 pushState() 和 replaceState() 方法。(需要特定浏览器支持)
这两个方法应用于浏览器的历史记录栈,在当前已有的 back、forward、go 的基础之上,它们提供了对历史记录进行修改的功能。只是当它们执行修改时,虽然改变了当前的 URL,但浏览器不会立即向后端发送请求
hash模式:在浏览器中符号“#”,#以及#后面的字符称之为hash,用window.location.hash读取;
特点:hash虽然在URL中,但不被包括在HTTP请求中;用来指导浏览器动作,对服务端安全无用,hash不会重加载页面。
hash 模式下,仅 hash 符号之前的内容会被包含在请求中,如 http://www.xxx.com,因此对于后端来说,即使没有做到对路由的全覆盖,也不会返回 404 错误。
history模式:history采用HTML5的新特性;且提供了两个新方法:pushState(),replaceState()可以对浏览器历史记录栈进行修改,以及popState事件的监听到状态变更。
history 模式下,前端的 URL 必须和实际向后端发起请求的 URL 一致,如 http://www.xxx.com/items/id。后端如果缺少对 /items/id 的路由处理,将返回 404 错误。Vue-Router 官网里如此描述:“不过这种模式要玩好,还需要后台配置支持……所以呢,你要在服务端增加一个覆盖所有情况的候选资源:如果 URL 匹配不到任何静态资源,则应该返回同一个 index.html 页面,这个页面就是你 app 依赖的页面。”
和计算属性一起使用的,组件的名字可以更改的组件
一般的动态组件的外面合一使用keep-alive进行缓存
当你修改了data的值然后马上获取这个dom元素的值,是不能获取到更新后的值,
你需要使用$nextTick这个回调,让修改后的data值渲染更新到dom元素之后在获取,才能成功。
http://caibaojian.com/vue3-composition-api.html
vue项目解决跨域: proxy ,但是打包后不能用 ;打包后需要在后台设置 nginx
使用vue开发时,在vue初始化之前,由于div是不归vue管的,所以我们写的代码在还没有解析的情况下会容易出现花屏现象,看到类似于{{message}}的字样,虽然一般情况下这个时间很短暂,但是我们还是有必要让解决这个问题的。
首先:在css里加上[v-cloak] {
display: none;
}。
如果没有彻底解决问题,则在根元素加上style=“display: none;” :style="{display: ‘block’}"
共同点:都能控制元素的显示和隐藏;
不同点:实现本质方法不同,
v-show本质就是通过控制css中的display设置为none,控制隐藏,只会编译一次;
v-if是动态的向DOM树内添加或者删除DOM元素,若初始值为false,就不会编译了。而且v-if不停的销毁和创建比较消耗性能。
v-show 只编译一次,后面其实就是控制 css,而 v-if 不停的销毁和创建,故 v-show性能更好一。
总结:如果要频繁切换某节点,使用v-show(切换开销比较小,初始开销较大)。
如果不需要频繁切换某节点使用v-if(因为懒加载,初始为 false 时,不会渲染,但是因为它是通过添加和删除 dom元素来控制显示和隐藏的,因此初始渲染开销较小,切换开销比较大)。
在组件中的style前面加上scoped
(1)Vue组件(component)用来构成你的App的业务模块,它的目标是App.vue。 引入 ,注册,html中作为标签名的形式使用。请说下封装 vue 组件的过程?
答:
Vue插件(plugin) 用来增强你的技术栈的功能模块, 它的目标是Vue本身。(插件是对Vue的功能的增强和补充)
插件一般需要写成一个独立的js文件,需要安装,需要 引入,需要 use(使用)
插件的封装 **
VUE常用插件库总结
我封装过tab标签的插件 ,封装过 弹窗的插件,封装过列表的插件,封装过瀑布式布局的插件
暴露的接口(可变的,用户可以向里面输入内容的,选择不同的显示状态的地方) ,
1.Vue 提供了 transition 的封装组件,在下列情形中,可以给任何元素和组件添加进入/离开过渡
hello
new Vue({
el: '#demo',
data: {show: true}
})
.fade-enter-active, .fade-leave-active { transition: opacity .5s;}
.fade-enter, .fade-leave-to /* .fade-leave-active below version 2.1.8 */ { opacity: 0;}
过渡的类名
在进入/离开的过渡中,会有 6 个 class 切换。
v-enter:定义进入过渡的开始状态。在元素被插入之前生效,在元素被插入之后的下一帧移除。
v-enter-active:定义进入过渡生效时的状态。在整个进入过渡的阶段中应用,在元素被插入之前生效,在过渡/动画完成之后移除。这个类可以被用来定义进入过渡的过程时间,延迟和曲线函数。
v-enter-to:2.1.8 版及以上定义进入过渡的结束状态。在元素被插入之后下一帧生效 (与此同时 v-enter 被移除),在过渡/动画完成之后移除。
v-leave:定义离开过渡的开始状态。在离开过渡被触发时立刻生效,下一帧被移除。
v-leave-active:定义离开过渡生效时的状态。在整个离开过渡的阶段中应用,在离开过渡被触发时立刻生效,在过渡/动画完成之后移除。这个类可以被用来定义离开过渡的过程时间,延迟和曲线函数。
v-leave-to:2.1.8 版及以上定义离开过渡的结束状态。在离开过渡被触发之后下一帧生效 (与此同时 v-leave 被删除),在过渡/动画完成之后移除。
2.还可以使用css3的动画效果:
.bounce-enter-active {animation: bounce-in .5s;}
.bounce-leave-active { animation: bounce-in .5s reverse;}
@keyframes bounce-in {
0% { transform: scale(0); }
50% { transform: scale(1.5);}
100% { transform: scale(1);}
}
3.可以使用 js钩子
methods: {
// --------// 进入中// --------
beforeEnter: function (el) { // ...},
// 当与 CSS 结合使用时 // 回调函数 done 是可选的
enter: function (el, done) { // ... done() },
afterEnter: function (el) { // ...},
enterCancelled: function (el) { // ...},
// -------- // 离开时 // --------
beforeLeave: function (el) { // ...},
// 当与 CSS 结合使用时
// 回调函数 done 是可选的
leave: function (el, done) { // ... done() },
afterLeave: function (el) {// ...},
// leaveCancelled 只用于 v-show 中
leaveCancelled: function (el) { // ... }
}
4.可以引入Velocity
$props $attrs $listeners $root
$el $options $refs $watch() $emit $on $off $once
jquery对dom操作 是单向的
vue 使用双向绑定
layout布局
form表单里的组件(input button checkbox)
Cascader级联选择器
Breadcrumb面包屑导航栏……
1、使用路由懒加载
2、组件异步加载
3、组件模块化,提高代码复用率
……
父组件
filter 过滤器 后台项目
你的站点上动态渲染的任意 HTML 可能会非常危险,因为它很容易导致 XSS 攻击。请只对可信内容使用 HTML 插值,绝不要对用户提供的内容使用插值。
可能会导致xss攻击
V-html更新的是元素的 innerHTML 。内容按普通 HTML 插入, 不会作为 Vue 模板进行编译 。
但是有的时候我们需要渲染的html片段中有插值表达式,或者按照Vue模板语法给dom元素绑定了事件。
在单文件组件里,scoped 的样式不会应用在 v-html 内部,因为那部分 HTML 没有被 Vue 的模板编译器处理。如果你希望针对 v-html 的内容设置带作用域的 CSS,你可以替换为 CSS Modules 或用一个额外的全局 style元素手动设置类似 BEM 的作用域策略。
后台返回的html片段,以及css样式和js,但是返回的js是不执行的,因为浏览器在渲染的时候并没有将js渲染,这时要在$nextTick中动
态创建script标签并插入
pc:
1、ES6语法不支持
解决方法:
引入babel-polyfill
npm install --save bable-polyfill
webpack.base.conf.js中修改为
app: [‘event-source-polyfill’, ‘babel-polyfill’, ‘./src/main.js’]
main.js 中引入
import ‘babel-polyfill’;
2、GET非首次请求时,IE默认使用缓存而不是去后台请求
解决方法:
在request拦截时,加时间戳
service.interceptors.request.use(config => {
// Do something before request is sent
// // 时间戳
if (config.method === ‘get’) {
config.params = {
t: Date.parse(new Date()) / 1000,
…config.params
}
}
return config;
}, error => {
// Do something with request error
console.log(error); // for debug
Promise.reject(error);
})
3、上传文件时,文件类型检查。如果为.apk文件,则file.type为" ".而jpg/png等文件正常
导致上传apk文件时,会报类型检查错误
解决方法:
export function validateApk(file) {
if (file.type === ‘application/vnd.android.package-archive’) {
return true;
} else {
if (file.name.substring(file.name.lastIndexOf(’.’) + 1) === ‘apk’) {
return true;
}
}
return false;
}
4、上传文件时,后台读取file.getName或者file.getOriginalName为全路径名称
解决方法:
后台去处理,如果为全路径,则进行字符串截取
IE目前已经放弃了自己的独特化,正一步步迎入互联网的主流怀抱。但迫于有用户存在,还是要兼容到IE8,9, 以上。
下面聊一下如何在vue框架中兼容IE
1.首先在index.html
问题:Vue2.0的官方脚手架工具构建的项目,chrome中跑一直没有问题,但ie打开出现了bug:
原因:Babel 默认只转换新的 JavaScript 句法(syntax),而不转换新的 API ,比如 Iterator、Generator、Set、Maps、Proxy、Reflect、Symbol、Promise 等全局对象,以及一些定义在全局对象上的方法(比如 Object.assign)都不会转码。为了解决这个问题,我们使用一种叫做 Polyfill
(代码填充,也可译作兼容性补丁) 的技术。 简单地说,polyfill即是在当前运行环境中用来复制(意指模拟性的复制,而不是拷贝)尚不存在的原生 api 的代码。
方案:安装babel-polyfill
步骤
1.安装babel-polyfill
npm install --save-dev babel-polyfill
2.然后再main.js中引入
import 'babel-polyfill'
3.如果也是用了官方脚手架vue-cli,还需要在webpack.config.js配置文件中做各修改,用
module.exports = {
entry: {
app: ["babel-polyfill", "./src/main.js"] // 替换 app: './src/main.js'
}
};
https://blog.csdn.net/qq_40816649/article/details/92799569
https://blog.csdn.net/qq_42269433/article/details/106838947
1、vue从a页面跳到b页面,b页面的值是从a页面带过来的,b页面刷新,a页面带过来的值没有了,怎么解决
react | vue |
---|---|
单向数据流,不支持双向绑定 | 可以双向绑定(父子组件:props, 组件与dom:v-model) |
不能精确知道数据变化 | 通过 getter/setter以及一些函数的劫持,能精确知道数据变化 |
函数式编程 | 声明式写法 |
redux | vuex |
… | … |
vue和react的全面对比
1、使用路由懒加载
2、使用hooks,增加代码复用率减少代码量
。。。
1.使用Fragment。减少不必要的节点生成,也可以使用空标签
2.类组件使用 shouldComponentUpdate,减少不必要的组件渲染
3.多使用 函数式组件渲染、减少使用类组件
4.函数式组件中使用 memo 避免重复渲染
5.使用React.lazy()和Suspense进行懒加载
6.异常捕获边界(Error Boundaries)
捕获发生异常的React组件。将异常组件和正常组件分割开。提高用户的体验性能。
7. 骨架屏
骨架屏插件以react-content-loader(svg图片生层)为基础。用于在页面初始加载时,避免出现白屏现象。
8.长列表优化
虚拟化长列表:只加载可视范围内的数据。
当网站需要加载大批量数据(成千上万)时,会加载特别慢。
这个时候我们可以使用“虚拟滚动”技术(react-window或者react-virtualized),只渲染当前屏幕范围内的数据。
鼠标滚动去触发事件,再渲染一屏。
9. 根据性能优化工具修改代码
componentWillUnmount = () => {
//停止定时器
clearInterval(this.inter);
//如果页面跳转时,setState还没有执行完,就停止它,return
this.setState = (state,callback)=>{
return;
};
}
1.context 可以跨组件传参
2.lazy、suspense 动态引入组件
3.memo 相当于 shouldComponentUpdate 使用在函数式组件中
4.hooks
context 可以跨组件传参,既从根节点可以直接传参到叶子节点
1.创建 const ThemeContext = React.createContext(‘light’);
2.传参
组件名
3.接收
function MyButton(props){
//3.接收参数
return {
theme=>
}
}
hooks
1.useState 可以在函数式组件中使用state ,并且可以调用函数更改state的值
2.useEffect useEffect它与 React 类中的 componentDidMount,componentDidUpdate,和
componentWillUnmount 有相同的功能,但是统一为单个 API。
memo
是在 函数式组件中,如果有组件不需要更新时,调用memo ,相当于 类组件中的 shouldComponentUpdate
lazy\Suspense\错误边界(Error boundaries)
在函数式组件中调用 state,调用钩子, useState, useEffect
初始化阶段:
getDefaultProps:获取实例的默认属性
getInitialState:获取每个实例的初始化状态
componentWillMount:组件即将被装载、渲染到页面上
render:组件在这里生成虚拟的 DOM 节点
componentDidMount:组件真正在被装载之后
运行中状态:
componentWillReceiveProps:组件将要接收到属性的时候调用
shouldComponentUpdate:组件接受到新属性或者新状态的时候(可以返回 false,接收数据后不更新,阻止 render 调用,后面的函数不会被继续执行了)
componentWillUpdate:组件即将更新不能修改属性和状态
render:组件重新描绘
componentDidUpdate:组件已经更新
销毁阶段:
componentWillUnmount:组件即将销毁
V17.0之后的版本删除的钩子函数
componentWillMount ,componentWillReceiveProps ,componentWillUpdate
在 v16.3以上版本新增的钩子函数
getDerivedStateFromProps,getSnapshotBeforeUpdate
componentWillMount 新版去掉
render
componentDidMount
componentWillReceiveProps 新版去掉
shouldComponentUpdate 作用?函数式组件中 使用memo0
componentWillUpdate 新版去掉
componentDidUpdate
componentWillUnmount
初始化阶段:
getDefaultProps:获取实例的默认属性
getInitialState:获取每个实例的初始化状态
componentWillMount:组件即将被装载、渲染到页面上
render:组件在这里生成虚拟的 DOM 节点
componentDidMount:组件真正在被装载之后
运行中状态:
componentWillReceiveProps:组件将要接收到属性的时候调用
shouldComponentUpdate:组件接受到新属性或者新状态的时候(可以返回 false,接收数据后不更新,阻止 render 调用,后面的函数不会被继续执行了)
componentWillUpdate:组件即将更新不能修改属性和状态
render:组件重新描绘
componentDidUpdate:组件已经更新
销毁阶段:
componentWillUnmount:组件即将销毁
V17.0之后的版本删除的钩子函数
componentWillMount ,componentWillReceiveProps ,componentWillUpdate
在 v16.3以上版本新增的钩子函数
getDerivedStateFromProps,getSnapshotBeforeUpdate
keys 是 React 用于追踪哪些列表中元素被修改、被添加或者被移除的辅助标识。
render () {
return (
{this.state.todoItems.map(({item, key}) => {
return - {item}
})}
)
}
在开发过程中,我们需要保证某个元素的 key 在其同级元素中具有唯一性。在 React Diff 算法中 React 会借助元素的 Key 值来判断该元素是新近创建的还是被移动而来的元素,从而减少不必要的元素重渲染。此外,React 还需要借助 Key 值来判断元素与本地状态的关联关系,因此我们绝不可忽视转换函数中 Key 的重要性。
在代码中调用 setState 函数之后,React 会将传入的参数对象与组件当前的状态合并,然后触发所谓的调和过程(Reconciliation)。经过调和过程,React 会以相对高效的方式根据新的状态构建 React 元素树并且着手重新渲染整个 UI 界面。在 React 得到元素树之后,React 会自动计算出新的树与老树的节点差异,然后根据差异对界面进行最小化重渲染。在差异计算算法中,React 能够相对精确地知道哪些位置发生了改变以及应该如何改变,这就保证了按需更新,而不是全部重新渲染
shouldComponentUpdate 这个方法用来判断是否需要调用 render 方法重新描绘 dom。因为 dom 的描绘非常消耗性能,如果我们能在 shouldComponentUpdate 方法中能够写出更优化的 dom diff 算法,可以极大的提高性能。
参考react 性能优化-sf
虚拟 dom 相当于在 js 和真实 dom 中间加了一个缓存,利用 dom diff 算法避免了没有必要的 dom 操作,从而提高性能。
用 JavaScript 对象结构表示 DOM 树的结构;然后用这个树构建一个真正的 DOM 树,插到文档当中当状态变更的时候,重新构造一棵新的对象树。然后用新的树和旧的树进行比较,记录两棵树差异把 2 所记录的差异应用到步骤 1 所构建的真正的 DOM 树上,视图就更新了。
参考 如何理解虚拟 DOM?-zhihu
把树形结构按照层级分解,只比较同级元素。
给列表结构的每个单元添加唯一的 key 属性,方便比较。
React 只会匹配相同 class 的 component(这里面的 class 指的是组件的名字)
合并操作,调用 component 的 setState 方法的时候, React 将其标记为 dirty.到每一个事件循环结束, React 检查所有标记 dirty 的 component 重新绘制.
选择性子树渲染。开发人员可以重写 shouldComponentUpdate 提高 diff 的性能。
参考:React 的 diff 算法
refs的适用情况:
1.处理焦点,文本选择,媒体控制
2.触发强制动画
3.继承第三方的dom库
4.如果可以通过声明能实现的,尽量避免使用refs
Refs 是 React 提供给我们的安全访问 DOM 元素或者某个组件实例的句柄。我们可以为元素添加 ref 属性然后在回调函数中接受该元素在 DOM 树中的句柄,该值会作为回调函数的第一个参数返回:
class CustomForm extends Component {
handleSubmit = () => {
console.log("Input Value: ", this.input.value)
}
render () {
return (
)
}
}
上述代码中的 input 域包含了一个 ref 属性,该属性声明的回调函数会接收 input 对应的 DOM 元素,我们将其绑定到 this 指针以便在其他的类函数中使用。另外值得一提的是,refs 并不是类组件的专属,函数式组件同样能够利用闭包暂存其值:
function CustomForm ({handleSubmit}) {
let inputElement
return (
)
}
{(user) => user === null
?
: }
import React, { Component, PropTypes } from 'react'
import fetchUser from 'twitter'
// fetchUser take in a username returns a promise
// which will resolve with that username's data.
class Twitter extends Component {
// finish this
}
如果你还不熟悉回调渲染模式(Render Callback Pattern),这个代码可能看起来有点怪。这种模式中,组件会接收某个函数作为其子组件,然后在渲染函数中以 props.children 进行调用:
import React, { Component, PropTypes } from 'react'
import fetchUser from 'twitter'
class Twitter extends Component {
state = {
user: null,
}
static propTypes = {
username: PropTypes.string.isRequired,
}
componentDidMount () {
fetchUser(this.props.username)
.then((user) => this.setState({user}))
}
render () {
return this.props.children(this.state.user)
}
}
这种模式的优势在于将父组件与子组件解耦和,父组件可以直接访问子组件的内部状态而不需要再通过 Props 传递,这样父组件能够更为方便地控制子组件展示的 UI 界面。譬如产品经理让我们将原本展示的 Badge 替换为 Profile,我们可以轻易地修改下回调函数即可:
{(user) => user === null
?
: }
展示组件关心组件看起来是什么。展示专门通过 props 接受数据和回调,并且几乎不会有自身的状态,但当展示组件拥有自身的状态时,通常也只关心 UI 状态而不是数据的状态。
容器组件则更关心组件是如何运作的。容器组件会为展示组件或者其它容器组件提供数据和行为(behavior),它们会调用 Flux actions,并将其作为回调提供给展示组件。容器组件经常是有状态的,因为它们是(其它组件的)数据源。
类组件不仅允许你使用更多额外的功能,如组件自身的状态和生命周期钩子,也能使组件直接访问 store 并维持状态
当组件仅是接收 props,并将组件自身渲染到页面时,该组件就是一个 ‘无状态组件(stateless component)’,可以使用一个纯函数来创建这样的组件。这种组件也被称为哑组件(dumb components)或展示组件
State
是一种数据结构,用于组件挂载时所需数据的默认值。State 可能会随着时间的推移而发生突变,但多数时候是作为用户事件行为的结果。
Props
(properties 的简写)则是组件的配置。props 由父组件传递给子组件,并且就子组件而言,props 是不可变的(immutable)。组件不能改变自身的 props,但是可以把其子组件的 props 放在一起(统一管理)。Props 也不仅仅是数据–回调函数也可以通过 props 传递。
在 HTML 中,类似 , 和 这样的表单元素会维护自身的状态,并基于用户的输入来更新。当用户提交表单时,前面提到的元素的值将随表单一起被发送。但在 React 中会有些不同,包含表单元素的组件将会在 state 中追踪输入的值,并且每次调用回调函数时,如 onChange 会更新 state,重新渲染组件。一个输入表单元素,它的值通过 React 的这种方式来控制,这样的元素就被称为"受控元素"。
高阶组件是一个以组件为参数并返回一个新组件的函数。HOC 运行你重用代码、逻辑和引导抽象。最常见的可能是 Redux 的 connect 函数。除了简单分享工具库和简单的组合,HOC 最好的方式是共享 React 组件之间的行为。如果你发现你在不同的地方写了大量代码来做同一件事时,就应该考虑将代码重构为可重用的 HOC。
因为 this.props 和 this.state 的更新可能是异步的,不能依赖它们的值去计算下一个 state。
你可以使用属性初始值设定项(property initializers)来正确绑定回调,create-react-app 也是默认支持的。在回调中你可以使用箭头函数,但问题是每次组件渲染时都会创建一个新的回调。
在 super() 被调用之前,子类是不能使用 this 的,在 ES2015 中,子类必须在 constructor 中调用 super()。传递 props 给 super() 的原因则是便于(在子类中)能在 constructor 访问 this.props。
在 React 组件中,应该在 componentDidMount 中发起网络请求。这个方法会在组件第一次“挂载”(被添加到 DOM)时执行,在组件的生命周期中仅会执行一次。更重要的是,你不能保证在组件挂载之前 Ajax 请求已经完成,如果是这样,也就意味着你将尝试在一个未挂载的组件上调用 setState,这将不起作用。在 componentDidMount 中发起网络请求将保证这有一个组件可以更新了。
为了解决跨浏览器兼容性问题,您的 React 中的事件处理程序将传递 SyntheticEvent 的实例,它是 React 的浏览器本机事件的跨浏览器包装器。
这些 SyntheticEvent 与您习惯的原生事件具有相同的接口,除了它们在所有浏览器中都兼容。有趣的是,React 实际上并没有将事件附加到子节点本身。React 将使用单个事件监听器监听顶层的所有事件。这对于性能是有好处的,这也意味着在更新 DOM 时,React 不需要担心跟踪事件监听器。
React.createClass()、ES6 class 和无状态函数。
根据组件的职责通常把组件分为 UI 组件和容器组件。
UI 组件负责 UI 的呈现,容器组件负责管理数据和逻辑。
两者通过 React-Redux 提供 connect 方法联系起来。
redux 是一个应用数据流框架,主要是解决了组件间状态共享的问题,原理是集中式管理,主要有三个核心方法,action,store,reducer,工作流程是 view 调用 store 的 dispatch 接收 action 传入 store,reducer 进行 state 操作,view 通过 store 提供的 getState 获取最新的数据,flux 也是用来进行数据操作的,有四个组成部分 action,dispatch,view,store,工作流程是 view 发出一个 action,派发器接收 action,让 store 进行数据更新,更新完成以后 store 发出 change,view 接受 change 更新视图。Redux 和 Flux 很像。主要区别在于 Flux 有多个可以改变应用状态的 store,在 Flux 中 dispatcher 被用来传递数据到注册的回调事件,但是在 redux 中只能定义一个可更新状态的 store,redux 把 store 和 Dispatcher 合并,结构更加简单清晰
新增 state,对状态的管理更加明确,通过 redux,流程更加规范了,减少手动编码量,提高了编码效率,同时缺点时当数据更新时有时候组件不需要,但是也要重新绘制,有些影响效率。一般情况下,我们在构建多交互,多数据流的复杂项目应用时才会使用它们
redux 有什么缺点
一个组件所需要的数据,必须由父组件传过来,而不能像 flux 中直接从 store 取。
当一个组件相关数据更新时,即使父组件不需要用到这个组件,父组件还是会重新 render,可能会有效率影响,或者需要写复杂的 shouldComponentUpdate 进行判断。
Reducx-状态管理
redux-saga可以解决thunk 的两个问题:
1.action的形式不统一
2.就是异步操作太为分散,分散在了各个action中 不易维护
3.saga将异步操作放到统一的一个文件中处理
优点:
(1)集中处理了所有的异步操作,异步接口部分一目了然
(2)action是普通对象,这跟redux同步的action一模一样
(3)通过Effect,方便异步接口的测试
(4)通过worker 和watcher可以实现非阻塞异步调用,并且同时可以实
现非阻塞调用下的事件监听
(5) 异步操作的流程是可以控制的,可以随时取消相应的异步操作。
缺点:太复杂,学习成本较高
put:对应的是middleware中的dispatch方法,可以发送一个动作
call: 表示异步调用,其中call表示的是阻塞调用,
fork:表示异步调用,表示的是非阻塞调用。
take:监听action,返回监听到的action对象
delay:延时
takeEvery:予以相当于 on ,允许并发action
all:创建effect的描述信息,用来命令中间件,并行多个effect,并等待他们全部完成
xxx
this.props.history.push({pathname:"/path/" + name});
读取参数用:this.props.match.params.name
优势 : 刷新地址栏,参数依然存在
缺点:只能传字符串,并且,如果传的值太多的话,url会变得长而丑陋。
<Route path='/query' component={Query}/>
<Link to={{ path : ' /query' , query : { name : 'sunny' }}}>
this.props.history.push({pathname:"/query",query: { name : 'sunny' }});
读取参数用: this.props.location.query.name
优势:传参优雅,传递参数可传对象;
缺点:刷新地址栏,参数丢失
<Route path='/sort ' component={Sort}/>
<Link to={{ path : ' /sort ' , state : { name : 'sunny' }}}>
this.props.history.push({pathname:"/sort ",state : { name : 'sunny' }});
读取参数用: this.props.location.query.state
优缺点同query
xxx
this.props.history.push({pathname:"/web/departManange?tenantId" + row.tenantId});
读取参数用: this.props.location.search
优缺点同params
根据自己项目自行解说
wx.navigateTo():保留当前页面,跳转到应用内的某个页面。但是不能跳到 tabbar 页面
wx.redirectTo():关闭当前页面,跳转到应用内的某个页面。但是不允许跳转到 tabbar 页面
wx.switchTab():跳转到 abBar 页面,并关闭其他所有非 tabBar 页面
wx.navigateBack()关闭当前页面,返回上一页面或多级页面。可通过 getCurrentPages() 获取当前的页面栈,决定需要返回几层
wx.reLaunch():关闭所有页面,打开到应用内的某个页面
– 父传子
父组件传递参数,子组件使用 properties 接收
– 子传父
子组件wxml:绑定事件
点击,隐藏我自己
子组件的js:
changeP:function(){
console.log('子组件的函数触发了');
const myEventDetail = {type:false};//子传父的参数设置
const myEventOption = {};//调用时的触发事件选项
//主动触发事件,自动绑定父组件中的自定义事件
this.triggerEvent('myevent',myEventDetail,myEventOption);
}
父组件wxml:
父组件js:
//接收从子组件传过来的参数
getValue:function(data){
console.log("接收了从子组件传过来的参数",data);
this.setData({
type:data.detail.type
})
},
1、提高页面加载速度
2、用户行为预测
3、减少默认 data 的大小 ***
4、组件化方案 ***
控制包的大小
提升体验最直接的方法是控制小程序包的大小,基本上可以说,1M的代码包,下载耗时1秒左右。
控制包的大小的措施
压缩代码,清理无用的代码
使用外部图片 ***
采用分包策略 ***
分包预加载
独立分包(版本要求有点高)
除了上面讲的控制包的大小,对异步请求的优化也很重要。
对异步请求的优化
onLoad 阶段就可以发起请求,不用等ready
请求结果放在缓存中, 下次接着用
请求中可以先展示骨架图
先反馈,再请求。比如说,点赞的按钮,可以先改变按钮的样式,再发起异步请求。
提升渲染性能
减少使用data,减少使用setData ***
合并setData的请求,减少通讯的次数
列表的局部更新,做分页,上拉加载更多页 ***
onPageScroll,考虑使用防抖节流 ***
尽可能使用小程序组件
一共可以有10个分包 ,一个分包可以有2M
.wxml 相当于 html页
.wxss 相当于css页
.json 小程序页面的配置
.js 小程序的javascript页面
请谈谈WXSS和CSS的异同?
都是用来描述页面的样子;
WXSS 具有 CSS 大部分的特性,也做了一些扩充和修改;
WXSS新增了尺寸单位,WXSS 在底层支持新的尺寸单位 rpx;
WXSS 仅支持部分 CSS 选择器;
WXSS 提供全局样式与局部样式
WXSS 不支持window和dom 文档流
7.1 App 注册小程序。接受一个 Object 参数,其指定小程序的生命周期回调等。
钩子函数有:
属性 类型 默认值 必填 说明 最低版本
onLaunch function 否 生命周期回调——监听小程序初始化。
onShow function 否 生命周期回调——监听小程序启动或切前台。
onHide function 否 生命周期回调——监听小程序切后台。
onError function 否 错误监听函数。
onPageNotFound function 否 页面不存在监听函数。 1.9.90
onUnhandledRejection
--getApp 获取小程序的实例
--var myApp = getApp();
--myApp.globalData.全局变量名 可以获取在app.js中定义的全局变量的值
--全局变量可以跨页面传参
7.2 Page(Object object)
注册小程序中的一个页面。接受一个 Object 类型参数,其指定页面的初始数据、生命周期回调、事件处理函数等。
页面的钩子函数:
**onLoad function 生命周期回调—监听页面加载 只执行一次的
**onShow function 生命周期回调—监听页面显示 执行多次
**onReady function 生命周期回调—监听页面初次渲染完成 只执行一次的
**onHide function 生命周期回调—监听页面隐藏 执行多次
**onUnload function 生命周期回调—监听页面卸载 只执行一次的
**onPullDownRefresh function 监听用户下拉动作
**onReachBottom function 页面上拉触底事件的处理函数
**onShareAppMessage function 用户点击右上角转发
onPageScroll function 页面滚动触发事件的处理函数
onResize function 页面尺寸改变时触发,详见 响应显示区域变化
onTabItemTap function 当前是 tab 页时,点击 tab 时触发
事件分为冒泡事件和非冒泡事件:
bindtap冒泡事件:当一个组件上的事件被触发后,该事件会向父节点传递。
catchtap非冒泡事件:当一个组件上的事件被触发后,该事件不会向父节点传递。
1.1 网页开发渲染线程和脚本线程是互斥的,这也是为什么长时间的脚本运行可能会导致页面失去响应;
二者是分开的,分别运行在不同的线程中
1.2
页开发者可以使用到各种浏览器暴露出来的 DOM API,进行 DOM 选中和操作;
小程序的逻辑层和渲染层是分开的,逻辑层运行在 JSCore 中,并没有一个完整浏览器对象,因而缺少相关的DOM API和BOM API。
1.3
网页开发者需要面对的环境是各式各样的浏览器;
而小程序开发过程中需要面对的是两大操作系统 iOS 和 Android 的微信客户端
1.4网页开发者在开发网页的时候,只需要使用到浏览器,并且搭配上一些辅助工具或者编辑器即可。
小程序的开发则有所不同,需要经过申请小程序帐号、安装小程序开发者工具、配置项目等等过程方可完成。
1.5 网页 标签 div span img…
小程序 view text image button template block
1.6
普通的网页 做不到
小程序可以使用 api调用 手机底层接口 比如:获取摄像头、获取通讯录、获取相册…
1 小程序无需安装、无需卸载,不占内存,用完即走
2 小程序的开发成本低,开发速度快
3 学习成本低 ,js,html,css 就可以开发小程序了
4 运行速度比原生的app慢
5 微信的客户群体大,推广容易
小程序直接 this.data 的属性是不可以同步到视图的,必须调用:
this.setData({
// 这里设置
})
1.使用全局变量实现数据传递
在 app.js 文件中定义全局变量 globalData, 将需要存储的信息存放在里面
2.路由传参使用 wx.navigateTo 与 wx.redirectTo 的时候,可以将部分数据放在 url 里面,并在新页面 onLoad 的时候初始化
3.使用本地缓存 Storage 相关
4.使用模块,创建独立的模块文件,输出对象,
模块的使用,可以使用 封装好的js的对象进行传参 ,比如: utils/util.js
module.exports = {
formatTime: formatTime,
ggdata:'测试utils中数据是否能跨页传递'
}
在页面中使用时,用 require引入该模块文件
例如:
const util = reqiure("../../utils/util.js");
优势
即用即走,不用安装,省流量,省安装时间,不占用桌面
依托微信流量,天生推广传播优势
开发成本比 App 低
缺点
用户留存,即用即走是优势,也存在一些问题
入口相对传统 App 要深很多
限制较多,页面大小不能超过2M。不能打开超过10个层级的页面
首先在全局 config 中的 window 配置 enablePullDownRefresh
在 Page 中定义 onPullDownRefresh 钩子函数,到达下拉刷新条件后,该钩子函数执行,发起请求方法
请求返回后,调用 wx.stopPullDownRefresh 停止下拉刷新
都是用来描述页面的结构;
都由标签、属性等构成;
标签名字不一样,且小程序标签更少,单一标签更多;
多了一些 wx:if 这样的属性以及 {{ }} 这样的表达式
WXML仅能在微信小程序开发者工具中预览,而HTML可以在浏览器内预览
组件封装不同, WXML对组件进行了重新封装,
小程序运行在JS Core内,没有DOM树和window对象,小程序中无法使用window对象和document对象。
在根目录下创建utils目录及api.js文件和apiConfig.js文件;
在appConfig.js封装基础的get\post\put\upload等请求方法,设置请求体,带上token和异常处理等,
封装了数据没获取过来时,旋转和加载中的提示,及数据返回后,返回promise对象,解决回调地狱问题;
在api.js中引入apiConfig.js封装好的请求方法,根据页面数据请求的urls,设置对应的方法并导出;
在具体页面导入;
小程序支持 ES6 语法 在返回成功的回调里面处理逻辑 Promise 异步 async/await
utils文件夹
http.js 封装 了 request
config.js 做配置
api.js 对获取后台数据的统一管理
1.使用 函数进行传参,
需要在 js文件中接收 ev的值
写法是:
saveText: function(ev){
console.log(ev.detail.value);
},
2.给按钮绑定事件,需要传递 for循环中的数据的属性,比如:id
在 js中接收数据:
delFunc:function(ev){
console.log(ev);
const id = ev.currentTarget.dataset.id;
},
小程序本质就是一个单页面应用,所有的页面渲染和事件处理,都在一个页面内进行,但又可以通过微信客户端调用原生的各种接口;
它的架构,是数据驱动的架构模式,它的UI和数据是分离的,所有的页面更新,都需要通过对数据的更改来实现;
它从技术讲和现有的前端开发差不多,采用JavaScript、WXML、WXSS三种技术进行开发;
功能可分为webview和appService两个部分;
webview用来展现UI,appService有来处理业务逻辑、数据及接口调用;
两个部分在两个进程中运行,通过系统层JSBridge实现通信,实现UI的渲染、事件的处理等。
或
微信小程序采用JavaScript、wxml、wxss三种技术进行开发,与现有前端开发的区别:
JavaScript的代码是运行在微信APP中的,因此一些h5技术的应用需要微信APP提供对应的API支持;
wxml微信自己基于xml语法开发的,因此在开发时只能使用微信提供的现有标签,html的标签是无法使用的;
wxss具有css的大部分特性,但并不是所有都支持没有详细文档(wxss的图片引入需使用外链地址,没有body,样式可直接使用import导入)。
微信的架构,是数据驱动的架构模式,它的UI和数据是分离的,所有的页面更新,都需要通过对数据的更改来实现。
小程序功能分为webview和APPservice,webview主要用来展示UI,appservice用来处理业务逻辑、数据及接口调用。它们在两个进程中进行,通过系统层JSBridge实现通信,实现UI的渲染、事件处理。
使用uni-app 可以使用 vue语法开发小程序
taro 可以使用react开发小程序
个人认为,如果是新项目,且没有旧的 h5 项目迁移,则考虑用小程序原生开发,好处是相比于第三方框架,坑少。
而如果有 老的 h5 项目是 vue 开发 或者 也有 h5 项目也需要小程序开发,则比较适合 wepy 或者 mpvue 来做迁移或者开发,近期看wepy几乎不更新了,所以推荐美团的mpvue。
而如果如果团队前端强大,自己做一套框架也没问题。
必须要在小程序后台使用管理员添加业务域名;
h5页面跳转至小程序的脚步必须是1.3.1以上;
微信分享只可以是小程序的主名称,如要自定义分享内容,需小程序版本在1.7.1以上;
h5的支付不可以是微信公众号的appid,必须是小程序的appid,而且用户的openid也必须是用户和小程序的
数据的大小限制,超过范围会直接导致整个小程序崩溃,除非重启小程序;
小程序不可以直接渲染文章内容这类型的html文本,显示需借助插件
注:插件渲染会导致页面加载变慢,建议在后台对文章内容的html进行过滤,后台直接处理批量替换p标签div标签为view标签。然后其他的标签让插件来做。
//跳转到小程序导航页面
wx.miniProgram.switchTab({
url:’/pages/index/index’
})
22.2 小程序跳转到h5
从小程序跳转到html5页面
src需要在小程序后台进行配置
22.3 小程序怎样跳转到另一个小程序:
https://www.cnblogs.com/strong514/p/12470365.html
“navigateToMiniProgramAppIdList”: [
“目标小程序的appid”
],
##23.你说你负责支付环节,那么微信支付的 流程是否可以简单说一下? *****
临时凭证 获取 wxid
生成repayid
json,返回给小程序,小程序调支付窗口。
支持成功提示 + POST回调。
a.使用wx.login获取code值
b.使用wx.request请求后台的api,把code值作为参数发送给后台
后台会根据我们传过去的code值来获取openid和session_key,后台需要调用数据库,将登录的信息进行保存,如果是第一次登录,会生成一条新的注册记录
把微信账号登录态生成一个session id并维护在我们自己的session机制中,然后把登录成功的状态返回到小程序客户端作为已经登录成功的凭证。并且返回token值。
c.把登录成功的状态的session值保存到本地,使用wx.setStorage把token保存到本地,
d.在你需要使用的地方session_id的地方调用wx.getStorage(建议你也可以封装一个方法,就可以很方便的取出你要的数据)
e.登录成功后,需要 if (res.authSetting[‘scope.userInfo’]) {
//如果返回true表示 已经授权,可以直接调用 getUserInfo 获取头像昵称,不会弹框
如果授权成功,调用 wx.getUserInfo ,获取用户信息,保存到 this.globalData中
注意:有的网站,登录成功后,还有一个手机绑定的功能,获取该微信的手机号,使用wx.request传到后台,与相应的注册账号进行绑定
25.1 支付之前的准备工作 ,微信账号是企业级的,需要认证,需要申请小程序支付,并获得小程序支付的后台账号,
并且配置好后台的对公账号,打较少的钱,测试账号是否可用
25.2 首先判断是否是已经登录状态,如果不是就跳转登录
25.3 如果已经登录完,我们根据一个用户表将id和openid联系起来,对应openID的id则是用户的uid,生成token,保存缓存
25.4 调用后台 统一下单接口,获取prepay_id,获取所有的签名信息,保存缓存中
25.5 在小程序中调用后台的 order订单接口,获取订单信息,在后台创建商品订单,在订单中会保存商品的id、名称、数量…;如果订单创建成功,将订单内容保存到缓存;
25.6 如果订单创建成功,使用 wx.request调用后台的支付接口 ‘/pay/pre_order’,进行后台的支付流程;
在 success的回调中 ,调用 wx.requestPayment ,请求小程序的支付,在请求的参数中传递 签名信息和商品信息;如果返回 success,那么表示支付成功;如果失败则提示支付失败,并跳转到 未支付页面
支付流程
小程序面试题
当后台接口开发完 ,将 模拟数据替换成真实数据时
第一种: 你的模拟数据和后台数据格式不一样,导致页面报错
需要和 后台人员沟通,看看是后台改接口还是前台改页面
第二种: 接口调用不到 ,
报301 304 400 401 403 404 405
5**(服务器端错误)
小程序更多