2025场景面试题跟练(三)

61 阅读1分钟

1.移动端如何实现下拉刷新

关键在于:

  • 使用 touch 事件监听移动端的手势。
  • 添加阻尼效果(moveY * 0.5),使下拉更自然。
  • 仅在滚动到顶部(scrollTop === 0)时启用下拉。
<!DOCTYPE html>
<html>
<head>
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <style>
        #refresh-area {
            position: absolute;
            top: -50px;
            height: 50px;
            width: 100%;
            text-align: center;
            transition: top 0.3s;
            background: #f0f0f0;
        }
        #content {
            height: 1000px; /* 模拟内容区域 */
            overflow: auto;
        }
    </style>
</head>
<body>
    <div id="refresh-area">下拉刷新</div>
    <div id="content">页面内容...</div>

    <script>
        const refreshArea = document.getElementById('refresh-area');
        const content = document.getElementById('content');
        let startY = 0;
        let moveY = 0;
        let isPulling = false;

        content.addEventListener('touchstart', (e) => {
            startY = e.touches[0].clientY;
            isPulling = content.scrollTop === 0; // 仅在顶部时生效
        });

        content.addEventListener('touchmove', (e) => {
            if (!isPulling) return;
            moveY = e.touches[0].clientY - startY;
            if (moveY > 0) {
                // 设置下拉距离(阻尼效果)
                const pullDistance = Math.min(moveY * 0.5, 50);
                refreshArea.style.top = `${pullDistance - 50}px`;
                if (pullDistance >= 50) {
                    refreshArea.textContent = '释放刷新';
                } else {
                    refreshArea.textContent = '下拉刷新';
                }
            }
        });

        content.addEventListener('touchend', () => {
            if (!isPulling) return;
            if (moveY * 0.5 >= 50) {
                // 触发刷新
                refreshArea.textContent = '正在刷新...';
                refreshArea.style.top = '0px';
                setTimeout(() => {
                    // 模拟刷新完成
                    refreshArea.style.top = '-50px';
                    refreshArea.textContent = '下拉刷新';
                    console.log('刷新完成');
                }, 1000);
            } else {
                // 未达到阈值,回弹
                refreshArea.style.top = '-50px';
            }
            isPulling = false;
        });
    </script>
</body>
</html>

2. PerformanceObeserver如何测量页面性能?

const observer = new PerformanceObserver((list)=>{
  const entries = list.getEntries();
  entries.forEach(entry=>{
    console.log(entry)
  })
})
observer.observe({
  entryTypes:['longtask']
})

3. 如何统计用户pv访问时发起的请求数量?

前端统计

  1. 封装应用请求方法,通过单例模式在请求时进行计数,使用统计API调用场景,无法捕获img,script等标签的静态资源请求
  2. 借用performance API获取加载期间所有资源请求,能统计所有资源请求(包括图片、CSS、JS 等),但仅限于页面加载完成时的统计,无法实时更新
window.addEventListener('load', function () {
    const resources = performance.getEntriesByType('resource');
    const requestCount = resources.length;
    console.log(`页面加载期间总请求数: ${requestCount}`);
    // 可选:发送到服务器
    fetch('/log-requests', {
        method: 'POST',
        body: JSON.stringify({ pvRequests: requestCount }),
    });
});

后端统计

服务器日志+会话标识

4.如何实现拖拽效果

5. 统计全站每一个静态资源加载耗时,该如何做

// 获取所有资源的加载信息
function getResourceTiming() {
    const resources = performance.getEntriesByType('resource');
    
    const result = resources.map(resource => {
        const {
            name,              // 资源URL
            startTime,         // 开始时间
            responseEnd,       // 响应结束时间
            transferSize,      // 传输大小
            decodedBodySize    // 解码后大小
        } = resource;

        // 计算加载耗时(ms)
        const loadTime = responseEnd - startTime;

        return {
            url: name,
            loadTime: loadTime.toFixed(2),
            size: transferSize,
            decodedSize: decodedBodySize
        };
    });

    console.table(result); // 以表格形式输出,便于查看
}

// 在页面加载完成后执行
window.addEventListener('load', () => {
    setTimeout(getResourceTiming, 0); // 确保所有资源加载完成
});

// 动态加载的资源可以通过观察者持续监控
const observer = new PerformanceObserver((list) => {
    const entries = list.getEntries();
    entries.forEach(entry => {
        console.log(`${entry.name} 加载耗时: ${(entry.responseEnd - entry.startTime).toFixed(2)}ms`);
    });
});
observer.observe({ entryTypes: ['resource'] });