撩课-Web大前端每天5道面试题-Day4
程序员文章站
2022-09-14 08:16:38
1. 如何实现瀑布流? 高清视频讲解(第53节)-->点我 2. 原生JS都有哪些方式可以实现两个页面间的通信? 3. 原生JS动态向一个div中插入1000个div标签,如何实现? 4. 程序出现bug了,你是如何调试的? 5. 开发中是如何进行性能优化的? 6. 如何实现电商网站中的楼层效果? ......
1. 如何实现瀑布流?
瀑布流布局的原理: 1) 瀑布流布局要求要进行布置的元素等宽, 然后计算元素的宽度, 与浏览器宽度之比,得到需要布置的列数; 2) 创建一个数组,长度为列数, 里面的值为已布置元素的总高度(最开始为0); 3) 然后将未布置的元素依次布置到高度最小的那一列, 就得到了瀑布流布局; 4) 滚动加载, scroll事件得到scrolltop, 与最后盒子的offsettop对比, 符合条件就不断滚动加载。 瀑布流布局核心代码: /** * 实现瀑布流的布局 * @param {string}parentbox * @param {string}childbox */ function waterfull(parentbox, childbox) { // 1. 求出父盒子的宽度 // 1.1 获取所有的子盒子 var allbox = $(parentbox). getelementsbyclassname(childbox); // console.log(allbox); // 1.2 求出子盒子的宽度 var boxwidth = allbox[0].offsetwidth; // console.log(boxwidth); // 1.3 获取窗口的宽度 var clientw = document. documentelement.clientwidth; // console.log(clientw); // 1.4 求出总列数 var cols = math.floor(clientw / boxwidth); // console.log(cols); // 1.5 父盒子居中 $(parentbox).style.width = cols * boxwidth + 'px'; $(parentbox).style.margin = '0 auto'; // 2. 子盒子定位 // 2.1 定义变量 var heightarr = [], boxheight = 0, minboxheight = 0, minboxindex = 0; // 2.2 遍历所有的子盒子 for (var i = 0; i < allbox.length; i++) { // 2.2.1 求出每一个子盒子的高度 boxheight = allbox[i].offsetheight; // console.log(boxheight); // 2.2.2 取出第一行盒子的高度放入高度数组中 if (i < cols) { // 第一行 heightarr.push(boxheight); } else { // 剩余行的盒子 // 2.2.3 取出数组中最矮的高度 minboxheight = _.min(heightarr); // 2.2.4 求出最矮高度对应的索引 minboxindex = getminboxindex(heightarr, minboxheight); // 2.2.5 盒子定位 allbox[i].style.position = 'absolute'; allbox[i].style.left = minboxindex * boxwidth + 'px'; allbox[i].style.top = minboxheight + 'px'; // 2.2.6 更新最矮的高度 heightarr[minboxindex] += boxheight; } } } /** * 根据内容取出在数组中对应的索引 * @param {object}arr * @param {number}val * @returns {boolean} */ function getminboxindex(arr, val) { for (var i = 0; i < arr.length; i++) { if (arr[i] === val) return i; } } /** * 判断是否具备加载子盒子的条件 * @returns {boolean} */ function checkwillloadimage() { // 1. 获取最后一个盒子 var allbox = $('main').getelementsbyclassname('box'); var lastbox = allbox[allbox.length - 1]; // 2. 求出高度 var lastboxdis = lastbox.offsetheight * 0.5 + lastbox.offsettop; // 3. 求出窗口的高度 var clienth = document.documentelement.clientheight; // 4. 求出页面滚动产生的高度 var scrolltoph = scroll().top; // 5. 对比 return lastboxdis <= clienth + scrolltoph; }
2. 原生js都有哪些方式可以实现两个页面间的通信?
1) 通过url地址栏传递参数; 例如:点击列表页中的每一条数据, 我们跳转到同一个详细页面, 但是根据点击的不一样可以看到 不同的内容,这样的话我们就可以 在url中传递不同的值来区分了; 2) 通过本地存储 cookie、localestorage、 sessionstroage...,例如:京东的登录, 我们在登录页登录完成后, 把用户信息存储到本地, 然后在其它页面中如果需要使用的话, 我们直接从本地的存储数据中拿 出来用即可; 3) 使用iframe在a页面中嵌入b页面, 这样的话,在a中可以通过一些属性 和方法实现和b页面的通信; 4) 利用postmessage实现页面间通信, 父窗口往子窗口传递信息, 子窗口往父窗口传递信息。
3. 原生js动态向一个div中插入1000个div标签,如何实现?
此题主要考性能! 1) 可以用js中的createelement创建div, 每当创建一个就把它添加到div中, 但会造成引发回流的次数太多; 2) 使用字符串拼接的方式, 把1000个div都拼接完成后, 统一的添加到页面中, 但会对div原有的元素标签产生影响: 原来标签绑定的事件都消失了 3) 综合1和2可以使用文档碎片方式来处理。 追问:如果是创建1000万个呢? 可采用的方案: 数据分批异步加载 1) 首先把前两屏幕的数据量 (例如:300条)先获取到, 然后使用字符串拼接或者文档碎片 的方式绑定到页面中; 2) 当浏览器滚动到指定的区域的 时候在加载300条...以此类推。
4. 程序出现bug了,你是如何调试的?
1) 在控制台加断点, f10->逐过程 f11->逐语句; 2) 在代码重点的位置加入 console.log输出对应的值来进行调试; 3) debugger调试; 4) 代码分割还原调试; 5) 异常捕获机制, 记录运行日志; 6) 单元测试。
5. 开发中是如何进行性能优化的?
现在框架(vue, react,...)、构建工具(webpack, ...) 已经给我们解决掉大部分的性能优化问题, 面试时, 可以就你了解的框架来深入剖析, 但此题应该是考原生js的范畴, 参考答案如下: 1) 雅虎35条性能优化黄金定律; 2) js代码优化: a. 项目中的js/css文件最好一个页面只用一个, 需要把js/css进行合并压缩, 并且减少页面中的垃圾冗余代码。 项目的资源文件在服务器上最好 做一下gzip压缩。 b. 解除文件缓存; 我们修改代码并上传, 如果之前页面访问过该网站, 很有可能不能立即见效; 我们在引入css/js文件的时候, 在文件名的后面加上版本号(加时间戳), 比如: <script src='itlike.com.js?_=202001...'></script>; 当我们上传新的文件后 把时间戳改一下就可以清除缓存了。 c. 移动端尽量少用图片: icon能用svg画的不用图片; 静态资源图:做布局的时候就能确定下来的图片, 比如: 1) css sprite图片合并 (针对于小图片) 2) 做图片延迟加载 (针对于大图片 头部的长条图片、背景大图...), 开始给一张默认的小的图片 (最好维持在10kb以内) 3) base64 (存在问题: 页面的代码太臃肿了,以后维护不好操作); 如果项目中由于图片太大实在解决不了, 改成base64就解决了 d. 动态数据图: 通过ajax从后台读取回来的图片 , 图片懒加载; e. 音视频文件的优化: 加载页面的时候,尽量不要加载音视频文件, 当页面中的其他资源加载完成后, 再开始加载音视频文件; 目前移动端经常给音视频做的优化是: 走直播流文件(音频后缀名是m3u8格式); f. 减少页面资源请求的次数: 如果当前只是一个宣传页, 或者是一个简单的页面, 使用的css和js可以采用内嵌式开发; g. ajax数据请求分批请求, 例如:一次要请求10000条数据的话, 我们每一次只请求100条,第一屏幕肯定能看全了, 当页面滚动到对应的其它屏幕的时候, 在加载下一个100条... h. 做数据的二次缓存, 能用css3做动画的绝对不用js, 能使用transform尽量使用, 能用animation的进行不用transition... 尽量减少同步操作,多用异步操作; 能使用原生js自己编写的, 绝对不用插件或者框架;
6. 如何实现电商网站中的楼层效果?
1) 封装缓动动画函数; 2) 点击切换, 滚动切换, 联动处理; 核心代码如下: // 3. 监听gps上的li的点击 for (var j = 0; j < ollis.length; j++) { (function (index) { var olli = ollis[index]; olli.onmousedown = function () { isclick = true; // 3.1 排他 for (var m = 0; m < ollis.length; m++) { ollis[m].classname = '' } addclass(this, 'current'); // 3.2 让楼层滚动起来 buffer( document.documentelement, {'scrolltop': index * client().height}, function () { isclick = false; }) } })(j) } // 4. 监听文档的滚动 window.onscroll = function (ev1) { // 4.1 没有点击产生的滚动 if (!isclick) { // 4.2 获取页面产出的头部滚动的高度 var roll = math.ceil(scroll().top); console.log(roll); // 4.3 遍历 for (var i = 0; i < ollis.length; i++) { // 4.4 判断 if (roll >= ullis[i].offsettop) { for (var m = 0; m < ollis.length; m++) { ollis[m].classname = '' } addclass(ollis[i], 'current'); } } } } 缓动动画函数: /** * 缓动动画(撩课学院) * @param {object}obj * @param {object}json * @param {function}fn */ function buffer(obj, json, fn) { // 1.1 清除定时器 clearinterval(obj.timer); // 1.2 设置定时器 var begin = 0, target = 0, speed = 0; obj.timer = setinterval(function () { // 1.3.0 旗帜 var flag = true; for (var k in json) { // 1.3 获取初始值 if ("opacity" === k) { // 透明度 begin = parseint(parsefloat(getcssattrvalue(obj, k)) * 100); target = parseint(parsefloat(json[k]) * 100); } else if ("scrolltop" === k) { begin = math.ceil(obj.scrolltop); target = parseint(json[k]); } else { // 其他情况 begin = parseint(getcssattrvalue(obj, k)) || 0; target = parseint(json[k]); } // 1.4 求出步长 speed = (target - begin) * 0.2; // 1.5 判断是否向上取整 speed = (target > begin) ? math.ceil(speed) : math.floor(speed); // 1.6 动起来 if ("opacity" === k) { // 透明度 // w3c的浏览器 obj.style.opacity = (begin + speed) / 100; // ie 浏览器 obj.style.filter = 'alpha(opacity:' + (begin + speed) + ')'; } else if ("scrolltop" === k) { obj.scrolltop = begin + speed; } else if ("zindex" === k) { obj.style[k] = json[k]; } else { obj.style[k] = begin + speed + "px"; } // 1.5 判断 if (begin !== target) { flag = false; } } // 1.3 清除定时器 if (flag) { clearinterval(obj.timer); // 判断有没有回调函数 if (fn) { fn(); } } }, 20); }
上一篇: python简单贪吃蛇开发