JavaScript进阶--一文带你认识动画与Canvas 图形

一、前言

动画这方面不太熟悉,自己用的也很少,只能在用到和看到相关书籍学习的时候将经验写下来了...

二、requestAnimationFrame

1.早期定时动画

说明: 早期动画使用setInterval来控制动画的运行,不过存在两个问题,一是定时的间隔必须足够短,这样才能让不同的动画类型运行流畅,但是又需要足够长,以便浏览器可以将变化渲染出来,大部分屏幕的刷新率都是60hz,意味着每秒重绘60次,那么最佳的时间间隔就是17ms了,二是定时器的第二个参数表示隔多久将代码添加到任务队列中去,并不能保证动画立即执行,因此也就不能保证动画时间的精度

js 复制代码
(function() { 
  function updateAnimations() { 
    doAnimation1(); 
    doAnimation2(); 
    // 其他任务
  } 
  setInterval(updateAnimations, 100); 
})(); 

浏览器计时器的精度:

  • IE8及更早:15.625毫秒
  • IE9及更晚:4毫秒
  • Firefox 和 Safari:约为10毫秒
  • Chrome:4毫秒

2.requestAnimationFrame

说明: 参数是一个回调函数,用于告诉浏览器在下次重绘之前调用指定的回调函数更新动画,不过它只会调用一次传入的函数,如果需要动画循环下去,可以把多个 requestAnimationFrame()调用串联起来

html 复制代码
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Progress Bar Animation</title>
    <style>
      #status {
        width: 10%;
        height: 20px;
        background-color: #4caf50;
      }
    </style>
  </head>
  <body>
    <div id="status"></div>

    <script>
      function updateProgress(e) {
        // 回调函数接受一个参数,这个参数表示执行回调函数的时刻
        console.log(e);

        var div = document.getElementById("status");
        div.style.width = div.offsetWidth + 5 + "px";
        if (div.offsetWidth < window.innerWidth) {
          requestAnimationFrame(updateProgress);
        }
      }

      requestAnimationFrame(updateProgress);
    </script>
  </body>
</html>

3.cancelAnimationFrame

说明: 上面那个方法的返回值是一个整数ID,可以通过这个ID像定时器那样取消已经注册的动画,取消时使用的是最后一个ID

js 复制代码
let requestID = window.requestAnimationFrame(() => { 
  // 不会执行
  console.log('Repaint!'); 
}); 
window.cancelAnimationFrame(requestID);

三、canvas

说明: 创建<canvas>元素时至少要设置其widthheight属性,这样才能告诉浏览器在多大面积上绘图。出现在开始和结束标签之间的内容是后备数据,会在浏览器不支持<canvas>元素时显示,对于样式来说,可以像其它元素那样,通过css添加,也可以通过JavaScript来添加,在画布上面绘制图形,需要获取绘图上下文,可以通过getContext()来获取,对于平面图形,参数传"2d",在图形绘制完毕后,可以通过toDataURL()方法将画布上面的图形导出来

html 复制代码
<canvas id="drawing" width="200" height="200">A drawing of something.</canvas>

<script>
  let drawing = document.getElementById("drawing");
  // 检测元素是否存在getContext,确保浏览器支持<canvas>
  if (drawing.getContext) {
    // 取得图像的数据 URI
    let imgURI = drawing.toDataURL("image/png");
    // 显示图片
    let image = document.createElement("img");
    image.src = imgURI;
    document.body.appendChild(image);
  }
</script>

四、context

说明: context用来表示绘图上下文,这里说的是2d绘图上下文,它提供了绘制 2D 图形的方法,包括矩形、弧形和路径。2D 上下文的坐标原点(0, 0)在 元素的左上角。所有坐标值都相对于该点计算,因此 x 坐标向右增长,y 坐标向下增长。默认情况下,width 和 height 表示两个方向上像素的最大值。

1.填充和描边

说明: 填充(fillStyle)以指定样式自动填充形状,而描边(strokeStyle)只为图形边界着色,这两个属性可以是字符串、渐变对象或图案对象,默认值为"#000000"。字符串表示颜色值,可以是CSS支持的任意格式:名称、十六进制代码、rgb、rgba、hsl 或 hsla

相关的方法:

  • fill():会根据当前的样式进行填充
  • stroke():会根据当前的线条进行描边
js 复制代码
let drawing = document.getElementById("drawing");
if (drawing.getContext) {
    let context = drawing.getContext("2d");
    // 设置描边
    context.strokeStyle = "red";
    // 设置填充
    context.fillStyle = "#0000ff";
}

2.绘制矩形

说明: 矩形是可以在直接在绘图上下文中绘制的图形,与其相关的方法有三个:fillRect()strokeRect()clearRect(),它们的参数都是:左上顶点的x坐标左上顶点的y坐标矩形的宽度矩形的高度,单位是像素,需要注意,如果需要填充颜色需要先填充再绘制,否则填充无法生效

  • fillRect():以指定颜色在画布上绘制并填充矩形

  • strokeRect():以指定颜色在画布上绘制矩形的轮廓

  • clearRect():在画布上擦出一个矩形,先绘制后擦除
    常用属性:

  • lineWidth:整数,表示描边的宽度

  • lineCap:线条端点的形状,取值如下

    • "butt:平头
    • "round":圆头
    • "square":方头
  • lineJoin:线条交点的形状,取值如下

    • "round:圆的
    • "bevel":平的
    • "miter":尖的
html 复制代码
<canvas id="drawing" width="200" height="200">A drawing of something.</canvas>

<script>
  let drawing = document.getElementById("drawing");
  if (drawing.getContext) {
    let context = drawing.getContext("2d");

    // 绘制红色矩形
    context.fillStyle = "#ff0000";
    context.fillRect(10, 10, 50, 50);
    // 绘制半透明蓝色矩形
    context.fillStyle = "rgba(0,0,255,0.5)";
    context.fillRect(30, 30, 50, 50);
  }
</script>
html 复制代码
<canvas id="drawing" width="200" height="200">A drawing of something.</canvas>

<script>
  let drawing = document.getElementById("drawing");
  if (drawing.getContext) {
    let context = drawing.getContext("2d");

    // 绘制红色轮廓的矩形
    context.strokeStyle = "#ff0000";
    context.strokeRect(10, 10, 50, 50);
    // 绘制半透明蓝色轮廓的矩形
    context.strokeStyle = "rgba(0,0,255,0.5)";
    context.strokeRect(30, 30, 50, 50);
  }
</script>
html 复制代码
<canvas id="drawing" width="200" height="200">A drawing of something.</canvas>

<script>
  let drawing = document.getElementById("drawing");
  if (drawing.getContext) {
    let context = drawing.getContext("2d");

    // 绘制红色矩形
    context.fillStyle = "#ff0000";
    context.fillRect(10, 10, 50, 50);
    // 绘制半透明蓝色矩形
    context.fillStyle = "rgba(0,0,255,0.5)";
    context.fillRect(30, 30, 50, 50);
    // 在前两个矩形重叠的区域擦除一个矩形区域
    context.clearRect(40, 40, 10, 10);
  }
</script>

3.绘制路径

说明: 通过路径可以创建复杂的形状和线条。要绘制路径,必须首先调用 beginPath()方法以表示要开始绘制新路径,然后可以使用下面这些方法来进行绘制,绘制完成,使用closePath()方法结束绘制,对于判断一个点是否被一段路径所使用,可以使用isPointInPath(x,y)方法来判定,它的返回值是布尔值

  • arc(x, y, radius, startAngle, endAngle, counterclockwise):以坐标(x, y)为圆 心,以 radius 为半径绘制一条弧线,起始角度为 startAngle,结束角度为 endAngle(都是 弧度)。最后一个参数 counterclockwise 表示是否逆时针计算起始角度和结束角度(默认为 顺时针)。
  • arcTo(x1, y1, x2, y2, radius):以给定半径 radius,经由(x1, y1)绘制一条从上一点 到(x2, y2)的弧线。
  • lineTo(x, y):绘制一条从上一点到(x, y)的直线。
  • moveTo(x, y):不绘制线条,只把绘制光标移动到(x, y),表示当前绘制的路径是一条新路径,跟之前的路径没有关系
  • quadraticCurveTo(cx, cy, x, y):以(cx, cy)为控制点,绘制一条从上一点到(x, y) 的弧线(二次贝塞尔曲线)。
  • bezierCurveTo(c1x, c1y, c2x, c2y, x, y):以(c1x, c1y)和(c2x, c2y)为控制点, 绘制一条从上一点到(x, y)的弧线(三次贝塞尔曲线)。
  • rect(x, y, width, height):以给定宽度和高度在坐标点(x, y)绘制一个矩形。这个方法 与 strokeRect()和 fillRect()的区别在于,它创建的是一条路径,而不是独立的图形。
html 复制代码
<canvas id="drawing" width="200" height="200">A drawing of something.</canvas>

<script>
  let drawing = document.getElementById("drawing");
  if (drawing.getContext) {
    let context = drawing.getContext("2d");

    // 获取当前时间
    let now = new Date();
    let hour = now.getHours();
    let minute = now.getMinutes();
    let second = now.getSeconds();

    // 清除画布
    context.clearRect(0, 0, drawing.width, drawing.height);

    // 创建路径
    context.beginPath();
    // 绘制外圆
    context.arc(100, 100, 99, 0, 2 * Math.PI, false);
    // 绘制内圆,将画笔起始点移动到内圆上,表示这是一条新的路径,与不是与外圆连接的一部分
    context.moveTo(194, 100);
    context.arc(100, 100, 94, 0, 2 * Math.PI, false);
    // 绘制分针
    context.moveTo(100, 100);
    context.lineTo(
      100 +
        60 * Math.cos((Math.PI / 30) * (minute + second / 60) - Math.PI / 2),
      100 + 60 * Math.sin((Math.PI / 30) * (minute + second / 60) - Math.PI / 2)
    );
    // 绘制时针
    context.moveTo(100, 100);
    context.lineTo(
      100 +
        50 *
          Math.cos(
            (Math.PI / 6) * ((hour % 12) + minute / 60 + second / 3600) -
              Math.PI / 2
          ),
      100 +
        50 *
          Math.sin(
            (Math.PI / 6) * ((hour % 12) + minute / 60 + second / 3600) -
              Math.PI / 2
          )
    );
    // 描画路径
    context.stroke();
  }
</script>

4.绘制文本

说明: 绘图上下文提供了两个方法:即fillText()strokeText()。这两个方法都接收4个参数:要绘制的字符串x坐标y坐标最大像素宽度(可选),前者绘制的文本是填充的,后者是描边的,绘制的结果取决于下面三个属性的设定,先设定后绘制,其次对于文本大小的确定,可以使用measureText("需要测量的文本")方法,如果使用了第四个可选参数限制文本的宽度,绘制的字符串超出了最大宽度限制,则文本会以正确的字符高度绘制,这时字符会被水平压缩,以达到限定宽度

  • font:以 CSS 语法指定的字体样式
  • textAlign:文本的对齐方式的属性
  • textBaseLine:指定文本的基线
js 复制代码
// 在前面的时钟绘制前加上下面这些就可以绘制时刻文本了

// 正常
context.font = "bold 14px Arial";
context.textAlign = "center";
context.textBaseline = "middle";
context.fillText("12", 100, 20);

// 与开头对齐
context.textAlign = "start";
context.fillText("12", 100, 40);

// 与末尾对齐
context.textAlign = "end";
context.fillText("12", 100, 60);

5.变换

说明: 2D绘图上下文支持所有常见的绘制变换。在创建绘制上下文时,会以默认值初始化变换矩阵,从而让绘制操作如实应用到绘制结果上,可以使用下面这些方法:

  • rotate(angle):围绕原点把图像旋转 angle 弧度(约为57.3度),先旋转再绘制,不然会失效
  • scale(scaleX, scaleY):通过在 x 轴乘以 scaleX、在 y 轴乘以 scaleY 来缩放图像。scaleX 和 scaleY 的默认值都是 1.0。
  • translate(x, y):把原点移动到(x, y)。执行这个操作后,坐标(0, 0)就会变成(x, y)。
  • transform(m1_1, m1_2, m2_1, m2_2, dx, dy):像下面这样通过矩阵乘法直接修改矩阵。
    m1_1 m1_2 dx
    m2_1 m2_2 dy
    0 0 1
  • setTransform(m1_1, m1_2, m2_1, m2_2, dx, dy):把矩阵重置为默认值,再以传入的参数调用 transform()。
  • save():将当前绘图上下文的设置(如颜色、线条样式等)和变换(如平移、旋转等)保存在一个栈中。这些设置和变换的保存并不包括已经绘制的图形内容,只是记录了当前的状态,状态可以保存多次的时,恢复状态会就近恢复
  • restore():恢复上一次保存的状态
html 复制代码
<canvas id="drawing" width="200" height="200">A drawing of something.</canvas>

<script>
  let drawing = document.getElementById("drawing");
  if (drawing.getContext) {
    let context = drawing.getContext("2d");
    // 创建路径
    context.beginPath();
    // 绘制外圆
    context.arc(100, 100, 99, 0, 2 * Math.PI, false);
    // 绘制内圆
    context.moveTo(194, 100);
    context.arc(100, 100, 94, 0, 2 * Math.PI, false);
    // 移动原点到表盘中心,此时(100,100)这个点就是原点(0,0)了
    context.translate(100, 100);
    // 旋转表针,上面已经改变了原点的坐标,所以此时旋转是围绕钟的中心点旋转的
    context.rotate(1);
    // 绘制分针
    context.moveTo(0, 0);
    context.lineTo(0, -85);
    // 绘制时针
    context.moveTo(0, 0);
    context.lineTo(-65, 0);
    // 描画路径
    context.stroke();
  }
</script>
html 复制代码
<canvas id="drawing" width="1000" height="1000">A drawing of something.</canvas>

<script>
  let drawing = document.getElementById("drawing");
  if (drawing.getContext) {
    let context = drawing.getContext("2d");
    // 设置绘图上下文的填充颜色为红色。
    context.fillStyle = "#ff0000";
    // 将当前绘图状态保存到绘图状态栈中。
    context.save();
    // 设置绘图上下文的填充颜色为绿色。
    context.fillStyle = "#00ff00";
    // 平移绘图上下文的原点位置到 (100, 100)。
    context.translate(100, 100);
    // 再次将当前绘图状态保存到绘图状态栈中。
    context.save();
    // 设置绘图上下文的填充颜色为蓝色。
    context.fillStyle = "#0000ff";
    // 在当前绘图上下文的原点位置 (100, 100) 绘制宽度为 100、高度为 200 的蓝色矩形。
    context.fillRect(0, 0, 100, 200);
    // 从绘图状态栈中取出上一个保存的绘图状态,恢复为之前的状态。此时填充颜色为绿色。
    context.restore();
    // 在当前绘图上下文的原点位置 (100, 100) 绘制宽度为 100、高度为 200 的绿色矩形。
    context.fillRect(10, 10, 100, 200);
    // 再次从绘图状态栈中取出上一个保存的绘图状态,恢复为最初的状态。此时填充颜色为红色。
    context.restore();
    // 在当前绘图上下文的原点位置 (0, 0) 绘制宽度为 100、高度为 200 的红色矩形。
    context.fillRect(0, 0, 100, 200);
  }
</script>

save()保存状态之后,在没有恢复状态之前,都可以基于这个状态上进行操作,恢复之后,后续操作只能基于这个保存的状态进行操作了,如果保存的状态存在多个,恢复状态只能就近恢复,只能恢复上一次的状态

6.绘制图像

说明: 如果想把现有图像绘制到画布上,可以使用drawImage()方法,它存在如下的传参方式:

  • drawImage(<img>元素, 绘制的x, 绘制的y):绘制出来的图形与原来一样大
  • drawImage(<img>元素, 绘制的x, 绘制的y, 目标宽度,目标高度):绘制出来的图形的大小会缩放/扩大至指定的高度和宽度
  • drawImage(<img>元素, 截取的x, 截取的y, 截取宽度,截取高度,绘制的x,绘制的y,绘制宽度,绘制高度):会从图像的(x,y)处截取指定宽度和高度,并将其渲染在画布(x,y)处,大小为指定的宽高
html 复制代码
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Canvas Image Example</title>
  </head>
  <body>
    <img src="./1.jpg" width="400" alt="" style="display: none" />
    <canvas id="drawing" width="400" height="400"
      >A drawing of something.</canvas
    >

    <script>
      const drawing = document.getElementById("drawing");
      const image = document.querySelector("img");

      if (drawing.getContext) {
        // 图片加载过程中的存在异步获取
        image.onload = function () {
          const context = drawing.getContext("2d");
          context.drawImage(image, 10, 10);
        };
      }
    </script>
  </body>
</html>

7.阴影

说明: 可以使用以下属性为已有的路径和形状生成阴影,这些属性都可以通过 context对象读写。只要在绘制图形或路径前给这些属性设置好适当的值,阴影就会自动生成

  • shadowColor:CSS 颜色值,表示要绘制的阴影颜色,默认为黑色。
  • shadowOffsetX:阴影相对于形状或路径的 x 坐标的偏移量,默认为 0。
  • shadowOffsetY:阴影相对于形状或路径的 y 坐标的偏移量,默认为 0。
  • shadowBlur:像素,表示阴影的模糊量。默认值为 0,表示不模糊。
html 复制代码
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Canvas Image Example</title>
  </head>
  <body>
    <img src="./1.jpg" width="400" alt="" style="display: none" />
    <canvas id="drawing" width="400" height="400"
      >A drawing of something.</canvas
    >

    <script>
      const drawing = document.getElementById("drawing");

      if (drawing.getContext) {
        const context = drawing.getContext("2d");
        // 设置阴影
        context.shadowOffsetX = 5;
        context.shadowOffsetY = 5;
        context.shadowBlur = 4;
        context.shadowColor = "rgba(0, 0, 0, 0.5)";
        // 绘制红色矩形
        context.fillStyle = "#ff0000";
        context.fillRect(10, 10, 50, 50);
        // 绘制蓝色矩形
        context.fillStyle = "rgba(0,0,255,1)";
        context.fillRect(30, 30, 50, 50);
      }
    </script>
  </body>
</html>

8.渐变

说明: 创建一个线性渐变需要使用createLinearGradient(起点x,起点y,终点x,终点y)方法,如果需要径向渐变需要使用createRadialGradient(起点圆心x,起点圆心y,起点圆半径,终点圆心x,终点圆心y,终点圆半径)方法,它们都会返回一个CanvasGradient对象实例,实例上可以用下面的方法,

  • addColorStop(色标位置,CSS颜色字符串):指定渐变的颜色,色标位置通过 0~1 范围内的值表示,0 是第一种颜色,1 是最后 一种颜色
html 复制代码
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Canvas Image Example</title>
  </head>
  <body>
    <img src="./1.jpg" width="400" alt="" style="display: none" />
    <canvas id="drawing" width="400" height="400"
      >A drawing of something.</canvas
    >

    <script>
      const drawing = document.getElementById("drawing");

      if (drawing.getContext) {
        const context = drawing.getContext("2d");

        // 渐变对象
        let gradient = context.createLinearGradient(30, 30, 70, 70);
        // 渐变起始色
        gradient.addColorStop(0, "white");
        // 渐变终止色
        gradient.addColorStop(1, "black");
        // 绘制红色矩形
        context.fillStyle = "#ff0000";
        context.fillRect(10, 10, 50, 50);
        // 渐变色对象可以给fillStyle或strokeStyle属性赋值
        context.fillStyle = gradient;
        context.fillRect(30, 30, 50, 50);
      }
    </script>
  </body>
</html>

如果绘制的矩形在有部分不在渐变的范围内,则只有在渐变范围内的部分存在渐变

js 复制代码
// 如果上面渐变的矩形这样写,渐变就只有一点点了
context.fillStyle = gradient;
context.fillRect(50, 50, 50, 50);
html 复制代码
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Canvas Image Example</title>
  </head>
  <body>
    <img src="./1.jpg" width="400" alt="" style="display: none" />
    <canvas id="drawing" width="400" height="400"
      >A drawing of something.</canvas
    >

    <script>
      const drawing = document.getElementById("drawing");

      if (drawing.getContext) {
        const context = drawing.getContext("2d");

        let gradient = context.createRadialGradient(55, 55, 10, 55, 55, 30);
        gradient.addColorStop(0, "white");
        gradient.addColorStop(1, "black");
        // 绘制红色矩形
        context.fillStyle = "#ff0000";
        context.fillRect(10, 10, 50, 50);
        // 绘制渐变矩形
        context.fillStyle = gradient;
        context.fillRect(30, 30, 50, 50);
      }
    </script>
  </body>
</html>

9.图案

说明: 这个可以理解为背景图,用于填充和描画图形的重复图像,创建一个图案使用createPattern(<img>元素,如何重复)完成,第二个参数的值可选择的值为repeat、repeat-x、repeat-y、no-repeat,一样是先创建后填充

js 复制代码
// 举个栗子

let image = document.images[0], 
pattern = context.createPattern(image, "repeat"); 
context.fillStyle = pattern;
context.fillRect(10, 10, 150, 150);

10.图像数据

说明: 获取图像数据可以使用getImageData(第一个像素的x,第一个像素的y,取取得的宽度,取得的高度)方法,返回值是一个ImageData实例,里面data属性包含所有区域内像素的信息,每个像素都包含四个值,分别对应r、g、b、a

html 复制代码
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Canvas Image Example</title>
  </head>
  <body>
    <img src="./1.jpg" width="400" alt="" style="display: none" />
    <canvas id="drawing" width="400" height="400"
      >A drawing of something.</canvas
    >

    <script>
      const drawing = document.getElementById("drawing");

      if (drawing.getContext) {
        const context = drawing.getContext("2d");

        let gradient = context.createRadialGradient(55, 55, 10, 55, 55, 30);
        gradient.addColorStop(0, "white");
        gradient.addColorStop(1, "black");
        // 绘制红色矩形
        context.fillStyle = "#ff0000";
        context.fillRect(10, 10, 50, 50);
        // 绘制渐变矩形
        context.fillStyle = gradient;
        context.fillRect(30, 30, 50, 50);

        // 获取图像坐标为(10,10)这个点的像素信息
        let imageData = context.getImageData(10, 10, 1, 1);
        console.log(imageData);
        console.log(imageData.data);
      }
    </script>
  </body>
</html>

11.合成

说明: 关于合成有两个属性,分别是globalAlphaglobalComposition Operation,前者是设置绘制的透明度,后者类似PS中的布尔运算,其取值超级多,详细可以看MDN具体的属性值

html 复制代码
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Canvas Image Example</title>
  </head>
  <body>
    <img src="./1.jpg" width="400" alt="" style="display: none" />
    <canvas id="drawing" width="400" height="400"
      >A drawing of something.</canvas
    >

    <script>
      const drawing = document.getElementById("drawing");

      if (drawing.getContext) {
        const context = drawing.getContext("2d");

        // 绘制红色矩形
        context.fillStyle = "#ff0000";
        context.fillRect(10, 10, 50, 50);
        // 修改全局透明度
        context.globalAlpha = 0.5;
        // 绘制蓝色矩形
        context.fillStyle = "rgba(0,0,255,1)";
        context.fillRect(30, 30, 50, 50);
        // 重置
        context.globalAlpha = 0;
      }
    </script>
  </body>
</html>
相关推荐
a栋栋栋3 小时前
apifox
java·前端·javascript
请叫我飞哥@3 小时前
HTML 标签页(Tabs)详细讲解
前端·html
Anlici4 小时前
React18与Vue3组件通信对比学习(详细!建议收藏!!🚀🚀)
前端·vue.js·react.js
m0_748251524 小时前
PDF在线预览实现:如何使用vue-pdf-embed实现前端PDF在线阅读
前端·vue.js·pdf
中生代技术4 小时前
3.从制定标准到持续监控:7个关键阶段提升App用户体验
大数据·运维·服务器·前端·ux
m0_748239334 小时前
从零开始:如何在.NET Core Web API中完美配置Swagger文档
前端·.netcore
m0_748232925 小时前
【前端】Node.js使用教程
前端·node.js·vim
hawleyHuo5 小时前
umi 能适配 taro组件?
前端·前端框架
web130933203985 小时前
[JAVA Web] 02_第二章 HTML&CSS
java·前端·html
黑客呀5 小时前
Go Web开发之Revel - 网页请求处理流程
开发语言·前端·web安全·golang·系统安全