专业编程基础技术教程

网站首页 > 基础教程 正文

撩课-Web大前端每天5道面试题-Day2

ccvgpt 2024-10-15 09:15:42 基础教程 7 ℃

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都有哪些方式可以实现两个页面间的通信?

撩课-Web大前端每天5道面试题-Day2

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.6 清除定时器
 if (flag) {
 clearInterval(obj.timer);
 // 判断有没有回调函数
 if (fn) {
 fn();
 }
 }
 }, 20);
}

Tags:

最近发表
标签列表