大厂前端岗重复率极高的场景面试原题解析

怎么在前端页面中添加水印?
如何封装一个请求,让其多次调用的时候,实际只发起一个请求的时候,返回同一份结果
web网页如何禁止别人移除水印
react中怎么实现下拉菜单场景,要求点击区域外能关闭下拉组件
如何搭建一套灰度系统?
React 如何实现vue 中 keep-alive 的功能?
如何监控前端页面的崩溃?
如何在前端团队快速落地代码规范
前端如何实现即时通讯?
用户访问页面白屏了,原因是啥,如何排查?
如何给自己团队的大型前端项目设计单元测试?
如何做一个前端项目工程的自动化部署,有哪些规范和流程设计?

以上:https://github.com/encode-studio-fe/natural_traffic/wiki/scan_material5

怎么在前端页面中添加水印?

在前端页面中添加水印可以通过以下几种方法实现:

1. 使用 CSS 实现

使用 CSS 伪元素和 background 属性来添加水印。

复制代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Watermark Example</title>
<style>
  .watermarked {
    position: relative;
  }
  .watermarked::before {
    content: "Watermark";
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%) rotate(-30deg);
    font-size: 3rem;
    color: rgba(0, 0, 0, 0.1);
    pointer-events: none;
    z-index: 1000;
  }
</style>
</head>
<body>
<div class="watermarked">
  <!-- Your content here -->
  <p>Some content with a watermark.</p>
</div>
</body>
</html>

2. 使用 Canvas

通过在 canvas 上绘制水印来实现。

复制代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Canvas Watermark Example</title>
</head>
<body>
<canvas id="watermarkCanvas" width="600" height="400"></canvas>
<script>
  const canvas = document.getElementById('watermarkCanvas');
  const ctx = canvas.getContext('2d');

  // Draw background
  ctx.fillStyle = '#fff';
  ctx.fillRect(0, 0, canvas.width, canvas.height);

  // Draw watermark text
  ctx.font = '48px Arial';
  ctx.fillStyle = 'rgba(0, 0, 0, 0.2)';
  ctx.textAlign = 'center';
  ctx.textBaseline = 'middle';
  ctx.save();
  ctx.translate(canvas.width / 2, canvas.height / 2);
  ctx.rotate(-Math.PI / 6);
  ctx.fillText('Watermark', 0, 0);
  ctx.restore();
</script>
</body>
</html>

3. 使用 HTML 的 background 属性

将水印作为背景图像设置到页面的某个容器上。

复制代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Background Watermark Example</title>
<style>
  .watermarked {
    background-image: url('watermark.png');
    background-repeat: no-repeat;
    background-size: 200px 100px;
    background-position: center;
  }
</style>
</head>
<body>
<div class="watermarked">
  <!-- Your content here -->
  <p>Some content with a watermark.</p>
</div>
</body>
</html>

4. 使用 JavaScript 动态生成水印

通过 JavaScript 在 DOM 中添加水印元素。

复制代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Dynamic Watermark Example</title>
<style>
  .watermark {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    pointer-events: none;
    z-index: 9999;
    text-align: center;
    font-size: 3rem;
    color: rgba(0, 0, 0, 0.1);
    transform: rotate(-30deg);
  }
</style>
</head>
<body>
<div id="content">
  <!-- Your content here -->
  <p>Some content with a watermark.</p>
</div>
<script>
  const watermark = document.createElement('div');
  watermark.className = 'watermark';
  watermark.textContent = 'Watermark';
  document.body.appendChild(watermark);
</script>
</body>
</html>

如何封装一个请求,让其多次调用的时候,实际只发起一个请求的时候,返回同一份结果?

封装一个请求使其在多次调用时只发起一次请求,并返回相同结果,通常是通过请求去重(debouncing)来实现的。这种功能对于避免重复的网络请求、提高性能和减少不必要的负载非常有用。

同时,我们需要确保在请求完成之前,对相同请求的重复调用都会共享相同的请求 Promise。避免出现连续发出相同的请求,在第一个请求尚未完成时,那么可能会发出多个请求的情况。

可以通过以下步骤来实现这个功能:

1. 使用一个缓存机制

我们可以使用 JavaScript 对象或 Map 来缓存已经发起的请求,并在 subsequent 请求中返回缓存的结果。缓存的关键是确保相同的请求参数对应同一个缓存条目。

2. 创建请求缓存封装

以下是一个基于 axios 的请求去重的封装示例:

复制代码
import axios from 'axios';

// 请求缓存
const requestCache = new Map();

async function fetchData(url, params) {
  // 生成缓存 key
  const cacheKey = `${url}?${new URLSearchParams(params).toString()}`;

  // 检查缓存中是否已有数据
  if (requestCache.has(cacheKey)) {
    return requestCache.get(cacheKey);
  }

  // 创建请求 Promise
  const requestPromise = axios.get(url, { params })
    .then(response => {
      // 请求成功,存储结果
      requestCache.delete(cacheKey); // 请求完成后,移除缓存
      return response.data;
    })
    .catch(error => {
      // 请求失败,清除缓存
      requestCache.delete(cacheKey);
      throw error;
    });

  // 存储请求 Promise
  requestCache.set(cacheKey, requestPromise);

  // 返回 Promise
  return requestPromise;
}

export default fetchData;

注意事项:

  • 缓存请求 Promise:每个请求的 Promise 被缓存到 requestCache 中。后续的相同请求会返回这个缓存的 Promise。
  • 请求完成后移除缓存:请求成功或失败后,删除缓存,以防止缓存中的 Promise 长时间存在,避免内存泄漏。
  • 请求失败处理:如果请求失败,清理缓存并抛出错误,以便后续调用可以重新发起请求。

3. 使用请求缓存

使用封装好的 fetchData 函数来发起请求。多次调用相同的请求 URL 和参数只会发起一次网络请求,并返回相同的结果。

复制代码
import fetchData from './fetchData';

// 使用示例
fetchData('https://api.example.com/data', { id: 1 })
  .then(data => console.log(data))
  .catch(error => console.error(error));

// 再次调用相同的请求
fetchData('https://api.example.com/data', { id: 1 })
  .then(data => console.log(data)) // 共享相同的请求结果
  .catch(error => console.error(error));

web 网页如何禁止别人移除水印

防止DOM被删除

为了防止水印被删除,可以利用 MutationObserver API 监听 DOM 变化。MutationObserver 可以监控 DOM 树的变化并触发回调函数。回调函数可以用于检测水印是否被移除,并采取相应的措施进行恢复。

以下是一个示例代码,演示了如何使用 MutationObserver 监听 DOM 变化并检测水印的删除:

复制代码
// 目标节点
const targetNode = document.body;

// 创建 MutationObserver 实例
const observer = new MutationObserver(mutationsList => {
    mutationsList.forEach(mutation => {
        // 检查是否有子节点被删除
        if (mutation.removedNodes.length > 0) {
            // 检查被删除的节点是否为水印
            // 如果是,则重新插入水印元素
            // targetNode.appendChild(watermarkElement);
        }
    });
});

// 配置 MutationObserver
const config = { childList: true, subtree: true };

// 开始观察目标节点
observer.observe(targetNode, config);

在上述代码中,我们创建了一个 MutationObserver 实例,并通过 observe 方法绑定到目标节点。在回调函数中,使用 mutation.removedNodes 检测子节点删除情况。如果发现水印被删除,可以在此处重新插入水印元素。

需要注意的是,MutationObserver 是现代浏览器的特性,可能不兼容老旧浏览器。因此,实际应用中应考虑浏览器兼容性。

此外,为了确保水印能迅速恢复,可以在检测到水印被删除时立即执行插入操作。

防止DOM被隐藏

除了防止DOM被删除,还要考虑DOM被隐藏的情况。

要检测到水印DOM被设置为 display: none 隐藏,可以通过 MutationObserver 观察元素的属性变化,而不是仅仅关注子节点的删除。监听 attributes 类型的变化,以检测到 display 样式属性的改变。

以下示例展示了如何监控 display 属性的变化:

复制代码
// 目标节点(假设水印元素是一个特定的节点)
const watermarkElement = document.querySelector('.watermark');

// 创建 MutationObserver 实例
const observer = new MutationObserver(mutationsList => {
    mutationsList.forEach(mutation => {
        if (mutation.type === 'attributes' && mutation.attributeName === 'style') {
            // 检查水印的 display 属性是否被设置为 none
            if (getComputedStyle(watermarkElement).display === 'none') {
                // 如果水印被隐藏,重新显示水印
                watermarkElement.style.display = 'block';
            }
        }
    });
});

// 配置 MutationObserver
const config = { attributes: true, subtree: true, attributeFilter: ['style'] };

// 开始观察目标节点
observer.observe(document.body, config);

说明

  1. 目标节点 :在代码中,watermarkElement 代表水印元素。请确保选择器正确。
  2. MutationObserver 实例 :观察属性变化 (attributes) 和特定的属性 style
  3. 属性变化检测 :在回调函数中,使用 getComputedStyle 检查 display 属性的值。如果水印被设置为 display: none,则将其恢复为 display: block

react 中怎么实现下拉菜单场景,要求点击区域外能关闭下拉组件

涉及以下几个步骤:

  1. 创建下拉菜单组件
  2. 监听点击事件
  3. 判断点击事件是否在下拉菜单外部

步骤说明

1. 创建下拉菜单组件

复制代码
import React, { useState, useRef, useEffect } from 'react';

const Dropdown = () => {
  const [isOpen, setIsOpen] = useState(false);
  const dropdownRef = useRef(null);

  const toggleDropdown = () => {
    setIsOpen(!isOpen);
  };

  // 监听点击事件
  useEffect(() => {
    const handleClickOutside = (event) => {
      if (dropdownRef.current && !dropdownRef.current.contains(event.target)) {
        setIsOpen(false);
      }
    };

    document.addEventListener('mousedown', handleClickOutside);
    return () => {
      document.removeEventListener('mousedown', handleClickOutside);
    };
  }, []);

  return (
    <div ref={dropdownRef}>
      <button onClick={toggleDropdown}>
        Toggle Dropdown
      </button>
      {isOpen && (
        <div className="dropdown-menu">
          <p>Menu Item 1</p>
          <p>Menu Item 2</p>
          <p>Menu Item 3</p>
        </div>
      )}
    </div>
  );
};

export default Dropdown;

2. 监听点击事件

  • useEffect 钩子中,添加一个全局的 mousedown 事件监听器,用于检测点击是否发生在下拉菜单外部。
  • handleClickOutside 函数会检查点击事件的目标是否在下拉菜单外部,如果是则关闭下拉菜单。

3. 判断点击事件是否在下拉菜单外部

  • 使用 useRef 钩子获取下拉菜单组件的引用(dropdownRef)。
  • handleClickOutside 函数中使用 dropdownRef.current.contains(event.target) 来判断点击的目标是否在下拉菜单的 DOM 结构内。

注意事项

  • 确保 ref 正确设置在包含下拉菜单的最外层容器上。
  • 在组件卸载时移除事件监听器,以避免内存泄漏。
  • 在大型应用中,可以考虑使用更复杂的事件处理库或工具来处理全局点击事件。

通过上述步骤,你可以实现点击区域外关闭下拉菜单的功能。


如何搭建一套灰度系统?

搭建一套灰度发布系统涉及多个方面的技术和流程,目的是在发布新版本时,能够逐步、部分地将新功能或改动推送给用户,以降低发布的风险。

以下是搭建的一般步骤和要点:

1. 明确灰度发布的需求和目标

  • 降低风险:避免一次性发布导致的全局性错误影响所有用户。
  • 收集反馈:逐步推出新功能,观察用户行为和收集反馈,及时进行调整。
  • 验证性能和稳定性:在小范围内测试新版本的性能和稳定性。

2. 架构设计

  • 服务分层:将应用分成多个服务或模块,每个服务独立发布,方便单独进行灰度发布。
  • 支持多版本并存:确保系统能同时运行多个版本的新旧功能,以便不同用户访问到不同版本。

3. 用户分组策略

  • 按用户分组:根据用户的特征(如地域、设备类型、用户等级等)或随机分配,决定哪些用户先接收到新版本。
  • 流量分配:通过配置逐步增加新版本的流量比例。例如,先让 5% 的用户使用新版本,然后观察反馈,逐步增加到 10%、20% 等。

4. 灰度发布系统的功能

  • 流量调度:能够动态调整不同版本的流量占比,通常由一个流量调度模块控制。
  • 用户分组管理:可以管理用户分组,并将用户分配到对应的版本。
  • 监控和日志收集:实时监控系统的性能指标(如请求响应时间、错误率、资源使用情况等),并收集用户行为日志。
  • 自动回滚:当检测到新版本出现问题时,系统可以自动回滚到稳定的旧版本。
  • A/B 测试:结合 A/B 测试工具,进行功能对比测试,进一步细化灰度策略。

5. 工具与技术栈

  • 负载均衡器:使用负载均衡器(如 Nginx、HAProxy)进行流量分配,决定哪些请求应该分配到新版本。
  • 微服务架构:使用 Kubernetes、Docker 等技术支持微服务架构,方便独立部署和灰度发布。
  • CI/CD 工具:结合 Jenkins、GitLab CI/CD、GitHub Actions 等工具进行自动化构建、测试和部署。
  • 监控系统:使用 Prometheus、Grafana、ELK 等工具进行系统监控和日志分析。
  • A/B 测试工具:如 Google Optimize、Optimizely,结合灰度发布进行用户体验的差异化测试。

6. 实施灰度发布

  • 部署基础设施:搭建好灰度发布的基础设施,包括流量调度、监控、日志收集等模块。
  • 制定灰度策略:根据业务需求,制定详细的灰度发布策略,包括用户分组、流量占比、回滚条件等。
  • 逐步推进:从小规模用户开始,逐步扩大灰度范围,并观察各项指标以确保系统稳定。
  • 持续监控与反馈:在整个灰度发布期间持续监控系统表现,收集用户反馈,及时作出调整或回滚。

7. 回滚策略

  • 快速回滚机制:在发布过程中出现问题时,灰度系统应能快速回滚到上一稳定版本。
  • 保持数据一致性:确保新版本的数据格式与旧版本兼容,回滚时不会导致数据丢失或不一致。

8. 总结与优化

  • 记录发布过程:详细记录每次灰度发布的过程、问题和解决方案,为后续发布积累经验。
  • 优化灰度系统:根据发布过程中的经验,不断优化灰度系统,提升系统的健壮性和可操作性。

React 如何实现 vue 中 keep-alive 的功能?

在 React 中实现类似于 Vue 中 keep-alive 的功能,可以使用组件状态和 React 的生命周期方法来控制组件的挂载和卸载。

以下是一种实现方式:

1. 使用状态管理组件

创建一个 KeepAlive 组件,用于存储和管理被"缓存"的组件。

复制代码
import React, { useState } from 'react';

// KeepAlive 组件
const KeepAlive = ({ children, name }) => {
  const [cache, setCache] = useState({});

  // 保存组件
  const saveCache = () => {
    setCache((prev) => ({
      ...prev,
      [name]: children,
    }));
  };

  // 恢复组件
  const getCachedComponent = () => {
    return cache[name] || children;
  };

  // 组件挂载时保存
  React.useEffect(() => {
    saveCache();
  }, [children]);

  return <>{getCachedComponent()}</>;
};

// 示例用法
const App = () => {
  const [activeComponent, setActiveComponent] = useState('ComponentA');

  return (
    <div>
      <button onClick={() => setActiveComponent('ComponentA')}>Component A</button>
      <button onClick={() => setActiveComponent('ComponentB')}>Component B</button>

      <KeepAlive name={activeComponent}>
        {activeComponent === 'ComponentA' ? <ComponentA /> : <ComponentB />}
      </KeepAlive>
    </div>
  );
};

const ComponentA = () => <div>Component A</div>;
const ComponentB = () => <div>Component B</div>;

export default App;

2. 实现逻辑

  • 状态管理KeepAlive 组件使用一个状态 cache 来存储被缓存的组件。
  • 保存和恢复:在组件挂载时保存当前子组件到缓存中;每次渲染时,检查缓存并返回之前的组件,避免重新渲染。
  • 使用示例 :通过按钮切换 activeComponent 的状态,展示不同的组件,同时保留它们的状态。

如何监控前端页面的崩溃?

监控前端页面的崩溃通常涉及捕获和报告 JavaScript 错误、性能问题以及页面状态。

以下是一些常见的方法和工具来实现这些监控:

1. 使用 window.onerror

  • 定义window.onerror 是一个全局事件处理程序,用于捕获 JavaScript 执行时的错误。

  • 实现

    window.onerror = function(message, source, lineno, colno, error) {
    // 处理错误信息,例如发送到服务器
    console.error('Error captured:', { message, source, lineno, colno, error });
    // 可以通过 HTTP 请求将错误信息发送到日志服务器
    };

2. 使用 window.addEventListener('unhandledrejection')

  • 定义:捕获未处理的 Promise 拒绝(rejections)。

  • 实现

    window.addEventListener('unhandledrejection', function(event) {
    // 处理 Promise 拒绝,例如发送到服务器
    console.error('Unhandled rejection:', event.reason);
    // 可以通过 HTTP 请求将错误信息发送到日志服务器
    });

3. 使用 try...catch

  • 定义 :在可能出现错误的代码块中使用 try...catch 捕获异常。

  • 实现

    try {
    // 可能会抛出错误的代码
    } catch (error) {
    // 处理错误,例如发送到服务器
    console.error('Caught error:', error);
    // 可以通过 HTTP 请求将错误信息发送到日志服务器
    }

4. 使用错误监控工具

  • Sentry:捕获前端错误并提供详细的堆栈跟踪和上下文信息。
  • New Relic:提供全面的前端性能监控和错误捕获。
  • Rollbar:实时捕获和报告 JavaScript 错误和异常。
  • LogRocket:记录用户会话并捕获前端错误。

5. 性能监控和日志

  • 浏览器开发者工具:使用 DevTools 监控网络请求、性能和资源使用。
  • Web Vitals:跟踪核心 Web Vitals 指标(如 LCP、FID、CLS)来发现性能问题。
  • Custom Logging:自定义日志记录功能,将应用程序状态和错误发送到日志服务器。

6. 网络请求监控

  • 自定义错误日志:在 JavaScript 错误处理程序中,通过 HTTP 请求将错误信息发送到远程服务器进行存储和分析。
  • 日志服务器:维护一个后端日志服务器,用于存储和分析前端错误和崩溃数据。

以上丸整:https://github.com/encode-studio-fe/natural_traffic/wiki/scan_material5

因为篇幅原因,只展示部分内容了,全部写出来太长了,欢迎沟通讨论,以上内容都有对应答案

祝大家求职顺利

相关推荐
IT_陈寒2 小时前
Redis 高并发实战:我从 5000QPS 优化到 5W+ 的7个核心策略
前端·人工智能·后端
绝无仅有2 小时前
某东电商平台的MySQL面试知识点分析
后端·面试·架构
vortex52 小时前
ASP vs ASP.NET vs ASP.NET Core:三代微软 Web 技术核心区别解析
前端·microsoft·asp.net
Apifox2 小时前
如何在 Apifox 中使用「模块」合理地组织接口
前端·后端·测试
冰暮流星3 小时前
css之flex属性
前端·css
无心水3 小时前
【中间件:Redis】1、Redis面试核心:线程模型深度解析(6.0前后变化+工作流程)
数据库·redis·面试·redis面试·redis原理·redis线程模型·后端技术
若安程序开发3 小时前
WEBweb前端OPPO手机商城网站项目
前端·智能手机
范德萨_3 小时前
JavaScript 实用技巧(总结)
开发语言·前端·javascript
李志2783 小时前
初识预加载
javascript