又一次百度面试

最近又参加了百度电商部门的面试,在此进行回顾和整理,注意添加"(延伸)"字样的为整理过程中本人进行延伸的,并非面试官提问问题,各位读者注意甄别~~

一面

  1. 实现快速排序:答案参考我的这篇文章

  2. 实现Promise.all:答案参考我的这篇文章

  3. 项目内容询问:项目因人而异,这里就不过多赘述了~

  4. ReactVue 的理解,各自的使用场景以及差异:答案参考我的这篇文章

  5. 什么场景下的项目比较倾向于使用React答案参考我的这篇文章

  6. 页面从输入url到展示经过哪些过程:答案参考我的这篇文章

  7. 谈一下对JS的原型和原型链的理解:答案参考我的这篇文章

  8. 防抖和节流,以及应用场景,以及实现:答案参考我的这篇文章

二面

  1. 自我介绍
  2. 在当前团队中的角色
  3. 针对项目询问

Echarts的底层是用什么做的有了解过吗

ECharts(百度ECharts)是一个基于JavaScript的开源可视化库,用于创建丰富的交互式数据图表。它的底层实现主要依赖于Canvas和SVG两种技术。

  1. Canvas(画布): ECharts使用HTML5的Canvas标签来进行绘图。Canvas是一个通过JavaScript脚本来绘制图形的HTML元素,提供了一种在网页上绘制图形的方式。ECharts利用Canvas绘制图表,这使得它能够高效地处理大量的数据并在不同平台上实现良好的性能。

  2. SVG(可缩放矢量图形): 另外,ECharts还可以选择使用SVG进行图形渲染。SVG是一种用于描述二维矢量图形的XML语言,它可以在不失真的情况下缩放,适合用于创建可伸缩的图表。通过在SVG中定义图形元素和属性,ECharts可以实现丰富的图表效果。

总体而言,ECharts的底层使用Canvas和SVG这两种技术,具体的选择取决于图表的类型和配置。Canvas 适用于处理大量数据点和像素级操作,而 SVG 则适用于需要灵活路径和交互性的情况。 ECharts的设计灵活,通过选择不同的渲染方式,可以在不同的场景中实现更好的性能和效果。

Canvas和SVG有什么区别(延伸)

Canvas和SVG(可缩放矢量图形)是两种用于在Web上绘制图形的不同技术,它们有一些关键的区别:

  1. 绘图方式:

    • Canvas: 使用JavaScript通过绘制像素来创建图形。Canvas提供了一个类似于画布的区域,你可以在上面绘制图形,但它并不保留图形的具体信息,只是绘制了最终的结果。因此,Canvas适合处理实时生成的图形,如动画或大规模数据的渲染。
    • SVG: 使用XML来描述图形,它本质上是一种基于文档对象模型(DOM)的图形表示方法。SVG创建的图形是具有结构的矢量图形,每个图形元素都是一个独立的DOM元素,可以通过JavaScript或CSS进行访问和修改。这使得SVG适合处理需要交互性和可访问性的图形。
  2. 性能:

    • Canvas: 由于Canvas绘制的是像素,它在处理大量图形或像素级操作时性能较好。适合用于图形密集型的场景,如游戏或图像处理。
    • SVG: 在处理大量图形时,特别是复杂的图形,SVG的性能可能相对较差。但对于相对简单的图形和需要缩放的图形,SVG通常更为合适。
  3. 交互性:

    • Canvas: 因为Canvas只是绘制最终的图形,它对于图形的交互性处理相对较复杂。你需要手动处理用户输入(如鼠标点击事件)并确定点击的是画布上的哪个区域。
    • SVG: SVG元素是真实的DOM元素,因此可以直接添加事件监听器,更容易实现交互性。你可以为SVG图形添加事件,如点击、悬停等,以便更容易地响应用户交互。
  4. 可访问性:

    • Canvas: 由于Canvas只是像素的集合,它的内容对于屏幕阅读器等无障碍技术来说不够友好。
    • SVG: 由于SVG是基于DOM的,可以更容易地实现可访问性,使得图形对于残障人士更具有可用性。

总体而言,选择Canvas还是SVG取决于具体的应用场景和需求。Canvas适合处理复杂的图像和动画,而SVG适合需要交互性和可访问性的图形。在一些情况下,两者也可以结合使用,根据需求选择合适的技术。

Canvas如何实现交互(延伸)

Canvas也可以实现交互,但相对于SVG,它的交互性实现相对更为复杂,因为Canvas只是绘制最终的图形,而不保留图形的结构信息。在Canvas上实现交互需要手动处理用户输入事件,并编写代码来判断用户交互发生在画布的哪个区域。

对于Canvas,你可以通过以下方式实现一些基本的交互:

  1. 事件监听: 你可以使用JavaScript为Canvas元素添加事件监听器,如鼠标点击事件(click)、鼠标移动事件(mousemove)等。

  2. 坐标判断: 在事件监听器中,你需要编写代码来判断用户的交互发生在画布上的哪个位置。这通常涉及到将鼠标事件的坐标转换为Canvas坐标系内的坐标。

  3. 绘制更新: 在用户与Canvas进行交互时,你可能需要重新绘制Canvas上的图形,以实现一些动态效果。

虽然Canvas可以通过编写复杂的JavaScript代码来实现各种交互效果,但相对而言,SVG更容易实现这些效果,因为SVG本身就是基于DOM的,每个图形元素都是独立的DOM元素,可以直接添加事件监听器。

总的来说,如果你的应用场景需要较为复杂的交互效果,而且对于可访问性有一定要求,SVG可能是更好的选择。但在一些简单的应用场景下,Canvas仍然可以实现一些基本的交互。

如何手动实现折线图,输入是各个点的坐标

使用Canvas进行绘制,过程中用到的api

  1. getContext:上下文对象,用来进行绘制图形,操作像素
  2. beginPath:清空当前路径,以便绘制新的路径
  3. moveTo:移动当前绘图位置到指定坐标,而不划线
  4. lineTo:从当前位置绘制一条线到指定点
  5. stroke:绘制路径轮廓,在此之前可以通过strokeStyle设置轮廓颜色,lineWidth设置轮廓宽度,什么都不设置的话默认棕色直线。
  6. fillText:绘制填充文本,对应参数(文本字符串,绘制开始的x,绘制开始的y,绘制文本的最大宽度超过就换行)

Canvas上绘制路径是一个两步过程:

  1. 绘制路径: 使用 moveTolineTo 等路径操作方法定义路径。
  2. 描边或填充路径: 使用 ctx.stroke() 描边路径,或者使用 ctx.fill() 填充路径。

如果只执行第一步,即定义路径而不调用 ctx.stroke()ctx.fill(),则路径不会在Canvas上实际显示。只有在调用了 ctx.stroke()ctx.fill() 时,Canvas 才会根据路径的描边或填充样式将路径绘制出来。

注意:(0,0)位于canvas画布的左上角,而不是左下角。同时绘制折线图时,如果存在边距,记得减掉

html 复制代码
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>手动实现折线图</title>
    <style>
      canvas {
        border: 1px solid #ccc;
      }
    </style>
  </head>
  <body>
    <canvas id="lineChartCanvas" width="400" height="300"></canvas>

    <script>
      // 输入坐标数据
      const coordinates = [
        { x: 50, y: 250 },
        { x: 70, y: 200 },
        { x: 120, y: 150 },
        { x: 220, y: 100 },
        { x: 250, y: 50 },
      ];

      // 获取 Canvas 元素和上下文
      const canvas = document.getElementById('lineChartCanvas');
      const ctx = canvas.getContext('2d'); // 获取上下文对象,可以用来绘制图形,访问像素

      // 绘制坐标轴
      function drawAxis() {
        // X 轴
        ctx.beginPath();
        ctx.moveTo(30, canvas.height - 30);
        ctx.lineTo(canvas.width - 30, canvas.height - 30);
        ctx.stroke();

        // Y 轴
        ctx.beginPath();
        ctx.moveTo(30, canvas.height - 30);
        ctx.lineTo(30, 30);
        ctx.stroke();
      }

      // 标注坐标刻度
      function drawScale() {
        // X 轴刻度
        for (let i = 0; i < coordinates.length; i++) {
          ctx.beginPath();
          ctx.moveTo(30 + i * 50, canvas.height - 30);
          ctx.lineTo(30 + i * 50, canvas.height - 25);
          ctx.stroke();

          // 标注 X 轴坐标值
          ctx.fillText(coordinates[i].x, 30 + i * 50 - 10, canvas.height - 10);
        }

        // Y 轴刻度
        for (let i = 0; i <= 5; i++) {
          ctx.beginPath();
          ctx.moveTo(30, canvas.height - 30 - i * 50);
          ctx.lineTo(35, canvas.height - 30 - i * 50);
          ctx.stroke();

          // 标注 Y 轴坐标值
          ctx.fillText(50 * i, 5, canvas.height - 30 - i * 50 + 5);
        }
      }

      // 绘制折线图
      function drawLineChart(coordinates) {
        ctx.beginPath();
        ctx.moveTo(coordinates[0].x, canvas.height - coordinates[0].y);

        for (let i = 1; i < coordinates.length; i++) {
          ctx.lineTo(coordinates[i].x, canvas.height - coordinates[i].y);
        }

        ctx.strokeStyle = 'blue';
        ctx.lineWidth = 2;
        ctx.stroke();
      }

      // 主绘制函数
      function draw() {
        drawAxis();
        drawScale();
        drawLineChart(coordinates);
      }

      // 调用主绘制函数
      draw();
    </script>
  </body>
</html>

加入购物车动画实现如何去做的

通过parent水平的匀速运动和box纵向的贝塞尔曲线结合实现的。

html 复制代码
<div id="parent">
    <div id="box"></div>
</div>

转盘活动:一张图片,点击开始之后旋转并向后端请求结果,根据结果将图片停止在某一个区域,如何去做(整体方案)

  1. conic-gradient 是 CSS 中的一个渐变函数,用于创建圆锥渐变。它允许你在一个元素的背景中创建从一个颜色到另一个颜色的平滑渐变,沿着元素的边缘形成一个锥形。
  2. 获取后端结果后更新animation属性,避免原来动画不停止
  3. animationend监听动画结束函数,实现最后结果角度的转变
html 复制代码
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <style>
      #wheel {
        width: 300px;
        height: 300px;
        /* 定义6个区域的颜色 */
        background: conic-gradient(
          #ff6347 0deg 60deg,
           #ffd700 60deg 120deg,
          #98fb98 120deg 180deg,
          #4169e1 180deg 240deg,
          #ff69b4 240deg 300deg,
          #ff8c00 300deg 360deg 
        );
        border-radius: 50%;
        position: relative;
        overflow: hidden;
      }
      .startRotate {
        animation: rotateWheel 5s cubic-bezier(0.2, 0.4, 0.8, 0.6);
      }

      @keyframes rotateWheel {
        0% {
          transform: rotate(0deg);
        }
        100% {
          transform: rotate(1800deg); /* 5圈,根据需要调整 */
        }
      }

      #arrow {
        width: 10px;
        height: 80px;
        background-color: red;
        position: absolute;
        top: 50%;
        left: 50%;
        transform: translate(-50%, -50%) rotate(0deg);
        transform-origin: bottom;
        cursor: pointer;
      }
    </style>
  </head>
  <body>
    <div id="wheel">
      <div id="arrow"></div>
    </div>

    <script>
      const wheel = document.getElementById('wheel');
      const arrow = document.getElementById('arrow');

      arrow.addEventListener('click', () => {
        // 开启动画
        wheel.classList.add('startRotate');

        // 模拟后端请求,实际情况中应该使用实际的后端API
        setTimeout(() => {
          wheel.classList.remove('startRotate');
          const randomDegrees = 80;

          // 计算停止时需要旋转的总度数,这里设置 1 圈,根据需要调整
          const totalRotation = 1 + randomDegrees;

          // 设置动画
          wheel.style.animation = `rotateWheel 5s cubic-bezier(0.2, 0.4, 0.8, 0.6)`;

          // 在动画结束时,使用 JavaScript 设置停止时的旋转角度
          wheel.addEventListener(
            'animationend',
            () => {
              wheel.style.animation = ''; // 清除动画
              wheel.style.transition = 'transform 1s ease-out'; // 添加过渡效果
              wheel.style.transform = `rotate(${totalRotation}deg)`;
            },
            { once: true }
          ); // 只监听一次 animationend 事件
        }, 2000);
      });
    </script>
  </body>
</html>

小程序打电话功能,从我们调用API到实现过程中经历了什么

当小程序调用 wx.makePhoneCall API 时,微信客户端会接收到这个请求。微信客户端内置了相关的功能,可以处理拨打电话的请求。

  1. 调用 wx.makePhoneCall API
  2. 微信客户端处理:当小程序调用 wx.makePhoneCall API 时,微信客户端会接收到这个请求。微信客户端内置了相关的功能,可以处理拨打电话的请求。
  3. 用户授权: 在调用 wx.makePhoneCall API 时,微信客户端会弹出一个确认框,询问用户是否同意拨打电话。用户点击同意后,微信客户端才会执行实际的拨打电话操作。这是微信小程序的一种安全机制,确保用户同意进行电话呼叫。
  4. 小程序权限配置:在小程序的配置文件(如 app.json)中,配置"scope.phoneNumber"以确保用户授权后可以顺利调起打电话功能
  5. 电话呼叫

为什么h5不能实现打电话功能,或者h5要实现打电话功能,我们如何做

通过 H5 页面调用打电话功能被限制的主要原因包括:

  1. 安全性和隐私: 直接通过浏览器的 H5 页面调用电话功能可能存在滥用的风险。如果浏览器允许在 H5 页面中执行这样的操作,那么恶意网站可能会滥用这一功能,自动拨打电话,对用户造成骚扰。

  2. 用户体验和交互: 打电话是一种涉及到用户设备的敏感操作,用户通常希望有明确的用户交互触发。直接在 H5 页面中实现拨打电话功能可能会破坏用户体验,因为它绕过了用户的明示意愿。

尽管直接通过 H5 页面无法实现拨打电话的功能,但可以通过其他方式实现:

  • 使用电话链接: 在 H5 页面中,可以使用 <a> 标签的 tel 协议创建电话链接,让用户点击链接后由系统默认电话应用进行拨打。例如:

    html 复制代码
    <a href="tel:+123456789">拨打电话</a>

    用户点击这个链接后,系统会调起默认的电话应用,并自动填充给定的电话号码。

  • JavaScript Bridge: 在混合应用中,可以使用 JavaScript 桥接技术,通过与原生代码通信,实现调用拨打电话的原生功能。这需要在原生应用中提供一个接口,供 H5 页面调用。

总体而言,浏览器出于安全和用户体验的考虑,限制了直接在 H5 页面中调用一些敏感的设备功能,如拨打电话。

h5实现打电话功能

使用电话链接

在 H5 页面中,可以使用 <a> 标签的 tel 协议创建电话链接,让用户点击链接后由系统默认电话应用进行拨打。例如:

html 复制代码
<a href="tel:+123456789">拨打电话</a>

用户点击这个链接后,系统会调起默认的电话应用,并自动填充给定的电话号码。

借助jsBridge

JavaScript Bridge(简称 jsBridge)是一种用于在 Web 页面中的 JavaScript 代码与原生代码之间进行通信的技术。在移动应用开发中,常常会使用 WebView 来加载 Web 页面,而 JavaScript Bridge 则提供了一种机制,允许 JavaScript 代码与嵌入 WebView 的原生代码进行双向通信。

通常,这种通信是通过在 JavaScript 和原生代码之间建立桥梁,使它们能够调用对方的方法。这样,Web 开发人员可以利用 JavaScript 调用原生的功能,而原生开发人员也可以通过调用 JavaScript 函数来与 Web 页面进行交互。

在 Android 和 iOS 上,提供这种桥接功能的类库有很多,比如:

  1. WebViewJavascriptBridge: 这是一个常用的 JavaScript Bridge 库,它提供了一个简单的 API,允许 JavaScript 代码和原生代码之间相互调用。

  2. WKWebView JavaScript Bridge(iOS): 对于使用 iOS 的 WKWebView 的情况,可以使用专门为 WKWebView 设计的 JavaScript Bridge 库,例如 WebViewJavascriptBridge 的 iOS 版本或者其他类似的库。

  3. js2native-loader(Android): 在 Android 中,js2native-loader 是一个用于实现 JavaScript 与原生代码通信的库。

使用 JavaScript Bridge 的一些常见场景包括:

  • 调用原生功能: 通过 JavaScript 调用原生代码提供的功能,例如打电话、获取设备信息、分享等。

  • 在原生代码中调用 JavaScript 函数: 原生代码可以触发 WebView 中的 JavaScript 函数,实现与 Web 页面的交互。

  • 传递数据: 可以在 JavaScript 和原生代码之间传递复杂的数据结构,实现更复杂的交互。

在实际使用时,需要注意安全性和良好的设计实践,以确保在 JavaScript 和原生代码之间的通信中不会引入潜在的安全风险。

css3新的特性

篇幅过长,总结到了一篇新的文章

如何实现一个图片的翻转效果

  1. 通过scale(-1)实现翻转:

    html 复制代码
    <div>这里是元素</div>
    <div style="transform: scaleX(-1)">这里是元素</div>
  2. rotate3d实现翻转:

    html 复制代码
    <div>这里是元素</div>
    <div style="transform: rotate3d(0, 1, 0, 180deg)">这里是元素</div>

语义化的好处

答案看我的这篇文章

less中常用的功能

页面双列文本,每个占百分之50,超出显示省略号,如何实现

html 复制代码
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <style>
      .container {
        display: flex;
      }

      .column {
        width:50%;
        margin: 0 5px; 可以添加一些间距
      }

       /* 省略号要添加在文本元素上 */
      p{
        overflow: hidden;
        white-space: nowrap;
        text-overflow: ellipsis;
      }
    </style>
  </head>
  <body>
    <div class="container">
      <div class="column">
        <p>
          这是左侧列的文本内容。这是左侧列的文本内容。这是左侧列的文本内容。
        </p>
      </div>
      <div class="column">
        <p>
          这是右侧列的文本内容。这是右侧列的文本内容。这是右侧列的文本内容。
        </p>
      </div>
    </div>
  </body>
</html>

父元素下存在多个子元素,子元素最少展示两行,最多展示四行,两行的结尾存在展开按钮,四行的结尾存在收起按钮

基本思路如下:

  1. 判断两行以内是否可以放下,如果可以那就不需要添加"展开"

  2. 两行放不下:找到第二行最后一个元素,添加"展开",并监听点击事件

  3. 展开后判断是不是四行以内放的下:

    1. 放得下:直接在最后一个元素添加"收起",并监听点击事件
    2. 放不下:找到第四行最后一个元素添加"收起",并监听点击事件

计算两行或者四行是否能放下的思路:同一行元素getBoundingClientRect返回的top是一样的,通过map进行记录,size超过2代表两行放不下。同时也可以找到第二行的最后一个元素。

html 复制代码
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Get Second Row Last Element</title>
    <style>
      .parent {
        display: flex;
        flex-wrap: wrap;
        border: 2px solid red;
      }

      .child {
        border: 1px solid #ccc;
        margin: 5px;
        padding: 10px;
        box-sizing: border-box;
      }

      .open::after {
        content: '展开';
        display: inline;
      }

      .close::after {
        content: '收起';
      }
    </style>
  </head>
  <body>
    <div id="container" class="">
      <div class="parent">
        <div class="child">111111</div>
        <div class="child">2</div>
        <div class="child">3</div>
        <div class="child">4</div>
        <div class="child">5</div>
        <div class="child">6</div>
        <div class="child">7</div>
        <div class="child">8</div>
        <div class="child">9</div>
        <div class="child">10</div>
        <div class="child">11</div>
        <div class="child">12</div>
        <div class="child">13</div>
        <div class="child">14</div>
        <div class="child">15</div>
        <div class="child">16</div>
        <div class="child">17</div>
        <div class="child">18</div>
        <div class="child">19</div>
        <div class="child">20</div>
        <div class="child">21</div>
        <div class="child">22</div>
        <div class="child">23</div>
        <div class="child">24</div>
        <div class="child">25</div>
        <div class="child">26</div>
        <div class="child">27</div>
        <div class="child">28</div>
        <div class="child">29</div>
        <div class="child">30</div>
        <div class="child">31</div>
        <div class="child">32</div>
        <div class="child">33</div>
        <div class="child">34</div>
        <div class="child">35</div>
        <div class="child">36</div>
        <div class="child">37</div>
        <div class="child">38</div>
        <div class="child">39</div>
        <div class="child">40</div>
        <div class="child">41</div>
        <div class="child">42</div>
        <div class="child">last</div>
      </div>
    </div>

    <script>
      document.addEventListener('DOMContentLoaded', function () {
        const container = document.querySelector('#container');
        const parent = document.querySelector('.parent');
        const children = parent.children;
        const lineHeight = children[0].getBoundingClientRect().height; //border以内部分的高度
        const towLineHeight = lineHeight * 2 + 10 * 2;
        const fourLineHeight = lineHeight * 4 + 10 * 4;
        let openElement;
        let closeElement;

        // 收起部分逻辑
        function showFourLine() {
          const { height: parentHeight } = parent.getBoundingClientRect();
          console.log(parentHeight, fourLineHeight);
          //-4是减去border
          if (parentHeight - 4 <= fourLineHeight) {
            // 全部元素没有超过四行,直接将"收起"放到最后一个元素即可
            closeElement = children[children.length - 1];
          } else {
            // 只展示4行,超过部分不展示
            parent.style = `height:${fourLineHeight}px;overflow:hidden`;

            // 全部元素超过四行了,找到四行最后一个元素
            let map = new Map();
            for (let i = 0; i < children.length; i++) {
              const { top } = children[i].getBoundingClientRect();
              map.set(top, i); //记录每一行的最后一个元素
              if (map.size > 4) {
                closeElement = children[i - 1];
                break;
              }
            }
          }
          function closeCb(e) {
            closeElement.classList.remove('close');
            console.log('收起');
            closeElement.removeEventListener('click', closeCb);
            showTwoLine(); //重新展开两行
          }
          if (!closeElement) {
            console.log('四行显示正好');
            return;
          }
          closeElement.classList.add('close');
          closeElement.addEventListener('click', closeCb);
        }

        // 添加展开样式
        function addOpenBtn() {
          openElement = null;
          // 找到第二行的最后一个元素,也就是当前可见的最后一个元素
          let map = new Map();
          for (let i = 0; i < children.length; i++) {
            const { top } = children[i].getBoundingClientRect();
            map.set(top, i); //记录每一行的最后一个元素
            if (map.size > 2) {
              openElement = children[i - 2];
              console.log(openElement);
              break;
            }
          }
          console.log(openElement);
          if (!openElement) {
            console.log('没有超过两行');
            return;
          }
          // 给最后一个元素添加"展开":也可以通过插入展开元素到18和19之间实现
          openElement.classList.add('open');

          function openCb(e) {
            parent.style = '';
            openElement.classList.remove('open');
            openElement.removeEventListener('click', openCb);

            // 展开四行
            showFourLine();
          }
          // 添加点击"展开"事件:显示全部元素,并且移除"展开"按钮
          openElement.addEventListener('click', openCb);
        }

        // 展开部分逻辑
        function showTwoLine() {
          // 将父元素的高度设置为towLineHeight,超出部分隐藏
          parent.style = `height:${towLineHeight}px;overflow:hidden`;
          addOpenBtn();
        }

        showTwoLine();
      });
    </script>
  </body>
</html>

页面上有三张图,比如"新年好",三张图片加载完成后再统一展示

  1. 首先将图片隐藏
  2. 监听图片load事件,当图片加载完时触发
  3. 每张图片load后判断是不是3张完全加载完成,如果完全加载完再展示图片
html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Load and Display Images</title>
  <style>
    .hidden {
      display: none;
    }
  </style>
</head>
<body>

<img id="image1" class="hidden" src="image1.jpg" alt="Image 1">
<img id="image2" class="hidden" src="image2.jpg" alt="Image 2">
<img id="image3" class="hidden" src="image3.jpg" alt="Image 3">

<script>
  // 获取图片元素
  const image1 = document.getElementById('image1');
  const image2 = document.getElementById('image2');
  const image3 = document.getElementById('image3');

  // 添加图片加载完成的事件监听器
  image1.addEventListener('load', checkAllImagesLoaded);
  image2.addEventListener('load', checkAllImagesLoaded);
  image3.addEventListener('load', checkAllImagesLoaded);

  // 显示所有图片的函数
  function checkAllImagesLoaded() {
    // 检查所有图片是否加载完成
    if (
      image1.complete &&
      image2.complete &&
      image3.complete
    ) {
      // 所有图片都加载完成后执行的操作
      displayImages();
    }
  }

  // 显示所有图片的函数
  function displayImages() {
    // 移除隐藏样式,显示图片
    image1.classList.remove('hidden');
    image2.classList.remove('hidden');
    image3.classList.remove('hidden');
  }
</script>

</body>
</html>

按钮点击后生成文本:字符长度为5~5000,由小写字母和数字组成。将文本插入到页面后,获取文本的高度

html 复制代码
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Generate and Measure Text Height</title>
    <style>
      #output {
        margin-top: 10px;
        width: 200px;
        word-wrap: break-word;
      }
    </style>
  </head>
  <body>
    <button id="generateButton">Generate Text</button>
    <div id="output"></div>

    <script>
      document
        .getElementById('generateButton')
        .addEventListener('click', function () {
          // 生成长度为5~5000的随机字符串
          const randomText = generateRandomText(
            5 + Math.floor(Math.random() * 4996)
          );

          // 插入文本到页面
          const outputDiv = document.getElementById('output');
          outputDiv.textContent = randomText;

          // 获取插入文本的高度
          const textHeight = outputDiv.offsetHeight;
          console.log('Text Height:', textHeight);
        });

      function generateRandomText(length) {
        const characters = 'abcdefghijklmnopqrstuvwxyz0123456789';
        let result = '';
        for (let i = 0; i < length; i++) {
          result += characters.charAt(
            Math.floor(Math.random() * characters.length)
          );
        }
        return result;
      }
    </script>
  </body>
</html>

字符长度为5~5000 这个文本如何生成

js 复制代码
      function generateRandomText(length) {
        const characters = 'abcdefghijklmnopqrstuvwxyz0123456789';
        let result = '';
        for (let i = 0; i < length; i++) {
          result += characters.charAt(
            Math.floor(Math.random() * characters.length)
          );
        }
        return result;
      }
      
          // 生成长度为5~5000的随机字符串
          const randomText = generateRandomText(
            5 + Math.floor(Math.random() * 4996)
          );

原生和React和vue获取元素高度有什么区别

原生获取元素尺寸:

  1. clientHeight: 它是元素内部的高度(以像素为单位),包含内边距,但不包括边框、外边距和水平滚动条(如果存在),也是一个四舍五入的整数。
  2. offsetHeight: 包含该元素的垂直内边距和边框,且是一个整数(四舍五入)。
  3. getBoundingClientRect()返回的height: 包含了 paddingborder-width 的,而不仅仅是内容部分的宽度和高度。

React和vue中通过ref获取节点,之后获取高度(当时想到了,没敢说~)

实现倒计时01:01:01组件实现

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

const CountdownTimer = ({ initialMilliseconds }) => {
  const [milliseconds, setMilliseconds] = useState(initialMilliseconds);

  useEffect(() => {
    const intervalId = setInterval(() => {
      setMilliseconds(prevMilliseconds => {
        if (prevMilliseconds <= 0) {
          clearInterval(intervalId);
          return 0;
        }
        return prevMilliseconds - 1000;
      });
    }, 1000);

    return () => clearInterval(intervalId);
  }, [milliseconds]);

  const formatTime = (time) => {
    const hours = Math.floor(time / 3600000);
    const minutes = Math.floor((time % 3600000) / 60000);
    const seconds = Math.floor((time % 60000) / 1000);

    const formatNumber = (num) => (num < 10 ? `0${num}` : num);

    return `${formatNumber(hours)}:${formatNumber(minutes)}:${formatNumber(seconds)}`;
  };

  return (
    <div>
      <h2>Countdown Timer</h2>
      <div>{formatTime(milliseconds)}</div>
    </div>
  );
};

export default CountdownTimer;

// 使用
<CountdownTimer initialMilliseconds={1000 * 60 * 60} />

git 如何修改commit信息

使用git commit --amend

如果已经推送到远程了,可能需要修改后强制推送,目前没有找到别的方法。

相关推荐
杰哥在此16 分钟前
Python知识点:如何使用Multiprocessing进行并行任务管理
linux·开发语言·python·面试·编程
汪子熙17 分钟前
Angular 服务器端应用 ng-state tag 的作用介绍
前端·javascript·angular.js
昨天;明天。今天。6 小时前
案例-表白墙简单实现
前端·javascript·css
安冬的码畜日常6 小时前
【玩转 JS 函数式编程_006】2.2 小试牛刀:用函数式编程(FP)实现事件只触发一次
开发语言·前端·javascript·函数式编程·tdd·fp·jasmine
小御姐@stella6 小时前
Vue 之组件插槽Slot用法(组件间通信一种方式)
前端·javascript·vue.js
GISer_Jing6 小时前
【React】增量传输与渲染
前端·javascript·面试
GISer_Jing6 小时前
WebGL在低配置电脑的应用
javascript
万叶学编程9 小时前
Day02-JavaScript-Vue
前端·javascript·vue.js
Neituijunsir11 小时前
2024.09.22 校招 实习 内推 面经
大数据·人工智能·算法·面试·自动驾驶·汽车·求职招聘