理论系列
-
script 引入方式
html 静态 <script> 引入
js 动态插入 <script>
<script defer>
: 异步加载,和元素解析一起进行,但是等元素解析完成后才执行。如果有多个defer脚本,则按照它们在文档中出现的顺序依次执行。<script async>
: 异步加载,和元素解析一起进行,在当前js解析完成后立即执行,可能执行时会阻塞元素渲染。如果有多个async脚本,则它们的执行顺序是不确定的。
-
webpack和gulp的区别
- gulp 致力于自动化和优化你的工作流,侧重于整体过程的控制管理。通过定义许多task来执行构建任务,使用起来更像是任务流。因此他的任务定义和管理是webpack所没有的。
- 特点:
- 任务定义和管理
- 基于文件 stream 的构建
- 特点:
- webpack 有人也称之为 模块打包机 ,由此也可以看出webpack更侧重于模块打包。
我们可以把开发中的所有资源(js文件、css文件、图片、字体等)都可以看成模块。
最初webpack本身就是为前端JS代码打包而设计的,后来被扩展到其他资源的打包处理。webpack是通过loader(加载器)
和plugins(插件)
对资源进行处理的。- 特点:
- 按照模块的依赖来构建文件
- 通过loader来支持不同模块
- 特点:
- gulp 致力于自动化和优化你的工作流,侧重于整体过程的控制管理。通过定义许多task来执行构建任务,使用起来更像是任务流。因此他的任务定义和管理是webpack所没有的。
-
使用javascript创建一个函数test1。此函数接受一个参数seconds,调用此函数可实现等待指定秒数。请注意,请使用setInterval
function test1(seconds) { let timer = null; return new Promise(resolve => { timer = setInterval(() => { console.log('123'); resolve(clearInterval(timer)); }, seconds) }) }
-
请使用setTimeout实现一个函数test2。 此函数接受三个参数: callback, seconds, n。 该函数被调用后,会每隔设定的秒数调用callback函数n次
function test2(callback, seconds, n) { let executor = (callback, seconds) => { setTimeout(() => { for (let index = 0; index < n.length; index++) { callback(); } executor(callback, seconds); }, time) } executor(callback, seconds); }
-
有一个用元祖记录着多个点坐标的二维数组,例如[[30,30],[20,30],[30,9],[10,10]],请用js将这四个点按从左往右,从上到下排序,输出[[10,10],[20,30],[30,9],[30,30]]
// 使用sort方法对点进行排序 points.sort(function(a, b) { // 首先按第一个元素(x坐标)排序 if (a[0] < b[0]) { return -1; } if (a[0] > b[0]) { return 1; } // 如果第一个元素相同,则按第二个元素(y坐标)排序 if (a[1] < b[1]) { return -1; } if (a[1] > b[1]) { return 1; } // 如果两个元素都相同,则返回0 return 0; });
-
请编写一个函数test3。 该函数接受一个参数data。 data为一个仅包含字符串的数组。 这个数组中每个元素都不可以包含“, ”。如果有“, ”,需要将对应的元素分割。 例如,
// 运行test3(["id1,", "id2,id3", "id4"]) 后, 输入数组变为["id1", "id2", "id3", "id4"] // 运行test3(["id1,", "id2,id3", "id4,id5,id6"]) 后, 输入数组变为["id1", "id2", "id3", "id4", "id5", "id6"] function test3(data) { // 创建新数据 // return data = data.toString().split(",").filter(e => !!e); // 修改原始数据 data.forEach((element,index) => { let reg = /\w+/g let matchs = element.match(reg); console.log('matchs :>> ', matchs); if (matchs) { if (matchs.length == 1) data.splice(index, 1, matchs[0]) else matchs.map((e,i) => { if (1 == 0) data.splice(index, 1, e) else data.splice(index+i, 0, e) }) } }); }
-
数组与树形数据互相转化
//列表到树的转化 function arrayToTree(items) { const result = []; const lookup = {}; // 遍历数组,将每个项目的id作为key存入lookup对象中 for (let item of items) { // 如果当前项目未存在于lookup对象中,则创建一个新数组 if (!lookup[item.id]) { lookup[item.id] = { children: [], // 将当前项目放入lookup对象中对应的数组中 ...item }; } } for (let item of items) { // 如果当前项目的parentId存在于lookup对象中,则将当前项目添加到其children数组中 if (lookup[item.parentId]) { lookup[item.parentId].children.push(lookup[item.id]); } else { // 当前项没有父节点 -> 顶层 result.push(lookup[item.id]); } } return result; } function arrayToTree(data) { const res = []; data.forEach((item) => { const parent = data.find((node) => node.id === item.parentId); if (parent) { parent.children = parent.children || []; parent.children.push(item); } else { // * 根节点 res.push(item); } }); return res; } //树转换成为列表 function treeToArray(tree) { let arr = []; function traverse(node) { arr.push(node); if (node.children && node.children.length > 0) { node.children.forEach(traverse); } } traverse(tree); return arr; } function treeToList(tree) { const { children } = this.config; const result = [...tree]; for (let i = 0; i < result.length; i++) { if (!result[i][children]) {continue;} result.splice(i + 1, 0, ...result[i][children]); } return result; }
-
DOM 元素e的 e.getAttribute(propName)和 e.propName 有什么区别和联系
-
e.getAttribute:获取的是标签上属性,可以通过e.setAttribute(propName, propValue)设置标签上属性
-
e.propName:获取的是元素对象上属性
-
-
设置小于浏览器最小字体的实现
{ font-size: 20px; transform: scale(0.5); //缩放 }
-
正则中使用变量
let name = 'John Doe'; let regex = /Hello, ${name}!/; console.log(regex.test('Hello, John Doe!')); // 输出: true
-
H5自定义属性data-*?
const root = document.getElementById("root"); console.log(root.dataset); // DOMStringMap {weather: "阳光明媚"} root.dataset.rain = '大暴雨'; // 添加属性 console.log(root.dataset); // DOMStringMap {weather: "阳光明媚", rain: "大暴雨"} delete root.dataset.rain; // 删除操作 console.log(root.dataset); // DOMStringMap {weather: "阳光明媚"} console.log(root); // <div id="root" data-weather="阳光明媚"> 多云转晴 </div> root.dataset.cloudy = '大雨转阴'; // 添加属性 // 循环获取所有属性及属性值 let dataset = {}; for (let i = 0; i < root.attributes.length; i++) { let name = root.attributes[i].name; if (name.substring(0, 5) == 'data-') { dataset[name.substring(5)] = root.attributes[i].value; }; }; console.log(root.dataset, dataset); // DOMStringMap {weather: "阳光明媚", cloudy: "大雨转阴"} {weather: "阳光明媚", cloudy: "大雨转阴"} console.log(root.getAttribute('data-cloudy')); // 大雨转阴 root.setAttribute('data-cloudy', '阴转小雨'); console.log(root.dataset); // DOMStringMap {cloudy: "阴转小雨",weather: "阳光明媚"}
-
attribute 和 property 的区别是什么?
-
attribute 是 dom 元素在文档中作为 html 标签拥有的属性
-
property 就是 dom 元素在 js 中作为对象拥有的属性
-
对于 html 的标准属性来说,attribute 和 property 是同步的,是会自动更新的,但是对于自定义的属性来说,他们是不同步的
-
-
http状态码
switch (error.response.status) { case 301: error.message = '永久移动(301)'//今后任何新的请求都应使用新的URI代替 break; case 302: error.message = '临时移动(302)'//资源只是临时被移动。客户端继续使用原有URI break; case 303: error.message = '请求错误(303)'//表示必须临时重定向,查看其它地址。与301类似。使用GET和POST请求查看 break; case 304: error.message = '未修改(304)'//所请求的资源未修改,服务器返回此状态码时,不会返回任何资源。客户端通常会缓存访问过的资源,这样可以减少网络开销 break; case 400: error.message = '请求错误(400)'//请求方式错误,比如get使用了post break; case 401: error.message = '未授权,请重新登录(401)';//验证码错误/账号密码错误/没有携带Token break; case 403: error.message = '拒绝访问(403)';//表示没有权限,服务器拒绝访问请求 break; case 404: error.message = `请求地址错误: ${error.response.config.url}`; break; case 405: error.message = '请求方法未允许(405)'; break; case 408: error.message = '请求超时(408)'; break; case 500: error.message = '服务端内部错误(500)'; break; case 501: error.message = '服务未实现(501)'; break; case 502: error.message = '网络错误(502)';//作为网关或者代理工作的服务器尝试执行请求时,从远程服务器接收到了一个无效的响应。一般是架构网关层问题 break; case 503: error.message = '服务不可用(503)';//表示服务器繁忙,或者服务器负载,通常这只是一个临时状态 break; case 504: error.message = '网络超时(504)'; break; case 505: error.message = 'HTTP版本不受支持(505)'; break; default: error.message = `连接错误: ${error.message}`; }
-
new关键字
new 是一个关键字,用于创建对象和构造函数。在内存中创建一个新的空对象,让this指向创建出来的空对象,执行构造函数里面的代码,给这个空的对象添加属性和方法,返回这个新对象(所以构造函数里面不需要return)function myNew(constructor, ...args) { const obj = Object.create(constructor.prototype); const result = constructor.apply(obj, args); if (typeof result === 'object' && result !== null) { return result; } else { return obj; } }
-
HTML标签a和link的区别
<a>
标签是用来创建超链接的,而<link>
标签则是用来链接外部资源的。 -
什么是标识符?
- 在JS中,可以自定义命名的东西都是属性标识符
- 比如变量名,函数名,参数名都是标识符
-
数组扁平化
var arr = [1, [2, [3, 4, 5]]]; function flatten(arr) { return arr.flat(infinit) } function flatten(arr) { arr = arr.toString().split(','); var newArr = arr.map((item) => { item = +item return item }) return newArr } function flatten(arr) { while (arr.some(item => Array.isArray(item))) { arr = [].concat(...arr); } return arr; } function flatten(arr) { return arr.reduce(function(prev, next){ return prev.concat(Array.isArray(next) ? flatten(next) : next) }, []) }
-
函数接受一个字符串参数,返回该字符串中出现次数最多的字符。
maxBlock(str) { if (!str) return; let map = {}; for (var i = 0; i < str.length; i++) { if (map[str[i]]) { map[str[i]] += 1; } else { map[str[i]] = 1; } } return Object.values(map).sort((a, b) => b - a)[0]; },
-
数组排序
//选择排序 //基本思想:首先在未排序数组中找到最小(大)元素,存放在数组的起始位置。 //再从剩余数组元素中继续寻找最小(大)元素,返回放在已排序数组的末尾 //重复第二步,直到所有元素都排序完成 var arr = [123,203,23,13,34,65,65,45,89,13,1]; for(var i=0;i<arr.length;i++){ for(var j=i+1;j<arr.length;j++){ //如果第一个比第二个大,就交换他们两个位置 if(arr[i]>arr[j]){ var temp = arr[i]; arr[i] = arr[j]; arr[j] = temp; } } } //冒泡排序 //基本思想:一次比较两个相邻的数,如果不符合规则互换位置 //一次比较就能够将最大或最小的值放在数组最后一位 for(var i=0; i<arr.length-1; i++){ //每一轮比较要比多少次 for(var j=0; j<arr.length-1-i; j++){ //如果第一个比第二个大,就交换他们两个位置 if(arr[j]>arr[j+1]){ var temp = arr[j]; arr[j] = arr[j+1]; arr[j+1] = temp; } } } //快速排序(依托递归函数) //基本思想:在已知数据集合中随便去一个基准(pivot) //将其余数据以基准为中心,大于分放右边,小于的放左边 //将左右两个子集重复以上两个步骤 function quickSort(tempArr){ //递归终止条件 if(tempArr.length<=1){ return tempArr; }; //取基准 一般取第一个或者最后一个 var pivotIndex = Math.floor(tempArr.length/2); var pivot = tempArr.splice(pivotIndex,1); //分左右 var leftArr = []; var rightArr = []; for(var i=0;i<tempArr.length;i++){ if(tempArr[i]>pivot){ rightArr.push(tempArr[i]); }else{ leftArr.push(tempArr[i]); }; }; return quickSort(leftArr).concat(pivot,quickSort(rightArr)); };
-
防抖:任务频繁触发的情况下,重新计时,只有任务触发的间隔超过指定间隔的时候,任务才会执行。
function debounce(fn) { // 1、创建一个标记用来存放定时器的返回值 let timeout = null; return function() { // 2、每次当用户点击/输入的时候,把前一个定时器清除 clearTimeout(timeout); // 3、然后创建一个新的 setTimeout, // 这样就能保证点击按钮后的 interval 间隔内 // 如果用户还点击了的话,就不会执行 fn 函数 timeout = setTimeout(() => { fn.call(this, arguments); }, 1000); }; }
-
节流:指定时间间隔内只会执行一次任务
function throttle(fn) { // 1、通过闭包保存一个标记 let canRun = true; return function() { // 2、在函数开头判断标志是否为 true,不为 true 则中断函数 if(!canRun) return; // 6、将 canRun 设置为 false,防止执行之前再被执行 canRun = false; // 3、定时器 setTimeout(() => { fn.call(this, arguments); // 4、执行完事件(比如调用完接口)之后,重新将这个标志设置为 true canRun = true; }, 1000); };
-
对象深拷
浅拷贝:只是拷贝一层,更深层次对象级别的只拷贝了地址
深拷贝:层层拷贝,每一级别的数据都会拷贝
这篇文章有详细的说明:javaScript实现浅拷贝和深拷贝的方法有哪些?看这一篇就够了(详细)_js深拷贝和浅拷贝方法-CSDN博客-
function deepCopy(newObj,obj) { for(var key in obj) { //判断属性值属于哪种数据类型 //属性值 obj[key] //1.判断这个值是否为数组(数组也属于特殊对象,也是引用类型数据) if(obj[key] instanceof Array) { newObj[key] = [] deepCopy(newObj[key],obj[key]) //运用递归,把原对象属性值给新对象 //判断这个值是否为对象 } else if(obj[key] instanceof Object) { newObj[key] = {} deepCopy(newObj[key],obj[key]) //运用递归,把原对象属性值给新对象 } else { //若是普通数据类型 newObj[key] = obj[key] } } } // 数组和对象和基本数据类型的深拷贝,但不能处理函数、RegExp、Date JSON.parse(JSON.stringify())
-
-
css中伪元素和伪类的差别
伪类是针对 HTML 元素的状态描述,可以描述 HTML 元素的不同阶段或状态,例如:link、:visited、:hover 等,:first-child 和 :last-child 表示伪类。
伪元素是用于描述 HTML 元素的一部分,它们实际上是虚拟的 DOM 节点,而不是真实的 HTML 元素,例如::before 和 ::after。 -
XSS和CSRF的区别
XSS 是把受害者 的 Cookie 偷盗过来,而 CSRF 则是借用了受害者的 Cookie。
-
export和export default导出的内容可以更改么
export导出的内容:需要包再{}中接收,导出的对象属性在外部脚本中是可以修改的。
export default导出的内容:在一个模块中只能有一个,不需要加{},导出的值在外部脚本中不可修改,只是属性可以被修改。 -
ajax和fetch的区别
- ajax基于原生的XHR开发架构不清晰,fetch采用了Promise的异步处理机制,使用比ajax简单
- ajax利用XMLHttpRequest对象来请求数据,fetch只是全局变量window的一个方法。
- fetch只对网络错误报错,对400,500都当做成功的请求,需要封装去处理
- fetch没有办法原生监测请求的进度,而XHR可以(onprogress)
-
完整的HTTP事务是怎样的一个过程
1、域名解析:使用DNS协议进行域名解析
2、建立连接:发起TCP三次握手
3、发起http请求:建立TCP连接成功后,浏览器发起http请求
4、响应http请求:服务端响应http请求,浏览器得到返回response
5、解析response:浏览器解析response,并请求其它的资源(如js、css等)
6、浏览器渲染展示页面:浏览器根据内核对页面进行渲染展示
7、断开连接:TCP四次挥手
详细说明:【精选】一次完整的http请求过程_一个完整的http请求过程详细_三也_小也的博客-CSDN博客 -
TCP、UDP的区别
所有的TCP、UDP都是以IP数据报格式传输。- TCP协议:传输控制协议
- 面向连接,需要先建立连接,结束后再断开连接,常见的三次握手、四次挥手,即用于此协议
- 传输速度慢
- 数据要求按顺序传输,传输过程中数据报不需要携带目的地址,保证数据的正确性
- 基于流模式传输,可传输大数据
- 系统资源要求多
- 主要提供完整性服务
- UDP协议:用户数据报协议
-
面向非连接
-
传输速度快
-
对传输顺序无要求,准确性无法保证,有丢包可能
-
基于数据报模式,按包传输,传输数据量少,一次传输的数据大小有限,最大64k
-
资源要求少
-
主要提供及时性服务
-
- TCP协议:传输控制协议
-
vue属性的访问顺序
vue2 inject => props => methods => data => computed => watch => provide
vue3 porps => inject => methods => data => computed => watch => provide
- 什么是强缓存、协商缓存
为了减少资源请求次数,加快资源访问速度,浏览器会对资源文件如图片、css文件、js文件等进行缓存,而浏览器缓存策略又分为强缓存和协商缓存。在强缓存里,是否使用缓存是由浏览器来确定的,而协商缓存则是由服务器来告诉浏览器是否使用缓存资源,也就是浏览器每一次都要发送请求到服务器询问是否使用缓存。
强缓存就是浏览器本地根据服务器设置的过期时间来判断是否使用缓存,未过期则从本地缓存里拿资源,已过期则重新请求服务器获取最新资源。
协商缓存则是浏览器本地每次都向服务器发起请求,由服务器来告诉浏览器是从缓存里拿资源还是返回最新资源给浏览器使用。
强缓存的具体流程为:
浏览器第一次请求远程服务器的某个资源时,如果服务器希望浏览器得到该资源后一段时间内不要再发送请求过来,直接从浏览器里的缓存里取,则服务器可以通过在响应头里设置Cache-Control、
Expires。Expires
是Http1.0规范,Cache-Control
是Http1.1规范,Expires
参照的是本地客户端的时间,而客户端的时间是可以被修改的,所以有了后来Http1.1规范的Cache-control,Cache-control
的优先级要高于Expires。
浏览器缓存资源的地方有两个:磁盘缓存(disk cache)和内存缓存(memory cache)。
协商缓存的具体流程:
浏览器初次请求资源,服务器返回资源,同时生成一个Etag
值(哈希值)携带在响应头里返回给浏览器,当浏览器再次请求资源时会在请求头里携带If-None-Match
,值是之前服务器返回的Etag
的值,服务器收到之后拿该值与资源文件最新的Etag
值做对比。如果没有变化则返回304,告诉浏览器继续使用缓存(不返回资源文件)。如果发生变化,则返回200和最新的资源文件给浏览器使用。除了Etag
外,还有一个Last-Modified
的属性,它是Http1.0规范的,服务器返回Last-Modified
,浏览器请求头对应携带的是If-Modified-since
,与Etag
不同的是,Last-Modified
的值是一个时间值,代表文件的修改时间,服务器通过对比文件的修改时间是否发生改变来判断是否使用缓存。相比Last-Modified
,Etag
优先级更高,使用上也更精确一些,因为有时候会存在文件内容并没有改变,但文件的修改时间变更了。 -
什么是跨域?说出几种解决跨域的办法?
指浏览器不能执行其他网站的脚本(域名、协议、端口任意不相同),它是由浏览器的同源策略造成的,浏览器对js实施的安全限制。- Jsonp 跨域 只能够实现get请求
- PostMessage
- 服务端设置Access-Control-Allow-Origin,若要带cookie请求:前后端都需要设置
- nginx反向代理接口跨域,做跳板机,反向代理访问domain2接口
- WebSocket实现了浏览器与服务器全双工通信,同时允许跨域通讯
-
get和post的区别
1.GET请求会被缓存,而POST请求不会被缓存
2.GET请求会被保留在浏览器历史中,而POST请求则不会
3.GET的安全性相对于POST较差,因为发送的数据是URL的一部分,而POST不会放到浏览器历史中
4.GET向URL中传递数据,对数据长度有限制,POST则没有限制 -
垃圾回收机制
自动内存管理技术,它的目的是为了有效地管理和回收那些不再使用的内存资源。- 引用计数:统计对象的引用数量,当对象的引用数量变为零时,则认为该对象不再被使用,然后回收它的内存。(IE)
- 标记清除:将每个对象标记为活跃的或未使用的,然后删除未使用的对象。(chrome)
-
前台兼容性问题有哪些
主要是常用浏览的(前端)API差异(HTML/CSS/Javascript 语法不兼容),渲染差异,浏览器内置样式不一致,字体渲染差异 -
SEO优化
模板引擎会影响SEO优化,为了解决这个问题,需要关注SEO的页面最好采用服务端渲染的方式(ssr)。
设置正确的元标记和标题。使用 vue-meta 插件来管理和设置元标记和标题。
压缩 CSS 和 JavaScript 文件、减少 HTTP 请求次数等方式来提高网页速度。
创建 XML 站点地图。站点地图是一份清单,列出站点上所有页面的 URL。使用 vue-router-sitemap 插件生成 XML 站点地图。
-
浏览器一次可以从一个域名下请求多少资源
浏览器的并发请求数目限制是针对同一域名的,同一时间针对同一域名下的请求有一定数量限制,不同浏览器这个限制的数目不一样,超过限制数目的请求会被阻塞;
目前的话,所有浏览器的并发数目一般限制在10以内。
-
offsetWidth/offsetHeight,clientWidth/clientHeight,scrollWidth/scrollHeight 的区别?
- offsetWidth/offsetHeight 返回值包含 content + padding + border + 包含滚动条,效果与 e.getBoundingClientRect()相同
- clientWidth/clientHeight 返回值只包含 content + padding,如果有滚动条,也不包含滚动条
- scrollWidth/scrollHeight 返回值包含 content + padding + 溢出内容的尺寸
-
浏览器事件循环机制和Node事件循环机制的区别
浏览器事件循环机制中,微任务的任务队列是在每个宏任务执行完之后执行。
Node事件循环机制中,微任务会在事件循环的各个阶段之间执行,也就是说,一个阶段执行完毕,就会去执行微任务队列的任务。
-
html5有哪些新特性
1.拖拽释放(Draganddrop)API ondrop 自定义属性 data-id 获取 li.getAttribute(‘data-id’)或者 li.dataset.type=‘guoji’
2.语义化更好的内容标签(header,nav,footer,aside,article,section)
3.音频、视频 API(audio,video) 如果浏览器不支持自动播放怎么办?
4.画布(Canvas)API 热 canvas 和 image 的区别?
5.地理(Geolocation)API
6.本地离线存储 localStorage 长期存储数据,浏览器关闭后数据不丢失;sessionStorage 的数据在浏览器关闭后自动删除
7.表单控件,calendar、date、time、email、url、search 、tel、file、number
9.新的技术 webworker,websocket,Geolocation
-
CSS3新特性
1.过渡 transition: CSS属性,花费时间,效果曲线(默认ease),延迟时间(默认0)复制代码
2.动画 animation:动画名称,一个周期花费时间,运动曲线(默认ease),动画延迟(默认0),播放次数(默认1),是否反向播放动画(默认normal),是否暂停动画(默认running)复制代码
3.形状转换 transform:适用于2D或3D转换的元素
rotate(30deg); translate(30px,30px); scale(.8); skew(10deg,10deg); rotateX(180deg); rotateY(180deg); rotate3d(10,10,10,90deg);
4.选择器
5.阴影 box-shadow: 水平阴影的位置 垂直阴影的位置 模糊距离 阴影的大小 阴影的颜色 阴影开始方向(默认是从里往外,设置inset就是从外往里);复制代码
6.边框 border-image: 图片url 图像边界向内偏移 图像边界的宽度(默认为边框的宽度) 用于指定在边框外部绘制偏移的量(默认0) 铺满方式–重复(repeat)、拉伸(stretch)或铺满(round)(默认:拉伸(stretch));
7.背景 background-clip 制定背景绘制(显示)区域 background-origin background-size
1.(background-clip: border-box;)默认情况(从边框开始绘制) 2.(background-clip: padding-box;)从padding开始绘制(显示),不算border,,相当于把border那里的背景给裁剪掉! 3.(background-clip: content-box;)只在内容区绘制(显示),不算padding和border,相当于把padding和border那里的背景给裁剪掉!
8.文字 换行 语法:word-break: normal|break-all|keep-all;、语法:word-wrap: normal|break-word; 超出省略号 text-overflow:clip|ellipsis|string
文字阴影 语法:text-shadow:水平阴影,垂直阴影,模糊的距离,以及阴影的颜色。
9.颜色 rgba(rgb为颜色值,a为透明度)
10.渐变
11.弹性布局 Flex
12.盒模型定义 box-sizing:border-box的时候,边框和padding包含在元素的宽高之内!
box-sizing:content-box的时候,边框和padding不包含在元素的宽高之内!
13.媒体查询
-
cookies、sessionStorage和localStorage的区别
-
存储大小
cookie数据大小不能超过4k。
sessionStorage和localStorage 虽然也有存储大小的限制,但比cookie大得多,可以达到5M或更大。
-
有效时间
localStorage 存储持久数据,浏览器关闭后数据不丢失除非主动删除数据;
sessionStorage 数据在当前浏览器窗口关闭后自动删除
cookie 设置的cookie过期时间之前一直有效,即使窗口或浏览器关闭
-
数据与服务器之间的交互方式
cookie的数据会自动的传递到服务器,服务器端也可以写cookie到客户端 , 每次都会携带在HTTP头中,如果使用cookie保存过多数据会带来性能问题
sessionStorage和localStorage不会自动把数据发给服务器,仅在本地保存
-
作用范围
-
cookies只能作用于当面目录以及当前的子目录。(同源窗口,子域也可以)
-
cookie的作用域和域名有关,和协议以及端口无关。
path属性
cookie的path属性决定了访问该域名的那些路径时可以携带cookie,当一个tomcat部署多个服务时,将path设置为/,则访问所有tomcat项目时都可以携带。domain属性
cookie的domain属性才是决定了访问哪个域名时可以携带哪些cookie,服务器可以手动设置domian,默认的domain就是请求url中的域名,但是服务器也可以设置当前域名的子域名,但是不允许设置其他域名,如果设置了其他域名,会直接被浏览器丢弃。 例如,访问 www.baidu.com ,则 服务器可以设置cookie的域名为 www.baidu.com、.baidu.com、baike.baidu.com。当baidu.com下的子域名访问时,也可以携带上.baidu.com的cookie,例如当前网站是 www.baike.baidu.com,访问baike的请求时也可以携带 baidu.com的cookie。利用这个特性也可以实现多个相互信任系统之间的单点登录问题。
-
-
localStorage是同一浏览器不同标签页之间数据可以共享。(同源窗口)
默认是不允许跨域的,但是不同域名使用相同的document.domain=“xxx”可以实现
-
sessionStorage中存储的数据是只能在当前标签页中使用。(同源且同个窗口)
-
-
-
promise
优点:
1.解决回调地狱问题 ,有时我们要进行一些相互间有依赖关系的异步操作,比如有多个请求,后一个的请求需要上一次请求的返回结果。
2.更好地进行错误捕获
缺点:
1.无法取消Promise,一旦新建它就会立即执行,无法中途取消。
2.如果不设置回调函数,promise内部抛出的错误,不会反应到外部。
3.当处于pending状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)
-
介绍一下Vue的响应式系统
-
任何一个 Vue Component 都有一个与之对应的 Watcher 实例
-
Vue 的 data 上的属性会被添加 getter 和 setter 属性
-
当 Vue Component render 函数被执行的时候, data 上会被 触碰(touch), 即被读, getter 方法会被调用, 此时 Vue 会去记录此 Vue component 所依赖的所有 data。(这一过程被称为依赖收集)
-
data 被改动时(主要是用户操作), 即被写, setter 方法会被调用, 此时 Vue 会去通知所有依赖于此 data 的组件去调用他们的 render 函数进行更新
-
-
vue怎么进行依赖收集
-
每个属性都拥有自己的dep属性,存放依赖他的
watcher
,当属性变化后会通知自己对应的watcher
去更新 -
默认在初始化时会调用render函数,此时会触发属性依赖收集
dep.depend
-
当属性发生修改时会触发watcher更新
dep.notify()
-
-
keep-alive 的作用是什么
包裹动态组件时,会缓存不活动的组件实例,主要用于保留组件状态或避免重新渲染。
-
什么是预加载?
- 预加载其实是声明式的 fetch ,强制浏览器请求资源,并且不会阻塞 onload 事件,可以使用以下代码开启预加载
<link rel="preload" href="http://example.com">
- 预加载可以一定程度上降低首屏的加载时间,因为可以将一些不影响首屏但重要的文件延后加载,唯一缺点就是兼容性不好
-
css预处理器的区别(Sass/Less/SCSS)
总的来说,Less、Sass和SCSS都是强大的CSS预处理器,拥有变量,运算,继承,混合,函数,嵌套的功能,使用两者可以使代码更加的便于阅读和维护。Less具有更简单的语法和支持JavaScript函数,而Sass和SCSS提供了额外的功能,例如条件语句(if else)、循环(for)。选择使用哪个预处理器最终取决于个人偏好和项目要求。无论选择哪个预处理器,它们都有潜力极大地改善您的CSS工作流程。
Less:是一种动态的样式表语言,可以编译为CSS。它在功能和特性上类似于Sass,但其语法更简单。变量@符号,变量插值@{XXX}
Sass代表Syntactically Awesome Style Sheets。它是一种预处理器,可以编译为CSS,并为CSS增加了额外的功能。变量($符号),变量插值${XXX}。Sass有两种语法选项:Sass(缩进语法)和SCSS(Sassy CSS)。Sass使用空格缩进来定义代码块,而SCSS具有更传统的CSS语法
-
scss是什么?在Vue.cli中的安装使用步骤是?有哪几大特性?
是css的预编译语言。
使用步骤:
第一步:先装css-loader、node-loader、sass-loader等加载器模块;
第二步:在build目录找到webpack.base.config.js,在extends属性中加一个拓展.scss;
第三步:在同一个文件,配置一个module属性;
第四步:然后在组件的style标签加上lang属性 ,例如:lang=”scss”;
特性:
可以用变量,例如($变量名称=值);
可以用混合器;
可以嵌套; -
什么是 MVVM ?
MVVM是Model-View-ViewModel的缩写。MVVM是一种设计思想。Model 层代表数据模型,也可以在Model中定义数据修改和操作的业务逻辑;View 代表UI 组件,它负责将数据模型转化成UI 展现出来,ViewModel 是一个同步View 和 Model的对象。
在MVVM架构下,View 和 Model 之间并没有直接的联系,而是通过ViewModel进行交互,Model 和 ViewModel 之间的交互是双向的, 因此View 数据的变化会同步到Model中,而Model 数据的变化也会立即反应到View 上。
ViewModel 通过双向数据绑定把 View 层和 Model 层连接起来,而View 和 Model 之间的同步工作完全是自动的,无需人为干涉,因此开发者只需关注业务逻辑,不需要手动操作DOM, 不需要关注数据状态的同步问题,复杂的数据状态维护完全由 MVVM 来统一管理。 -
vuex是什么?怎么使用?哪种功能场景使用它?
vue框架中状态管理。在main.js引入store注入。新建一个目录store 。场景有:单页应用中,组件之间的状态,音乐播放、登录状态、加入购物车等。
-
vuex有哪几种属性?
有五种,分别是 State、 Getters、Mutations 、Actions、 Modules。
-
Vuex的State特性
Vuex就是一个仓库,仓库里面放了很多对象。其中state就是数据源存放地,对应于一般Vue对象里面的data。state里面存放的数据是响应式的,Vue组件从store中读取数据,若是store中的数据发生改变,依赖这个数据的组件也会发生更新。
通过mapState,mapGetters把全局 state 、 getters 映射到当前组件的 computed 计算属性中。
-
Vuex的Getter特性
getters 可以对State进行计算操作,它就是Store的计算属性。
虽然在组件内也可以做计算属性,但是getters 可以在多组件之间复用。如果一个状态只在一个组件内使用,可以不用getters。
-
Vuex的Mutations特性
我们只能通过mutation去更改state里面的值。mutations需要通过commit来调用其里面的方法,它也可以传入参数,第一个参数是state,第二个参数是载荷(payLoad),也就是额外的参数。
Action 类似于 mutation,不同在于:Action 提交的是 mutation,而不是直接变更状态;Action 可以包含任意异步操作。
通过mapMutations、mapActions把全局 mutation、 Action映射到当前组件的 methods属性中。
Vuex所谓的单向数据流:界面—>派发action—>action提交mutation—>mutation更改state—>getters返回最新的state值到界面 -
不用Vuex会带来什么问题?
可维护性会下降,想修改数据要维护三个地方;
可读性会下降,因为一个组件里的数据,根本就看不出来是从哪来的;
增加耦合,大量的上传派发,会让耦合性大大增加,Vue用Component本意就是为了减少耦合,现在这么用,和组件化的初衷相背。
-
vue-loader 是什么?用途有哪些?
是解析.vue文件的一个加载器。
用途:js 可以写es6、style样式可以scss或less、template可以加jade等。
-
如何获取dom
在我们的vue项中,难免会因为引第三库需要操作DOM标签,vue为我们提供了ref属性。 ref 被来给元素或组件注册引信息。引信息将会注册在组件的 $refs 对象上。如果在普通的 DOM 元素上使,引指向的就是 DOM 元素;如果在组件上,引就指向组件实例 -
iframe的优缺点?
iframe也称作嵌式框架,嵌式框架和框架页类似,它可以把个页的框架和内容嵌入在现有的页中。
优点:
解决加载缓慢的第三内容如图标和告等的加载问题,Security sandbox,并加载脚本,方便制作导航栏
缺点:
iframe会阻塞主页的Onload事件,即使内容为空,加载也需要时间,没有语意。浏览器的连接池是有限的,太多的iframe会直接影响网站的性能。 -
请说出vue.cli项中src录每个件夹和件的法?
assets件夹是放静态资源;static是放静态文件(打包不会压缩此文件夹下的内容,直接拷贝放进dist文件中);components是放组件;router是定义路由相关的配置;store是定义公共仓库相关的配置;view视图;app.vue是个应主组件;main.js是入口 -
vue常的修饰符
.stop:等同JavaScript中的event.stopPropagation(),防事件冒泡
.prevent:等同于JavaScript中的event.preventDefault(),防执预设的为(如果事件可取消,则取消该事件,不停事件的进步传播);
.capture:与事件冒泡的向相反,事件捕获由外到内
.self:只会触发范围内的事件,不包含元素;
.once:只会触发一次。
.native:捕获原生事件
.sync:类似双向数据绑定,父、子组件修改值,会自动更新 -
定义指令(v-check、v-focus)的方法有哪些?它有哪些钩子函数?哪些钩子函数参数?
全局定义指令:在vue对象的directive法有两个参数,第一个是指令名称,另外一个是对象。组件内定义指令:directives。
钩子函数:bind(第一次绑定事件时触发)、inserted(元素已插入到父节点的时候触发)、update(被绑定元素更新时调用该函数,可能在其子级更新前调用)、componentUpdated(组件已经更新时调用)、unbind(指令与元素解绑时调用)。
钩子函数参数:el(dom原素的引用)、binding(value属性) -
vue的两个核心点:数据驱动,组件系统
数据驱动:ViewModel,保证数据和视图的一致性
组件系统:spa应用类的UI可以看做全部是由组件树构成的 -
delete和Vue.delete删除数组的区别
delete只是被删除的元素变成了empty。undefined是未定义,他的元素的键值还是不变。
Vue.delete直接删除了数组 改变了数组的键值 -
如何开发vue插件?
如果插件是一个对象,必须提供install方法。如果插件是一个函数,它会被作为install方法。调用install方法时,会将Vue作为参数传入。install方法被同一个插件多次调用时,插件也只会被安装一次。 -
前端路由和后端路由的区别
- 映射关系不同。前端路由是一个路径映射一个组件;后端路由是一个路径映射一个处理本次请求的响应函数。
- 前端路由不需要走网络,而后端路由需要走网络。
- 前端路由切换页面不会使得网页刷新,后端路由切换页面会导致网页刷新。
- 前端路由采用的是客户端渲染,后端路由是服务端渲染。
-
vue-router的原理和模式
路由描述的是 URL 与 UI 之间的映射关系,这种映射是单向的,即 URL 变化引起 UI 更新(无需刷新页面)。有hash 和 history 两种实现方式
hash:hash 是 URL 中 hash (#) 及后面的那部分,常用作锚点在页面内进行导航,改变 URL 中的 hash 部分不会引起页面刷新。通过 hashchange 事件监听 URL 的变化,改变 URL 的方式只有这几种:1.通过浏览器前进后退改变 URL;2.通过<a>
标签改变 URL;3.通过window.location改变URL。
history:history 提供了 pushState 和 replaceState 两个方法,这两个方法改变 URL 的 path 部分不会引起页面刷新。history 提供类似 hashchange 事件的 popstate 事件,但 popstate 事件有些不同:1.通过浏览器前进后退改变 URL 时会触发 popstate 事件;2.通过pushState/replaceState或<a>
标签改变 URL 不会触发 popstate 事件;3.好在我们可以拦截 pushState/replaceState的调用和<a>
标签的点击事件来检测 URL 变化;4.通过js 调用history的back,go,forward方法课触发该事件 -
完整的vue-router导航解析流程
导航被触发。
在失活的组件里调用beforeRouterLeave离开守卫(组件)可以访问组件 ‘this’。
调用全局的beforeEach守卫(全局)
在重用的组件里调用beforeRouterUpdate守卫(2.2+)(组件)可以访问组件 ‘this’。
在路由配置里调用beforeEnter(单个)。
解析异步路由组件。
在被激活的组件里调用beforeRouterEnter(组件)不能获取组件实例 ‘this’ 这时组件 this 还没有被创建。
调用全局的beforeResolve守卫(2.5+)。
导航被确认。
调用全局的afterEach钩子(全局)。
触发DOM更新。
调用 beforeRouteEnter 守卫中传给 next 的回调函数,创建好的组件实例会作为回调函数的参数传入。 -
Vue-router跳转和location.href有什么区别
使用location.href=/url 来跳转,简单方便,但是刷新了页面;使history.pushState(/url),刷新页,静态跳转;引进router,然后使router.push(/url)来跳转,使了diff算法,实现了按需加载,减少了dom的消耗。其实使router跳转和使history.pushState()没什么差别,因为vue-router就是了history.pushState(),尤其是在history模式下。 -
params和query的区别
用法:query要path来引,params要name来引,接收参数都是类似的,分别是this.router .query.name和this.router.params.name。
url地址显示:query更加类似于我们ajax中get传参,params则类似于post,说的再简单点,前者在浏览器地址栏中显参数,后者则不显示。
注意点:query刷新不会丢失query的数据params刷新会丢失params的数据 -
RouterLink在IE和Firefox中不起作用(路由不跳转)的问题
可能是因为IE和Firefox不支持RouterLink指令。
只a标签,不使button标签法
使button标签绑定Router.navigate方法 -
请说下封装 vue 组件的过程?
首先,组件可以提升整个项目的开发效率。能够把页抽象成多个相对独立的模块,解决了我们传统项开发的弊端:效率低、难维护、复性等问题。
然后,使Vue.extend法创建个组件,然后使Vue.component法注册组件。组件需要数据,可以在props中接受定义。组件修改好数据后,想把数据传递给组件。可以采emit方法。 -
vue mock数据
在项中尝试了mockjs,mock数据,实现前后端分离开发。
关于mockjs,官描述的是1.前后端分离
2.不需要修改既有代码,就可以拦截 Ajax 请求,返回模拟的响应数据。
3.数据类型丰富
4.通过随机数据,模拟各种场景。
总结:在后端接没有开发完成之前,前端可以已有的接口文档,在真实的请求上拦截ajax,并根据mockjs的mock数据的规则,模拟真实接返回的数据,并将随机的模拟数据返回参与相应的数据交互处理,这样真正实现了前后台的分离开发。
与以往的模拟的假数据不同,mockjs可以带给我们的是:在后台接未开发完成之前模拟数据,并返回,完成前台的交互;在后台数据完成之后,你所做的只是去掉mockjs:停拦截真实的ajax,仅此已。 -
vue初始化页闪动问题
使vue开发时,在vue初始化之前,由于div是不归vue管的,所以我们写的代码在还没有解析的情况下会容易出现花屏现象,看到类似于{{message}}的字样,虽然般情况下这个时间很短暂,但是我们还是有必要解决这个问题的。
先:在css加上[v-cloak]{display:none;},如果没有彻底解决问题,则在根元素加上style=“display:none;” :style=“{display:block}” -
vue更新数组时触发视图更新的法
push();pop();shift();unshift();splice();sort();reverse();$set -
vue常的UI组件库
Mint UI,element,iview -
mint-ui是什么?怎么使?说出少三个组件使法?
基于vue的前端组件库。
npm安装,然后import样式和js,vue.use(mintUi)全局引。在单个组件局部引:import {Toast} from ‘mint-ui’。组件:Toast(‘登录成功’);
组件:mint-header;
组件三:mint-swiper -
Vue的router-link在电脑上有,在安卓上没反应怎么解决?
Vue路由在Android机上有问题,babel问题,安装babel polypill插件解决 -
Vue2中注册在router-link上事件效解决法
使@click.native。原因:router-link会阻click事件,.native指直接监听个原事件。 - 不同设备间是怎么通信的,IP和MAC地址详解
- 引用大佬文章,清晰明了
- 文章地址IP地址与Mac地址的关系与区别 - 学习/实践_ip地址和mac地址的关系_宁小法的博客-CSDN博客
- 引用大佬文章,清晰明了
手写系列(引用大佬)
- 文件下载(blob)
/** * 检验返回数据是否是文件流 * @param {*} res * @returns */ export function isStream(res){ console.log(6666,res.headers['content-type'],res); return res.headers['content-type'].includes('application/octet-stream') } /** * 获取文件名称 * @param {*} res */ export function getFileName(res){ // /* 截取头部获取文件名 utf8转中文 */ let str = res.headers['content-disposition'] return decodeURI(str.split('=')[1].split('.xls')[0]) } /** * 导出文件 * (bold文件流方式导出) * @param {*} res * @param {*} fileName */ export function download(res, fileName) { var blob = new Blob([res.data]) const reader = new FileReader() reader.readAsDataURL(blob) reader.onload = (e) => { const a = document.createElement('a') a.download = `${fileName}.xls` a.href = e.target.result document.body.appendChild(a) a.click() document.body.removeChild(a) } }