前端面试题大杂烩

一、HTML / CSS

简述对 Web 语义化的理解?

就是让浏览器更好的读懂你写的代码,在进行 HTML 结构、表现、行为设计时,尽量使用语义化的标签,使程序代码简介明了,易于进行 Web 操作和网站 SEO,方便团队协作的一种标准,以图实现一种“无障碍”的 Web 开发。

①去掉或者丢失样式的时候能够让页面呈现出清晰的结构;
②有利于SEO:和搜索引擎建立良好沟通,有助于爬虫抓取更多的有效信息:爬虫依赖于标签来确定上下文和各个关键字的权重;
③方便其他设备解析(如屏幕阅读器、盲人阅读器、移动设备)以意义的方式来渲染网页;
④便于团队开发和维护,语义化更具可读性,是下一步吧网页的重要动向,遵循W3C标准的团队都遵循这个标准,可以减少差异化

解决兼容问题

所谓的浏览器兼容性问题,是指因为不同的浏览器对同一段代码有不同的解析,造成页面显示效果不统一的情况。
 (Q1) 浏览器:IE,Chrome,FireFox,Safari,Opera。
 (Q2) 内核:Trident,Gecko,Presto,Webkit。

1. 浏览器兼容
   版本兼容 私有前缀  (优雅降级/ 渐进增强)

2. CSS兼容
   base文件 统一重新设置 默认字体大小等

3. JS兼容
   事件方法不同
   addEventListener
   attachEvent
// 常见的兼容性问题:

1、不同浏览器的标签默认的外边距( margin )和内边距(padding)不同
解决方案: css 里增加通配符 * { margin: 0; padding: 0; }

2、IE6双边距问题;在 IE6中设置了float , 同时又设置margin , 就会出现边距问题
解决方案:设置display:inline;

3、当标签的高度设置小于10px,在IE6、IE7中会超出自己设置的高度
解决方案:超出高度的标签设置overflow:hidden,或者设置line-height的值小于你的设置高度

4、图片默认有间距
解决方案:使用float 为img 布局

5、IE9一下浏览器不能使用opacity
解决方案:opacity: 0.5;filter: alpha(opacity = 50);filter: progid:DXImageTransform.Microsoft.Alpha(style = 0, opacity = 50);

6、边距重叠问题;当相邻两个元素都设置了margin 边距时,margin 将取最大值,舍弃最小值;
解决方案:为了不让边重叠,可以给子元素增加一个父级元素,并设置父级元素为overflow:hidden;

7、两个块级元素,父元素设置了overflow:auto;子元素设置了position:relative ;且高度大于父元素,在IE6、IE7会被隐藏而不是溢出;
解决方案:父级元素设置position:relative 
// IE8兼容问题

1. H5与C3的东西  在IE8 都不能用
	比如 H5的  canvas  webSocket  audio   video    localStorage   sessionStorage
	C3 的  圆角  阴影  transition  animation   transform    弹性布局

2. 阻止事件冒泡 
- chrome firefox 
  - e.stopPropogation()
- IE8 之前
  - e.cancelBubble = true

3. 事件名
- chrome Firefox
  - 加on  onclick
- IE8之前 
  - 是不加on的

兼容问题补充

兼容问题补充

前端如何优化网站性能

1.减少http请求次数。比如说把多张图片做成精灵图,合并css js文件(打包工具),使用图片懒加载(lazyLoad)
2.控制资源文件加载优先级。由于js文件比css加载耗费时间,可以将css代码放js代码的前面。
3.可以利用网站的缓存来减少服务器请求 缓存ajax
4.懒加载,先把页面所需的最小内容集加载出来一个极端的做法,确保网页在不需要js的情况下将页面加载出来,再延迟加载出js
    vue里路由懒加载 :  (避免流量浪费)
    改变router.js里路由的导入方式 const 路由名字 = ()=>import("路径")
    这样打包的时候就不是一个js文件,而是会多一些js文件对应不同的页面
4.减少Reflow(重排),如果需要在DOM操作时添加样式,尽量使用增加class属性,而不是通过style操作样式。
5.减少dom操作
6.网站图标尽量使用iconfont字体图标
//提高网站性能

1.资源加载
      css顶部,js底部
      css,js文件压缩,使用精灵图
      图片使用预加载,懒加载(总之就是减少资源的请求次数)
      
2.代码性能
    - css:
        减少css代码量,减少查询层级与范围
        避免类与id跟标签同名
    - html:
       	减少dom节点:加速页面渲染,减少页面重绘
    - js:
        少用全局变量
        使用委托事件,利用body来代理
        减少dom操作
        减少对象查找,尽量使用变量查找

回流与重绘

回流:当渲染树因为元素的规模尺寸,布局等改变而需要重新构建。(也就是重新布局)每个页面最少要进行一次回流,就是第一次加载。当我们通过渲染树获取节点的信息时会有回流。

重绘:当渲染树中的一些元素需要更新属性,而这些属性只影响元素的外观风格,不会影响布局,就叫重绘。(回流必引起重绘,重绘不一定会回流)

减少回流与重绘: 减少对dom树的操作。

​ 1.使用translate代替top改变。

​ 2.使用opacity代替visibility改变。

​ 3.修改dom的classname。

​ 4.将dom离线后修改。

CSS选择器有哪些,请简单说一下优先级排序

1.标签选择器(如:div   p   ul   li  )
2.ID选择器(如: # box)
3.类选择器(如: . box)
4.全局选择器(如:*号)
5.复合选择器(交集、并集、子代、后代)

排序:!important > 行内样式 > ID选择器 > 类选择器 > 标签 > 通配符 > 继承 > 浏览器默认属性

css伪元素选择器的常用场景

::first-letter:为某个元素中的文字的首字母或第一个字使用样式。
::first-line:为某个元素的第一行文字使用样式。
::before:在某个元素之前插入一些内容。
::after:在某个元素之后插入一些内容
::selection:匹配元素中被用户选中或处于高亮状态的部分。

盒子水平垂直居中

1.magin负间距
绝对定位; left和top为50%; margin-left和margin-top为负自身的一半

2.transform变形
绝对定位; left和top为50%; transform:translate(-50%,-50%)

3.利用magin的auto
绝对定位; left, top ,right,bottom 都为0; margin:auto

4.弹性布局
display:flex; justify-content和align-items都为center

清除浮动影响

1,父级 div 定义 height

原理:父级 div 手动定义 height,就解决了父级 div 无法自动获取到高度的问题。

简单、代码少、 容易掌握 ,但只适合高度固定的布局.

2,结尾处加空 div 标签 clear:both

原理:在浮动元素的后面添加一个空 div 兄弟元素,利用 css 提高的 clear:both 清除浮动,让父级

div 能自动获取到高度 ,如果页面浮动布局多,就要增加很多空 div,让人感觉很不好 .

3,父级 div 定义 overflow:hidden

超出盒子部分会被隐藏,不推荐使用.

4,单伪元素法: 父级 div 定义 伪类:after 和 zoom
.clearfix:after{ 
    content:""; 
    display:block;
    visibility:hidden; 
    height:0; 
    line-height:0; 
    clear:both;
}
.clearfix { 
    *zoom:1; // 针对低版本浏览器做兼容
} 

原理:IE8 以上和非 IE 浏览器才支持:after,原理和方法 2 有点类似,zoom(IE 转有属性)可解决

ie6,ie7 浮动问题 ,推荐使用,建议定义公共类,以减少 CSS 代码。

5, 双伪元素法:
.clearfix:before,
.clearfix:after { 
    content: ""; 
    display: block; 
    clear: both;
}
.clearfix { 
    *zoom:1;
} 

移动端的布局方式,适配的方法

禁用用户自动缩放功能:
	<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
	
1) 百分比布局(流式布局)
	 流式布局其实就是宽度用百分比,高度用固定值的布局方式,宽度通过百分比来适配不同宽度的屏幕。

2) 弹性布局 (flex)
	 这种布局方式是通过css3新增的一些辅助布局的样式属性来制作布局的方式。

3) rem布局
	 rem是一种相对长度单位,通过这个长度单位可以实现元素宽高等比例缩放,从而完成不同宽度屏幕的适配。

4) 响应式布局 (媒体查询)
	 通过样式动态查询屏幕的宽度,动态切换样式来适配不同宽度屏幕的布局方式。

一个页面从输入 URL 到页面加载显示完成,这个过程中都发生了什么?

DNS 域名解析器 (字典) 把域名转成ip地址 …

简洁版:
  浏览器根据请求的URL交给DNS域名解析,找到真实IP,向服务器发起请求;
  服务器交给后台处理完成后返回数据,浏览器接收文件(HTML、JS、CSS、图象等);
  浏览器对加载到的资源(HTML、JS、CSS等)进行语法解析,建立相应的内部数据结构(如HTML的DOM);
  载入解析到的资源文件,渲染页面,完成。
  
详细版:
1. 浏览器的地址栏输入URL并按下回车
2. 浏览器查找当前URL的DNS(域名解析器) 的缓存记录
3. DNS解析URL对应的IP地址 
      ( DNS解析会先查找本地DNS解析器缓存,如果查到就返回    
           如果没有找到 就查找本地的DNS服务器
             - 查找方式:迭代查询   
                 * 以www.baidu.com为例  
                    先从根域开始查找  .com   
                    再查找 第二级域  baidu.com   
                    再找子域 www.baidu.com 的顺序来查找ip地址 )                    
4. 根据ip地址建立TCP连接(三次握手)
   DNS域名解析之后,获取到了服务器的ip地址,在获取到IP地址的时候就开始建立一次TCP连接  
       第一次握手: 客户端发送syn(请求连接)包到服务器 并进入syn_sent状态(发送状态) 
       			  等待服务器确认
       第二次握手: 服务器收到syn包之后  确认客户端的syn包,同时给自己也发送了一个syn+ack包  
      			  服务器进入syn_recv状态(接受状态)
       第三次握手: 客户端接收服务器发送的syn包  同时向服务器发送确认ack包  
       			  发送完毕之后 客户端和服务器进入established
                 (TCP连接成功) 
5. 浏览器向服务器发送HTTP请求,服务器响应浏览器的HTTP请求
6. 浏览器解析HTML,CSS结构 , 构建DOM树和CSS树,  渲染页面,
   解析js代码
        (reflow:回流, 一般指元素的内容,结构,位置尺寸发生变化,需要重新计算和渲染树)
        (repaint:重绘,一般只指颜色,背景颜色,边框颜色等发生外观变化)
7. 关闭TCP连接(四次挥手)
    第一次挥手:浏览器发完数据后,请求FIN 断开连接
    第二次挥手:服务器发送ACK表示同意,
    第三次挥手:服务器可能还有数据要发送给浏览器 所以此时的服务器再发送一次FIN请求断开连接
    第四次挥手:浏览器确认断开连接

webSocket 的理解

  • webSocket 是一种双向通信协议
  • webSocket 是 浏览器 与服务器 一次进行连接 除非浏览器主动断开连接 否则连接一直都在
  • 优势: 极大的节省了网络带宽资源的消耗, 而且客户端发送请求,服务端响应数据是在同一个连接上发起的, 实时性优势更明显
  • 注 : 执行 webSocket 需要python 环境来支持

二、 Java Script

基本数据类型和复杂数据类型有哪些

简单数据类型:
    数值(NaN)
    字符串(string)
    布尔值(Boolean)
    undefined
    Null

复杂数据类型:
    new Object()
    new Array()
    new Function()

数组的方法

// 1.splice(); 删除数组中元素
// splice(index,number)  删除从index开始 number个元素 如果number不写 就是后面的全部删掉
var arr = ['路飞', '索隆', '乌索普', '娜美']
arr.splice(1,2) // ['路飞','娜美']
arr.splice(2,1); // ['路飞', '索隆', '娜美']
// 插入的话 就是在指定下标前插入 splice(index,number,插入的元素)
arr.splice(2, 0, '山治'); // ["路飞", "索隆", "山治", "乌索普", "娜美"]
arr.splice(2,1,'山治'); // ["路飞", "索隆", "山治", "娜美"] 
console.log(arr);

// 2.slice() 截取数组的下标并返回新的数组 slice(index,index)  左闭右开
var arr = [0, 7, 4, 1, 2, 5, 8, 9, 3];
var arr2 = arr.slice(1, 4);// [7, 4, 1]
console.log(arr2); 

// 3.concat() 数组的拼接 并返回一个新的数组
var arr1 = [1, 2, 3];
var arr2 = [7, 8, 9];
var arrnew = arr1.concat(arr2);
console.log(arrnew); // [1, 2, 3, 7, 8, 9]

// 4.join() 数组按照指定的形式来分割 并返回一个字符串
var arr = [1, 2, 3, 4, 5];
var arrnew = arr.join('-');
console.log(arrnew);  // 1-2-3-4-5

// 5.sort() 排序  从小到大排序
var arr = [0,7,4,1,2,5,8,9,6,3]
arr.sort();
console.log(arr); // [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

// 6.reverse() 数组翻转
var arr = [1,2,3];
arr.reverse();
console.log(arr); // [3,2,1]

// push() 向数组的末尾添加
// pop() 向数组的末尾删除
// unshift() 向数组的头部添加
// shift() 向数组的头部减少

readonly与disabled 的异同

相同点: 都是不能编辑文本 但是可以通过js来改变

不同点: disabled 不能获取焦点   并且不会提交表单
	   readonly 可以获取焦点   可以提交表单

字符串的方法

// 1.slice() 截取字符串 slice(index,index) 左闭右开
// 2.substring() 截取字符串 str(index,index)  左闭右开
var str = '以前我没得选,现在我想做个好人,对不起,我是警察';
var strnew = str.slice(5, 9); // 选,现在
var strnew = str.substring(5, 9); // 选,现在
console.log(strnew); 

// 3.substr() 截取字符串  str(index,numer) 返回新的字符串
var str = '123456789';
var strnew = str.substr(1, 6)
console.log(strnew); // 234567

// 4.charAt() 根据下标找字符 找不到 返回空
var str = '我于杀戮之中盛放';
var strnew = str.charAt(5) // 中
var strnew = str.charAt(15) // 
console.log(strnew);

// 5.indexOf() 根据字符找下标 如果找不到 就返回-1
var str = '让我们来猎杀那些陷入黑暗中的人吧';
var index = str.indexOf('猎杀'); // 4
var index= str.indexOf('呵呵') // -1
console.log(index);

// 6.concat() 拼接两个字符串
var strnew = str1.concat(str2)

// 7.replace();  replace(old,new) old:想要替换的元素 , new: 新的元素 
var str = '北京是首都,深圳是特区,深圳深圳深圳'
var strnew = str.replace('深圳','汕头') //但是只能换第一个
var strnew = str.replace(/深圳/g, '汕头');
console.log(strnew);

// toUpperCase()  把字符串转换成大写   返回一个新的字符串
// toLowerCase()  把字符串转换成小写   返回一个新的字符串

Bootstrap的常用组件

  • 栅格系统
    • 一行有12份
      • .col-xs 小于768屏幕 手机
      • .col-sm 大于等于768屏幕 平板
      • .col-md 大于992屏幕 中等显示屏
      • .col-lg 大于1200屏幕 大显示屏
  • 表格
    • table
      • table-hover 悬停变色
  • 按钮
    • button
      • type=“success” 绿色
      • type=“info” 青色
      • type=“primary” 蓝色
      • type=“error” 红色
      • type=“warning” 黄色

this的四种指向问题 + 箭头函数

在普通函数中 this  ==> window

在定时器中  this==>  window

在构造函数中  this ==> 实例化的对象

在事件触发中  谁触发的这个事件  this就是指向谁

箭头函数和普通函数的区别

1. 箭头函数是匿名函数,不能作为构造函数,不能使用new
2. 箭头函数不能绑定arguments,取而代之用rest参数...解决
3. 箭头函数没有原型属性(prototype) , 所以本身没有this
4. 箭头函数不会创建自己的this,this永远指向其上下文的this,没有办法改变其指向;  普通函数的this指向调用它的对象
5. 箭头函数相对普通函数的语法更加简洁优雅

cookies,sessionStorage 和 localStorage 的区别?

携带: 
	cookie数据始终在同源的http请求中携带(即使不需要),记会在浏览器和服务器间来回传递。
	sessionStorage和localStorage不会自动把数据发给服务器,仅在本地保存。

存储大小:
  	cookie数据大小不能超过4k。
  	sessionStorage和localStorage虽然也有存储大小的限制,但可以达到5M或更大。

有期时间:
  	localStorage    存储持久数据,浏览器关闭后数据不丢失除非主动删除数据;
  	sessionStorage  数据在当前浏览器窗口关闭后自动删除。
  	cookie          设置的cookie过期时间之前一直有效,即使窗口或浏览器关闭
  	
共享:
    localstorage和cookie会在所有同源窗口中共享,
    sessionstorage不在不同的浏览器共享。

localStroage只能存字符串,我们看百度的那个历史记录看起来像存了数组,其实存的是JSON字符串

JSON 的了解

JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式。
它是基于JavaScript的一个子集。
特点:数据简单、易于读写、占用带宽小
    
    
// js中对应JSON的使用 2个方法

1. JSON.parse('JSON格式的字符串') -- 这个用的 最多
    把JSON格式的字符串转化为对应的js对象(数组)
 
2. JSON.stringify(js对象或者数组) -- 了解即可
    把js对象(数组)转化为对应的JSON格式的字符串

操作DOM常用API(增删查改)

怎样添加、移除、移动、复制、创建和查找节点?

 1)创建新节点
    createDocumentFragment() //创建一个DOM片段
    createElement() //创建一个具体的元素
    createTextNode() //创建一个文本节点
    cloneNode() // 创建节点

2)修改
    appendChild() //将child追加到parent的子节点的最后面
    removeChild() // 移除子节点
    replaceChild() //替换
    insertBefore() //将某个节点插入到另外一个节点的前面

3)查找
    document.getElementsByTagName() //通过标签名称
    document.getElementsByName() //通过元素的Name属性的值
    document.getElemnetsByClassName() // 标签名
    document.getElementById() //通过元素Id,唯一性
    document.querySelector(); //传入css选择器,找到第一个匹配的元素,只返回元素
    document.querySelectorAll(); //传入css选择器,选择器能找到几个,这方法就找到几个,返回伪数组
    
4) 属性型
    元素.getAttribute(); 获取行内属性
    元素.setAttribute(); 设置行内属性
    元素.removeAttribute(); 删除行内属性


    
5) 修改元素样式
	elem.style.color = "red";

...

jQuery操作Dom

1. html
text()、html() 以及 val()

2. css
addClass() ,removeClass() , toggleClass()

3.属性
attr(),removeAttr(),prop(),removeProp()

4.事件
	原生去掉"on"

5.动画效果
hide(),show(),fadeIn(),slideDown(),

BOM 的常用对象

window  document   location   screen    history    navigator

jquery转成原生dom

 jQuery对象的本质其实就是JS中的伪数组,所以你取下标其实就取到了元素,而每个元素就是DOM对象

原生实现轮播

两链一包(原型链,作用域链,闭包)

原型链

[外链图片转存失败(img-uR5hfzk0-1568132368089)(C:\Users\enidchan\AppData\Roaming\Typora\typora-user-images\1568120528584.png)]

作用域链
通俗地讲,当声明一个函数时,局部作用域一级一级向上包起来,就是作用域链。

1.当执行函数时,总是先从函数内部找寻局部变量
2.如果内部找不到(函数的局部作用域没有),则会向创建函数的作用域(声明函数的作用域)寻找,依次向上
3.内层作用域可以访问外层作用域,反之不行
闭包的实现和原理
闭包就是能够读取其他函数内部变量的函数。由于在Javascript语言中,只有函数内部的子函数才能读取局部变量,因此可以把闭包简单理解成“定义在一个函数内部的函数”。谈函数闭包要说两点:
1.作用域链,
2.垃圾回收机制

// 1.作用域链:由本身最前端的作用域链为起点,以全局作用域为终点的一个单向通道。

// 2.垃圾回收机制:当开辟完一个作用域并且把内部的代码都执行完毕后,没有变量的引用(在内存中失去了引用),就会自动的回收清除。

?闭包产生: 
	本身是是一个特殊对象,由两部分组成,一部分是执行化上下文(一个函数也可以创建一个执行化上下文),一个是执行化上下文A中创建的函数(B), 执行B时调用了A中对象的值,就会产生闭包。(chrome调试里面scope的closure是闭包)

执行化上下文
	可以理解为一段代码的执行过程,会被保存在一个栈中,最先入栈的是全局的执行化上下文,在依次把执行的代码的上下文压入栈中。处理完一个就弹出一个。

// 闭包最大的作用:
	可以访问其他作用域内的变量;
	可以让这些变量的值始终保持在内存中,延长变量的生命周期。

闭包应用场景: 防抖 / 节流 (联想功能的节流)

优点:闭包可以形成独立的空间,永久的保存局部变量
缺点:保存中间值的状态缺点是造成内存泄漏,因为闭包中的局部变量永远不会被回收

所以少用闭包,并且记得如果这个闭包不用了就记得把闭包赋值为null

深拷贝 浅拷贝

简单解释:
     浅拷贝和深拷贝都只针对于引用数据类型.
     浅拷贝只复制指向某个对象的指针,而不复制对象本身,新旧对象还是共享同一块内存;
     但深拷贝会另外创造一个一模一样的对象,新对象跟原对象不共享内存,修改新对象不会改到原对象;
     
区别:
	浅拷贝只复制对象的第一层属性,
	深拷贝可以对对象的属性进行递归复制;

内存泄漏

1)意外的全局变量引起的内存泄露

function leak(){  

  leak="xxx"; // leak成为一个全局变量,不会被回收  

}

2)闭包引起的内存泄露

3)没有清理的DOM元素引用

4)被遗忘的定时器或者回调

5)子元素存在引起的内存泄露

事件捕获 / 事件冒泡 / 事件委托

1.事件捕获:
	当一个事件触发后,从Window对象触发,不断经过下级节点,直到目标节点。在事件到达目标节点之前的过程就是捕获阶段。所有经过的节点,都会触发对应的事件(事件捕获默认看不到)

2.事件冒泡:
	当一个元素的事件触发后,会依次一级一级往上调用父元素的同名事件,直到window,事件冒泡默认就存在(必须是在触发的元素开始往上)
	当事件到达目标节点后,会沿着捕获阶段的路线原路返回。同样,所有经过的节点,都会触发对应的事件
	
3.事件委托的优点: 
    提高性能:每一个函数都会占用内存空间,只需添加一个事件处理程序代理所有事件,所占用的内存空间更少。
    动态监听:使用事件委托可以自动绑定动态添加的元素,即新增的节点不需要主动添加也可以一样具有和其他元素一样的事件
    
阻止冒泡/捕获:
	通过e.stopPropagation()方式阻止事件的冒泡.阻止冒泡或捕获的继续执行,在需要停止的函数使用.在该函数使用时,该函数还是会执行,但是函数外之后的代码不会执行.
	IE8只有事件没有捕获,
	IE8不支持e.stopPropagation()
	IE8支持e.cancelBubble = true;

为什么会造成跨域问题?如何解决?

在浏览器中,<script>、<img>、<iframe>、<link>等标签都可以加载跨域资源,而不受同源限制,
但浏览器会限制脚本中发起的跨域请求。
何谓同源:URL由协议、域名、端口和路径组成,如果两个URL的(协议、域名和端口)相同,则表示它们同源。

解决跨域限制的方法有:
1.通过jsonp跨域
// jsonp利用src属性访问资源时可以无视同源策略这个特点,我们可以实现跨域请求
// jsonp的原理: ajax请求接受同源策略影响,不允许进行跨域请求,而script标签中的src属性的链接可以访问跨域,利用这个特性,服务器不再返回 JSON格式的数据,而是返回一段 JS代码 ,在src中进行调用,实现跨域
// jsonp缺点:只能实现get一种请求,不支持post请求。

2.CORS技术(跨域资源共享)
  CORS技术的关键点在于响应头Access-Control-Allow-Origin,表示是否接收跨域请求的标记,当我们想跨域请求时要有这个请求头才能实现,会先发送一个加单的请求,origin+url,是允许源的话就会把上述代码加入请求头
  cors会把跨域请求分成两类,一类是简单请求,一类是非简单请求
   - 简单请求有两个特点,一个请求方式是head,get,post;头部信息不超过几种字段,content-type这些
   - 非简单请求会在发送前执行一次预检的请求,来判断是否在许可名单内
  cors是默认不带cookie的需要添加一个字段
  CORS需要浏览器和服务器同时支持,目前,所有浏览器都支持该功能(IE浏览器不能低于IE10),因此,实现CORS通信的关键是服务器。只要服务器实现了CORS接口,就可以跨源通信。
// cors与jsonp作用相同但是功能更加强大,没有请求类型的限制,jsonp的兼容性更好

3. 代理服务器。 请求向本地发起,然后本地服务器向资源所在服务器请求数据。
    使用代理方式跨域更加直接,因为同源限制是浏览器实现的。
    如果请求不是从浏览器发起的,就不存在跨域问题了。
      	使用本方法跨域步骤如下:
        (1) 把访问其它域的请求替换为本域的请求
        (2)服务器端的动态脚本负责将本域的请求转发成实际的请求

css预处理器

  • sass和less的区别在变量声明: less用@ sass用$

ES6新特性

(1)变量定义(let、const)块级作用域

(2)解构赋值(一个对象的方法属性定义给另一个)
	let { message, meta } = res.data
    
(3)箭头函数(this指向)

(4)forEach循环   Set数组去重 ( ...new Set(arr) )

(5)模板字符串(嵌入变量,需要将变量名写在${}中,空格tab符同是)

(6)展开运算符 ... 

(7)Promise对象(包含resolve、reject两个属性)

 (8) 获取元素的方式 querySelector 和 querySelectorAll
 
 (9) 对象的键值相同可以使用简写语法

ES6模块化导入、导出语法

  1. Node.js中的模块化标准是CommonJS
    - 导入:require
    - 暴露:module.exports
    
    
  2. ES6的模块化语法 (vue采用这种)
    > ES6默认语法
    - 导入: import xxx from '模块'
    - 导出(暴露): export default 名字
    
    > 按名字导入导出
    - 导入: import {名字} from '模块'
    - 导出: export const 名字 = 值
    
    注意:
      导出时必须要赋值
      在按名字导出的模块里,也可以再用默认导出,用什么方式导出的就要用对应的方式导入
    
    

简述同步和异步的区别

同步是阻塞模式,异步是非阻塞模式。

同步就是指一个进程在执行某个请求的时候,若该请求需要一段时间才能返回信息,那么这个进程将会一直等待下去,直到收到返回信息才继续执行下去;
异步是指进程不需要一直等下去,而是继续执行下面的操作,不管其他进程的状态。当有消息返回时系统会通知进程进行处理,这样可以提高执行的效率。

同步:代码从上到下执行,碰到功能调用时在没有得到结果之前,该调用就不会返回或继续执行后续操作;
异步:在代码执行过程中,碰到功能调用时在没有得到结果之前,可以继续执行后续操作;功能得到结果后会通过状态,通知和回调来通知调用者;

原生ajax请求

  • 原生ajax请求步骤:

    ​ 1.创建XMLHttpRequest对象

    ​ 2.调用open方法,设置请求方式和请求路径

    ​ 3.监听响应完成事件 : onreadystatechange方法里 拿到responseText

    ​ 4.调用send方法发送请求

//1.创建XMLHttpRequest对象
var xhr = new XMLHttpRequest();

//2.调用open方法,设置请求方式和请求路径
// 如果是get请求带参数,那么要在网址后面拼接问号,再写参数名=值
xhr.open('get','https://autumnfish.cn/api/joke/list?num=3');

//3.监听响应完成事件
xhr.onreadystatechange = function() {
    if (xhr.readyState == 4 && xhr.status == 200) {
        alert(xhr.responseText)
    }
}

// 如果是post防范,则要设置请求头
// xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');

//4.调用send方法发送请求
// 如果是post请求带参数 则要写在send括号里面 'xx=abc'
xhr.send();

node是否有了解,主要内容都有哪些,请简答介绍一下

1. 概述
    Node.js是基于Chrome JavaScript运行时建立的一个平台,实际上它是对Google Chrome V8引擎进行了封装,它主要用于创建快速的、可扩展的网络应用。Node.js采用事件驱动和非阻塞I/O模型,使其变得轻量和高效,非常适合构建运行在分布式设备的数据密集型的实时应用。

    运行于浏览器的JavaScript,浏览器就是JavaScript代码的解析器,而Node.js则是服务器端JavaScript的代码解析器,存在于服务器端的JavaScript代码由Node.js来解析和运行。

    JavaScript解析器只是JavaScript代码运行的一种环境,浏览器是JavaScript运行的一种环境,浏览器为JavaScript提供了操作DOM对象和window对象等的接口。Node.js也是JavaScript运行的一种环境,Node.js为JavaScript提供了操作文件、创建HTTP服务、 创建TCP/UDP服务等的接口,所以Node.js可以完成其他后台语言(Python、PHP等)能完成的工作。

2. node.js安装
    a. 安装node.exe
    b. 根据自己电脑的版本选择对应的安装
       \1. 32安装86
       \2. 64安装64
    c. 确认是否成功
    d. 打开小黑窗(终端)
        \1. windows+r cmd 回车
        \2. 输入node -v
    e. node 是安装了 node之后可以运行的命令
    	-v 查看版本
    f. 输入npm -v
    	-v 查看版本  

3.交互式运行环境:REPL
    Node.js提供了一个交互式运行环境,通过这个环境,可以立即执行JavaScript代码块。
    我们用Visual Studio Code自带的终端或Cmder即可

4. Node.js模块和包
  a.模块
    Node.js官方提供了很多模块,这些模块分别实现了一种功能,如操作文件的模块fs,构建http服务的模块http等,每个模块都是一个JavaScript文件,当然也可以自己编写模块。
    
  b.包
    包可以将多个具有依赖关系的模块组织在一起,封装多个模块,以方便管理。Node.js采用了CommonJS规范,根据CommonJS规范规定,一个JavaScript文件就是一个模块,而包是一个文件夹,包内必须包含一个JSON文件,命名为package.json。一般情况下,包内的bin文件夹存放二进制文件,包内的lib文件夹存放JavaScript文件,包内的doc文件夹存放文档,包内的test文件夹存放单元测试。package.json文件中需要包含的字段及包的使用

常见的HTTP状态码

2开头 (请求成功)表示成功处理了请求的状态代码。

200 (成功) 服务器已成功处理了请求。 通常,这表示服务器提供了请求的网页。
201 (已创建) 请求成功并且服务器创建了新的资源。
202 (已接受) 服务器已接受请求,但尚未处理。
203 (非授权信息) 服务器已成功处理了请求,但返回的信息可能来自另一来源。
204 (无内容) 服务器成功处理了请求,但没有返回任何内容。
205 (重置内容) 服务器成功处理了请求,但没有返回任何内容。
206 (部分内容) 服务器成功处理了部分 GET 请求。

3开头 (请求被重定向)表示要完成请求,需要进一步操作。 通常,这些状态代码用来重定向。

300 (多种选择) 针对请求,服务器可执行多种操作。 服务器可根据请求者 (user agent) 选择一项操作,或提供操作列表供请求者选择。
301 (永久移动) 请求的网页已永久移动到新位置。 服务器返回此响应(对 GET 或 HEAD 请求的响应)时,会自动将请求者转到新位置。
302 (临时移动) 服务器目前从不同位置的网页响应请求,但请求者应继续使用原有位置来进行以后的请求。
303 (查看其他位置) 请求者应当对不同的位置使用单独的 GET 请求来检索响应时,服务器返回此代码。
304 (未修改) 自从上次请求后,请求的网页未修改过。 服务器返回此响应时,不会返回网页内容。
305 (使用代理) 请求者只能使用代理访问请求的网页。 如果服务器返回此响应,还表示请求者应使用代理。
307 (临时重定向) 服务器目前从不同位置的网页响应请求,但请求者应继续使用原有位置来进行以后的请求。

4开头 (请求错误)这些状态代码表示请求可能出错,妨碍了服务器的处理。

400 (错误请求) 服务器不理解请求的语法。
401 (未授权) 请求要求身份验证。 对于需要登录的网页,服务器可能返回此响应。
403 (禁止) 服务器拒绝请求。
404 (未找到) 服务器找不到请求的网页。
405 (方法禁用) 禁用请求中指定的方法。
406 (不接受) 无法使用请求的内容特性响应请求的网页。
407 (需要代理授权) 此状态代码与 401(未授权)类似,但指定请求者应当授权使用代理。
408 (请求超时) 服务器等候请求时发生超时。
409 (冲突) 服务器在完成请求时发生冲突。 服务器必须在响应中包含有关冲突的信息。
410 (已删除) 如果请求的资源已永久删除,服务器就会返回此响应。
411 (需要有效长度) 服务器不接受不含有效内容长度标头字段的请求。
412 (未满足前提条件) 服务器未满足请求者在请求中设置的其中一个前提条件。
413 (请求实体过大) 服务器无法处理请求,因为请求实体过大,超出服务器的处理能力。
414 (请求的 URI 过长) 请求的 URI(通常为网址)过长,服务器无法处理。
415 (不支持的媒体类型) 请求的格式不受请求页面的支持。
416 (请求范围不符合要求) 如果页面无法提供请求的范围,则服务器会返回此状态代码。
417 (未满足期望值) 服务器未满足"期望"请求标头字段的要求。

5开头(服务器错误)这些状态代码表示服务器在尝试处理请求时发生内部错误。 这些错误可能是服务器本身的错误,而不是请求出错。

500 (服务器内部错误) 服务器遇到错误,无法完成请求。
501 (尚未实施) 服务器不具备完成请求的功能。 例如,服务器无法识别请求方法时可能会返回此代码。
502 (错误网关) 服务器作为网关或代理,从上游服务器收到无效响应。
503 (服务不可用) 服务器目前无法使用(由于超载或停机维护)。 通常,这只是暂时状态。
504 (网关超时) 服务器作为网关或代理,但是没有及时从上游服务器收到请求。
505 (HTTP 版本不受支持) 服务器不支持请求中所用的 HTTP 协议版本。

三、Vue

vue-cli中如何使用自定义组件? 遇到的问题?

第一步:在 components 目录新建你的组件文件(smithButton.vue),script 一定要 export default 
第二步:在需要用的页面(组件)中导入:import smithButton from '../components/smithButton.vue'
第三步:注入到 vue 的子组件的 components 属性上面,components: {smithButton} 
第四步:在 template 视图 view 中使用,<smith-button> </smith-button> 

遇到的问题有:smithButton 命名,使用的时候则 smith-button。(标签名要小写)

vue-cli 2.0 和3.0区别

vue-cli搭建的时候 借助了node
// vue-cli 3.0
- default ( babel  ,   eslint )
- babel  是 把  ES6  ==>  ES5  
- elint    是语法规范
- Manually  select  features   用户手动配置
- 创建项目的方法 : vue create  项目名
- 可以默认设置  
- 项目运行的方法: npm run serve

// 2.0 vue-cli
- 创建项目的方法: vue init webpack 项目名
- 每一步都要自己手动设置
- 运行项目的方法 : npm run dev 

- 安装完vue-cli后 运行vue serve命令可以直接打开app.vue文件进行预览

axios

饿了么ui使用过的组件

echarts的使用

<!-- 为ECharts准备一个具备大小(宽高)的Dom -->
<div id="main" style="width: 800px;height:400px;"></div>
<script type="text/javascript">
// 基于准备好的dom,初始化echarts实例
var myChart = echarts.init(document.getElementById('main'));

// 指定图表的配置项和数据

vue的虚拟DOM

vue的处理 :

​ 改数据 vue是先改虚拟DOM( 只是改了数组和对象 ) 等一段同步代码都完成了 ( 可能已经改了很多DOM数据 ) 再一次性根据 虚拟DOM 修改的 地方 去更新真实DOM 对应的 界面

Vue的生命周期

vue实例从创建到销毁的过程   创建vue实例  ==>  初始化数据 ==>  形成虚拟DOM  ==>  挂载DOM  ==>渲染,更新  ==>  销毁 

1. beforeCreate : Vue实例(或组件)创建并初始化调用,但data还未挂载
2. created : data已挂载 ------------------(最早能访问到data数据) 
3. beforeMount: DOM渲染前调用,访问不到DOM元素(虚拟dom)
4. mounted: DOM渲染完毕后调用-------------------(最早访问到DOM元素) 
5. beforeUpdate: 数据改变但DOM还没变化之前调用(旧数据)
6. updated: 数据改变并且DOM已经变化了调用(在这里可以设置滚动条滚动到最后)
7. beforeDestroy: 组件销毁之前调用
8. destroyed: 组件销毁完成时调用 

请求拦截和响应拦截

// 1. 请求拦截
http.interceptors.request.use(function (config) {
    // 发送请求前调用(发送请求做一些事)
    // 把你所有的请求拦下来
    // 拦下来给你加一个请求头,请求头的内容是token
    config.headers.Authorization = window.localStorage.getItem('token')
    return config;
}, function (error) {
    //发生错误的回调函数
    return Promise.reject(error);
});


// 2. 响应拦截
http.interceptors.response.use(function (config) {
    // 如果有值就返回了,因为有值代表它调用过一次了
    if(flag){
        return config;
    }
    // config就是响应返回的所有数据
    // window.console.log(config);
    if (config.data.meta.status == 400 && config.data.meta.msg == "无效token") {
        Vue.prototype.$message.error('请先登录!');
        //打回登录页
        router.push('/login')
    }
    return config;
}, function (error) {
    //发生错误的回调函数
    return Promise.reject(error);
});

导航守卫

// 全局导航守卫
router.beforeEach((to, from, next) => {
    // 如果你有这个标签,就代表你要做登录验证
    if (to.meta.needLogin) {
        //判断是否有登录,就是判断有没有token,有代表登录,没有代表没登录
        //还是要经过服务器,让服务器告诉我这是不是有效token
        menus().then(res => {
            if (res.data.meta.status == 400 && res.data.meta.msg == '无效token') {
                //没值
                //提示请先登录
                Vue.prototype.$message.error('请先登录!')
                // 打回登录页
                router.push('/login')
            } else {
                //有值代表登录,那么就放行
                next()
            }
        })
    } else {
        // 访问其他页
        next();
    }
})

Git相关指令

git命令(举例说明)
    (1)创建和使用 git ssh key                (5)git push/pull
    (2)配置git config                       (6)git commit
    (3)变更git remote set                   (7)git add/remove
    (4)查看git show                         (8)git log(日志)/branch(分支)


webpack命令(举例说明)
    (1)安装:npm install webpack -g
    (2)下载插件:npm install webpack --save-dev
    (3)自动监控:webpack  --watch
    (4)打包隐藏:webpack --display
    (5)安装loader:npm install  {whatever}-loader --save-dev

vue组件之间的传值

  1. 父传子 / props
(1) 父传: 自定义属性传递给子组件  <son :abc="msg"></son>
(2) 子接: 通过 props 属性来进行接收  props: ['abc']

  1. 子传父 / $emit
(1) 子传: 子组件通过自定义事件 $emit 将参数交给父组件
	methods: {
        toFather() {
        this.$emit('sendval', this.msg)
        }
    }
(2) 父接: 在父组件中组实现子组件的自定义事件,并设置对应的函数
	methods: {
        getVal(value) {
        this.msg = value
        }
    }
  1. 兄弟组件传值 / eventbus
-- 先在js文件里: var bus = new Vue()

(1) 组件1: 自定义事件 bus.$emit 传给组件2 
	methods: {
        toSon2() {
        bus.$emit('fn', this.msg)
        }
    }
(2) 组件2: 在mounted用 bus.$on的回调函数来接收
	 mounted() {
         bus.$on('fn', value => {
         this.msg = value
         })
     }
  1. Vuex 适用于 父子、隔代、兄弟组件通信

路由的传值

声明式 : router-link
父路由组件上使用router-link进行路由导航,传参用<router-link to="/one/login/001">
子路由通过 this.$route.params.num 的形式来获取父路由向子路由传递过来的参数

编程式导航: $router.push

方案一: 直接携带参数

getDescribe(id) {
    this.$router.push({
     path: `/describe/${id}`,
    })
 
// 方案一,需要对应路由配置如下:
  {
   path: '/describe/:id',
   name: 'Describe',
   component: Describe
  }
// 很显然,需要在path中添加/:id来对应 $router.push 中path携带的参数。
 
// 在子组件中可以使用来获取传递的参数值。
$route.params.id

方案二: 通过路由属性中的name来确定匹配的路由,通过params来传递参数

// 父组件中:通过路由属性中的name来确定匹配的路由,通过params来传递参数。
this.$router.push({
    name: 'Describe',
    params: {
   	 	id: id
    }
})
 
// 对应路由配置: 注意这里不能使用:/id来传递参数了,因为父组件中,已经使用params来携带参数了。
  {
   path: '/describe',
   name: 'Describe',
   component: Describe
  }
 
//子组件中: 这样来获取参数
$route.params.id

方案三: 使用path来匹配路由,然后通过query来传递参数

// 父组件:使用path来匹配路由,然后通过query来传递参数
这种情况下 query传递的参数会显示在url后面?id=xxx
  this.$router.push({
     path: '/describe',
     query: {
      id: id
     }
  })
 
// 对应路由配置:
  {
   path: '/describe',
   name: 'Describe',
   component: Describe
  }
 
// 对应子组件: 这样来获取参数
$route.query.id

vue-router的原理

// vue-router
1. 是什么
VueRouter 是vue.js官方的路由管理器

2. 有什么用
vue-router 可以使页面无刷新跳转

3. 怎么用
下包    npm i vue-router
导包    import VurRouter from ('vue-router')
用包    Vue.use(VueRouter)

1) 创造路由规则
const route = [   {  path:'路径',   conponent:' 导入的组件 '}]

2) 创建路由对象
const router=new  VueRouter ={
	route
}

3) 挂载实例

vue-router默认 hash 模式 —— 
	使用 URL 的 hash 来模拟一个完整的 URL,于是当 URL 改变时,页面不会重新加载。

vuex的使用

Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。每一个 Vuex 应用的核心就是 store(仓库)。“store” 基本上就是一个容器,它包含着你的应用中大部分的状态 ( state )。

(1)Vuex 的状态存储是响应式的。当 Vue 组件从 store 中读取状态的时候,若 store 中的状态发生变化,那么相应的组件也会相应地得到高效更新。
(2)改变 store 中的状态的唯一途径就是显式地提交 (commit) mutation。这样使得我们可以方便地跟踪每一个状态的变化。

主要包括以下几个模块:
state    - data . 定义了应用状态的数据结构,可以在这里设置默认的初始状态。
getter   - 允许组件从Store中获取数据,mapGetters辅助函数仅仅是将store中的getter映射到局部计算属性。
mutation - 是唯一更改 store 中状态的方法,且必须是同步函数。
action   - 用于提交 mutation,而不是直接变更状态,可以包含任意异步操作。
module   - 允许将单一的 Store 拆分为多个 store 且同时保存在单一的状态树中

Promise的原理

  • promise的核心原理其实就是发布订阅模式,通过两个队列来缓存成功的回调(onResolve)和失败的回调(onReject)
// Promise的基本使用

// 1.创建对象
const p = new Promise( (resolve,reject) => {
    // 逻辑代码
    if(){
       resolve(data)
	}else{
        reject(err)
	}
})

// 2.调用方法
p.then(res=>{
    console.log(res)
}).catch(err=>{
    console.log(err)
})
所谓Promise,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。从语法上说,Promise 是一个对象,从它可以获取异步操作的消息。Promise 提供统一的 API,各种异步操作都可以用同样的方法进行处理。

有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败)。

Promise的缺点:  
  首先,无法取消Promise,一旦新建它就会立即执行,无法中途取消。
  其次,如果不设置回调函数,Promise内部抛出的错误,不会反应到外部。
  第三,当处于pending状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。

async 和 await 的本质

async和await的本质是 语法糖

async 是写在函数前面的  目的是告诉调用者  里面函数的代码 可能包含异步代码

await 是写在异步代码前面的   有返回值 

作用是  让异步代码  同步书写

MVC 设计模式

M 是model  数据层   
V 是view   视图层   
C 是controller   控制层

用户将view的操作交给controller处理, 在controller 中 响应view的事件调用model的接口进行操作
所以  以前程序员把大量的事件都用在了controller上

MVVM的了解

  • 数据驱动视图
?? 什么是数据驱动视图
数据驱动是vuejs最大的特点。在vuejs中,所谓的数据驱动就是当数据发生变化的时候,用户界面发生相应的变化,开发者不需要手动的去修改dom。

  • MVVM (解释对MVVM的理解, 面试可答)
Vuejs的数据驱动是通过MVVM这种框架来实现的。MVVM框架主要包含3个部分:model、view和 viewmodel。

Model:指的是数据部分,对应到前端就是javascript对象
View:指的是视图部分,对应前端就是dom
Viewmodel:就是连接视图与数据的中间件

数据(Model)和视图(View)是不能直接通讯的,而是需要通过ViewModel来实现双方的通讯。
- 当数据变化的时候,viewModel能够监听到这种变化,并及时的通知view做出修改。
- 同样的,当页面有事件触发时,viewMOdel也能够监听到事件,并通知model进行响应。
Viewmodel就相当于一个观察者,监控着双方的动作,并及时通知对方进行相应的操作。

  • 双向绑定
MVC与MVVM框架的理解?二者区别是什么?

(1)从字面定义来说,
    MVC: model-view-controller     单向绑定
    MVVM:model-view-viewmodel      双向绑定

(2)从原理上来说,
    MVC:SSH、ASP.net

    用户操作—>View(负责接收用户输入操作)—>controller(业务逻辑层)—>Model(数据持久化)—>View(结果反馈给用户)

    MVVM:.NET的WPF、Vue
    View与Model无任何联系,view与Viewmodel、viewmodel与model是双向改变的
     
(3)从优点触发,
   MVC:比较直观的后台框架,易于维护,减少耦合度,易于管理
   MVVM:低耦合(view可独立model变化/更改,viewmodel可绑定到多个view中,view与model可以双向绑定)

   可重用性(将视图逻辑放于viewModel中,view可重用viewModel实例)
   独立开发(开发人员——viewModel业务逻辑+数据,设计人员——view界面)   
   可测试性(针对viewModel对view界面进行测试)

双向绑定原理:

Vue采用数据劫持&发布-订阅模式的方式,通过ES5提供的Object.defineProperty()方法来劫持(监控)各属性的getter、setter,并在数据(对象)发生变动时通知订阅者,触发相应的监听回调。

  1. vue2.0
    // 给对象添加属性的方法 (绑定的是obj的'name'属性)
    Object.defineProperty(obj,"name",{
        get(){ 
        	return _name
        },
        set(value){ 
        	_name = value 
        }
    })
    // set方法里可以监听到传过来的值 并在这个防范里赋值给另外
    
  2. vue3.0

    proxy 可以监听对象里的所有属性,还可以多向绑定,而defineProperty只能是绑定的属性

  3. v-model的原理

    子组件向父组件传值 , v-on和v-bind 的结合

模块化

​ 模块化开发: 单独抽取文件,实现单一功能

模块化、组件化区别?

(1)模块化:关注功能和数据的封装,根据项目业务内容划分大模块;
(2)组件化:关注UI部分的设计,根据小功能通用性和可复用性抽象组件

 区别:一个模块(抽象)包含多个组件(具体),组件是模块的子集。

Webpack的了解: (前端工程化)

// webpack是javascript应用程序中的静态模块资源打包器

  • vue-cli打包:

    脚手架是基于webpack , 所以用 npm run build指令便可以打包

  • webpack 默认:

    是基于node的打包工具, 默认打包js文件, 实现js的模块化, 使用npx webpack指令;

  • webpack进行配置 :

    npx webpack  --config webpack.config.js
    
    
    配置 : 出口 入口 模式

    ​ entry

    ​ output

    ​ mode: 生产模式(代码体积小,压缩文件) / 开发模式(过程清晰,不压缩文件)

    loader : 打包其他资源

    ​ 打包css/less/sass/图片/vue

    ​ es6转es5

    插件 : 用来提供额外功能

    ​ 以某个静态文件为模板来生成一个html文件

    ​ 开启一个服务器

    注意:
    • 如果要想实现像脚手架一样的自动刷新, 需要安装webpack-dev-server

---- Vue遇到的坑点 / 问题 ----

关于深度侦听:
  • 我之前写vue项目的时候用了侦听器,为了侦听一个对象的改变,我用了深度侦听
  • 但是我又想比较两次数据的异同,结果发现侦听器两个传递过来的参数居然一毛一样
  • 当时百思不得其解,然后因为项目赶,想了想我就没用深度侦听,而是直接改成普通侦听,具体侦听对象里的哪个属性,这样的话就能比较异同了
  • 后面项目做完了,我想起这个问题,去查了一些资料,才发现原来因为我侦听的是对象,而我改的只是属性值,那么侦听对象,对象的两次值没变(就是它的地址没变),仅仅变得只是属性值,所以才会新值和旧值一样,就此后觉得自己对于基础的细节掌握的不够深和细致,所以后面又多去看博客和书籍来补充了一下这方面的知识,比如说我就看了一本书叫《你不知道的JavaScript》里面好多细节,补充了我这方面的知识盲点
$nextTick
  • 数据修改之后直接取数据, 可能不会立即更新 , 所以并没有取到更新后的数据

  • 解决 : 用$nextTick , 它是DOM下一次更新后调用的

    其实相当于就是延迟执行(setTimeout),只不过执行时机是下一次DOM更新

---- 小程序坑点 / 问题 -----

坑点问题:
小程序的分享按钮必须要button但是会影响原来的布局和样式?
解决: 
	把button做定位, 覆盖, 然后透明度设置为0 

坑点:
后端获取到的数据 含有标签, 解析不出来?
解决:
	查完资料发现要用v-html解析

bug :
页面上拉加载更多时 : 加载完毕后 再往下拉 页面依旧+1  无限次发送请求 ? 
解决: 
	做判断: 当商品数量等于商品总数时,说明加载完成,就无须再发送请求了

但是注意! total 初始值要改为 -1, 否则 刚打开页面 goodlist的长度为0, 与total相等,会使页面无法显示

滚动条持续滚动导致发请求次数很多 --> 优化?

解决: js防抖

购物车页面删除商品:
商品列表是一个对象, 数量点击为0时,删除一条商品, 也就是删除对象中的属性,但是删除后页面没有动态更新?  
原本我是想调用方法,重新赋值 ,但是同事告诉我: 
	用解构赋值的方法:  this.goodsList = {...this.goodsList}, 就不用重新调用方法了

加入购物车 (详情页面)- 重复添加到storage ?

解决: 去重. 首先要将原本的数组改成对象

 addCart() {
      if (this.goodsList[this.detailObj.goods_id]) {
        // 如果存在,直接给它的 num 属性加 1
        this.goodsList[this.detailObj.goods_id].num++
      } else {
        // 如果不存在,给对象添加一个属性num,并且将对象添加到 goodsList 中
        this.detailObj.num = 1
        this.goodsList[this.detailObj.goods_id] = this.detailObj;
      }
      // 保存到 storage 中
      wx.setStorageSync('cart', this.goodsList)
 }
mpvue坑点:

mpvue的特点: 一进来页面就会把所有的created的函数都执行一遍

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值