前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布

Canvas

作者头像
jinghong
发布2020-05-09 15:30:13
12.6K0
发布2020-05-09 15:30:13
举报
文章被收录于专栏:前端开发0202前端开发0202

Canvas

canvas 是HTML5新出的标签,可以用来做小游戏,特效,作图等,自己并没有作画能力,只能通过Javascript脚本来操控

Canvas标准

http://www.w3c.org/TR/2dcontext/ https://html.spec.whatwg.org/

创建Canvas

创建canvas几个主要的问题:

1.不能通过CSS设置画布的大小,否则会造成画布拉伸变形等问题,只能设置本身自带width、height属性,也可以在js里设置

2.兼容性:对一些不支持的浏览器,可以在标签内输入提示,不支持的浏览器会显示此提示、支持的浏览器会自动忽略掉

3.创建并设置好宽高后,通过js获取,还要设置其getContext,成功返回一个对象后即可作画,这里用js也可判断其是否支持canvas

语法格式:

代码语言:javascript
复制
<canvas width="1024" height="570" class="canvas">由于您的浏览器版本过低,此图片不能加载</canvas>
<script>
    var ctx = document.querySelector(".canvas").getContext("2d|3d");
</script>

手册参考网址

线

画布的x、y起点默认在右上角的位置(0,0), 分别对应的最大值是画布的宽和高

绘制线条的函数:

moveTo(x,y) : 开始位置

lineTo(x,y):结束位置

stroke :准备好后,开始画线条

设置线条样式的函数:

lineWidth:设置线条粗细

strokeStyle:设置线条的颜色

lineCap:设置线条首尾处的形状 俗称帽子

lineJoin:设置连接处的样式

miterLimit:内角与外角的距离。默认值是10,此属性只有在lineJoin = “miter”并且有设置线条粗细情况下才有效,且斜接长度大于miterLimit ,线条连接处自动斜切(lineJoin =”bevel”)

另起一条路径的函数:

beginPath:起始一条路径,或重置当前路径

closePath:创建从当前点回到起始点的路径

语法格式:

代码语言:javascript
复制
<canvas width="1024" height="760" class="canvas">由于您的浏览器版本过低,此图片不能加载</canvas><script>
   var ctx = document.querySelector(".canvas").getContext("2d|3d");
    ctx.beginPath();
    ctx.moveTo(100,100);
    ctx.lineTo(700,700);
    ctx.lineTo(100,700);
    ctx.lineTo(100,100);
    ctx.lineWidth = 5;
    ctx.strokeStyle = "green";
    ctx.stroke();
    ctx.closePath();

    ctx.beginPath();
    ctx.lineCap = "round" //butt(default) round圆头 square方头
    //lineCap 有时可以填补连接处的空缺
    ctx.moveTo(200,200);
    ctx.lineTo(400,400);
    ctx.lineTo(200,400);
    ctx.lineTo(200,200);
    ctx.lineWidth = 5;
    ctx.strokeStyle = "yellow";
    ctx.stroke();
    ctx.closePath();
</script>
===============================================================
ctx.lineWidth = 15;
DrawStart(ctx, 100, 20, 400, 400, -30);
      ctx.lineJoin = "miter"; //可以设置的样式有:miter(default)、 bevel斜接、 round圆角
      ctx.miterLimit = 7; //如果斜接长度超过 miterLimit 的值,边角会以 lineJoin 的 "bevel" 类型来显示。,这里等于7时,边角会以lineJoin的bevel显示,等于8时则会以miter显示
    //斜接长度指的是在两条线交汇处内角和外角之间的距离。


      ctx.stroke();
      function DrawStart(context, R, r, x, y, rotate) {
        //绘画对象 大圆的半径 小圆半径  x轴 y轴
        ctx.beginPath();
        for (var i = 0; i < 5; i++) {
          ctx.lineTo(
            Math.cos(((18 + 72 * i - rotate) / 180) * Math.PI) * R + x,
            -Math.sin(((18 + 72 * i - rotate) / 180) * Math.PI) * R + y
          );
          ctx.lineTo(
            Math.cos(((54 + 72 * i - rotate) / 180) * Math.PI) * r + x,
            -Math.sin(((54 + 72 * i - rotate) / 180) * Math.PI) * r + y
          );
        }
        ctx.closePath();
      }

填充

填充函数:

fill :填充当前路径 (注意:如果路径未关闭,那么 fill() 方法会从路径结束点到开始点之间添加一条线,以关闭该路径,然后填充该路径)

填充样式:

fillStyle:填充颜色

语法格式:

代码语言:javascript
复制
<canvas width="1024" height="760" class="canvas">由于您的浏览器版本过低,此图片不能加载</canvas><script>
   var ctx = document.querySelector(".canvas").getContext("2d|3d");
    ctx.beginPath();
    ctx.moveTo(100,100);
    ctx.lineTo(700,700);
    ctx.lineTo(100,700);
    ctx.lineTo(100,100);
    ctx.lineWidth = 5;
    ctx.strokeStyle = "green";
    ctx.stroke();
    ctx.fillStyle = "red";
    ctx.fill()
    ctx.closePath();

    ctx.beginPath();
    ctx.moveTo(200,200);
    ctx.lineTo(400,400);
    ctx.lineTo(200,400);
    ctx.lineTo(200,200);
    ctx.lineWidth = 5;
    ctx.strokeStyle = "yellow";
    ctx.stroke();
    ctx.closePath();
</script>

案例:四个正方形组成的大方形

代码语言:javascript
复制
   var ctx = document.querySelector(".canvas").getContext("2d");
let box = [
        {p:[{x:0,y:0},{x:512,y:0},{x:512,y:380},{x:0,y:380},{x:0,y:0}],color:"red"},
        {p:[{x:512,y:0},{x:1024,y:0},{x:1024,y:380},{x:512,y:380},{x:512,y:0}],color:"green"},
        {p:[{x:0,y:380},{x:512,y:380},{x:512,y:760},{x:0,y:760},{x:0,y:380}],color:"blue"},
        {p:[{x:512,y:380},{x:1024,y:380},{x:1024,y:760},{x:512,y:760},{x:512,y:380}],color:"yellow"},

      ]
      for(let i=0;i<box.length;i++)
      {
        draw(box[i],ctx);
      }

      function draw(p,c)
      {
        c.beginPath();
          c.moveTo(p.p[0].x,p.p[0].y);
          for(let i=1;i<p.p.length;i++)
          {
            c.lineTo(p.p[i].x,p.p[i].y);
          }
          c.lineWidth = 5;
          c.strokeStyle = p.color;
          c.fillStyle = p.color;
        c.stroke();
        c.fill();
        c.closePath();
      }

注意点:

  1. closePath可以解决闭合图形的空隙问题,也有自动闭合的作用。
  2. 当边框或者填充被遮挡掉的时候,这时可以先填充在画边框,或者先画边框再画线
  3. 后绘制的图形会顶替掉前面的图形

画圆的函数:

arc(x,y,r,start,end,true|false):画圆\弧

arcTo(x1,y1,x2,y2,r):绘制圆弧

语法格式:

代码语言:javascript
复制
 var ctx = document.querySelector(".canvas").getContext("2d");
      var i = 0;
      setInterval(() => {
        i++;
        ctx.fillStyle = "yellow";
        ctx.strokeStyle = "red";
        ctx.beginPath();                       
        ctx.arc(512, 380, 100, 0, Math.PI * 2 - (Math.PI * 2 * i / 30), true);
            //  x    y  半径 开始位置  结束位置                      是否逆时针旋转
        ctx.lineWidth = 10;
        ctx.stroke();
        ctx.fill();
      }, 1);
//顺时针:Math.PI * 2 * i / 30
//逆时针:Math.PI * 2 - (Math.PI * 2 * i / 30)

//使用arcTo绘圆角矩形
var ctx = document.querySelector("canvas").getContext("2d");
      // ctx.translate(200,200)
      // ctx.beginPath();
      // ctx.moveTo(100,0);
      // ctx.arcTo(400,0,400,800,100);
      // ctx.lineTo(400,400);
      // ctx.arcTo(400,500,350,500,100);
      // ctx.lineTo(100,500);
      // ctx.arcTo(0,500,0,450,100);
      // ctx.lineTo(0,100);
      // ctx.arcTo(0,0,100,0,100)
      // ctx.closePath();

      function RoundRect(ctx, width, height, r) 
      {
        ctx.beginPath();
        ctx.moveTo(r, 0);
        ctx.arcTo(width, 0, width, height - r, r);
        ctx.lineTo(width, height);
        ctx.arcTo(width, height + r, width - 50, height + r, r);
        ctx.lineTo(r, height + r);
        ctx.arcTo(0, height + r, 0, height - 50, r);
        ctx.lineTo(0, r);
        ctx.arcTo(0, 0, r, 0, r);
        ctx.closePath();
      }
      RoundRect(ctx, 200, 100, 10);
      ctx.stroke();

矩形

矩形函数:

reac:绘制矩形附带填充和边框

fillRect:绘制只填充的矩形

strokeRect:绘制只带边框的矩形

语法格式:

代码语言:javascript
复制
//  参数:  x , y , width , height  
var ctx = document.querySelector(".canvas").getContext("2d");
      ctx.fillStyle = "red";
      ctx.strokeStyle = "yellow";
      ctx.lineWidth = 5;
      var x = 0;
      ctx.beginPath();
      ctx.rect(100, 100, 300, 300);
      ctx.stroke();
      ctx.fill();

      ctx.beginPath();
      ctx.fillStyle = "rgba(0,255,155,0.5)";
      ctx.strokeStyle = "yellow";
      ctx.fillRect(150, 150, 300, 300);
      ctx.strokeRect(100, 100, 400, 400);

案例:绘制五角星

代码语言:javascript
复制
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>Document</title>
  </head>
  <body>
    <canvas width="800" height="800"></canvas>
    <script>
      var ctx = document.querySelector("canvas").getContext("2d");
      ctx.lineWidth = 10;
      ctx.beginPath();
      for (var i = 0; i <= 5; i++) {
        ctx.lineTo(
          Math.cos(((18 + 72 * i) / 180) * Math.PI) * 100 + 200,
                    //步骤:先求出角度在转弧度
                    //cos(18deg)*R   sin(18deg)*R
                    //角度转弧度公式:角度/180*r
                    //由于数学中的坐标系与canvas的坐标不同所以y轴要为负
          -Math.sin(((18 + 72 * i) / 180) * Math.PI) * 100 + 200
        );
        ctx.lineTo(
          Math.cos(((54 + 72 * i) / 180) * Math.PI) * 50 + 200,
          -Math.sin(((54 + 72 * i) / 180) * Math.PI) * 50 + 200
        );
      }
      ctx.closePath();
      ctx.stroke();
     =================================================================================
         //五角星封装函数
      DrawStart(ctx, 200, 100, 400, 400 , 30);
      ctx.stroke();
      function DrawStart(context, R, r, x, y,rotate) {
                        //绘画对象 大圆的半径 小圆半径  x轴 y轴  旋转角度
        ctx.beginPath();
        for (var i = 0; i < 5; i++) {
          ctx.lineTo(
            Math.cos(((18 + 72 * i -rotate) / 180) * Math.PI) * R + x,
            -Math.sin(((18 + 72 * i -rotate) / 180) * Math.PI) * R + y
          );
          ctx.lineTo(
            Math.cos(((54 + 72 * i -rotate) / 180) * Math.PI) * r + x,
            -Math.sin(((54 + 72 * i -rotate) / 180) * Math.PI) * r + y
          );
        }
        ctx.closePath();
      }
    </script>
  </body>
</html>

参考链接:https://www.baidu.com/link?url=3j7UmP9XbkLh0ww6tMOChL_7CATbIoQ15GBatuaJdx2_yCn-jcdshTRF9-l6kMmbONf5cgLEviZEpV4QhjLf2q&wd=&eqid=e9fcd7b0000436fd000000065d2e7488

随机不重复、不切边五角星

代码语言:javascript
复制
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>Document</title>
  </head>
  <body>
    <canvas width="800" height="800" class="canvas"></canvas>
    <script src="../node/jquery.js"></script>
    <script>
      var ctx = document.querySelector("canvas").getContext("2d");
      ctx.fillStyle = "black";
      ctx.fillRect(
        0,
        0,
        document.querySelector("canvas").width,
        document.querySelector("canvas").height
      );

      ctx.fillStyle = "#fc1";
      ctx.strokeStyle = "#fb5";
      ctx.lineWidth = 5;
      ctx.lineJoin = "round";
      var ele = [];
      start(ele);
      end(ele);

      function start(arr) {
        for (var i = 0; i < 200; i++) {
          var flag = true,
            ran = Math.random() * 10 + 10,
            x =
              Math.random() *
                (document.querySelector("canvas").width - ran * 2) +
              ran,
            y =
              Math.random() *
                (document.querySelector("canvas").height - ran * 2) +
              ran,
            rotate = Math.random() * 360;
          for (var j = 0; j < ele.length; j++) {
            var oldx = Math.pow(x - arr[j][1], 2);
            var oldy = Math.pow(y - arr[j][2], 2);
            var oldr = Math.pow(ran + arr[j][0], 2);
            if (oldx + oldy < oldr) {
              flag = false;
            }
          }

          flag ? arr.push([ran, x, y, rotate]) : i--;
        }
      }
      function end(arr) {
        for (var i = 0; i < arr.length; i++) {
          DrawStart(
            ctx,
            arr[i][0],
            arr[i][0] / 2,
            arr[i][1],
            arr[i][2],
            arr[i][3]
          );
          ctx.fill();
          ctx.stroke();
        }
      }
      function DrawStart(context, R, r, x, y, rotate) {
        //绘画对象 大圆的半径 小圆半径  x轴 y轴
        ctx.beginPath();
        for (var i = 0; i < 5; i++) {
          ctx.lineTo(
            Math.cos(((18 + 72 * i - rotate) / 180) * Math.PI) * R + x,
            -Math.sin(((18 + 72 * i - rotate) / 180) * Math.PI) * R + y
          );
          ctx.lineTo(
            Math.cos(((54 + 72 * i - rotate) / 180) * Math.PI) * r + x,
            -Math.sin(((54 + 72 * i - rotate) / 180) * Math.PI) * r + y
          );
        }
        ctx.closePath();
      }
    </script>
  </body>
</html>

绘画状态保存与还原

状态的保存与还原可以使操作更加简便,快速,主要作用于将绘画的状态来回快速切换,状态保存,可以保存如:线条的样式、颜色、填充、图形变换等,特别是配合图形变换,两者可以互补长短

状态保存和还原的对应函数:

save:保存当前的状态,以便restore还原

restore:还原到之前sava保存的状态

语法格式:

代码语言:javascript
复制
//这里配合图形变换来演示
//图形变换系列的函数,重复使用是叠加效果,而不是替换,所以使用图形变换+状态保存还原可以更快速简便

//正常方式
  var ctx = document.querySelector(".canvas").getContext("2d");
      ctx.beginPath();
      ctx.fillStyle = "red";
      ctx.translate(100, 100);
      ctx.fillRect(0, 0, 400, 400);
      ctx.translate(-100, -100);
      ctx.fillStyle = "red";
      ctx.fillRect(400, 400, 400, 400);
      ctx.closePath();
      //图形变换函数连续使用会进行叠加效果,会影响到下面绘制的图形,为了不影响,必须再次使用变换函数来还原

//这里运用了canvas的状态保存还原后,可以更方便使用变换函数
var ctx = document.querySelector(".canvas").getContext("2d");
      ctx.beginPath();
      ctx.fillStyle = "red";
      ctx.save();
      ctx.translate(100, 100);
      ctx.fillRect(0, 0, 400, 400);
      ctx.restore();
      ctx.fillRect(400, 400, 400, 400);
      ctx.closePath();

图形变换

图形变换系列函数:

translate(x,y):偏移、移动

rotate(?deg):旋转

scale(sx,sy):缩放

变换矩阵:

transform(a,b,c,d,e,f):图形变换矩阵函数是一个把所有变换效果结于一身的函数,连续使用会造成链集和叠加效果

setTransform(a,b,c,d,e,f):可以重置transform函数,使之前的失效

语法格式:

代码语言:javascript
复制
//改用图形变换函数 translate rotate scale 后的无重复五角星
//scale 会有许多副作用如:边框将会变大、长宽比也好增大、x、y也会随之增大
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>Document</title>
  </head>
  <body>
    <canvas width="800" height="800" class="canvas"></canvas>
    <script src="../node/jquery.js"></script>
    <script>
      var ctx = document.querySelector("canvas").getContext("2d");
      ctx.fillStyle = "black";
      ctx.fillRect(
        0,
        0,
        document.querySelector("canvas").width,
        document.querySelector("canvas").height
      );

      ctx.fillStyle = "#fc1";
      ctx.strokeStyle = "#fb5";
      ctx.lineWidth = 5;
      ctx.lineJoin = "round";
      var ele = [];
      start(ele);
      end(ele);

      function start(arr) {
        for (var i = 0; i < 200; i++) {
          var flag = true,
            ran = Math.random() * 10 + 10,
            x =
              Math.random() *
                (document.querySelector("canvas").width - ran * 2) +
              ran,
            y =
              Math.random() *
                (document.querySelector("canvas").height - ran * 2) +
              ran,
            rotate = Math.random() * 360;
          for (var j = 0; j < ele.length; j++) {
            var oldx = Math.pow(x - arr[j][1], 2);
            var oldy = Math.pow(y - arr[j][2], 2);
            var oldr = Math.pow(ran + arr[j][0], 2);
            if (oldx + oldy < oldr) {
              flag = false;
            }
          }

          flag ? arr.push([ran, x, y, rotate]) : i--;
        }
      }
      function end(arr) {
        for (var i = 0; i < arr.length; i++) {
          ctx.save();
          ctx.beginPath();
          ctx.translate(arr[i][1], arr[i][2]);
          ctx.rotate(arr[i][3]);
          ctx.scale(0.5,0.5)
          DrawStart(ctx, arr[i][0]);
          ctx.fill();
          ctx.stroke();
          ctx.closePath();
          ctx.restore();
        }
      }
      function DrawStart(context, r) {
        //绘画对象 大圆的半径 小圆半径  x轴 y轴
        for (var i = 0; i <= 5; i++) {
          ctx.lineTo(
            Math.cos(((18 + 72 * i) / 180) * Math.PI) * r,
            -Math.sin(((18 + 72 * i) / 180) * Math.PI) * r
          );
          ctx.lineTo(
            (Math.cos(((54 + 72 * i) / 180) * Math.PI) * r) / 2,
            (-Math.sin(((54 + 72 * i) / 180) * Math.PI) * r) / 2
          );
        }
      }
    </script>
  </body>
</html>


//transform
 var ctx = document.querySelector(".canvas").getContext("2d");
      ctx.beginPath();
      ctx.fillStyle = "red";
      ctx.save();
      ctx.transform(1.5,0,0,1.5,200,100);
                  a:水平缩放 b:水平倾斜 c:垂直倾斜 d:垂直缩放 e:水平位移 f:垂直位移
      ctx.fillRect(0, 0, 400, 400);
      ctx.restore();
      ctx.fillRect(400, 400, 400, 400);
      ctx.closePath();

渐变

渐变系列函数:

createLinearGradient(x,y,EndX,EndY):创建渐变

addColorStop(0-1,color) :添加颜色

createRadialGradient(x1,y1,r1,x2,y2,r2):创建一个径向的渐变,整个径向渐变发生在俩个圆中间

语法格式:

代码语言:javascript
复制
var ctx = document.querySelector("canvas").getContext("2d");
      document.querySelector("canvas").width = document.body.clientWidth;
      document.querySelector("canvas").height = document.body.clientHeight;
      //创建渐变对象
      var grd = ctx.createLinearGradient(
        0,   //x
        0,    //y
        0,    //endX
        document.querySelector("canvas").height //endY
        //这里的渐变方向是从上往下
      );


      //下面的是径向渐变,在定义的两个圆之间产生渐变
      //第一个圆是外圆,内圆则是第二个
      //var grd =             ctx.createRadialGradient(document.querySelector("canvas").width/2,document.querySelector("canvas").height/2,400,document.querySelector("canvas").width/2,document.querySelector("canvas").height/2,0)


      //添加颜色,取值范围(0,1),必须有起点,终点
      grd.addColorStop(0, "black");
      grd.addColorStop(1, "#035");
      //最后把渐变对象添加到要应用的样式填充上
      ctx.fillStyle = grd;
      ctx.fillRect(
        0,
        0,
        document.querySelector("canvas").width,
        document.querySelector("canvas").height
      );

三角函数讲解

绘制圆形

1角度 = 1* Math.PI/ 180弧度

1弧度 = 1* 180 / Math.PI 角度

arc(x,y,r,0,360,false)

x,y 圆心坐标位置

r 圆半径

0,360

从0度到360度所对应的弧度 (弧度: 角度值*Math.PI/180) true/false 逆时针/顺时针绘图

添加图片、视频、canvas

相关函数:

createPattern(ele,repeat|repeat-x|repeat-y|no-repeat):添加图片、视频、画布到指定的场景

语法格式:

代码语言:javascript
复制
//添加图片
 var ctx = document.querySelector("canvas").getContext("2d");
      var img = new Image();
      img.src = "../newIMg.png";
      img.onload = () => {
        var createImg = ctx.createPattern(img, "repeat");
        ctx.fillStyle = createImg;
        ctx.fillRect(0, 0, 800, 800);
      };
 //添加图片时注意:必须图片加载完后在载入createPattern,否则载入失败

 //添加画布
 function createImgCanvas() {
        var c = document.createElement("canvas");
        var ctx = c.getContext("2d");

        c.width = 400;
        c.height = 400;
        ctx.fillStyle = "yellow";
        ctx.transform(1, 0, 0, 1, c.width / 2, c.height / 2);
        DrawStart(ctx, 200);
        ctx.fill();

        return c;
      }
      var ctx = document.querySelector("canvas").getContext("2d");

      document.querySelector("canvas").width = 1400;
      document.querySelector("canvas").height = 1400;
      ctx.fillStyle = ctx.createPattern(createImgCanvas(), "repeat");
      ctx.fillRect(0, 0, 1400, 1400);

案例:绘制圆角矩形

代码语言:javascript
复制
      /*
          把圆分为4份,顺时针顺序绘制 
          Math.PI / 2 半圆分1为2
          Math.PI 一个圆中的一半
          Math.PI*3/2 || Math.PI*1.5  1个半圆加一个1分为2的半圆
          Math.PI*2 完整的圆 
      */

var ctx = document.querySelector("canvas").getContext("2d");
      ctx.beginPath();
      ctx.arc(400 - 50, 400 - 50, 50, 0, Math.PI / 2);
      ctx.lineTo(50, 400);
      ctx.arc(50, 400 - 50, 50, Math.PI / 2, Math.PI);
      ctx.lineTo(0, 50);
      ctx.arc(50, 50, 50, Math.PI, (Math.PI * 3) / 2);
      ctx.lineTo(400 - 50, 0);
      ctx.arc(400 - 50, 50, 50, (Math.PI * 3) / 2, Math.PI * 2);
      ctx.closePath();
      ctx.stroke();

  //封装函数
  function PathRoundRect(ctx, width, height, r) 
      {
        ctx.beginPath();
        ctx.arc(width - r, height - r, r, 0, Math.PI / 2);
        ctx.lineTo(r, height);
        ctx.arc(r, height - r, r, Math.PI / 2, Math.PI);
        ctx.lineTo(0, r);
        ctx.arc(r, r, r, Math.PI, Math.PI * 1.5);
        ctx.lineTo(width - r, 0);
        ctx.arc(width - r, r, r, (Math.PI * 3) / 2, Math.PI * 2);
        ctx.closePath();
      }
  //升级版
  function PathRoundRect(ctx, width, height, r,optionColor,optionStyle)
      {
        if(r*2>width||r*2>height)return;
        if(optionStyle)
        {
        optionStyle.stroke === true ? (optionColor.stroke ? (ctx.strokeStyle =optionColor.stroke ):null) : null;
        optionStyle.fill === true ?(optionColor.fill ? (ctx.fillStyle =optionColor.fill):null) : null;
        }
        ctx.beginPath();
        ctx.arc(width - r, height - r, r, 0, Math.PI / 2);
        ctx.lineTo(r, height);
        ctx.arc(r, height - r, r, Math.PI / 2, Math.PI);
        ctx.lineTo(0, r);
        ctx.arc(r, r, r, Math.PI, Math.PI * 1.5);
        ctx.lineTo(width - r, 0);
        ctx.arc(width - r, r, r, (Math.PI * 3) / 2, Math.PI * 2);
        ctx.closePath();
      }
   //最终版
    function RoundRect(ctx, width, height, r, optionColor, optionStyle) {
        var flagfill,flagstroke;
        if (r*2 > width || r*2 > height) return;
        if (optionStyle) {
          optionStyle.stroke === true
            ? optionColor.stroke
              ? (ctx.strokeStyle = optionColor.stroke)
              : null
            : null;
          optionStyle.fill === true
            ? optionColor.fill
              ? (ctx.fillStyle = optionColor.fill)
              : null
            : null;
          flagfill = optionColor.fill ?true:false;
          flagstroke = optionColor.stroke ?true:false;
        }
        ctx.beginPath();
        ctx.arc(width - r, height - r, r, 0, Math.PI / 2);
        ctx.lineTo(r, height);
        ctx.arc(r, height - r, r, Math.PI / 2, Math.PI);
        ctx.lineTo(0, r);
        ctx.arc(r, r, r, Math.PI, Math.PI * 1.5);
        ctx.lineTo(width - r, 0);
        ctx.arc(width - r, r, r, (Math.PI * 3) / 2, Math.PI * 2);
        ctx.closePath();

        flagstroke ? ctx.stroke() : null;
        flagfill ? ctx.fill() : null;
      }

案例:2048九宫格

代码语言:javascript
复制
 var ctx = document.querySelector("canvas").getContext("2d");
      ctx.translate(800/4,800/4)
      RoundRect(
        ctx,
        480,
        470,
        10,
        { fill: "red", stroke: "green" },
        { fill: true, stroke: true }
      );
      for (var i = 0; i < 4; i++) {
        ctx.save();
        ctx.translate(10, i * 15);
        for (var j = 0; j < 4; j++) {
          ctx.save();
          ctx.translate(j * 120, i * 100 +15);
          RoundRect(
            ctx,
            100,
            100,
            10,
            { fill: "green", stroke: "green" },
            { fill: true, stroke: true }
          );
          ctx.restore();
        }
        ctx.restore();
      }

      function RoundRect(ctx, width, height, r, optionColor, optionStyle) {
        var flagfill, flagstroke;
        if (r > width || r > height) return;
        if (optionStyle) {
          optionStyle.stroke === true
            ? optionColor.stroke
              ? (ctx.strokeStyle = optionColor.stroke)
              : null
            : null;
          optionStyle.fill === true
            ? optionColor.fill
              ? (ctx.fillStyle = optionColor.fill)
              : null
            : null;
          flagfill = optionColor.fill ? true : false;
          flagstroke = optionColor.stroke ? true : false;
        }
        ctx.beginPath();
        ctx.arc(width - r, height - r, r, 0, Math.PI / 2);
        ctx.lineTo(r, height);
        ctx.arc(r, height - r, r, Math.PI / 2, Math.PI);
        ctx.lineTo(0, r);
        ctx.arc(r, r, r, Math.PI, Math.PI * 1.5);
        ctx.lineTo(width - r, 0);
        ctx.arc(width - r, r, r, (Math.PI * 3) / 2, Math.PI * 2);
        ctx.closePath();

        flagstroke ? ctx.stroke() : null;
        flagfill ? ctx.fill() : null;
      }

案例:绘制弯月

代码语言:javascript
复制
 pathMoon(ctx, 2, 300, 300, 200);
      function pathMoon(ctx, d, x, y, r, deg, color) {
        ctx.save();
        ctx.translate(x, y);
        ctx.scale(r, r);
        ctx.rotate(deg || 0);
        ctx.beginPath();
        Moon(d, ctx);
        ctx.fillStyle = color ? color : "yellow";
        ctx.fill();
        ctx.closePath();
        ctx.restore();
        function Moon(d, ctx) {
          ctx.arc(0, 0, 1, Math.PI * 0.5, Math.PI * 1.5, true);
          ctx.moveTo(0, -1);
          ctx.arcTo(d, 0, 0, 1, dis(0, -1, d, 0) / d);
        }
        function dis(x1, y1, x2, y2) {
          return Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));
        }
      }

贝塞尔曲线

贝塞尔曲线相关函数:

quadraticCurveTo(x1,y1,x2,y2):二次贝塞尔曲线 一个控制点 1

bezierCurveTo(x1,y1,x2,y2,x3,y3):三次贝塞尔曲线 两个控制点 1 2

代码语言:javascript
复制
//起始点不由函数来定,可以用moveTo等画路径的函数来定

//二次贝塞尔曲线
        ctx.moveTo(0, 0);
          ctx.quadraticCurveTo(800,400,400,800)
          ctx.stroke()

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>Document</title>
    <style>
      html,
      body {
        width: 100%;
        height: 100%;
      }
    </style>
  </head>
  <body>
    <canvas class="canvas"></canvas>
    <script src="../node/jquery.js"></script>
    <script>


      var ctx = document.querySelector("canvas").getContext("2d");

      document.querySelector("canvas").width = document.body.clientWidth;
      document.querySelector("canvas").height = document.body.clientHeight;
        ctx.save();
        var grd = ctx.createLinearGradient(0,0,0,document.querySelector("canvas").height);
        grd.addColorStop(0,"black");
        grd.addColorStop(1,"#035");
        ctx.fillStyle = grd;
        ctx.fillRect(0,0,document.querySelector("canvas").width,document.querySelector("canvas").height);
        ctx.restore();
      ctx.fillStyle = "#fc1";
      ctx.strokeStyle = "#fb5";
      ctx.lineWidth = 5;
      ctx.lineJoin = "round";
      var ele = [];
      start(ele,200);
      end(ele);
      pathMoon(ctx, 2, document.querySelector("canvas").width*0.85, document.querySelector("canvas").height/4,80,0,"#fc1");
      RectLoda(ctx);





      function RectLoda(ctx)
      {
        ctx.save();
        ctx.beginPath();
        ctx.moveTo(0,document.querySelector("canvas").height*0.65);

//三次贝塞尔曲线应用       ctx.bezierCurveTo(document.querySelector("canvas").width/2,650,document.querySelector("canvas").width/2,document.querySelector("canvas").height/3,document.querySelector("canvas").width,document.querySelector("canvas").height-200);
        ctx.lineTo(document.querySelector("canvas").width,document.querySelector("canvas").height)
        ctx.lineTo(0,document.querySelector("canvas").height)


       var bgcolor = ctx.createLinearGradient(0,document.querySelector("canvas").height,0,0);
        bgcolor.addColorStop(0,"#030");
        bgcolor.addColorStop(1,"#580");
        ctx.fillStyle = bgcolor;
        ctx.fill();
        ctx.closePath();
        ctx.restore();
      }
      function pathMoon(ctx, d, x, y, r, deg, color) {
        ctx.save();
        ctx.translate(x, y);
        ctx.scale(r, r);
        ctx.rotate(deg || 0);
        ctx.beginPath();
        Moon(d, ctx);
        ctx.fillStyle = color ? color : "yellow";
        ctx.fill();
        ctx.closePath();
        ctx.restore();
        function Moon(d, ctx) {
          ctx.arc(0, 0, 1, Math.PI * 0.5, Math.PI * 1.5, true);
          ctx.moveTo(0, -1);
          ctx.arcTo(d, 0, 0, 1, dis(0, -1, d, 0) / d);
        }
        function dis(x1, y1, x2, y2) {
          return Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));
        }
      }

      function start(arr,num) {
        for (var i = 0; i < num; i++) {
          var flag = true,
            ran = Math.random() * 10 + 5,
            x =
              Math.random() *
                (document.querySelector("canvas").width - ran * 2) +
              ran,
            y =
              (Math.random() *
                (document.querySelector("canvas").height - ran * 2) +
                ran) *
              0.65,
            rotate = Math.random() * 360;
          for (var j = 0; j < ele.length; j++) {
            var oldx = Math.pow(x - arr[j][1], 2);
            var oldy = Math.pow(y - arr[j][2], 2);
            var oldr = Math.pow(ran + arr[j][0], 2);
            if (oldx + oldy < oldr) {
              flag = false;
            }
            if(x>document.querySelector("canvas").width*0.85&&x<document.querySelector("canvas").width*0.85+80*1.15)
            {
              flag = false;

            }

          }

          flag ? arr.push([ran, x, y, rotate]) : i--;
        }
      }
      function end(arr) {
        for (var i = 0; i < arr.length; i++) {
          ctx.save();
          ctx.beginPath();
          ctx.translate(arr[i][1], arr[i][2]);
          ctx.rotate(arr[i][3]);
          ctx.scale(0.7, 0.7);
          DrawStart(ctx, arr[i][0]);
          ctx.fill();
          ctx.stroke();
          ctx.closePath();
          ctx.restore();
        }
      }

      function DrawStart(ctx, r) {
        //绘画对象 大圆的半径 小圆半径  x轴 y轴
        for (var i = 0; i <= 5; i++) {
          ctx.lineTo(
            Math.cos(((18 + 72 * i) / 180) * Math.PI) * r,
            -Math.sin(((18 + 72 * i) / 180) * Math.PI) * r
          );
          ctx.lineTo(
            (Math.cos(((54 + 72 * i) / 180) * Math.PI) * r) / 2,
            (-Math.sin(((54 + 72 * i) / 180) * Math.PI) * r) / 2
          );
        }
      }
    </script>
  </body>
</html>

字体

字体绘制相关函数:

font:设置字体样式属性 五个参数依次是font-style(italic oblique)、font-variant(small-caps)、font-weight(bold lighter bolder)、font-size、font-family

fillText(string,x,y,length):绘制带填充字体

strokeText(string,x,y,length):绘制带边框的字体

textAlign:设置字体水平对齐 参数有:right center left

textBaseline:设置字体垂直对齐 参数有:top middle bottom alphabetic(defalut) ideographic hanging

measureText(String).width:获取文本宽度(会根据font设置的字体、字号来决定)

语法格式:

代码语言:javascript
复制
 var ctx = document.querySelector(".canvas").getContext("2d");
    var grd = ctx.createLinearGradient(0,0,800,0);
    grd.addColorStop(0,"red");
    grd.addColorStop(0.5,"yellow");
    grd.addColorStop(1,"green");
    ctx.fillStyle = grd;
    ctx.font = "bold 40px 微软雅黑 ";
    ctx.fillText("How are you!",100,100,300);
    //字体可以填充渐变色、图形纹理、另一个画布

  ===================================================================
  //只带边框的字体
   var ctx = document.querySelector(".canvas").getContext("2d");
    var grd = ctx.createLinearGradient(0,0,800,0);
    grd.addColorStop(0,"red");
    grd.addColorStop(0.5,"yellow");
    grd.addColorStop(1,"green");
    ctx.lineWidth =2;
    ctx.strokeStyle = grd;
    ctx.font = "bold 40px 微软雅黑 ";
    ctx.strokeText("How are you!",100,100,300);
    ===============================================
   //带纹理的字体
    var ctx = document.querySelector(".canvas").getContext("2d");
      // var grd = ctx.createLinearGradient(0,0,800,0);
      // grd.addColorStop(0,"red");
      // grd.addColorStop(0.5,"yellow");
      // grd.addColorStop(1,"green");

      var img = new Image();
      img.src = "../newIMg.png";
      img.onload = function() {
        var pattern = ctx.createPattern(img, "repeat");
        ctx.fillStyle = pattern;
        ctx.strokeStyle = "red";
        ctx.lineWidth =1;
        ctx.font = "bold 40px 微软雅黑 ";
        ctx.strokeText("How are you!", 100, 100, 300);
        ctx.fillText("How are you!", 100, 100, 300);
      };

水平对齐效果:

垂直对齐效果:

案例:水平垂直居中

代码语言:javascript
复制
 var ctx = document.querySelector(".canvas").getContext("2d");
      ctx.fillStyle = "red";
      ctx.strokeStyle = "red";
      ctx.moveTo(400, 0);
      ctx.lineTo(400, 800);
      ctx.moveTo(0, 400);
      ctx.lineTo(800, 400);
      ctx.stroke();

      ctx.textAlign = "center";
      ctx.textBaseline = "middle";
      ctx.font = "bold 100px 微软雅黑 ";
      ctx.strokeText("How are you!", 400, 400);

阴影

阴影相关属性:

shadowColor:设置阴影颜色

shadowOffsetX:设置阴影X偏移

shadowOffsetY:设置阴影Y偏移

shadowBlur:设置阴影模糊扩散程度

语法格式:

代码语言:javascript
复制
  var ctx = document.querySelector("canvas").getContext("2d");
      ctx.shadowColor = "black";
     ctx.fillStyle = "red"
      var num = 0;
      var flag = true;
      setInterval(function() {
        ctx.shadowOffsetX = -20+num;
      ctx.shadowOffsetY = -20+num;
        num == 100 ? (flag = false) : num == 0 ? (flag = true) : null;
        flag ? num++ : num--;
        ctx.shadowBlur = num;
        ctx.clearRect(0, 0, 800, 800);
        ctx.fillRect(100, 100, 400, 400);
      }, 50);

透明

透明相关函数:

在canvas中要实现透明,可以使用rgba颜色,也可以使用以下方法

globalAlpha:设置透明度 范围(1-0) 全局透明

语法格式:

代码语言:javascript
复制
  var ctx = document.querySelector("canvas").getContext("2d");
      var color = ["red","green","yellow","blue","black"]
     for(var i=0;i<200;i++)
     {
       var randomX = Math.random()*800;
       var randomY = Math.random()*800;
       var randomR = Math.random()*30;
      var R = Math.floor(Math.random()*255),G = Math.floor(Math.random()*255),B = Math.floor(Math.random()*255);
       ctx.save();
       ctx.beginPath();
       ctx.globalAlpha = 0.7;
       ctx.fillStyle = `rgb(${R},${G},${B})`;
       ctx.arc(randomX,randomY,randomR,0,Math.PI*2);
       ctx.fill();
       ctx.closePath();
       ctx.restore();
     }

遮盖顺序

xx.globalCompositeOperation = “source-over” (默认,后绘制的图形会压在先绘制的图形上) / “destination-over”(先绘制的图形压在后绘制的图形上)

相关属性:

globalCompositeOperation :改变元素显示效果与遮盖顺序

各个参数的实现效果可以参考菜鸟,或有canvas手册的网址,或以下链接

https://blog.csdn.net/fe_dev/article/details/81985367

此链接,有水滴扩散、刮刮卡案例参考

参数:

语法格式:

代码语言:javascript
复制
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>Document</title>
    <style>
      html,
      body {
        width: 100%;
        height: 100%;
      }
    </style>
  </head>
  <body>
    <canvas class="canvas" width="800" height="800"></canvas>
    <script src="../node/jquery.js"></script>
    <script>
      var ctx = document.querySelector("canvas").getContext("2d");
      var color = ["red","green","yellow","blue","black"]
      var Balls = [];
     for(var i=0;i<200;i++)
     {
      var randomR = Math.random()*30+10;
       var randomX = Math.random()*(800-randomR*2)+randomR;
       var randomY = Math.random()*(800-randomR*2)+randomR;
      var R = Math.floor(Math.random()*255),G = Math.floor(Math.random()*255),B = Math.floor(Math.random()*255);

        let balls ={
          x:randomX,
          y:randomY,
          r:randomR,
          color:`rgb(${R},${G},${B})`,
          vx:(Math.random()*5+5)*(Math.pow(-1,Math.floor(Math.random()*100))),
          vy:(Math.random()*5+5)*(Math.pow(-1,Math.floor(Math.random()*100))),
        }
      Balls.push(balls);
     }

     setInterval(()=>{
       draw(ctx)
     },50)

     function draw(ctx)
     {
       ctx.clearRect(0,0,800,800)
       for(let i=0;i<Balls.length;i++)
       {
       ctx.save();
       ctx.beginPath();
      ctx.globalCompositeOperation = "xor";
       ctx.fillStyle = Balls[i].color;
       ctx.arc(Balls[i].x,Balls[i].y,Balls[i].r,0,Math.PI*2);
       ctx.fill();
       ctx.closePath();
       ctx.restore();
       Balls[i].x+=Balls[i].vx;
       Balls[i].y+=Balls[i].vy;
       if(Balls[i].x-Balls[i].r<=0)
       {
         Balls[i].vx = -Balls[i].vx;
          Balls[i].x = Balls[i].r;
       }
       if(Balls[i].x+Balls[i].r >= 800)
       {
         Balls[i].vx = -Balls[i].vx;
         Balls[i].x = 800-Balls[i].r;
       }
       if(Balls[i].y-Balls[i].r<=0)
       {
         Balls[i].vy = -Balls[i].vy;
         Balls[i].y = Balls[i].r;
       }
       if(Balls[i].y+Balls[i].r>=800)
       {
         Balls[i].vy = -Balls[i].vy;
         Balls[i].y = 800-Balls[i].r;
       }
       }
     }

    </script>
  </body>
</html>

剪切

相关函数:

clip:相对于上个填充路径做剪切效果

语法格式:

代码语言:javascript
复制
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>Document</title>
    <style>
      html,
      body {
        width: 100%;
        height: 100%;
      }
    </style>
  </head>
  <body>
    <canvas class="canvas" width="800" height="800"></canvas>
    <script src="../node/jquery.js"></script>
    <script>
      var ctx = document.querySelector("canvas").getContext("2d");
      var r = 150;
      ctx.fillStyle = "black";
      ctx.fillRect(0, 0, 800, 800);
      ctx.canvas.onmousemove = e => {
        ctx.clearRect(0, 0, 800, 800);
        ctx.beginPath();
        ctx.fillStyle = "black";
        ctx.fillRect(0, 0, 800, 800);
        ctx.closePath();

        ctx.save();
        ctx.beginPath();
        ctx.fillStyle = "rgba(255,255,255,1)";
        var x = e.pageX - r <= 0 ? r : e.pageX;
        var y = e.pageY - r <= 0 ? r : e.pageY;
        x = e.pageX + r > 800 ? 800 - r : x;
        y = e.pageY + r > 800 ? 800 - r : y;
        ctx.arc(x, y, r, 0, Math.PI * 2);
        ctx.fill();
        ctx.clip();
        ctx.closePath();

        ctx.beginPath();
        ctx.fillStyle = "red";
        ctx.font = "200px bold 微软雅黑";
        ctx.textAlign = "center";
        ctx.textBaseline = "middle";
        ctx.fillText("Canvas", 400, 400);
        ctx.closePath();
        ctx.restore();
        document.onkeyup = ev => {
          ev.keyCode === 38 ? (r += 20) : null;
          ev.keyCode === 40 ? (r -= 20) : null;
          if (r >= 390) r = 390;
          ctx.canvas.onmousemove(e);
          return false;
        };
      };
      ctx.canvas.onmouseout = () => {
        ctx.fillStyle = "black";
        ctx.fillRect(0, 0, 800, 800);
        document.onkeyup = null;
      };
    </script>
  </body>
</html>

实现剪纸效果

剪纸效果参考非零环绕原侧,自动识别里、外、面,一个面不同时出现顺时针和逆时针就填充,如果同时出现顺时针和逆时针就不填充,这也就说明了图形的绘制方向,会影响其是否填充

语法格式:

代码语言:javascript
复制
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>Document</title>
    <style>
      html,
      body {
        width: 100%;
        height: 100%;
      }
    </style>
  </head>
  <body>
    <canvas class="canvas" width="800" height="800"></canvas>
    <script src="../node/jquery.js"></script>
    <script>
      var ctx = document.querySelector("canvas").getContext("2d");
      ctx.beginPath();
      ctx.rect(200, 200, 400, 200);
      drawRect(ctx, 220, 220, 100, 100);
      ctx.arc(400, 270, 50, Math.PI * 2, 0, true);
      Triangle(ctx, 510, 220, 460, 320, 560, 320);
      ctx.closePath();
      ctx.fillStyle = "red";
      ctx.shadowColor = "black";
      ctx.shadowOffsetX = 10;
      ctx.shadowOffsetY = 10;
      ctx.fill();
      function drawRect(ctx, x, y, w, h) {
        ctx.moveTo(x, y);
        ctx.lineTo(x, y + h);
        ctx.lineTo(x + w, y + h);
        ctx.lineTo(x + w, y);
        ctx.lineTo(x, y);
      }
      function Triangle(ctx, x1, y1, x2, y2, x3, y3) {
        ctx.moveTo(x1, y1);
        ctx.lineTo(x2, y2);
        ctx.lineTo(x3, y3);
        ctx.lineTo(x1, y1);
      }
    </script>
  </body>
</html>

交互

canvas交互相关函数:

isPointInPath(x,y):检测指定的坐标是否在绘制元素内,只能判断最后一个绘制的封闭路径

语法格式:

代码语言:javascript
复制
//点击填充颜色
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>Document</title>
    <style>
      * {
        padding: 0;
        margin: 0;
      }
      html,
      body {
        width: 100%;
        height: 100%;
      }
    </style>
  </head>
  <body>
    <canvas class="canvas" width="800" height="800"></canvas>
    <script src="../node/jquery.js"></script>
    <script>
      var ctx = document.querySelector("canvas").getContext("2d");
      var Balls = [];
      for (var i = 0; i < 10; i++) {
        ctx.beginPath();
        Balls.push({
          x: Math.random() * 800,
          y: Math.random() * 800,
          r: Math.random() * 100
        });
      }
      Draw(ctx);
      function Draw(ctx) {
        for (let i = 0; i < Balls.length; i++) {
          ctx.beginPath();
          ctx.arc(Balls[i].x, Balls[i].y, Balls[i].r, 0, Math.PI * 2);
          ctx.stroke();
        }

        ctx.canvas.addEventListener("click", function(event) {
          for (let i = 0; i < Balls.length; i++) {
            ctx.beginPath();
            ctx.arc(Balls[i].x, Balls[i].y, Balls[i].r, 0, Math.PI * 2);
            if (ctx.isPointInPath(event.pageX, event.pageY)) {
              ctx.fillStyle = "yellow";
              ctx.fill();
            }
          }
        });
      }
    </script>
  </body>
</html>


//鼠标滑入填充颜色,滑出清空颜色


<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>Document</title>
    <style>
      * {
        padding: 0;
        margin: 0;
      }
      html,
      body {
        width: 100%;
        height: 100%;
      }
    </style>
  </head>
  <body>
    <canvas class="canvas" width="800" height="800"></canvas>
    <script src="../node/jquery.js"></script>
    <script>
      var ctx = document.querySelector("canvas").getContext("2d");
      var Balls = [];
      for (var i = 0; i < 10; i++) {
        ctx.beginPath();
        Balls.push({
          x: Math.random() * 800,
          y: Math.random() * 800,
          r: Math.random() * 100
        });
      }
      Draw(ctx);
      function Draw(ctx) {
        for (let i = 0; i < Balls.length; i++) {
          ctx.beginPath();
          ctx.arc(Balls[i].x, Balls[i].y, Balls[i].r, 0, Math.PI * 2);
          ctx.stroke();
        }

        ctx.canvas.addEventListener("mousemove", function(event) {
          ctx.clearRect(0, 0, 800, 800);
          for (let i = 0; i < Balls.length; i++) {
            ctx.beginPath();
            ctx.arc(Balls[i].x, Balls[i].y, Balls[i].r, 0, Math.PI * 2);
            if (ctx.isPointInPath(event.pageX, event.pageY)) {
              ctx.fillStyle =
                "rgb(" +
                Math.random() * 255 +
                "," +
                Math.random() * 255 +
                "," +
                Math.random() * 255 +
                ")";
              ctx.fill();
            } else ctx.stroke();
          }
        });
      }
    </script>
  </body>
</html>

案例:小球滚动(面向对象+控制面板)

代码语言:javascript
复制
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>Document</title>
    <style>
      html,
      body {
        width: 100%;
        height: 100%;
      }
      .canvasBox {
        width: 800px;
        height: 800px;
        position: relative;
      }
      .canvasBox > .SetupPanel {
        width: 300px;
        height: 200px;
        background: #99b4e487;
        border-radius: 30px;
        position: absolute;
        left: 0;
        top: 0;
        color: white;
      }
      .canvasBox > .SetupPanel > h1 {
        text-align: center;
        line-height: 25px;
      }
      .canvasBox > .SetupPanel > a {
        float: left;
        color: #478aff87;
        background: #e5eeff;
        border-radius: 5px;
        padding: 10px 0;
        margin: 3px 0;
        text-decoration: none;
        text-align: center;
        line-height: 15px;
        width: 100%;
      }
    </style>
  </head>
  <body>
    <div class="canvasBox">
      <canvas class="canvas" width="800" height="800"></canvas>
      <div class="SetupPanel">
        <h1>控制面板</h1>
        <a href="javascript:void(0)">点击停止</a>
        <a href="javascript:void(0)">点击切换背景颜色</a>
        <a href="javascript:void(0)">点击切换覆盖模式</a>
      </div>
    </div>
    <script src="../node/jquery.js"></script>
    <script>
      class Animate {
        constructor(canvas) {
          this.canvas = document.querySelector(canvas);
          this.ctx = this.canvas.getContext("2d");
          this.initAttr();
          this.initDraw();
          this.initEvent();
        }
        initAttr() {
          this.color = ["red", "green", "yellow", "blue", "black"];
          this.bgcolor = null;
          this.Balls = [];
          this.flag = true;
          this.module = ["xor", "lighter", null];
          this.option = null;
          this.time = null;
        }
        initEvent() {
          document.querySelectorAll(
            ".canvasBox>.SetupPanel>a"
          )[0].onclick = () => {
            if (this.flag) {
              clearInterval(this.time);
              this.flag = false;
              document.querySelectorAll(
                ".canvasBox>.SetupPanel>a"
              )[0].innerHTML = "点击开始";
              document.querySelectorAll(
                ".canvasBox>.SetupPanel>a"
              )[0].style.background = "red";
            } else {
              this.time = setInterval(() => {
                this.draw(this.bgcolor);
              }, 50);
              this.flag = true;
              document.querySelectorAll(
                ".canvasBox>.SetupPanel>a"
              )[0].innerHTML = "点击停止";
              document.querySelectorAll(
                ".canvasBox>.SetupPanel>a"
              )[0].style.background = "";
            }
          };
          document.querySelectorAll(
            ".canvasBox>.SetupPanel>a"
          )[1].onclick = () => {
            this.bgcolor = this.color[
              parseInt(Math.random() * this.color.length - 1)
            ];
          };
          document.querySelectorAll(
            ".canvasBox>.SetupPanel>a"
          )[2].onclick = () => {
            this.option = this.module[
              Math.ceil(Math.random() * this.module.length - 1)
            ];
          };
        }
        initDraw() {
          for (let i = 0; i < 200; i++) {
            let randomR = Math.random() * 30 + 10;
            let randomX = Math.random() * (800 - randomR * 2) + randomR;
            let randomY = Math.random() * (800 - randomR * 2) + randomR;
            let R = Math.floor(Math.random() * 255),
              G = Math.floor(Math.random() * 255),
              B = Math.floor(Math.random() * 255);

            let balls = {
              x: randomX,
              y: randomY,
              r: randomR,
              color: `rgb(${R},${G},${B})`,
              vx:
                (Math.random() * 5 + 5) *
                Math.pow(-1, Math.floor(Math.random() * 100)),
              vy:
                (Math.random() * 5 + 5) *
                Math.pow(-1, Math.floor(Math.random() * 100))
            };
            this.Balls.push(balls);
          }
        }
        draw(bgcolor) {
          this.ctx.clearRect(0, 0, 800, 800);

          this.bgDraw(bgcolor);
          for (let i = 0; i < this.Balls.length; i++) {
            this.ctx.save();
            this.ctx.beginPath();
            this.ctx.globalCompositeOperation = this.option;
            this.ctx.fillStyle = this.Balls[i].color;
            this.ctx.arc(
              this.Balls[i].x,
              this.Balls[i].y,
              this.Balls[i].r,
              0,
              Math.PI * 2
            );
            this.ctx.fill();
            this.ctx.closePath();
            this.ctx.restore();
            this.Balls[i].x += this.Balls[i].vx;
            this.Balls[i].y += this.Balls[i].vy;
            if (this.Balls[i].x - this.Balls[i].r <= 0) {
              this.Balls[i].vx = -this.Balls[i].vx;
              this.Balls[i].x = this.Balls[i].r;
            }
            if (this.Balls[i].x + this.Balls[i].r >= 800) {
              this.Balls[i].vx = -this.Balls[i].vx;
              this.Balls[i].x = 800 - this.Balls[i].r;
            }
            if (this.Balls[i].y - this.Balls[i].r <= 0) {
              this.Balls[i].vy = -this.Balls[i].vy;
              this.Balls[i].y = this.Balls[i].r;
            }
            if (this.Balls[i].y + this.Balls[i].r >= 800) {
              this.Balls[i].vy = -this.Balls[i].vy;
              this.Balls[i].y = 800 - this.Balls[i].r;
            }
          }
        }
        bgDraw(bgcolor) {
          this.ctx.beginPath();
          this.ctx.fillStyle = bgcolor;
          this.ctx.fillRect(0, 0, 800, 800);
          this.ctx.closePath();
        }
      }

      //初始化对象
      let animate = new Animate("canvas");
      var ctx = animate.ctx;
      //开始执行动画
      animate.time = setInterval(() => {
        animate.draw(animate.bgcolor);
      }, 50);
    </script>
  </body>
</html>

清除

清除也称重绘,在动画应用当中是不可分割的,动画是一帧一帧的播放,中间少不了清除的步骤,否则将达不到动画的播放帧数标准

清除画布相关函数:

clearRect(startX,startY,endX,endY):清除参数指定范围内绘制的元素

语法格式:

代码语言:javascript
复制
ctx.clearRect(0,0,canvas.width,canvas.height);

扩充Canvas 2d方法

在有些时候,我们自定义的函数,不能像canvas自带的函数一样,不用传入绘制上下午对象,而我们自定义的必须把绘制对象传入函数里才可以使用,那么有没有方法可以解决呢,在canvas实例对象的原型上添加方法即可

语法格式:

代码语言:javascript
复制
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>Document</title>
    <style>
      html,
      body {
        width: 100%;
        height: 100%;
      }
      .canvasBox {
        width: 800px;
        height: 800px;
        position: relative;
      }
      .canvasBox > .SetupPanel {
        width: 300px;
        height: 200px;
        background: #99b4e487;
        border-radius: 30px;
        position: absolute;
        left: 0;
        top: 0;
        color: white;
      }
      .canvasBox > .SetupPanel > h1 {
        text-align: center;
        line-height: 25px;
      }
      .canvasBox > .SetupPanel > a {
        float: left;
        color: #478aff87;
        background: #e5eeff;
        border-radius: 5px;
        padding: 10px 0;
        margin: 3px 0;
        text-decoration: none;
        text-align: center;
        line-height: 15px;
        width: 100%;
      }
    </style>
  </head>
  <body>
    <div class="canvasBox">
      <canvas class="canvas" width="800" height="800"></canvas>
    </div>
    <script src="../node/jquery.js"></script>
    <script>
      let ctx = document.querySelector(".canvas").getContext("2d");
      ctx.__proto__.fillStar = function(r)  

      //ctx.__proto__ === CanvasRenderingContext2D.prototype

      {
          this.beginPath();
        for(let i=0;i<=5;i++)
        {
          this.lineTo(
            Math.cos((18+i*72)/180*Math.PI)*r+this.lastMoveTo.x,
            -Math.sin((18+i*72)/180*Math.PI)*r+this.lastMoveTo.y
          );
          this.lineTo(
            Math.cos((54+i*72)/180*Math.PI)*r/2+this.lastMoveTo.x,
            -Math.sin((54+i*72)/180*Math.PI)*r/2+this.lastMoveTo.y
          );
        }
          this.closePath();
          this.fill();
      }
      ctx.lastMoveTo = {};
      CanvasRenderingContext2D.prototype.oldMoveTo = CanvasRenderingContext2D.prototype.moveTo;
      CanvasRenderingContext2D.prototype.moveTo = function(x,y)
      {
        this.oldMoveTo(x,y);
        this.lastMoveTo.x = x;
        this.lastMoveTo.y = y;
      }
      ctx.moveTo(400,400)
      ctx.fillStar(100);
    </script>
  </body>
</html>

图像处理

图像不同于图形,图像是位图是由无数个彩色像素点组成,图形是点线面结合而成,两者的处理方式也不相同,所干涉的区域也不相同

图形处理相关函数:

drawImage(img,sx,sy,sw,sh,dx,dy,dw,dh) :导入指定图片到canvas当中。 九个参数 首个是图片资源,s开头的是原图像的参数,d开头的是指在canvas绘制的参数

语法格式:

代码语言:javascript
复制
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>Document</title>
  </head>
  <body>
    <canvas
      class="canvas"
      width="800"
      height="800"
      style="border:1px solid blue"
    ></canvas>
    <script>
      var ctx = document.querySelector(".canvas").getContext("2d");
      var img = new Image();
      img.src = "../PHP操作MySQL.png";
      img.onload = () => {
        ctx.drawImage(img, 740, 450, 260, 70, 0, 0, 800, 800);
      };
    </script>
  </body>
</html>

案例:图像放大

代码语言:javascript
复制
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>Document</title>
    <style>
      body,
      html {
        background: black;
      }

input[type=range] {
    -webkit-appearance: none;
    width: 300px;
    border-radius: 10px; /*这个属性设置使填充进度条时的图形为圆角*/
    margin-top: 10px;
}
input[type=range]::-webkit-slider-thumb {
    -webkit-appearance: none;
} 

input[type=range]::-webkit-slider-runnable-track {
    height: 10px;
    border-radius: 10px; /*将轨道设为圆角的*/
    box-shadow: 0 1px 1px #def3f8, inset 0 .125em .125em #0d1112; /*轨道内置阴影效果*/
}
input[type=range]::-webkit-slider-thumb {
    -webkit-appearance: none;
    height: 25px;
    width: 25px;
    margin-top: -5px; /*使滑块超出轨道部分的偏移量相等*/
    background: #ffffff; 
    border-radius: 50%; /*外观设置为圆形*/
    border: solid 0.125em rgba(205, 224, 230, 0.5); /*设置边框*/
    box-shadow: 0 .125em .125em #3b4547; /*添加底部阴影*/
}

    </style>
  </head>
  <body>
    <canvas
      class="canvas"
      style="border:1px solid blue;margin: 0 auto;display: block"
    ></canvas>
    <input
      type="range"
      style="display:block;width:100%;"
      max="3.0"
      min="0.5"
      step="0.1"
      value="1"
      class="scale"
    />
    <script>
      var ctx = document.querySelector(".canvas").getContext("2d");
      var img = new Image();
      var scale = document.querySelector(".scale");
      img.src = "../1.jpg";
      img.onload = () => {
        ctx.canvas.width = img.width;
        ctx.canvas.height = img.height;
        drawImageByScale(ctx, scale.value, img.width, img.height);

        // scale.onchange = function() {
        //   ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
        //   drawImageByScale(ctx, scale.value, img.width, img.height);
        // };
        scale.onmousemove = function() {
          ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
          drawImageByScale(ctx, scale.value, img.width, img.height);
        };
      };

      function drawImageByScale(ctx, scale, w, h) {
        var imageWidth = w * scale;
        var imageHeight = h * scale;

        let x = ctx.canvas.width / 2 - imageWidth / 2,
          y = ctx.canvas.height / 2 - imageHeight / 2;
        ctx.drawImage(img, x, y, imageWidth, imageHeight);
      }
    </script>
  </body>
</html>
//水印版
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>Document</title>
    <style>
      body,
      html {
        background: black;
      }
      .bottom {
        width: 100%;
        position: fixed;
        bottom: 30px;
      }
      input[type="range"] {
        -webkit-appearance: none;
        width: 300px;
        border-radius: 10px; /*这个属性设置使填充进度条时的图形为圆角*/
        margin-top: 10px;
        position: relative;
      }
      input[type="range"]::-webkit-slider-thumb {
        -webkit-appearance: none;
      }

      input[type="range"]::-webkit-slider-runnable-track {
        height: 10px;
        border-radius: 10px; /*将轨道设为圆角的*/
        box-shadow: 0 1px 1px #def3f8, inset 0 0.125em 0.125em #0d1112; /*轨道内置阴影效果*/
      }
      input[type="range"]::-webkit-slider-thumb {
        -webkit-appearance: none;
        height: 25px;
        width: 25px;
        margin-top: -5px; /*使滑块超出轨道部分的偏移量相等*/
        background: #ffffff;
        border-radius: 50%; /*外观设置为圆形*/
        border: solid 0.125em rgba(205, 224, 230, 0.5); /*设置边框*/
        box-shadow: 0 0.125em 0.125em #3b4547; /*添加底部阴影*/
      }
    </style>
  </head>
  <body>
    <canvas
      class="canvas"
      style="border:1px solid blue;margin: 0 auto;display: block"
    ></canvas>
    <div class="bottom">
      <input
        type="range"
        style="display:block;width:100%;"
        max="3.0"
        min="0.5"
        step="0.1"
        value="1"
        class="scale"
      />
    </div>
    <script>
      var ctx = document.querySelector(".canvas").getContext("2d");
      var img = new Image();
      var scale = document.querySelector(".scale");
      img.src = "./img.jpg";
      var shuiying = document.createElement("canvas").getContext("2d");
      shuiying.canvas.width = 400;
      shuiying.canvas.height = 100;
      shuiying.font = "bold 50px 微软雅黑";
      shuiying.fillStyle = "white";
      shuiying.textAlign = "center";
      shuiying.textBaseline = "middle";
      shuiying.fillText("xuyuxin", 200, 50, 400);
      img.onload = () => {
        ctx.canvas.width = img.width;
        ctx.canvas.height = img.height;
        drawImageByScale(ctx, scale.value, img.width, img.height,shuiying);

        // scale.onchange = function() {
        //   ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
        //   drawImageByScale(ctx, scale.value, img.width, img.height);
        // };
        scale.onmousemove = function() {
          ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);

          drawImageByScale(ctx, scale.value, img.width, img.height, shuiying);
        };
      };

      function drawImageByScale(ctx, scale, w, h, c) {
        var imageWidth = w * scale;
        var imageHeight = h * scale;

        let x = ctx.canvas.width / 2 - imageWidth / 2,
          y = ctx.canvas.height / 2 - imageHeight / 2;

        ctx.drawImage(img, x, y, imageWidth, imageHeight);
        if(scale>=1)
        {
        ctxdrawImage(c.canvas, -40, ctx.canvas.height - 100);
        }
        else
        {
        ctx.drawImage(c.canvas, x, imageHeight-50);
        }
      }
    </script>
  </body>
</html>

案例:放大镜

代码语言:javascript
复制
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>Document</title>
    <style>
      body,
      html {
        background: black;
      }
      .bottom {
        width: 100%;
        position: fixed;
        bottom: 30px;
      }
      input[type="range"] {
        -webkit-appearance: none;
        width: 300px;
        border-radius: 10px; /*这个属性设置使填充进度条时的图形为圆角*/
        margin-top: 10px;
        position: relative;
      }
      input[type="range"]::-webkit-slider-thumb {
        -webkit-appearance: none;
      }

      input[type="range"]::-webkit-slider-runnable-track {
        height: 10px;
        border-radius: 10px; /*将轨道设为圆角的*/
        box-shadow: 0 1px 1px #def3f8, inset 0 0.125em 0.125em #0d1112; /*轨道内置阴影效果*/
      }
      input[type="range"]::-webkit-slider-thumb {
        -webkit-appearance: none;
        height: 25px;
        width: 25px;
        margin-top: -5px; /*使滑块超出轨道部分的偏移量相等*/
        background: #ffffff;
        border-radius: 50%; /*外观设置为圆形*/
        border: solid 0.125em rgba(205, 224, 230, 0.5); /*设置边框*/
        box-shadow: 0 0.125em 0.125em #3b4547; /*添加底部阴影*/
      }
    </style>
  </head>
  <body>
    <canvas
      class="canvas"
      style="border:1px solid blue;margin: 0 auto;display: block"
    ></canvas>

    <script>
      var ctx = document.querySelector(".canvas").getContext("2d");
      var offsetCanvas = document.createElement("canvas").getContext("2d");
      var img = new Image();
      var scale;
      img.src = "./img-lg.jpg";

      img.onload = () => {
        ctx.canvas.width = 1152;
        ctx.canvas.height = 768;

        offsetCanvas.canvas.width = img.width;
        offsetCanvas.canvas.height = img.height;

        scale = offsetCanvas.canvas.width / ctx.canvas.width;
        ctx.drawImage(img, 0, 0, ctx.canvas.width, ctx.canvas.height);
        offsetCanvas.drawImage(img, 0, 0);
      };

      ctx.canvas.onmousedown = function(e) {
        var x = e.clientX - this.getBoundingClientRect().left,
            y = e.clientY - this.getBoundingClientRect().top;
          Draw(ctx, true, x, y);

        this.onmousemove = e => {
          var x = e.clientX - this.getBoundingClientRect().left,
            y = e.clientY - this.getBoundingClientRect().top;
          Draw(ctx, true, x, y);
        };
        this.onmouseup = () => {
          ctx.canvas.onmousemove = null;
          Draw(ctx, false);
        };
        this.onmouseout = () => {
          ctx.canvas.onmousemove = null;
          Draw(ctx, false);
        };
      };
      function Draw(ctx, flag, x, y) {
        ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
        ctx.drawImage(img, 0, 0, ctx.canvas.width, ctx.canvas.height);
        if (flag) {
          drawImageRect(ctx, x, y);
        }
      }

      function drawImageRect(ctx, x, y) {
        var imageLgX = x * scale,
          imageLgY = y * scale;

        var r = 200;

        var sx = imageLgX - r,
          sy = imageLgY - r;

        var dx = x - r,
          dy = y - r;

        ctx.save();
        ctx.beginPath();
        ctx.arc(x,y,r,0,Math.PI*2);
        ctx.stroke();
        ctx.clip()
        ctx.drawImage(offsetCanvas.canvas, sx, sy, r * 2, r * 2, dx, dy, r * 2, r * 2);
        ctx.closePath();
        ctx.restore();
      }
    </script>
  </body>
</html>

像素处理

相关函数:

getImageData(x,y,w,h):获取指定图像像素数据 返回一个对象,里面有 data像素数据

putImageData(img,dx,dy,dirtx,dirty,dirtw,dirth):输出处理后的图像到指定位置

createImageData(w,h):创建一个空的图像

像素处理算法:

语法格式:

代码语言:javascript
复制
//像素自动变紫
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>Document</title>
    <style>
      body,
      html {
        /* background: black; */
        height: 2000px;
      }
    </style>
  </head>
  <body>
    <canvas
      class="canvas"
      style="border:1px solid blue;float:left"
      width="500"
      height="500"
    ></canvas>
    <canvas
      class="canvas"
      style="border:1px solid blue;float:right"
      width="500"
      height="500"
    ></canvas>
    <div class="btnbox" style="display: block;">
      <a href="javascript:void(0)" onclick="fillter()">fillter</a>
    </div>
    <script>
      var ctx1 = document.querySelectorAll(".canvas")[0].getContext("2d");
      var ctx2 = document.querySelectorAll(".canvas")[1].getContext("2d");
var n =0;
      var imageData;
      var data;
      var img = new Image();
      img.src = "./img.jpg";
      img.onload = function() {
        ctx1.drawImage(img, 0, 0, 500, 500);
      };
      function fillter() {
        imageData = ctx1.getImageData(0, 0, 500, 500);
        data = imageData.data;

        for (let i = 0; i < ctx2.canvas.width * ctx2.canvas.height; i++) {
          data[4 * i + 0] += n;
          // data[4 * i + 1] += n;
          data[4 * i + 2] += n;
          // data[4 * i + 3] = Math.ceil(Math.random()*255);
        }
        ctx2.putImageData(imageData, 0, 0, 0, 0, 500, 500);
      }
      setInterval(function(){
        n++;
        if(n===255)
        {
          n=Math.ceil(Math.random()*255)
        }
        fillter(n);
      },1);
    </script>
  </body>
</html>

案例:像素滤镜

代码语言:javascript
复制
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>Document</title>
    <style>
      body,
      html {
        /* background: black; */
        height: 2000px;
      }
      .btnbox > a {
        float: left;
        margin: 10px 20px;
      }
    </style>
  </head>
  <body>
    <canvas class="canvas" style="float:left" width="500" height="500"></canvas>
    <canvas
      class="canvas"
      style="float:right"
      width="500"
      height="500"
    ></canvas>
    <div class="btnbox" style="display: block;">
      <a href="javascript:void(0)" onclick="grey()">灰度 Grey Effect</a>
      <a href="javascript:void(0)" onclick="black()">黑白 black&white Effect</a>
      <a href="javascript:void(0)" onclick="revers()">反色 revers Effect</a>
      <a href="javascript:void(0)" onclick="Blur()">模糊 blur Effect</a>
      <a href="javascript:void(0)" onclick="mosaice()">马赛克 mosaice Effect</a>
    </div>
    <script>
      var ctx1 = document.querySelectorAll(".canvas")[0].getContext("2d");
      var ctx2 = document.querySelectorAll(".canvas")[1].getContext("2d");
      var imageData;
      var data;
      var img = new Image();
      img.src = "../1.jpg";
      img.onload = function() {
        ctx1.drawImage(img, 0, 0, 500, 500);
      };
      function mosaice() {
        var imgData = ctx1.getImageData(0, 0, 500, 500);
        var data = imgData.data;
        var tmpimgData = ctx1.getImageData(0, 0, 500, 500);
        var tmpData = tmpimgData.data;
        var size = 16,
          totalnum = Math.pow(size, 2);
        for (var i = 0; i < ctx2.canvas.height; i += size) {
          for (var j = 0; j < ctx2.canvas.width; j += size) {
            var totalr = 0,
              totalg = 0,
              totalb = 0;
            for (var dx = 0; dx < size; dx++) {
              for (var dy = 0; dy < size; dy++) {
                let x = i + dx,
                  y = j + dy;
                let p = x * ctx2.canvas.width + y;
                totalr += tmpData[p * 4 + 0];
                totalg += tmpData[p * 4 + 1];
                totalb += tmpData[p * 4 + 2];
              }
            }
            var p = i * ctx2.canvas.width + j;
            var resr = totalr / totalnum;
            var resg = totalg / totalnum;
            var resb = totalb / totalnum;
            for (var dx = 0; dx < size; dx++) {
              for (var dy = 0; dy < size; dy++) {
                var x = dx + i,
                  y = dy + j;
                var p = x * ctx2.canvas.width + y;
                data[4 * p + 0] = resr;
                data[4 * p + 1] = resg;
                data[4 * p + 2] = resb;
              }
            }
          }
        }
        ctx2.putImageData(imgData, 0, 0, 0, 0, 500, 500);
      }
      function revers() {
        imageData = ctx1.getImageData(0, 0, 500, 500);
        data = imageData.data;

        for (let i = 0; i < ctx2.canvas.width * ctx2.canvas.height; i++) {
          let r = 255 - data[4 * i + 0],
            g = 255 - data[4 * i + 1],
            b = 255 - data[4 * i + 2];
          data[4 * i + 0] = r;
          data[4 * i + 1] = g;
          data[4 * i + 2] = b;
        }
        ctx2.putImageData(imageData, 0, 0, 0, 0, 500, 500);
      }
      function Blur() {
        var imgData = ctx1.getImageData(0, 0, 500, 500);
        var data = imgData.data;
        var tmpimgData = ctx1.getImageData(0, 0, 500, 500);
        var tmpData = tmpimgData.data;
        var blurR = 2,
          totalnum = Math.pow(2 * blurR + 1, 2);
        for (var i = blurR; i < ctx2.canvas.height - blurR; i++) {
          for (var j = blurR; j < ctx2.canvas.width - blurR; j++) {
            var totalr = 0,
              totalg = 0,
              totalb = 0;
            for (var dx = -blurR; dx <= blurR; dx++) {
              for (var dy = -blurR; dy <= blurR; dy++) {
                let x = i + dx,
                  y = j + dy;
                let p = x * ctx2.canvas.width + y;
                totalr += tmpData[p * 4 + 0];
                totalg += tmpData[p * 4 + 1];
                totalb += tmpData[p * 4 + 2];
              }
            }
            var p = i * ctx2.canvas.width + j;
            data[p * 4 + 0] = totalr / totalnum;
            data[p * 4 + 1] = totalg / totalnum;
            data[p * 4 + 2] = totalb / totalnum;
          }
        }
        ctx2.putImageData(imgData, 0, 0, 0, 0, 500, 500);
      }
      function grey() {
        imageData = ctx1.getImageData(0, 0, 500, 500);
        data = imageData.data;

        for (let i = 0; i < ctx2.canvas.width * ctx2.canvas.height; i++) {
          let r = data[4 * i + 0],
            g = data[4 * i + 1],
            b = data[4 * i + 2];
          let grey = r * 0.3 + g * 0.59 + b * 0.11;
          data[4 * i + 0] = grey;
          data[4 * i + 1] = grey;
          data[4 * i + 2] = grey;
        }
        ctx2.putImageData(imageData, 0, 0, 0, 0, 500, 500);
      }
      function black() {
        imageData = ctx1.getImageData(0, 0, 500, 500);
        data = imageData.data;

        for (let i = 0; i < ctx2.canvas.width * ctx2.canvas.height; i++) {
          let r = data[4 * i + 0],
            g = data[4 * i + 1],
            b = data[4 * i + 2];
          let grey = r * 0.3 + g * 0.59 + b * 0.11;
          if (grey > 255 / 2) {
            v = 255;
          } else {
            v = 0;
          }
          data[4 * i + 0] = v;
          data[4 * i + 1] = v;
          data[4 * i + 2] = v;
        }
        ctx2.putImageData(imageData, 0, 0, 0, 0, 500, 500);
      }
    </script>
  </body>
</html>

案例:颜色板

代码语言:javascript
复制
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>Document</title>
    <style>
      body,
      html {
        /* background: black; */
        height: 2000px;
      }
      .btnbox > a {
        float: left;
        margin: 10px 20px;
      }
    </style>
  </head>
  <body>
    <canvas class="canvas" style="float:left" width="800" height="800"></canvas>

    <div class="btnbox" style="display: block;"></div>
    <script>
      var ctx = document.querySelectorAll(".canvas")[0].getContext("2d");
      var img = ctx.createImageData(800, 800);
      var data = img.data;
      for (var i = 0; i < ctx.canvas.height; i++) {
        for (var j = 0; j < ctx.canvas.width; j++) {
          var p = i * ctx.canvas.width + j;
          data[4 * p + 0] = parseInt(
            Math.pow(Math.cos(Math.atan2(j - 400, i - 400) / 2), 2) * 255
          );
          data[4 * p + 1] = parseInt(
            Math.pow(
              Math.cos(
                Math.atan2(j - 400, i - 400) / 2 - (2 * Math.acos(-1)) / 3
              ),
              2
            ) * 255
          );
          data[4 * p + 2] = parseInt(
            Math.pow(
              Math.cos(
                Math.atan2(j - 400, i - 400) / 2 + (2 * Math.acos(-1)) / 3
              ),
              2
            ) * 255
          );
          data[4 * p + 3] = 255;
        }
      }
      ctx.putImageData(img, 0, 0, 0, 0, 800, 800);
    </script>
  </body>
</html>

什么是Ajax?

Ajax是一种可以与服务器交换数据并更新部分页面内容,同时可以在不让整个网页重新加载的情况下更新网页的一种技术

Ajax请求过程:

1:创建一个异步对象
代码语言:javascript
复制
var xmlHttp = new XMLHttpRequest();
2:设置请求方式和请求地址
代码语言:javascript
复制
/*
    参数顺序,描述
    (1)method:请求的类型;GET 或 POST
    (2)url:文件在服务器上的位置
    (3)async:true(异步)或 false(同步) (一般为true,因ajax的精髓就是异步)
*/
    xmlHttp.open("GET||POST","url 如(./ajax.php)",true)
//注意点:url中不能出现中文,只能数字、字母、ASCII码、下划线
//  GET方式的 url格式:./ajax.php?t=123&321......
//如果出现中文也可以用encodeURIComponent方法转换


//  POST方式的url不能在后面接字符串传递参数
xmlHttp.setRequestHeader("Content-type","application/x-www-form-urlencoded");
//setRequestHeader 必须放在设置请求与发送请求之间
//下一步在发送请求send中传递参数即可
xmlHttp.send("name=xuyuxin&age=18")
3:发送请求
代码语言:javascript
复制
 xmlHttp.send();
4.监听状态变化
代码语言:javascript
复制
//监听事件: onreadystatechange 每当请求状态发生变化,就会触发此函数

xmlHttp.onreadystatechange = function (ev2){
    /*
    readyState 状态变化有以下5种
    0:请求未初始化
    1:服务器连接已建立
    2:请求已接收
    3:请求处理中
    4:请求已完成,且响应已就绪
*/
    if(xmlHttp.readyState === 4){

        //请求已完成,并不代表请求成功,因此还需判断是否请求成功
        //status是专门判断请求是否成功的状态码
        // 状态码大于或等于200并且不能超过300以上,300以上除了304以外全都是请求失败
                if(xmlHttp.status >= 200 && xmlHttp.status < 300 || xmlHttp.status === 304){
                       console.log('请求成功')
                }else{
                    console.log('请求失败')
                }
    }



}

http请求成功或失败状态码资料查询

IE低版本浏览器兼容问题

由于在IE6-IE5以下不支持XMLHttpRequest这个属性,因此会产生错误,在低级浏览器中可以使用ActiveXObject来实现同样的效果

代码语言:javascript
复制
var xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");

在IE低版本中ajax还有缓存的问题,解决这个问题,要url地址不断改变,不能为常量,即可解决

代码语言:javascript
复制
xmlhttp.open("GET","ajax.php?"+(new Date().getTime()),true)

解决兼容性通用方法

由于在Ajax中浏览器支持的属性不同,单一方案不能支持全部浏览器,有两种解决方案,因此可以把这两种方案合成一种,以便使用

代码语言:javascript
复制
  if(window.XMLHttpRuquest){
            var xmlHttp = new XMLHttpRequest();
        }else{
           var xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
        }

=====================================================================================

    var xmlHttp = window.XMLHttpRequest ? new XMLHttpRequest() : new                     ActiveXOject("Microsoft.XMLHTTP");

封装Ajax

代码语言:javascript
复制
/**
 * @param {请求的类型}option.type
 * @param {发送请求的地址} option.url
 * @param {发送请求的数据}option.data
 * @param {超时时间} option.timeout
 * @param {请求成功后执行的函数*} option.sucess
 * @param {请求失败后执行的函数*} option.error
 */
function createAjax(option) {
  //0.把传入对象处理成字符串,服务器才可接收
  var toStringObj = objToString(option.data);
  //1.创建ajax对象,并判断游览器支持那个属性
  var xmlHttp = window.XMLHttpRequest
    ? new XMLHttpRequest()
    : new ActiveXObject("Microsoft.XMLHTTP");
  var timer;
  if (option.type.toloworCase === "get") {
    //2.设置请求方式和地址
    xmlHttp.open("GET", option.url + "?" + toStringObj, true);
    //3.发送请求
    xmlHttp.send();
    //4.监听请求状态
  } else {
    // POST请求方式
    xmlHttp.open(option.type, option.url, true);
    xmlHttp.setRequestHeader(
      "Content-type",
      "application/x-www-form-urlencoded"
    );
    xmlHttp.send(toStringObj);
  }

  xmlHttp.onreadystatechange = function() {
    //请求完成,并不代表请求成功
    if (xmlHttp.readyState === 4) {
      //判断请求是否成功
      if (
        (xmlHttp.status >= 200 && xmlHttp.status < 300) ||
        xmlHttp.status === 304
      ) {
        clearInterval(timer);
        option.sucess(xmlHttp);
      } else {
        option.error(xmlHttp);
      }
    }
  };

  //判断外界是否传入超时时间
  if (option.timeout) {
    timer = setInterval(function() {
      //超时时间到后执行停止此次发送请求,默认为失败
      xmlHttp.abort();
      clearInterval(timer);
    }, option.timeout);
  }
}
//把obj转为字符串
function objToString(data) {
  var res = [];
  data.time = new Date().getTime();
  for (var key in data) {
      //encodeURLComponent函数对,对象名和属性进行转换,以防出现url中不能出现的字符而出错
    res.push(encodeURIComponent(key) + "=" + encodeURIComponent(data[key]));
  }
  return res.join("&");
}


//调用方式
    createAjax({
                    data:{
                       name: that.getAttribute('name')
                    },
                    type:"POST",
                    timeout:3000,
                    url:"./ajaxLesson2.php",
                    sucess:function(xml){
                         console.log('请求成功');
                    },
                    error:function(xml){
                        console.log("请求失败");
                    },

                });

获取服务器响应数据方式

  1. responseText 可以获取服务器以字符串形式返回的数据
  2. responseXML 可以获取服务器以XML形式返回的数据
代码语言:javascript
复制
//调用方式
// ajax对象.要获取的方式
xmlHttp.responseText

通过XML传输数据

XML数据基本格式

​ 1.开头前缀指定版本和编码(必要)

代码语言:javascript
复制
<?xml version="1.0" encoding="UTF-8"?>

​ 2.根目录(必要 和html标签一样要闭合)

代码语言:javascript
复制
<root>

</root>

​ 3.之后标签名不受限制,完整版

代码语言:javascript
复制
<?xml version="1.0" encoding="UTF-8"?>
<root>  

    <nz>
        <title>甜美女装</title>
        <des>人见人爱,花间花开,甜美系列</des>
        <image>images/1.jpg</image>
    </nz>
    <bb>
        <title>奢华驴包</title>
        <des>送女友,送情人,送学妹,一送一个准系列</des>
        <image>images/2.jpg</image>
    </bb>
    <tx>
        <title>键盘拖鞋</title>
        <des>程序员专属拖鞋, 屌丝气息浓郁, 你值得拥有</des>
        <image>images/3.jpg</image>
    </tx>

</root>
PHP基本XML配置格式
代码语言:javascript
复制
<?php
    //向客户端发送原始的 HTTP 报头。
    header("content-type:text/xml;charset=utf-8");
    //file_get_contents() 函数是用于将文件的内容读入到一个字符串中的首选方法。如果操作系统支持,还会使用    内存映射技术来增强性能。
    echo file_get_contents("xml文件地址如(./ajax.xml)")
    ?>
Ajax获取XML数据格式
代码语言:javascript
复制
//获取XML传输而来的数据要使用 responseXML方式获取
var Data = xml.responseXML; //返回的是一个document文档对象
//接着使用javascript获取遍历DOM元素
 var titleinfo = Data.querySelector(name+'>title'),
 des = Data.querySelector(name+'>des'),
 image = Data.querySelector(name+'>image');
//最后就可以对DOM里面存储的数据进行操作了
console.log(des.innerHTML);

通过JSON传输数据

JSON资料

JSON数据基本格式
代码语言:javascript
复制
{
    "nz":{
        "title":"甜美女装",
        "des":"人见人爱,花间花开,甜美系列",
        "image":"./images/1.jpg"
    },
        "bb":{
        "title":"奢华驴包",
        "des":"送女友,送情人,送学妹,一送一个准系列",
        "image":"./images/2.jpg"
    },
        "tx":{
        "title":"键盘拖鞋",
        "des":"程序员专属拖鞋, 屌丝气息浓郁, 你值得拥有",
        "image":"./images/3.jpg"
    }
}

//在 JS 语言中,一切都是对象。因此,任何支持的类型都可以通过 JSON 来表示,例如字符串、数字、对象、数组等。但是对象和数组是比较特殊且常用的两种类型:
//JSON 键/值对
//JSON 键值对是用来保存 JS 对象的一种方式,和 JS 对象的写法也大同小异,键/值对组合中的键名写在前面并用双引号 "" 包裹,使用冒号 : 分隔,然后紧接着值:
"{"firstName": "Json"}"
这很容易理解,等价于这条 JavaScript 语句:
{firstName : "Json"}

//JSON 与 JS 对象的关系
//很多人搞不清楚 JSON 和 Js 对象的关系,甚至连谁是谁都不清楚。其实,可以这么理解:
//JSON 是 JS 对象的字符串表示法,它使用文本表示一个 JS 对象的信息,本质是一个字符串。
//如:
var obj = {a: 'Hello', b: 'World'}; //这是一个对象,注意键名也是可以使用引号包裹的

var json = '{"a": "Hello", "b": "World"}'; //这是一个 JSON 字符串,本质是一个字符串
JSON和JS对象互转
代码语言:javascript
复制
//要实现从JSON对象转换为JS字符串,使用 JSON.parse() 方法:
var obj = JSON.parse('{"a": "Hello", "b": "World"}'); //结果是 {a: 'Hello', b: 'World'}
//要实现从JS对象转换为JSON字符串,使用 JSON.stringify() 方法:
var json = JSON.stringify({a: 'Hello', b: 'World'}); //结果是 '{"a": "Hello", "b": "World"}'
//当从服务器返回的数据不是标准json字符串时是无法使用parse的,那么可以试试用eval()强制转化和为js对象
非标准json转js对象
代码语言:javascript
复制
//当从服务器返回的数据不是标准json字符串时是无法使用parse的,那么可以试试用eval()强制转化和为js对象
//注意点: 转js对象必须加 "("+data+")"
var Data = eval("("+data+")")
JSON兼容性问题

在低版本的IE中, 不可以使用原生的JSON.parse方法, 但是可以使用json2.js这个框架来兼容 json2.js下载地址:

PHP基本JSON格式
代码语言:javascript
复制
echo file_get_contents(" JSON文件地址 如(./json.txt)");

跨域

ajax的请求过程:ajax发送请求–浏览器–服务器 响应过程则是请求过程的颠倒 当ajax发送请求到浏览器,浏览器发送到服务器,处理并响应后,原路返回到浏览器,此时会验证其请求来源的域名跟发送请求时是否一样,是则过,否则会被浏览器截止并提示错误,这正是跨域所造成的,想要解决此问题,并不能从前端入手,应该从后端,只有在后端响应并返回后告诉浏览器是自己人即可。 那怎么告诉浏览器是自己人呢? 只要设置其响应头部信息+(Access-Control-Allow-Origin:域名)告诉浏览器即可,允许多个、单个、全部 (*)。

PHP 方式

代码语言:javascript
复制
/*
    1、允许单个域名访问
*/
    header("Access-Control-Allow-Origin:(域名)");
/*
    2、允许多个域名访问
*/
    $origin = isset($_SERVER['HTTP_ORIGIN']) ? $_SERVER['HTTP_ORIGIN'] : '';
    $option = array(
        ('域名1'),
        ('域名2'),
        ....
    );
     if(in_array($origin,$option)) header("Access-Control-Allow-Origin:$origin");


/*
    3、允许全部域名访问
*/
    header("Access-Control-Allow-Origin:*");

node方式

代码语言:javascript
复制
/*
    1、允许单个域名访问
*/
    http.createServer(req,res)
    {
        res.setHeader("Access-Control-Allow-Origin","(域名)");
    }
/*
    2、允许多个域名访问
*/    
    let option = [
        (域名1),
        (域名2),
        ...
    ];

    http.createServer(req,res)
    {

      let {origin} =  req.headers;
      let ori = option["origin"] ? option["origin"] : null;
      res.setHeader("Access-Control-Allow-Origin",ori);

    }

/*
    3、允许全部域名访问
*/
    http.createServer(req,res)
    {
        res.setHeader("Access-Control-Allow-Origin","*");
    }

FormData

FormData是ajax2.0新添加的功能,其作用是让表单也能异步发送

语法格式:

代码语言:javascript
复制
//必须要new 一个FormData对象 参数是要应用的表单元素 
//禁止表单默认行为
//其请求方式、请求地址跟随表单元素
//最后发送formdata对象即可

//原生方式
         let form = document.querySelector("form");
        document.querySelector("form").onsubmit = ()=>{
        let xhr = new XMLHttpRequest();
        let formdata = new FormData(form);
        xhr.open(form.method,form.action,true);
        xhr.send(formdata);
        xhr.onreadystatechange =()=>{
          if(xhr.readyState === 4)
        {
          if(xhr.status === 200)
          {
            console.log("成功");
          }else
          {
            console.log("失败");
          }
        }
        }
          return false;
        }
  //jQuery方式 
        $(function(){
          $("form").on("submit",function(){
            console.log(1);
            let formdata = new FormData(this);
            $.ajax({
              url:this.action,
              type:this.method,
              data:formdata,
                //由于jq在发送请求时,会把请求数据自动处理为适合发送的数据格式,但是formdata对象本事就不用处理,系统识别会自动处理数据,如果被jq格式化后,数据就会出错,所以要关闭其数据格式化,以及发送的头部信息。
              processData:false,    
              contentType:false
            }).then((req)=>{
              console.log("成功");
            },(res)=>{
             console.log("失败");
            })

            return false;
          })
        })
//如果不使用表单提交,可以使用以下另门方式
<!DOCTYPE html>
<html lang="en" dir="ltr">
  <head>
    <meta charset="utf-8">
    <title></title>
  </head>
  <body>
    <div id="div1">
      用户:<input type="text" id="user" /><br>
      密码:<input type="password" id="pass" /><br>
      文件:<input type="file" id="f1" /><br>
      <input id="btn1" type="button" value="提交">
    </div>
  </body>
  <script>
  let oBtn=document.querySelector('#btn1');
  oBtn.onclick=function (){
    let formdata=new FormData();

    formdata.append('username', document.querySelector('#user').value);
    formdata.append('password', document.querySelector('#pass').value);
    formdata.append('f1', document.querySelector('#f1').files[0]);

    //
    let xhr=new XMLHttpRequest();

    xhr.open('post', 'http://localhost:8080/', true);
    xhr.send(formdata);

    xhr.onreadystatechange=function (){
      if(xhr.readyState==4){
        if(xhr.status==200){
          alert('成功');
        }else{
          alert('失败');
        }
      }
    };
  };
  </script>
</html>

fetch

fetch是官方用来解决原生js的ajax的繁杂步骤问题的一门新语法,大大简化了ajax操作,原理基于ajax

代码语言:javascript
复制
// get txt
 window.onload=function (){
      let oBtn=document.getElementById('btn1');
      oBtn.onclick=async function (){
        //1.请求
        let res=await fetch('data/1.txt');
        //2.解析
        let str=await res.text();

        alert(str);
      };
    };
//get json
 window.onload=function (){
      let oBtn=document.getElementById('btn1');
      oBtn.onclick=async function (){
        //1.请求
        let res=await fetch('data/1.json');
        //2.解析
        let json=await res.json();

        console.log(json);
      };
    };
//get blod
window.onload=function (){
      let oImg=document.getElementById('img1');
      let oBtn=document.getElementById('btn1');
      oBtn.onclick=async function (){
        //1.请求
        let res=await fetch('data/1.png');
        //2.解析
        let data=await res.blob();
        let url=URL.createObjectURL(data);

        oImg.src=url;
      };
    };
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2019-09-17,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Canvas
    • Canvas标准
      • 创建Canvas
        • 线
          • 填充
            • 案例:四个正方形组成的大方形
                • 矩形
                  • 案例:绘制五角星
                    • 随机不重复、不切边五角星
                  • 绘画状态保存与还原
                    • 图形变换
                      • 渐变
                        • 三角函数讲解
                          • 添加图片、视频、canvas
                            • 案例:绘制圆角矩形
                              • 案例:2048九宫格
                                • 案例:绘制弯月
                                  • 贝塞尔曲线
                                    • 字体
                                      • 案例:水平垂直居中
                                        • 阴影
                                          • 透明
                                            • 遮盖顺序
                                              • 剪切
                                                • 实现剪纸效果
                                                  • 交互
                                                    • 案例:小球滚动(面向对象+控制面板)
                                                      • 清除
                                                        • 扩充Canvas 2d方法
                                                          • 图像处理
                                                            • 案例:图像放大
                                                              • 案例:放大镜
                                                                • 像素处理
                                                                  • 案例:像素滤镜
                                                                    • 案例:颜色板
                                                                    • 什么是Ajax?
                                                                      • Ajax请求过程:
                                                                        • IE低版本浏览器兼容问题
                                                                          • 解决兼容性通用方法
                                                                            • 封装Ajax
                                                                              • 获取服务器响应数据方式
                                                                                • 通过XML传输数据
                                                                                  • 通过JSON传输数据
                                                                                    • 跨域
                                                                                      • PHP 方式
                                                                                      • node方式
                                                                                    • FormData
                                                                                      • 语法格式:
                                                                                    • fetch
                                                                                    相关产品与服务
                                                                                    云数据库 MySQL
                                                                                    腾讯云数据库 MySQL(TencentDB for MySQL)为用户提供安全可靠,性能卓越、易于维护的企业级云数据库服务。其具备6大企业级特性,包括企业级定制内核、企业级高可用、企业级高可靠、企业级安全、企业级扩展以及企业级智能运维。通过使用腾讯云数据库 MySQL,可实现分钟级别的数据库部署、弹性扩展以及全自动化的运维管理,不仅经济实惠,而且稳定可靠,易于运维。
                                                                                    领券
                                                                                    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档