canvas基础简单易懂教程(完结,多图)

Python微信订餐小程序课程视频

https://blog.csdn.net/m0_56069948/article/details/122285951

Python实战量化交易理财系统

https://blog.csdn.net/m0_56069948/article/details/122285941
目录* Canvas学习
+ 一、 Canvas概述
- 1.1 Hello world
- 1.2 Canvas的像素化
- 1.3 Canvas的动画思想
- 1.4 面向对象思维实现canvas动画
+ 二、Canvas的绘制功能
- 2.1 绘制矩形
- 2.2 绘制路径
- 2.3 绘制圆弧
- 2.4 炫彩小球
- 2.5 透明度
- 2.6 小球连线
- 2.7 线型
* lineWidth
* lineCap
* lineJoin
* setLineDash
* lineDashOffset
- 2.8 文本
- 2.9 渐变 Gradients
- 2.10 阴影
+ 三、使用图片
+ 四、资源管理器
+ 4.1 获取对象中属性的长度
+ 4.2 管理器的实现
+ 五、变形
- 5.1 移动translate
- 5.2 旋转 rotate
- 5.3 缩放 scale
- 5.4 变形 transform
- 5.5 滚动的车轮案例
+ 六、合成与裁剪
- 6.1 globalCompositeOperation
- 6.2 裁剪路径
- 6.3 刮刮乐案例
+ 七、总结

Canvas学习

canvas 读音 /ˈkænvəs/, 即kæn və s(看我死).

学习的目的主要是为了网状关系拓扑图形的绘制.

推荐文档:https://developer.mozilla.org/zh-CN/docs/Web/API/Canvas_API/Tutorial

一、 Canvas概述

canvas是用来绘制图形的.它可以用于动画、游戏画面、数据可视化、图片编辑以及实时视频处理等方面。

长久以来, web上的动画都是Flash. 比如动画广告\ 游戏等等, 基本都是Flash 实现的. Flash目前都被禁用了, 而且漏洞很多, 重量很大, 需要安装Adobe Flash Player, 而且也会卡顿和不流畅等等.

canvas是HTML5提出的新标签,彻底颠覆了Flash的主导地位。无论是广告、游戏都可以使用canvas实现。

Canvas 是一个轻量级的画布, 我们使用Canvas进行JS的编程,不需要增加额外的组件,性能也很好,不卡顿,在手机中也很流畅。

1.1 Hello world

我们可以在页面中设置一个canvas标签



|  |  |
|  |  当前的浏览器版本不支持,请升级浏览器 |
|  | canvas> |


canvas的标签属性只有两个,width和height,表示的是canvas画布的宽度和高度,不要用css来设置,而是用属性来设置,画布会失真变形。

标签的innerContent是用来提示低版本浏览器(IE6、7、8)并不能正常使用canvas,高版本的浏览器是看不到canvas标签内部的文字的。

canvas基础简单易懂教程(完结,多图)_第1张图片



|  | // 得到canvas的画布 |
|  | const myCanvas:HTMLCanvasElement = document.getElementById("main\_canvas") as HTMLCanvasElement// 返回某种类型的HTMLElement |
|  |  |
|  | // 得到画布的上下文,上下文有两个,2d的上下文和3d的上下文 |
|  | // 所有的图像绘制都是通过ctx属性或者是方法进行设置的,和canvas标签没有关系了 |
|  | const ctx = myCanvas.getContext("2d") |
|  | if(ctx !== null) { |
|  | // 设置颜色 |
|  |  ctx.fillStyle = 'green' |
|  | // 绘制矩形 |
|  |  ctx.fillRect(100, 100, 200, 50)  |
|  | } |


canvas基础简单易懂教程(完结,多图)_第2张图片

通过上面的代码我们发下canvas本质上就是利用代码在浏览器的页面上进行画画,比如上面的代码fillRect就代表在页面中绘制矩形,一共四个属性,前两个100,100代表(x, y), 即填充起始位置,200代表宽,50代表高,单位都是px。

1.2 Canvas的像素化

我们用canvas绘制了一个图形,一旦绘制成功了,canvas就像素化了他们。canvas没有能力,从画布上再次得到这个图形,也就是我们没有能力去修改已经在画布上的内容,这个就是canvas比较轻量的原因,Flash重的原因之一就有它可以通过对应的api得到已经上“画布”的内容然后再次绘制

如果我们想要这个canvas图形移动,必须按照:清屏——更新——渲染的逻辑进行编程。总之,就是重新再画一次

1.3 Canvas的动画思想

要使用面向对象的思想来创建动画。

canvas上画布的元素,就被像素化了,所以不能通过style.left方法进行修改,而且必须要重新绘制。



|  | // 得到画布 |
|  | const myCanvas:HTMLCanvasElement = document.getElementById("main\_canvas") as HTMLCanvasElement |
|  |  |
|  | // 获取上下文 |
|  | const ctx = myCanvas.getContext("2d") |
|  |  |
|  | if(ctx !== null) { |
|  | // 设置颜色 |
|  |  ctx.fillStyle = "blue" |
|  | // 初始信号量 |
|  | let left:number = -200 |
|  | // 动画过程 |
|  | setInterval(() => { |
|  | // 清除画布,0,0代表从什么位置开始,600,600代表清除的宽度和高度 |
|  |  ctx.clearRect(0,0,600,600) |
|  | // 更新信号量 |
|  |  left++ |
|  | // 如果已经走出画布,则更新信号量为初始位置 |
|  | if(left > 600) { |
|  |  left = -200 |
|  |  } |
|  |  ctx.fillRect(left, 100, 200, 200) |
|  |  },10) |
|  | } |


canvas基础简单易懂教程(完结,多图)_第3张图片

实际上,动画的生成就是相关静态画面连续播放,这个就是动画的过程。我们把每一次绘制的静态话面叫做一帧,时间的间隔(定时器的间隔)就是表示的是帧的间隔。

1.4 面向对象思维实现canvas动画

因为canvas不能得到已经上屏的对象,所以我们要维持对象的状态。在canvas动画重,我们都是用面向对象来进行编程,因为我们可以使用面向对象的方式来维持canvas需要的属性和状态;



|  | // 得到画布 |
|  | const myCanvas:HTMLCanvasElement = document.getElementById("main\_canvas") as HTMLCanvasElement |
|  |  |
|  | // 获取上下文 |
|  | const ctx = myCanvas.getContext("2d") |
|  |  |
|  | class Rect { |
|  | // 维护状态 |
|  | constructor( |
|  | public x: number, |
|  | public y: number,  |
|  | public w: number,  |
|  | public h: number,  |
|  | public color: string |
|  |  ) {  |
|  |  } |
|  | // 更新的方法 |
|  | update() { |
|  | this.x++ |
|  | if(this.x > 600) { |
|  | this.x = -200 |
|  |  } |
|  |  } |
|  | // 渲染 |
|  | render(ctx: CanvasRenderingContext2D) { |
|  | // 设置颜色 |
|  |  ctx.fillStyle = this.color |
|  | // 渲染 |
|  |  ctx.fillRect(this.x, this.y, this.w, this.h) |
|  |  } |
|  | } |
|  |  |
|  | // 实例化 |
|  | let myRect1: Rect = new Rect(-100, 200, 100, 100, 'purple') |
|  | let myRect2: Rect = new Rect(-100, 400, 100, 100, 'pink') |
|  |  |
|  | // 动画过程 |
|  |  |
|  | // 更新的办法 |
|  | setInterval(() => { |
|  | // 清除画布,0,0代表从什么位置开始,600,600代表清除的宽度和高度 |
|  | if(ctx !== null) { |
|  | // 清屏 |
|  |  ctx.clearRect(0,0,600,600) |
|  | // 更新方法 |
|  |  myRect1.update() |
|  |  myRect2.update() |
|  | // 渲染方法 |
|  |  myRect1.render(ctx) |
|  |  myRect2.render(ctx) |
|  |  } |
|  | },10) |


canvas基础简单易懂教程(完结,多图)_第4张图片

动画过程在主定时器重,每一帧都会调用实例的更新和渲染方法。

二、Canvas的绘制功能

2.1 绘制矩形

填充一个矩形:



|  | if(ctx !== null) { |
|  | // 设置颜色 |
|  |  ctx.fillStyle = 'green' |
|  | // 填充矩形 |
|  |  ctx.fillRect(100, 100, 300, 50) |
|  | } |


参数含义:分别代表填充坐标x、填充坐标y、矩形的高度和宽度。

绘制矩形边框,和填充不同的是绘制使用的是strokeRect, 和strokeStyle实现的



|  | if (ctx !== null) { |
|  | // 设置颜色 |
|  |  ctx.strokeStyle = 'red' |
|  | // 绘制矩形 |
|  |  ctx.strokeRect(300, 100, 100, 100) |
|  | } |


参数含义:分别代表绘制坐标x、绘制坐标y、矩形的高度和宽度。

canvas基础简单易懂教程(完结,多图)_第5张图片

清除画布,使用clearRect



|  | // 擦除画布内容 |
|  | btn3.onclick = () => { |
|  | if (ctx !== null) { |
|  |  ctx.clearRect(0, 0, 600, 600) |
|  |  } |
|  | } |


参数含义:分别代表擦除坐标x、擦除坐标y、擦除的高度和擦除的宽度。

2.2 绘制路径

绘制路径的作用是为了设置一个不规则的多边形状态

路径都是闭合的,使用路径进行绘制的时候需要既定的步骤:

  1. 需要设置路径的起点
  2. 使用绘制命令画出路径
  3. 封闭路径
  4. 填充或者绘制已经封闭路径的形状


|  | // 创建一个路径 |
|  | ctx.beginPath() |
|  | // 1. 移动绘制点 |
|  | ctx.moveTo(100, 100) |
|  | // 2. 描述行进路径 |
|  | ctx.lineTo(200, 200) |
|  | ctx.lineTo(400, 180) |
|  | ctx.lineTo(380, 50) |
|  | // 3. 封闭路径 |
|  | ctx.closePath(); |
|  |  |
|  | // 4. 绘制这个不规则的图形 |
|  | ctx.strokeStyle = 'red' |
|  | ctx.stroke() |
|  | ctx.fillStyle = 'orange' |
|  | ctx.fill() |


canvas基础简单易懂教程(完结,多图)_第6张图片

总结我们要绘制一个图形,要按照顺序

  1. 开始路径ctx.beginPath()
  2. 移动绘制点ctx.moveTo(x, y)
  3. 描述绘制路径ctx.lineTo(x, y)
  4. 多次描述绘制路径ctx.lineTo(x, y)
  5. 闭合路径ctx.closePath()
  6. 描边ctx.stroke()
  7. 填充ctx.fill()

此时我们发现之前我们在学习绘制矩形的时候使用的是fillRectstrokeRect,但是实际上fillstroke也是具有绘制填充功能的

stroke(): 通过线条来绘制图形轮廓。

fill(): 通过填充路径的内容区域生成实心的图形。

我们在绘制路径的时候选择不关闭路径(closePath),这个时候会实现自封闭现象(只针对fill,stroke不生效)

canvas基础简单易懂教程(完结,多图)_第7张图片

2.3 绘制圆弧

arc(x, y, radius, startAngle, endAngle, anticlockwise)

画一个以(x, y)为圆心的以radius为半径的圆弧(圆), 从startAngle开始到endAngle结束,按照anticlockwise给定的方向(默认为顺时针false, true为逆时针)来生成。



|  | // 创建一个路径 |
|  | ctx.beginPath() |
|  | // 移动绘制点 |
|  | // ctx.arc(200, 200, 100, 0, 2 * Math.PI, false) |
|  | ctx.arc(200, 200, 100, 0, 2 * 3.14, false) |
|  |  |
|  | ctx.stroke() |


圆弧也是绘制路径的一种,也需要beginPath和stroke.

canvas基础简单易懂教程(完结,多图)_第8张图片

参数的含义:200, 200代表的是起始x,y坐标,100代表的是圆心半径,0和1代表的是开始和结束位置,单位如果是数字,代表的是一个圆弧的弧度(一个圆的弧度是Math.PI * 2, 约等于7个弧度),所以在顺时针的情况下,如果如果两个参数的差为7,则代表绘制一个圆。

2.4 炫彩小球



|  | // 得到画布 |
|  | const myCanvas: HTMLCanvasElement = document.getElementById("main\_canvas") as HTMLCanvasElement |
|  |  |
|  | // 获取上下文 |
|  | const ctx = myCanvas.getContext("2d") |
|  |  |
|  | class Ball { |
|  | color: string // 小球的颜色 |
|  | r: number // 小球的半径 |
|  | dx: number // 小球在x轴的运动速度/帧 |
|  | dy: number // 小球在y轴的运动速度/帧 |
|  | constructor(public x: number, public y: number) { |
|  | // 设置随机颜色 |
|  | this.color = this.getRandomColor() |
|  | // 设置随机半径[1, 101) |
|  | this.r = Math.floor(Math.random() * 100 + 1) |
|  | // 设置x轴, y轴的运动速度(-5, 5) |
|  | this.dx = Math.floor(Math.random() * 10) - 5 |
|  | this.dy = Math.floor(Math.random() * 10) - 5 |
|  |  } |
|  | // 随机颜色,最后返回的是类似'#3fe432' |
|  | getRandomColor(): string { |
|  | let allType = "0,1,2,3,4,5,6,7,8,9,a,b,c,d,e,f" |
|  | let allTypeArr = allType.split(',') |
|  | let color = '#' |
|  | for (let i = 0; i < 6; i++) { |
|  | let random = Math.floor(Math.random() * allTypeArr.length) |
|  |  color += allTypeArr[random] |
|  |  } |
|  | return color |
|  |  } |
|  |  |
|  | // 渲染小球 |
|  | render(): void { |
|  | if(ctx !== null) { |
|  |  ctx.beginPath() |
|  |  ctx.arc(this.x, this.y, this.r, 0, Math.PI * 2, false) |
|  |  ctx.fillStyle=this.color |
|  |  ctx.fill() |
|  |  } |
|  |  } |
|  |  |
|  | // 更新小球 |
|  | update(): void { |
|  | // 小球的运动 |
|  | this.x += this.dx |
|  | this.y += this.dy |
|  | this.r -= 0.5 |
|  | // 如果小球的半径小于0了,从数组中删除 |
|  | if(this.r <= 0) { |
|  | this.remove() |
|  |  } |
|  |  } |
|  |  |
|  | // 移除小球 |
|  | remove(): void { |
|  | for(let i = 0; i < ballArr.length; i++) { |
|  | if(ballArr[i] === this) { |
|  |  ballArr.splice(i, 1) |
|  |  } |
|  |  } |
|  |  } |
|  | } |
|  | // 维护小球的数组 |
|  | let ballArr: Ball[] = [] |
|  |  |
|  | // canvas设置鼠标监听 |
|  | myCanvas.addEventListener("mousemove", (event)=> { |
|  |  ballArr.push(new Ball(event.offsetX, event.offsetY)) |
|  | }) |
|  |  |
|  |  |
|  | // 定时器进行动画渲染和更新 |
|  | setInterval(function() { |
|  | // 动画的逻辑,清屏-更新-渲染 |
|  | if(ctx !== null) { |
|  |  ctx.clearRect(0, 0, myCanvas.width, myCanvas.height) |
|  |  } |
|  | for(let i = 0; i < ballArr.length; i++) { |
|  | // 小球的更新和渲染 |
|  |  ballArr[i].update() |
|  | if(ballArr[i]) { |
|  |  ballArr[i].render() |
|  |  } |
|  |  |
|  |  } |
|  | // 60 帧 |
|  | }, 1000 / 60) |


2.5 透明度

透明度的值是0到1之间: (1是完全不透明,0是完全透明)



|  | ctx.globalAlpha = 1 |


2.6 小球连线



|  | // 得到画布 |
|  | const myCanvas: HTMLCanvasElement = document.getElementById("mycanvas") as HTMLCanvasElement |
|  |  |
|  | // 获取上下文 |
|  | const ctx = myCanvas.getContext("2d") |
|  |  |
|  | // 设置画布的尺寸 |
|  | myCanvas.width = document.documentElement.clientWidth - 30 |
|  | myCanvas.height = document.documentElement.clientHeight - 30 |
|  |  |
|  | class Ball { |
|  | x: number = Math.floor(Math.random() * myCanvas.width) |
|  | y: number = Math.floor(Math.random() * myCanvas.height) |
|  | r: number = 10 |
|  | color: string = 'gray' |
|  | dx: number = Math.floor(Math.random() * 10) - 5 |
|  | dy: number = Math.floor(Math.random() * 10) - 5 |
|  | constructor() { |
|  |  ballArr.push(this) |
|  |  } |
|  |  |
|  | // 小球的渲染 |
|  | render() { |
|  | if(ctx !== null) { |
|  |  ctx.beginPath() |
|  | // 透明度 |
|  |  ctx.globalAlpha = 1 |
|  | // 画小球 |
|  |  ctx.arc(this.x, this.y, this.r, 0, Math.PI * 2, false) |
|  |  ctx.fillStyle = this.color |
|  |  ctx.fill() |
|  |  } |
|  |  } |
|  | // 小球的更新 |
|  | update() { |
|  | // 更新x |
|  | this.x += this.dx |
|  | // 纠正x |
|  | if(this.x <= this.r) { |
|  | this.x = this.r |
|  |  } else if ( this.x >= myCanvas.width - this.r) { |
|  | this.x = myCanvas.width - this.r |
|  |  } |
|  | // 更新y |
|  | this.y += this.dy |
|  | // 纠正y |
|  | if(this.y <= this.r) { |
|  | this.y = this.r |
|  |  } else if ( this.y >= myCanvas.height - this.r) { |
|  | this.y = myCanvas.height - this.r |
|  |  } |
|  | // 碰壁返回 |
|  | if(this.x + this.r >= myCanvas.width || this.x - this.r <= 0) { |
|  | this.dx *= -1 |
|  |  } |
|  | if(this.y + this.r >= myCanvas.height || this.y - this.r <= 0) { |
|  | this.dy *= -1 |
|  |  } |
|  |  } |
|  |  |
|  | } |
|  |  |
|  | // 小球数组 |
|  | let ballArr: Ball[] = [] |
|  |  |
|  | // 创建20个小球 |
|  | for(let i = 0; i < 20; i++) { |
|  | new Ball() |
|  | } |
|  |  |
|  | // 定时器动画 |
|  | setInterval(() => { |
|  | // 清除画布 |
|  | if(ctx !== null) { |
|  |  ctx.clearRect(0, 0, myCanvas.width, myCanvas.height) |
|  |  } |
|  | // 小球渲染和更新 |
|  | for(let i = 0; i < ballArr.length; i++) { |
|  |  ballArr[i].render() |
|  |  ballArr[i].update() |
|  |  } |
|  | // 画线的逻辑 |
|  | if(ctx !== null) { |
|  | for(let i = 0; i < ballArr.length; i++) { |
|  | for(let j = i + 1; j < ballArr.length; j++) { |
|  | let distance = Math.sqrt(Math.pow((ballArr[i].x - ballArr[j].x), 2) + Math.pow((ballArr[i].y -ballArr[j].y), 2)) |
|  | if( distance <= 150) { |
|  |  ctx.strokeStyle = '#000' |
|  |  ctx.beginPath() |
|  | // 线的透明度,根据当前已经连线的小球的距离进行线的透明度设置 |
|  | // 距离越近透明度越大,距离越远透明度越小 |
|  |  ctx.globalAlpha = 1 - distance / 150 |
|  |  ctx.moveTo(ballArr[i].x, ballArr[i].y) |
|  |  ctx.lineTo(ballArr[j].x, ballArr[j].y) |
|  |  ctx.closePath() |
|  |  ctx.stroke() |
|  |  } |
|  |  } |
|  |  } |
|  |  } |
|  | }, 1000/60) |


2.7 线型

lineWidth

我们可以利用lineWidth设置线的粗细,属性值为number型,默认为1,没有单位



|  | ctx.lineWidth = 1.0 |


canvas基础简单易懂教程(完结,多图)_第9张图片

lineCap

我们可以使用lineCap指定如何绘制每一条线段末端的属性:"butt" | "round" | "square", 其中butt代表线段末端以方形结束,round表示线段末端以圆形结束,square线段末端以方形结束,但是增加了一个宽度和线段相同,高度是线段厚度一半的矩形区域,默认是butt



|  | ctx.lineCap = "round"; |


canvas基础简单易懂教程(完结,多图)_第10张图片

canvas基础简单易懂教程(完结,多图)_第11张图片

该图是三种lineCapd的类型,从左到右依次为buttroundsquare

lineJoin

我们可以使用lineJoin来设置设置2个长度不为0的相连部分(线段,圆弧,曲线)如何连接在一起的属性(长度为0的变形部分,其指定的末端和控制点在同一位置,会被忽略):"bevel" | "round" | "miter"



|  | ctx.lineJoin = "bevel"; |


  • round表示通过填充一个额外的,圆心在相连部分末端的扇形,绘制拐角的形状。 圆角的半径是线段的宽度。
  • bevel表示在相连部分的末端填充一个额外的以三角形为底的区域, 每个部分都有各自独立的矩形拐角。
  • mitter表示通过延伸相连部分的外边缘,使其相交于一点,形成一个额外的菱形区域。

canvas基础简单易懂教程(完结,多图)_第12张图片

setLineDash

我们可以使用setLineDash方法在填充线时使用虚线模式。



|  | ctx.setLineDash(segments); |


  • segments是一个Array数组。一组描述交替绘制线段和间距(坐标空间单位)长度的数字。 如果数组元素的数量是奇数, 数组的元素会被复制并重复。例如, [5, 15, 25] 会变成 [5, 15, 25, 5, 15, 25]。数组内部是虚线的交替状态


|  | // 得到画布 |
|  | const myCanvas: HTMLCanvasElement = document.getElementById("mycanvas") as HTMLCanvasElement |
|  |  |
|  | // 获取上下文 |
|  | const ctx = myCanvas.getContext("2d") |
|  |  |
|  | // 画布的尺寸 |
|  | myCanvas.width = document.documentElement.clientWidth - 30 |
|  | myCanvas.height = document.documentElement.clientHeight - 30 |
|  |  |
|  | if(ctx !== null) { |
|  |  ctx.setLineDash([15, 15]); |
|  |  ctx.strokeRect(50,50, 90, 90) |
|  |  ctx.setLineDash([15,10,2,10]) |
|  |  ctx.strokeRect(200,50, 90, 90) |
|  | } |


canvas基础简单易懂教程(完结,多图)_第13张图片

lineDashOffset

我们可以使用lineDashOffset设置虚线偏移量的属性。设置的是起始偏移量,使线向左移动value



|  | ctx.lineDashOffset = value; |


  • value偏移量是float精度的数字。 初始值为 0.0

2.8 文本

我们可以在画布上绘制文字:



|  | ctx.font = "30px 微软雅黑" // 空格前为文字大小,空格后为字体类型 |
|  | // 第一个参数为文字内容,第二和第三个参数为文字绘制坐标, |
|  | // 第四个参数是可选参数,代表文字的最大宽度,如果字体宽度超过该值则压缩字体宽度 |
|  | ctx.fillText("你好,世界!", 100, 100)  |


canvas基础简单易懂教程(完结,多图)_第14张图片

我们可以使用textAlign来设置文本的对齐选项。可选的值包括:start, end, left, right or center。默认值是 start。该对齐是基于fillText方法的x的值。



|  | ctx.textAlign = "left" || "right" || "center" || "start" || "end"; |


  • left : 文本左对齐。
  • right: 文本右对齐。
  • center: 文本居中对齐。
  • start: 文本对齐界线开始的地方 (左对齐指本地从左向右,右对齐指本地从右向左)。
  • end: 文本对齐界线结束的地方 (左对齐指本地从左向右,右对齐指本地从右向左)。

2.9 渐变 Gradients

提供两种渐变方式,一种是线性渐变,一种是径向渐变。

  • 线性渐变:createLinearGradient 方法接受 4 个参数,表示图形渐变线的起点 (x1,y1) 与终点 (x2,y2),渐变将沿着这条线向两边渐变。


|  | ctx.createLinearGradient(x1, y1, x2, y2) |


addColorStop内部接收两个参数,第一个参数是当前渐变的位置(0~1之间的小数),第二个参数是颜色。



|  | let liner: CanvasGradient = ctx.createLinearGradient(0, 0, 100, 100) |
|  | liner.addColorStop(0, 'red') |
|  | liner.addColorStop(.5, 'blue') |
|  | liner.addColorStop(.8, 'yellow') |
|  | liner.addColorStop(1, 'green') |
|  | ctx.fillStyle = liner |
|  | ctx.fillRect(10, 10, 100,100) |


canvas基础简单易懂教程(完结,多图)_第15张图片

径向渐变:createRadialGradient方法接受 6 个参数,前三个定义一个以 (x1,y1) 为原点,半径为 r1 的开始圆形,后三个参数则定义另一个以 (x2,y2) 为原点,半径为 r2 的结束圆形。



|  | let radial: CanvasGradient = ctx.createRadialGradient(100, 100, 0, 100, 100, 100) |
|  | radial.addColorStop(0, 'red') |
|  | radial.addColorStop(1, 'purple') |
|  | ctx.fillStyle = radial |
|  | ctx.arc(100, 100, 100, 0, Math.PI *2, false) |
|  | ctx.fill( |


canvas基础简单易懂教程(完结,多图)_第16张图片

2.10 阴影

我们可以在画布中设置画布的阴影的状态:

  • shadowOffsetX: shadowOffsetXshadowOffsetY 用来设定阴影在 X 和 Y 轴的延伸距离,它们是不受变换矩阵所影响的。负值表示阴影会往上或左延伸,正值则表示会往下或右延伸,它们默认都为 0
  • shadowOffsetY: shadowOffsetXshadowOffsetY 用来设定阴影在 X 和 Y 轴的延伸距离,它们是不受变换矩阵所影响的。负值表示阴影会往上或左延伸,正值则表示会往下或右延伸,它们默认都为 0
  • shadowBlur: shadowBlur 用于设定阴影的模糊程度,其数值并不跟像素数量挂钩,也不受变换矩阵的影响,默认为 0
  • shadowColor: shadowColor 是标准的 CSS 颜色值,用于设定阴影颜色效果,默认是全透明的黑色。


|  | ctx.shadowOffsetX = 1 // 阴影左右偏离的距离 |
|  | ctx.shadowOffsetY = 1 // 阴影上下偏离的距离 |
|  | ctx.shadowBlur = 1 // 模糊状态 |
|  | ctx.shadowColor = 'green' // 阴影颜色 |
|  | ctx.font ='30px 宋体' |
|  | ctx.fillText('你好,世界!', 100, 100) |


canvas基础简单易懂教程(完结,多图)_第17张图片

三、使用图片

canvs中使用drawImage来绘制图片,主要是把外部的图片导入进来,绘制到画布上。

图片的渲染过程:



|  | // 导入图片 |
|  | if(ctx !== null) { |
|  | // 第一步是创建一个image元素 |
|  | let image:HTMLImageElement = new Image() |
|  | // 用src设置图片的地址 |
|  |  image.src = "image/test1.png" |
|  | // 必须要在onload函数内绘制图片,否则不会渲染 |
|  |  image.onload = function() { |
|  |  ctx.drawImage(image, 100, 100) |
|  |  } |
|  | } |


canvas基础简单易懂教程(完结,多图)_第18张图片

如果我们在drawImage里设置的参数一共是两个(不包含第一个image参数),表示的是图片的加载位置。



|  | ctx.drawImage(image, 100, 100) |


canvas基础简单易懂教程(完结,多图)_第19张图片

如果drawImage有四个参数,分别表示图片的绘制位置和图片的宽高。(注意,此时图像会被拉伸)



|  | ctx.drawImage(image, 100, 100, 50, 50) |


canvas基础简单易懂教程(完结,多图)_第20张图片

还可以使用八个参数的drawImage, 前四个参数指的是你在图片中设置切片的宽度和高度,以及切片的位置,后四个参数指的是切片在画布上的位置和切片宽度高度



|  | // ctx.drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight); |
|  | ctx.drawImage(image, 100, 300, 200, 200) |
|  | ctx.drawImage(image, 100, 100, 200, 200, 100, 100, 200, 200) |


  • sx: 需要绘制到目标上下文中的,image的矩形(裁剪)选择框的左上角 X 轴坐标。
  • sy: 需要绘制到目标上下文中的,image的矩形(裁剪)选择框的左上角 Y 轴坐标。
  • sWidth: 需要绘制到目标上下文中的,image的矩形(裁剪)选择框的宽度。如果不说明,整个矩形(裁剪)从坐标的sxsy开始,到image的右下角结束。
  • sHeight: 需要绘制到目标上下文中的,image的矩形(裁剪)选择框的高度。
  • dx: image的左上角在目标canvas上 X 轴坐标。
  • dy: image的左上角在目标canvas上 Y 轴坐标。
  • dWidth: image在目标canvas上绘制的宽度。 允许对绘制的image进行缩放。 如果不说明, 在绘制时image宽度不会缩放。
  • dHeight: image在目标canvas上绘制的高度。 允许对绘制的image进行缩放。 如果不说明, 在绘制时image高度不会缩放。

canvas基础简单易懂教程(完结,多图)_第21张图片

canvas基础简单易懂教程(完结,多图)_第22张图片

四、资源管理器

canvas基础简单易懂教程(完结,多图)_第23张图片

我们在开发游戏的时候,有一些静态资源是需要请求回来的,否则如果直接开始,某些静态资源没有,会报错,或者空白,比如我们的游戏被禁锢,如果没有请求回来就直接开始,页面会有空白现象。

资源管理器就是当游戏需要资源全部加载完毕的时候,再开始游戏

我们现在主要是图片的资源,所以我们要在canvas渲染过程中进行图片的资源加载。

4.1 获取对象中属性的长度

有下面一个JSON(对象),此时我们想获取当前这个JSON属性数量



|  | this.imgURL = { |
|  | 'fengjing1':'./image/下载1.jpg', |
|  | 'fengjing2':'./image/下载2.jpg', |
|  | 'fengjing3':'./image/下载3.jpg', |
|  | 'fengjing4':'./image/下载4.jpg', |
|  | 'fengjing5':'./image/下载5.jpg', |
|  | } |


此时我们使用this.imgURL.length是得不到的,因为当前的this.imgURL.length指的是获取imgURL对象的length属性,而不是获取当前对象的属性个数,会返回undefined

正确答案是使用Object.keys()来获取当前的属性key列表,然后通过这个列表获取长度。



|  | Object.keys(this.imgURL).length |


4.2 管理器的实现



|  | interface StringOrImage { |
|  | // 定义了一个接口,该接口要求对象的属性是string或者是HTMLImageElement类型 |
|  |  [index: string]: string | HTMLImageElement |
|  | } |
|  |  |
|  | class Game { |
|  | dom: HTMLCanvasElement |
|  | ctx: CanvasRenderingContext2D | null |
|  | imgURL: StringOrImage |
|  | constructor() { |
|  | // 得到画布 |
|  | this.dom = document.getElementById("mycanvas") as HTMLCanvasElement |
|  | // 获取上下文 |
|  | this.ctx = this.dom.getContext("2d") |
|  | // 在属性中保存需要的图片地址 |
|  | this.imgURL = { |
|  | // 'fengjing1':'./image/下载1.jpg', |
|  | // 'fengjing2':'./image/下载2.jpg', |
|  | // 'fengjing3':'./image/下载3.jpg', |
|  | // 'fengjing4':'./image/下载4.jpg', |
|  | // 'fengjing5':'./image/下载5.jpg', |
|  | 'fengjing1':'https://gimg2.baidu.com/image\_search/src=http%3A%2F%2Fimg.jj20.com%2Fup%2Fallimg%2F4k%2Fs%2F02%2F2109242332225H9-0-lp.jpg&refer=http%3A%2F%2Fimg.jj20.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1651933471&t=34b40d339ce3bc4177afb393e7785575', |
|  | 'fengjing2':'https://gimg2.baidu.com/image\_search/src=http%3A%2F%2Ffile02.16sucai.com%2Fd%2Ffile%2F2014%2F0827%2Fc0c92bd51bb72e6d12d5b877dce338e8.jpg&refer=http%3A%2F%2Ffile02.16sucai.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1651933483&t=453f28e751e0d54d70a2e3393e57b423', |
|  | 'fengjing3':'https://gimg2.baidu.com/image\_search/src=http%3A%2F%2Fimg.jj20.com%2Fup%2Fallimg%2F1113%2F032120114622%2F200321114622-4-1200.jpg&refer=http%3A%2F%2Fimg.jj20.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1651933493&t=e9017fa69deb525312e214d2583a76d4', |
|  | 'fengjing4':'https://pic.rmb.bdstatic.com/1530971282b420d77bdfb6444d854f952fe31f0d1e.jpeg', |
|  | 'fengjing5':'https://gimg2.baidu.com/image\_search/src=http%3A%2F%2Fimg.jj20.com%2Fup%2Fallimg%2Ftp01%2F1ZZQ214233446-0-lp.jpg&refer=http%3A%2F%2Fimg.jj20.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1651933521&t=2cc050574824ec2761b539ab3a697522', |
|  |  } |
|  | // 获取资源图片的总数 |
|  | let imgCount = Object.keys(this.imgURL).length |
|  | // 计数器,记录的是加载完毕的数量 |
|  | let count = 0 |
|  | // 遍历imgURL对象获取每一个路径地址 |
|  | for(let key in this.imgURL) { |
|  | // 备份每一张图片的地址 |
|  | let src: string = this.imgURL[key] as string |
|  | // 创建一个图片 |
|  | this.imgURL[key] = new Image(); |
|  |  |
|  | // 判断图片是否加载完成,如果完成了,记数,如果加载完毕的数量和总数量相同了,则说明资源加载完毕 |
|  | // 第一种方法,将值提取出去做类型缩小 |
|  | let value = this.imgURL[key] |
|  | // 类型缩小成HTMLImageElement类型 |
|  | if(typeof value !== 'string') { |
|  |  value.src = src |
|  |  value.onload = () => { |
|  | // 增加计数器 |
|  |  count++ |
|  | if(this.ctx !== null) { |
|  | // 清屏 |
|  | this.ctx.clearRect(0, 0, 600, 600) |
|  | this.ctx.font = '16px Arial' |
|  | this.ctx.fillText("图片已经加载:" + count +" / " + imgCount, 50, 50) |
|  | // 判断图片是否加载完毕,如果加载完毕了再开始显示 |
|  | if(count === imgCount) { |
|  | this.start() |
|  |  } |
|  |  } |
|  |  }  |
|  |  } |
|  |  |
|  | // 第二种方法,使用as直接断言成HTMLImageElement |
|  | //(this.imgURL[key] as HTMLImageElement).src = src |
|  |  |
|  |  } |
|  |  } |
|  | start() { |
|  | if(this.ctx !== null) { |
|  | // 清屏 |
|  | this.ctx.clearRect(0, 0, 600, 600) |
|  | let startX = 0 |
|  | let startY = 0 |
|  | for(let key in this.imgURL) { |
|  | this.ctx.drawImage(this.imgURL[key] as HTMLImageElement, startX, startY, 100, 100) |
|  |  startX += 100 |
|  |  startY += 100 |
|  |  } |
|  |  } |
|  |  } |
|  | } |
|  |  |
|  | new Game() |


五、变形

canvas是可以进行变形的,但是变形的不是元素,而是ctx,ctx就是整个画布的渲染区域,整个画布在变形,我们需要在画布变形前进行保存和恢复:

  • save():保存画布(canvas)的所有状态。
  • restore():save 和 restore 方法是用来保存和恢复 canvas 状态的,都没有参数。Canvas 的状态就是当前画面应用的所有样式和变形的一个快照。

Canvas状态存储在栈中,每当save()方法被调用后,当前的状态就被推送到栈中保存。一个绘画状态包括:

  • 当前应用的变形(即移动,旋转和缩放,见下)
  • 以及下面这些属性:strokeStyle, fillStyle, globalAlpha, lineWidth, lineCap, lineJoin, miterLimit, lineDashOffset, shadowOffsetX, shadowOffsetY, shadowBlur, shadowColor, globalCompositeOperation, font, textAlign, textBaseline, direction, imageSmoothingEnabled
  • 当前的裁切路径(clipping path),会在下一节介绍

你可以调用任意多次 save方法。每一次调用 restore 方法,上一个保存的状态就从栈中弹出,所有设定都恢复。

以下的例子可以很好的印证这两个的用法:



|  | // 得到画布 |
|  | const myCanvas: HTMLCanvasElement = document.getElementById('mycanvas') as HTMLCanvasElement |
|  | // 获得上下文 |
|  | const ctx = myCanvas.getContext('2d') |
|  |  |
|  | if (ctx !== null) { |
|  |  ctx.fillRect(0, 0, 150, 150); // 使用默认设置绘制一个矩形 |
|  |  ctx.save(); // 保存默认状态 |
|  |  |
|  |  ctx.fillStyle = '#09F' // 在原有配置基础上对颜色做改变 |
|  |  ctx.fillRect(15, 15, 120, 120); // 使用新的设置绘制一个矩形 |
|  |  |
|  |  ctx.save(); // 保存当前状态 |
|  |  ctx.fillStyle = '#FFF' // 再次改变颜色配置 |
|  |  ctx.globalAlpha = 0.5; |
|  |  ctx.fillRect(30, 30, 90, 90); // 使用新的配置绘制一个矩形 |
|  |  |
|  |  ctx.restore(); // 重新加载之前的颜色状态 |
|  |  ctx.fillRect(45, 45, 60, 60); // 使用上一次的配置绘制一个矩形 |
|  |  |
|  |  ctx.restore(); // 加载默认颜色配置 |
|  |  ctx.fillRect(60, 60, 30, 30); // 使用加载的配置绘制一个矩形 |
|  | } |


canvas基础简单易懂教程(完结,多图)_第24张图片

5.1 移动translate

translate(x, y): translate 方法接受两个参数。x 是左右偏移量,y 是上下偏移量。

在做变形之前先保存状态是一个良好的习惯。大多数情况下,调用 restore 方法比手动恢复原先的状态要简单得多。又,如果你是在一个循环中做位移但没有保存和恢复 canvas 的状态,很可能到最后会发现怎么有些东西不见了,那是因为它很可能已经超出 canvas 范围以外了。

我们知道了变形实际上就是将整个画布进行的变形,所以如果一旦我们的变形操作变多了,画布将变得不可控。

所以如果我们使用到变形,一定记住下面的规律:变形之前要先备份,将世界和平的状态进行备份,然后再变形,变形完毕后再恢复到世界和平的样子,不要影响下一次的操作。



|  | // 得到画布 |
|  | const myCanvas: HTMLCanvasElement = document.getElementById('mycanvas') as HTMLCanvasElement |
|  | // 获得上下文 |
|  | const ctx = myCanvas.getContext('2d') |
|  |  |
|  | if (ctx !== null) { |
|  | // 保存 |
|  |  ctx.save() |
|  |  ctx.translate(50, 50) |
|  |  ctx.fillRect(0, 0, 120, 120) |
|  | // 恢复 |
|  |  ctx.restore() |
|  | // 渲染位置是没有存档之前的位置 |
|  |  ctx.fillRect(120, 300, 120, 120) |
|  | } |


canvas基础简单易懂教程(完结,多图)_第25张图片

5.2 旋转 rotate

rotate(angle)这个方法只接受一个参数:旋转的角度(angle),它是顺时针方向的,以弧度为单位的值。

旋转的中心点始终是 canvas 的原点,如果要改变它,我们需要用到 translate 方法。

5.3 缩放 scale

scale(x, y): scale 方法可以缩放画布的水平和垂直的单位。两个参数都是实数,可以为负数,x 为水平缩放因子,y 为垂直缩放因子,如果比1小,会缩小图形, 如果比1大会放大图形。默认值为1, 为实际大小。

画布初始情况下, 是以左上角坐标为原点的第一象限。如果参数为负实数, 相当于以x 或 y轴作为对称轴镜像反转(例如, 使用translate(0,canvas.height); scale(1,-1); 以y轴作为对称轴镜像反转, 就可得到著名的笛卡尔坐标系,左下角为原点)。

默认情况下,canvas 的 1 个单位为 1 个像素。举例说,如果我们设置缩放因子是 0.5,1 个单位就变成对应 0.5 个像素,这样绘制出来的形状就会是原先的一半。同理,设置为 2.0 时,1 个单位就对应变成了 2 像素,绘制的结果就是图形放大了 2 倍。

5.4 变形 transform

transform(a, b, c, d, e, f)

a (m11): 水平方向的缩放;

b(m12): 竖直方向的倾斜偏移;

c(m21): 水平方向的倾斜偏移;

d(m22): 竖直方向的缩放;

e(dx): 水平方向的移动;

f(dy): 竖直方向的移动.



|  | // 得到画布 |
|  | const myCanvas: HTMLCanvasElement = document.getElementById('mycanvas') as HTMLCanvasElement |
|  | // 获得上下文 |
|  | const ctx = myCanvas.getContext('2d') |
|  |  |
|  | if (ctx !== null) { |
|  | // 保存 |
|  |  ctx.save() |
|  |  ctx.transform(0.5, 0, 1, 0.5, 100, 100) |
|  |  ctx.fillRect(0, 0, 100,100) |
|  | // 恢复 |
|  |  ctx.restore() |
|  | // 渲染位置是没有存档之前的位置 |
|  |  ctx.fillRect(0, 200, 100, 100) |
|  |  |
|  | } |


canvas基础简单易懂教程(完结,多图)_第26张图片

5.5 滚动的车轮案例

  • index.html


|  | html> |
|  |  |
|  |  |
|  |  |
|  |  |
|  |  |
|  |  |
|  | canvas的变形-滚动的车轮title> |
|  | <link rel="stylesheet" href="./css/reset.css" type="text/css"> |
|  | <link rel="stylesheet" href="./css/index.css" type="text/css"> |
|  | head> |
|  |  |
|  | <body> |
|  | <canvas id="mycanvas"width="1200" height="600" > |
|  |  当前的浏览器版本不支持,请升级浏览器 |
|  | canvas> |
|  | <script src='./dist/canvas.js'>script> |
|  | body> |
|  | html> |


</code></pre> 
  <ul> 
   <li>所需图片</li> 
  </ul> 
  <p><a href="http://img.e-com-net.com/image/info8/755956050f4845f38be0cf085e5ce4c5.webp" target="_blank"><img src="http://img.e-com-net.com/image/info8/755956050f4845f38be0cf085e5ce4c5.webp" alt="canvas基础简单易懂教程(完结,多图)_第27张图片" width="886" height="890" style="border:1px solid black;"></a></p> 
  <ul> 
   <li>canvas.ts</li> 
  </ul> 
  <pre><code>

|  | // 得到画布 |
|  | const myCanvas: HTMLCanvasElement = document.getElementById('mycanvas') as HTMLCanvasElement |
|  | // 获得上下文 |
|  | const ctx = myCanvas.getContext('2d') |
|  |  |
|  |  |
|  | if (ctx !== null) { |
|  | // 第一步是创建一个image元素 |
|  | const image:HTMLImageElement = new Image() |
|  | // 用src设置图片的地址 |
|  |  image.src = "image/汽车车轮.png" |
|  | // 必须要在onload函数内绘制图片,否则不会渲染 |
|  |  image.onload = () => { |
|  | // 定时器 |
|  | // 旋转的度数 |
|  | let deg = 0 |
|  | // 位置 |
|  | let x= -100 |
|  |  |
|  | setInterval(() => { |
|  | // 清除画布 |
|  |  ctx.clearRect(0, 0, myCanvas.width, myCanvas.height) |
|  |  deg += 0.1 |
|  |  x += 5 |
|  | if(x >= myCanvas.width - 100) { |
|  |  x = -100 |
|  |  } |
|  | // 备份 |
|  |  ctx.save() |
|  | // 平移, 目前我们的原点为(100,300) |
|  |  ctx.translate(x, 300) |
|  | // 旋转,因为旋转始终在canvas的原点,所以我们得用translate改变原点。 |
|  |  ctx.rotate(deg) |
|  | // 我们得让车轮的中心处于原点,所以我们需要在第一个和第二个参数各为第三和第四个参数的一半然后再加负号 |
|  |  ctx.drawImage(image, -100, -100, 200, 200) |
|  | // 恢复 |
|  |  ctx.restore() |
|  |  }, 1000/60) |
|  |  } |
|  | } |


</code></pre> 
  <ul> 
   <li>整体架构</li> 
  </ul> 
  <p><a href="http://img.e-com-net.com/image/info8/34c9868282614ad7b86b7690195e19d8.jpg" target="_blank"><img src="http://img.e-com-net.com/image/info8/34c9868282614ad7b86b7690195e19d8.jpg" alt="canvas基础简单易懂教程(完结,多图)_第28张图片" width="152" height="177" style="border:1px solid black;"></a></p> 
  <ul> 
   <li>实现的效果<br> </li> 
  </ul> 
  <h2>六、合成与裁剪</h2> 
  <p>合成其实就是我们常见的蒙版状态,本质就是如何进行压盖,如何进行显示。</p> 
  <p>在之前我们总是将一个图形画在另一个之上,对于其他更多的情况,仅仅这样是远远不够的。比如,对合成的图形来说,绘制顺序会有限制。不过,我们可以利用 <code>globalCompositeOperation</code> 属性来改变这种状况。此外, <code>clip</code>属性允许我们隐藏不想看到的部分图形。</p> 
  <p>比如我们此时花了一个方和一个圆,第一次画的是方,第二次画的是圆,所以会出现圆压盖方的现象</p> 
  <pre><code>

|  | // 得到画布 |
|  | const myCanvas: HTMLCanvasElement = document.getElementById('mycanvas') as HTMLCanvasElement |
|  | // 获得上下文 |
|  | const ctx = myCanvas.getContext('2d') |
|  |  |
|  | if (ctx !== null) { |
|  |  ctx.fillStyle = 'skyblue' |
|  |  ctx.fillRect(100, 100, 100, 100) |
|  |  ctx.fillStyle = 'deeppink' |
|  |  ctx.beginPath() |
|  |  ctx.arc(200, 200, 60, 0, 7,false) |
|  |  ctx.fill() |
|  | } |


</code></pre> 
  <p><a href="http://img.e-com-net.com/image/info8/4d997d679ffa4951b8d8a1e270b6959c.png" target="_blank"><img src="http://img.e-com-net.com/image/info8/4d997d679ffa4951b8d8a1e270b6959c.png" alt="canvas基础简单易懂教程(完结,多图)_第29张图片" width="513" height="523" style="border:1px solid black;"></a></p> 
  <h3>6.1 globalCompositeOperation</h3> 
  <p><code>globalCompositeOperation = type</code></p> 
  <p>这个属性设定了在画新图形时采用的遮盖策略,其值是一个标识12种遮盖方式的字符串。具体情况看MDN。</p> 
  <p>我们可以通过这个属性来对上方设置压盖顺序:</p> 
  <p>比如说此时我们想让粉色在下面, 可以使用destination-over:</p> 
  <pre><code>

|  | // 得到画布 |
|  | const myCanvas: HTMLCanvasElement = document.getElementById('mycanvas') as HTMLCanvasElement |
|  | // 获得上下文 |
|  | const ctx = myCanvas.getContext('2d') |
|  |  |
|  | if (ctx !== null) { |
|  |  ctx.fillStyle = 'skyblue' |
|  |  ctx.fillRect(100, 100, 100, 100) |
|  |  ctx.globalCompositeOperation= 'destination-over' |
|  |  ctx.fillStyle = 'deeppink' |
|  |  ctx.beginPath() |
|  |  ctx.arc(200, 200, 60, 0, 7,false) |
|  |  ctx.fill() |
|  | } |


</code></pre> 
  <p><a href="http://img.e-com-net.com/image/info8/6fea087929cb4f1d80c0391c35f66d47.png" target="_blank"><img src="http://img.e-com-net.com/image/info8/6fea087929cb4f1d80c0391c35f66d47.png" alt="canvas基础简单易懂教程(完结,多图)_第30张图片" width="262" height="239" style="border:1px solid black;"></a></p> 
  <h3>6.2 裁剪路径</h3> 
  <p>裁切路径和普通的 canvas 图形差不多,不同的是它的作用是遮罩,用来隐藏不需要的部分。如下图所示。红边五角星就是裁切路径,所有在路径以外的部分都不会在 canvas 上绘制出来。</p> 
  <p><a href="http://img.e-com-net.com/image/info8/5aca7fea7801488b8c6806dd6e45f5fa.png" target="_blank"><img src="http://img.e-com-net.com/image/info8/5aca7fea7801488b8c6806dd6e45f5fa.png" alt="canvas基础简单易懂教程(完结,多图)_第31张图片" width="241" height="245" style="border:1px solid black;"></a></p> 
  <p>如果和上面介绍的 <code>globalCompositeOperation</code> 属性作一比较,它可以实现与 <code>source-in</code> 和 <code>source-atop</code>差不多的效果。最重要的区别是裁切路径不会在 canvas 上绘制东西,而且它永远不受新图形的影响。这些特性使得它在特定区域里绘制图形时相当好用。</p> 
  <p><code>clip()</code>: 将当前正在构建的路径转换为当前的裁剪路径。默认情况下,canvas 有一个与它自身一样大的裁切路径(也就是没有裁切效果)。</p> 
  <h3>6.3 刮刮乐案例</h3> 
  <ul> 
   <li>index.html</li> 
  </ul> 
  <pre><code>

|  | html> |
|  | <html lang="en"> |
|  |  |
|  | <head> |
|  | <meta charset="UTF-8"> |
|  | <meta http-equiv="X-UA-Compatible" content="IE=edge"> |
|  | <meta name="viewport" content="width=device-width, initial-scale=1.0"> |
|  | <title>canvas实现刮刮乐title> |
|  | <link rel="stylesheet" href="./css/reset.css" type="text/css"> |
|  | <link rel="stylesheet" href="./css/index.css" type="text/css"> |
|  | head> |
|  |  |
|  | <body> |
|  | <div> |
|  |  特等奖 |
|  | <canvas width="250" height="60" id="mycanvas"> |
|  |  当前的浏览器版本不支持,请升级浏览器 |
|  | canvas> |
|  | div> |
|  | <script src='./dist/canvas.js'>script> |
|  | body> |
|  | html> |


</code></pre> 
  <ul> 
   <li>index.css</li> 
  </ul> 
  <pre><code>

|  | div { |
|  | border: 1px solid #000; |
|  | width: 250px; |
|  | height: 60px; |
|  | font-size: 40px; |
|  | line-height: 60px; |
|  | text-align: center; |
|  | position: relative; |
|  |  user-select: none; |
|  | } |
|  |  |
|  | canvas { |
|  | position: absolute; |
|  | left: 0; |
|  | top: 0; |
|  | } |


</code></pre> 
  <ul> 
   <li>canvas.ts</li> 
  </ul> 
  <pre><code>

|  | // 得到画布 |
|  | const myCanvas: HTMLCanvasElement = document.getElementById('mycanvas') as HTMLCanvasElement |
|  | // 获得上下文 |
|  | const ctx = myCanvas.getContext('2d') |
|  |  |
|  | if (ctx !== null) { |
|  |  ctx.fillStyle = '#333' |
|  |  ctx.fillRect(0, 0, 250, 60) |
|  | // 设置新画上的元素,实际上就是擦除之前的元素 |
|  |  ctx.globalCompositeOperation = 'destination-out' |
|  |  |
|  | const func = (event:any) => { |
|  | // 画图 |
|  |  ctx.beginPath() |
|  |  ctx.arc(event.offsetX, event.offsetY,10, 0, Math.PI * 2,false) |
|  |  ctx.fill() |
|  |  } |
|  | // 按下 |
|  |  myCanvas.onmousedown = () => { |
|  | // 添加鼠标移动事件 |
|  |  myCanvas.addEventListener('mousemove', func) |
|  |  } |
|  | // 松开 |
|  |  myCanvas.onmouseup = () => { |
|  | // 删除鼠标移动事件 |
|  |  myCanvas.removeEventListener('mousemove', func) |
|  |  } |
|  | } |


</code></pre> 
  <ul> 
   <li>实现效果</li> 
  </ul> 
  <p><a href="http://img.e-com-net.com/image/info8/8053df5acdb64f5bb2c5f1f4c9a7f5fa.gif" target="_blank"><img src="http://img.e-com-net.com/image/info8/8053df5acdb64f5bb2c5f1f4c9a7f5fa.gif" alt="" width="281" height="79"></a></p> 
  <h2>七、总结</h2> 
  <p>至此,一个简单的学习canvas教程已经完结,大家还是多看看文档吧,希望这个教程能让大家喜欢上canvas并且好好的利用它!</p> 
 </div> 
</div>
                            </div>
                        </div>
                    </div>
                    <!--PC和WAP自适应版-->
                    <div id="SOHUCS" sid="1666203987755491328"></div>
                    <script type="text/javascript" src="/views/front/js/chanyan.js"></script>
                    <!-- 文章页-底部 动态广告位 -->
                    <div class="youdao-fixed-ad" id="detail_ad_bottom"></div>
                </div>
                <div class="col-md-3">
                    <div class="row" id="ad">
                        <!-- 文章页-右侧1 动态广告位 -->
                        <div id="right-1" class="col-lg-12 col-md-12 col-sm-4 col-xs-4 ad">
                            <div class="youdao-fixed-ad" id="detail_ad_1"> </div>
                        </div>
                        <!-- 文章页-右侧2 动态广告位 -->
                        <div id="right-2" class="col-lg-12 col-md-12 col-sm-4 col-xs-4 ad">
                            <div class="youdao-fixed-ad" id="detail_ad_2"></div>
                        </div>
                        <!-- 文章页-右侧3 动态广告位 -->
                        <div id="right-3" class="col-lg-12 col-md-12 col-sm-4 col-xs-4 ad">
                            <div class="youdao-fixed-ad" id="detail_ad_3"></div>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>
    <div class="container">
        <h4 class="pt20 mb15 mt0 border-top">你可能感兴趣的:(计算机,计算机)</h4>
        <div id="paradigm-article-related">
            <div class="recommend-post mb30">
                <ul class="widget-links">
                    <li><a href="/article/1892484969733877760.htm"
                           title="ug12在win8计算机名错,我电脑是win8.1的 装ug8.0 装ug为什么会提示错误??" target="_blank">ug12在win8计算机名错,我电脑是win8.1的 装ug8.0 装ug为什么会提示错误??</a>
                        <span class="text-muted">zc791022</span>
<a class="tag" taget="_blank" href="/search/ug12%E5%9C%A8win8%E8%AE%A1%E7%AE%97%E6%9C%BA%E5%90%8D%E9%94%99/1.htm">ug12在win8计算机名错</a>
                        <div>可以安装,64位的可能要通用许可证才能安装。安装NX8.0.0.25之前,最好卸载掉“大于4.0”的许可服务(因为你只要装了8.0的许可服务,7.0/6.0/5.0都可以启动的),安装后打不开NX8.0的,重启电脑试试!1.用记事本方式打开安装文件夹下的“crack\UGSLicensing\NX8.0.lic”(把里面SERVERthis_hostID=20110555528000里面的this</div>
                    </li>
                    <li><a href="/article/1892484213102407680.htm"
                           title="计算机程序制作的小作品,义乌市中小学生电脑作品制作比赛201203" target="_blank">计算机程序制作的小作品,义乌市中小学生电脑作品制作比赛201203</a>
                        <span class="text-muted">东南前哨</span>
<a class="tag" taget="_blank" href="/search/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%A8%8B%E5%BA%8F%E5%88%B6%E4%BD%9C%E7%9A%84%E5%B0%8F%E4%BD%9C%E5%93%81/1.htm">计算机程序制作的小作品</a>
                        <div>《义乌市中小学生电脑作品制作比赛201203》由会员分享,可在线阅读,更多相关《义乌市中小学生电脑作品制作比赛201203(4页珍藏版)》请在人人文库网上搜索。1、浙江省义乌市教育研修院关于举办2012年义乌市中小学生电脑作品制作比赛暨首届青少年网络道德建设专题创作活动的通知各中小学:为进一步推进和加强中小学信息技术教育,普及信息技术知识,培养学生创新精神和实践能力,提高信息技术水平,根据上级文件</div>
                    </li>
                    <li><a href="/article/1892469834516590592.htm"
                           title="网络安全常识" target="_blank">网络安全常识</a>
                        <span class="text-muted">网络安全Ash</span>
<a class="tag" taget="_blank" href="/search/web%E5%AE%89%E5%85%A8/1.htm">web安全</a><a class="tag" taget="_blank" href="/search/%E7%BD%91%E7%BB%9C/1.htm">网络</a><a class="tag" taget="_blank" href="/search/%E5%AE%89%E5%85%A8/1.htm">安全</a>
                        <div>一、网络安全常识什么是网络安全?网络安全是指网络系统的硬件、软件及其系统中的数据受到保护,不因偶然的或者恶意的原因而遭到破坏、更改、泄露,系统可以连续可靠正常地运行,网络服务不被中断。什么是计算机病毒?计算机病毒(ComputerVirus)是指编制者在计算机程序中插入的破坏计算机功能或者破坏数据,影响计算机使用并且能够自我复制的一组计算机指令或者程序代码。什么是木马?木马是一种带有恶意性质的远程</div>
                    </li>
                    <li><a href="/article/1892466933626892288.htm"
                           title="DeepSeek如何重塑我的编程学习:计算机新生的AI实践" target="_blank">DeepSeek如何重塑我的编程学习:计算机新生的AI实践</a>
                        <span class="text-muted">EnigmaCoder</span>
<a class="tag" taget="_blank" href="/search/DeepSeek/1.htm">DeepSeek</a><a class="tag" taget="_blank" href="/search/%E5%AD%A6%E4%B9%A0/1.htm">学习</a><a class="tag" taget="_blank" href="/search/%E4%BA%BA%E5%B7%A5%E6%99%BA%E8%83%BD/1.htm">人工智能</a>
                        <div>目录前言邂逅DeepSeek:从困惑到惊喜初学编程的困境DeepSeek的优势️DeepSeek在编程学习中的运用注释算法逐步分析调试帮助跨语言迁移学习AI时代学习方法论革新知识获取方式转变新型学习能力培养反思与展望反思展望总结前言大家好!我是EnigmaCoder,本文我将介绍我的AI编程学习之旅。春节期间,DeepSeek横空出世,迅速登顶热榜。它功能强大,精准答疑、高效创作,瞬间点燃大众热情</div>
                    </li>
                    <li><a href="/article/1892462137901641728.htm"
                           title="鸢尾花分类项目 GUI" target="_blank">鸢尾花分类项目 GUI</a>
                        <span class="text-muted">编织幻境的妖</span>
<a class="tag" taget="_blank" href="/search/%E5%88%86%E7%B1%BB/1.htm">分类</a><a class="tag" taget="_blank" href="/search/%E6%95%B0%E6%8D%AE%E6%8C%96%E6%8E%98/1.htm">数据挖掘</a><a class="tag" taget="_blank" href="/search/%E4%BA%BA%E5%B7%A5%E6%99%BA%E8%83%BD/1.htm">人工智能</a>
                        <div>1.机器学习的定义机器学习是一门人工智能的分支,专注于开发算法和统计模型,使计算机能够在没有明确编程的情况下从数据中自动学习和改进。通过识别数据中的模式和规律,机器学习系统可以做出预测或决策。常见的应用包括图像识别、语音识别、推荐系统等。2.为什么使用鸢尾花数据集(Irisdataset)鸢尾花数据集是一个经典的多类分类问题数据集,由英国统计学家和遗传学家RonaldFisher在1936年引入。</div>
                    </li>
                    <li><a href="/article/1892460368698077184.htm"
                           title="Java平台上的多线程与多核处理研究" target="_blank">Java平台上的多线程与多核处理研究</a>
                        <span class="text-muted">向哆哆</span>
<a class="tag" taget="_blank" href="/search/Java%E5%85%A5%E9%97%A8%E5%88%B0%E7%B2%BE%E9%80%9A/1.htm">Java入门到精通</a><a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/python/1.htm">python</a><a class="tag" taget="_blank" href="/search/%E5%BC%80%E5%8F%91%E8%AF%AD%E8%A8%80/1.htm">开发语言</a>
                        <div>Java平台上的多线程与多核处理研究在现代计算机架构中,多核处理器已成为主流。随着硬件性能的提升,如何有效利用多核处理器的计算能力成为开发者面临的重要问题之一。Java作为一种广泛使用的编程语言,提供了多线程编程的强大支持,使得开发者能够在多核环境下实现并行计算。本篇文章将深入探讨Java平台上的多线程与多核处理,探讨其工作原理、应用场景,并通过代码实例进行演示。1.多线程与多核处理的基本概念1.</div>
                    </li>
                    <li><a href="/article/1892459106929799168.htm"
                           title="十大经典排序算法的C++实现与解析" target="_blank">十大经典排序算法的C++实现与解析</a>
                        <span class="text-muted">金外飞176</span>
<a class="tag" taget="_blank" href="/search/%E7%AE%97%E6%B3%95/1.htm">算法</a><a class="tag" taget="_blank" href="/search/%E7%AE%97%E6%B3%95/1.htm">算法</a><a class="tag" taget="_blank" href="/search/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/1.htm">数据结构</a><a class="tag" taget="_blank" href="/search/c%2B%2B/1.htm">c++</a>
                        <div>经典排序算法的C++实现与解析在计算机科学中,排序算法是数据处理和算法设计的基础。无论是处理大规模数据还是优化小规模数据的性能,排序算法都扮演着重要角色。本文将介绍10种经典排序算法,并提供它们的C++实现代码。这些算法包括冒泡排序、选择排序、插入排序、希尔排序、归并排序、快速排序、堆排序、计数排序、基数排序和桶排序。1.冒泡排序(BubbleSort)原理冒泡排序是最简单的排序算法之一。它通过重</div>
                    </li>
                    <li><a href="/article/1892458727408201728.htm"
                           title="马斯克的Grok-3:技术突破与行业冲击的深度解析" target="_blank">马斯克的Grok-3:技术突破与行业冲击的深度解析</a>
                        <span class="text-muted">♢.*</span>
<a class="tag" taget="_blank" href="/search/%E9%A9%AC%E6%96%AF%E5%85%8B/1.htm">马斯克</a><a class="tag" taget="_blank" href="/search/%E4%BA%BA%E5%B7%A5%E6%99%BA%E8%83%BD/1.htm">人工智能</a><a class="tag" taget="_blank" href="/search/%E5%A4%A7%E6%A8%A1%E5%9E%8B/1.htm">大模型</a><a class="tag" taget="_blank" href="/search/xAI/1.htm">xAI</a><a class="tag" taget="_blank" href="/search/Grok/1.htm">Grok</a><a class="tag" taget="_blank" href="/search/3/1.htm">3</a>
                        <div>一、技术架构与核心突破超大规模算力集群Grok-3基于xAI自研的Colossus超级计算机训练完成,搭载20万块英伟达H100GPU,累计消耗2亿GPU小时,算力投入是前代Grok-2的10倍48。这一规模远超行业平均水平,例如中国团队DeepSeek-V3的算力消耗仅为Grok-3的1/2634。技术挑战:团队在122天内完成首期10万块GPU部署,克服了散热、电力供应等工程难题1。思维链推理</div>
                    </li>
                    <li><a href="/article/1892449900264747008.htm"
                           title="100道计算机网络面试八股文(答案、分析和深入提问)整理" target="_blank">100道计算机网络面试八股文(答案、分析和深入提问)整理</a>
                        <span class="text-muted">守护海洋的猫</span>
<a class="tag" taget="_blank" href="/search/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/1.htm">计算机网络</a><a class="tag" taget="_blank" href="/search/%E9%9D%A2%E8%AF%95/1.htm">面试</a><a class="tag" taget="_blank" href="/search/%E8%81%8C%E5%9C%BA%E5%92%8C%E5%8F%91%E5%B1%95/1.htm">职场和发展</a><a class="tag" taget="_blank" href="/search/python/1.htm">python</a><a class="tag" taget="_blank" href="/search/django/1.htm">django</a>
                        <div>1.说一说POST与GET有哪些区别回答在计算机网络中,POST和GET是HTTP协议中两种主要的请求方法,它们各自具有不同的特性和用途。下面是二者的主要区别:1.数据传输方式GET:数据通过URL传递,参数以查询字符串的形式附加在URL后面。示例:http://example.com/api?name=value&age=30POST:数据包含在HTTP请求的主体部分,数据不会显示在URL中。示</div>
                    </li>
                    <li><a href="/article/1892446114204938240.htm"
                           title="ECMAScript与JavaScript:探索两者之间的联系与区别" target="_blank">ECMAScript与JavaScript:探索两者之间的联系与区别</a>
                        <span class="text-muted">程序媛小果</span>
<a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a><a class="tag" taget="_blank" href="/search/ecmascript/1.htm">ecmascript</a><a class="tag" taget="_blank" href="/search/javascript/1.htm">javascript</a><a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a>
                        <div>在Web开发的早期,JavaScript成为了客户端脚本语言的代名词,而随着时间的推移,JavaScript已经发展成为一个功能强大的语言,它的影响力远远超出了浏览器的范畴。在这场语言演进的过程中,ECMAScript扮演了一个关键角色。本文将深入探讨ECMAScript与JavaScript之间的关系,以及它们之间的主要区别。1.什么是ECMAScript?ECMAScript是由欧洲计算机制造</div>
                    </li>
                    <li><a href="/article/1892445105034424320.htm"
                           title="DeepSeek原理介绍以及对网络安全行业的影响" target="_blank">DeepSeek原理介绍以及对网络安全行业的影响</a>
                        <span class="text-muted">AI拉呱</span>
<a class="tag" taget="_blank" href="/search/Deepseek/1.htm">Deepseek</a><a class="tag" taget="_blank" href="/search/%E4%BA%BA%E5%B7%A5%E6%99%BA%E8%83%BD/1.htm">人工智能</a>
                        <div>大家好,我是AI拉呱,一个专注于人工智领域与网络安全方面的博主,现任资深算法研究员一职,兼职硕士研究生导师;热爱机器学习和深度学习算法应用,深耕大语言模型微调、量化、私域部署。曾获多次获得AI竞赛大奖,拥有多项发明专利和学术论文。对于AI算法有自己独特见解和经验。曾辅导十几位非计算机学生转行到算法岗位就业。关注评审分享一起学习更多知识。1.DeepSeek公司介绍1.1DeepSeek是什么:wh</div>
                    </li>
                    <li><a href="/article/1892442574682124288.htm"
                           title="服务器与普通电脑有什么区别?" target="_blank">服务器与普通电脑有什么区别?</a>
                        <span class="text-muted">wayuncn</span>
<a class="tag" taget="_blank" href="/search/%E6%9C%8D%E5%8A%A1%E5%99%A8/1.htm">服务器</a><a class="tag" taget="_blank" href="/search/%E6%9C%8D%E5%8A%A1%E5%99%A8/1.htm">服务器</a><a class="tag" taget="_blank" href="/search/%E7%94%B5%E8%84%91/1.htm">电脑</a><a class="tag" taget="_blank" href="/search/%E8%BF%90%E7%BB%B4/1.htm">运维</a>
                        <div>服务器和普通电脑(通常指的是个人计算机,即PC)有众多相似之处,主要构成包含:CPU,内存,芯片,I/O总线设备,电源,机箱及操作系统软件等,鉴于使用要求不同,两者差别也很明显,区别如下:区别1、CPU处理性能不同。服务器对CPU要求很高,必须具备有很强数据处理能力,通常服务器要配置多颗CPU共同进行数据运算,普通电脑通常都配置单颗CPU,在数据处理能力就远比不上起服务器。区别2、安全性能不同。服</div>
                    </li>
                    <li><a href="/article/1892433618089865216.htm"
                           title="【系统架构设计师】系统性能之性能指标" target="_blank">【系统架构设计师】系统性能之性能指标</a>
                        <span class="text-muted">王佑辉</span>
<a class="tag" taget="_blank" href="/search/%E7%B3%BB%E7%BB%9F%E6%9E%B6%E6%9E%84%E8%AE%BE%E8%AE%A1%E5%B8%88/1.htm">系统架构设计师</a><a class="tag" taget="_blank" href="/search/%E7%B3%BB%E7%BB%9F%E6%9E%B6%E6%9E%84/1.htm">系统架构</a>
                        <div>目录1.说明2.计算机的性能指标3.路由器的性能指标4.交换机的性能指标5.网络的性能指标6.操作系统的性能指标7.数据库管理系统的性能指标8.Web服务器的性能指标9.例题9.1例题11.说明1.性能指标是软、硬件的性能指标的集成。2.在硬件中,包括计算机、各种通信交换设备、各类网络设备等;在软件中,包括操作系统、数据库、网络协议以及应用程序等。2.计算机的性能指标1.评价计算机的主要性能指标有</div>
                    </li>
                    <li><a href="/article/1892426922990825472.htm"
                           title="[附源码]计算机毕业设计基于SpringBoot的小说阅读系统" target="_blank">[附源码]计算机毕业设计基于SpringBoot的小说阅读系统</a>
                        <span class="text-muted">计算机毕设程序设计</span>
<a class="tag" taget="_blank" href="/search/spring/1.htm">spring</a><a class="tag" taget="_blank" href="/search/boot/1.htm">boot</a><a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/%E5%90%8E%E7%AB%AF/1.htm">后端</a>
                        <div>项目运行环境配置:Jdk1.8+Tomcat7.0+Mysql+HBuilderX(Webstorm也行)+Eclispe(IntelliJIDEA,Eclispe,MyEclispe,Sts都支持)。项目技术:SSM+mybatis+Maven+Vue等等组成,B/S模式+Maven管理等等。环境需要1.运行环境:最好是javajdk1.8,我们在这个平台上运行的。其他版本理论上也可以。2.ID</div>
                    </li>
                    <li><a href="/article/1892424151029837824.htm"
                           title="远程桌面的端口号是多少?" target="_blank">远程桌面的端口号是多少?</a>
                        <span class="text-muted">阿7_QuQ</span>
<a class="tag" taget="_blank" href="/search/%E7%BD%91%E7%BB%9C/1.htm">网络</a><a class="tag" taget="_blank" href="/search/windows/1.htm">windows</a><a class="tag" taget="_blank" href="/search/%E6%9C%8D%E5%8A%A1%E5%99%A8/1.htm">服务器</a>
                        <div>远程桌面(RemoteDesktop)是一种用于远程访问和控制计算机的技术,它允许用户通过网络连接到远程计算机并以图形化界面进行操作。远程桌面使用的端口号通常是3389。在Windows操作系统中,远程桌面协议(RemoteDesktopProtocol,简称RDP)默认使用3389端口。当您启用远程桌面功能并允许其他计算机通过网络连接时,远程桌面会监听3389端口,等待远程连接的请求。需要注意的</div>
                    </li>
                    <li><a href="/article/1892422259088355328.htm"
                           title="网络安全等级保护制度详解,一文掌握核心要点!_等级保护相关政策和法律法规" target="_blank">网络安全等级保护制度详解,一文掌握核心要点!_等级保护相关政策和法律法规</a>
                        <span class="text-muted">~小羊没烦恼~</span>
<a class="tag" taget="_blank" href="/search/web%E5%AE%89%E5%85%A8/1.htm">web安全</a><a class="tag" taget="_blank" href="/search/%E5%AE%89%E5%85%A8/1.htm">安全</a><a class="tag" taget="_blank" href="/search/%E7%BD%91%E7%BB%9C/1.htm">网络</a><a class="tag" taget="_blank" href="/search/%E6%9C%8D%E5%8A%A1%E5%99%A8/1.htm">服务器</a><a class="tag" taget="_blank" href="/search/%E6%95%B0%E6%8D%AE%E5%BA%93/1.htm">数据库</a>
                        <div>一、等级保护制度发展情况等级保护制度的法律依据Ø《计算机信息系统安全保护条例》(1994年GeneralOfficeoftheStateCouncil第147号令)公安部主管全国计算机信息系统安全保护工作。计算机信息系统实行安全等级保护,安全等级的划分标准和安全等级保护的具体办法,由公安部会同有关部门制定。Ø《中华人民共和国警察法》(1995,2012)人民警察履行“监督管理计算机信息系统的安全保</div>
                    </li>
                    <li><a href="/article/1892419226480734208.htm"
                           title="DeepSeek与ChatGPT:会取代搜索引擎和人工客服的人工智能革命" target="_blank">DeepSeek与ChatGPT:会取代搜索引擎和人工客服的人工智能革命</a>
                        <span class="text-muted">云边有个稻草人</span>
<a class="tag" taget="_blank" href="/search/%E7%83%AD%E9%97%A8%E6%96%87%E7%AB%A0/1.htm">热门文章</a><a class="tag" taget="_blank" href="/search/chatgpt/1.htm">chatgpt</a><a class="tag" taget="_blank" href="/search/%E6%90%9C%E7%B4%A2%E5%BC%95%E6%93%8E/1.htm">搜索引擎</a><a class="tag" taget="_blank" href="/search/%E4%BA%BA%E5%B7%A5%E6%99%BA%E8%83%BD/1.htm">人工智能</a><a class="tag" taget="_blank" href="/search/DeepSeek/1.htm">DeepSeek</a>
                        <div>云边有个稻草人-CSDN博客在众多创新技术中,DeepSeek和ChatGPT无疑是最为引人注目的。它们通过强大的搜索和对话生成能力,能够改变我们与计算机交互的方式,帮助我们高效地获取信息,增强智能服务。本文将深入探讨这两项技术如何结合使用,为用户提供更精准、更流畅的对话和搜索体验。目录一、介绍1.1什么是DeepSeek?1.2什么是ChatGPT?1.3DeepSeek与ChatGPT的结合:</div>
                    </li>
                    <li><a href="/article/1892416580906708992.htm"
                           title="事件驱动-事件驱动应用于软件开发" target="_blank">事件驱动-事件驱动应用于软件开发</a>
                        <span class="text-muted">海水天涯</span>
<a class="tag" taget="_blank" href="/search/%E4%BA%8B%E4%BB%B6%E9%A9%B1%E5%8A%A8/1.htm">事件驱动</a><a class="tag" taget="_blank" href="/search/%E9%A9%B1%E5%8A%A8%E5%BC%80%E5%8F%91/1.htm">驱动开发</a>
                        <div>一、前言1.1软件开发概述软件开发是一个涉及计算机科学、工程学、设计和项目管理等领域的广泛概念。它指的是创建、部署和维护软件应用程序或系统的整个过程。这包括从最初的构思和需求分析,到设计、编码、测试、部署,以及后续的维护和更新。在软件开发过程中,通常会遵循一定的方法论或开发模型,如瀑布模型、敏捷开发等,以确保项目能按时、按质完成。软件开发工具如集成开发环境(IDE)、版本控制系统等,也在这个过程中</div>
                    </li>
                    <li><a href="/article/1892414564209848320.htm"
                           title="如何备战软考网络工程师?" target="_blank">如何备战软考网络工程师?</a>
                        <span class="text-muted">互联网之路.</span>
<a class="tag" taget="_blank" href="/search/%E7%9F%A5%E8%AF%86%E7%82%B9/1.htm">知识点</a><a class="tag" taget="_blank" href="/search/%E7%BD%91%E7%BB%9C/1.htm">网络</a>
                        <div>互联网各领域资料分享专区(不定期更新):Sheet前言软考网络工程师属于中级资格考试,通过这个考试来获得职称或者提升自己的专业技能。软考网络工程师的考试内容和结构。考试分为上午的综合知识和下午的案例分析,可能涉及计算机网络的基础知识、网络设备配置、网络安全、网络管理等方面。实践操作对下午的案例题很重要,可能需要配置模拟器来练习。但一般没有实际设备,所以模拟器是必要的。同时,真题的重要性不可忽视,需</div>
                    </li>
                    <li><a href="/article/1892407882155094016.htm"
                           title="知识图谱的作用及其更新方式" target="_blank">知识图谱的作用及其更新方式</a>
                        <span class="text-muted">甜瓜瓜哥</span>
<a class="tag" taget="_blank" href="/search/%E9%9D%A2%E8%AF%95/1.htm">面试</a><a class="tag" taget="_blank" href="/search/%E4%BA%BA%E5%B7%A5%E6%99%BA%E8%83%BD/1.htm">人工智能</a><a class="tag" taget="_blank" href="/search/%E7%9F%A5%E8%AF%86%E5%9B%BE%E8%B0%B1/1.htm">知识图谱</a><a class="tag" taget="_blank" href="/search/%E4%BA%BA%E5%B7%A5%E6%99%BA%E8%83%BD/1.htm">人工智能</a>
                        <div>知识图谱的作用及其更新方式简介作用1.语义理解和推理2.信息检索3.推荐系统4.自然语言处理5.智能对话系统更新知识图谱的过程1.数据收集2.数据清洗和处理3.知识抽取4.知识融合5.验证和评估6.部署和应用总结简介知识图谱是一种以图形结构表示知识的方法,它包含了实体(如人物、地点、事物)以及它们之间的关系。知识图谱可以用于帮助计算机理解和处理自然语言,进行信息检索,进行推荐系统等多种应用。作用1</div>
                    </li>
                    <li><a href="/article/1892401826674831360.htm"
                           title="C++ 多线程" target="_blank">C++ 多线程</a>
                        <span class="text-muted">lly202406</span>
<a class="tag" taget="_blank" href="/search/%E5%BC%80%E5%8F%91%E8%AF%AD%E8%A8%80/1.htm">开发语言</a>
                        <div>C++多线程引言在计算机科学中,多线程是一种常用的技术,它允许一个程序同时执行多个任务。C++作为一门强大的编程语言,提供了多种多线程编程的机制。本文将详细介绍C++多线程编程的相关知识,包括多线程的概念、线程的创建与同步、互斥锁的使用等。一、多线程的概念1.1什么是多线程?多线程指的是在同一程序中,可以同时运行多个线程,每个线程都是程序的一个执行流。这些线程可以并行执行,从而提高程序的执行效率。</div>
                    </li>
                    <li><a href="/article/1892396029710495744.htm"
                           title="Linux搭建FTP服务器" target="_blank">Linux搭建FTP服务器</a>
                        <span class="text-muted">见字如晤X.</span>
<a class="tag" taget="_blank" href="/search/%E6%9C%8D%E5%8A%A1%E5%99%A8/1.htm">服务器</a><a class="tag" taget="_blank" href="/search/linux/1.htm">linux</a><a class="tag" taget="_blank" href="/search/%E8%BF%90%E7%BB%B4/1.htm">运维</a>
                        <div>FTP概述FTP服务(FileTransferProtocol服务,文件传输协议服务)是一种用于在网络上传输文件的协议。FTP服务允许用户将文件从一个计算机(本地主机)传输到另一个计算机(远程主机),或者从远程主机接收文件到本地主机。这种传输是基于客户端-服务器模式的,其中用户使用的本地计算机作为客户端,而提供文件存储和访问的远程计算机作为服务器传输连接与传输模式FTP客户端和服务器之间的连接,主</div>
                    </li>
                    <li><a href="/article/1892377744348606464.htm"
                           title="**激发创作潜能,CSDN创作挑战赛等你来战!**" target="_blank">**激发创作潜能,CSDN创作挑战赛等你来战!**</a>
                        <span class="text-muted">爱编程的Loren</span>
<a class="tag" taget="_blank" href="/search/%E6%B4%BB%E5%8A%A8%E6%96%87%E7%AB%A0/1.htm">活动文章</a><a class="tag" taget="_blank" href="/search/%E6%B4%BB%E5%8A%A8%E6%96%87%E7%AB%A0/1.htm">活动文章</a>
                        <div>  ####写作挑战赛来啦!  各位热爱写作的同学们,你们是否在寻找一个展示自己才华的平台?你们是否想要挑战自己,体验不一样的写作激情?现在,有一个绝佳的机会摆在你面前!我们特别举办一次为期14天的创作挑战赛,鼓励大家挖掘自己的创作潜能,展现自己的写作才华。让我们一起在写作的海洋中畅游,书写出属于我们的故事!  ####创作要求一览  1.**创作主题**:本次挑战赛的主题为计算机领域相关内容,欢</div>
                    </li>
                    <li><a href="/article/1892372950242357248.htm"
                           title="FastStone 10.x 注册码" target="_blank">FastStone 10.x 注册码</a>
                        <span class="text-muted">一条晓鱼</span>
<a class="tag" taget="_blank" href="/search/linux/1.htm">linux</a><a class="tag" taget="_blank" href="/search/c%2B%2B/1.htm">c++</a><a class="tag" taget="_blank" href="/search/github/1.htm">github</a><a class="tag" taget="_blank" href="/search/git/1.htm">git</a><a class="tag" taget="_blank" href="/search/windows/1.htm">windows</a>
                        <div>简介FastStoneCapture是一款经典好用的屏幕截图软件,在屏幕截图领域具有广泛的应用和众多优势。软件基本信息FastStoneCapture体积小巧,占用内存少,这使得它在运行时不会给计算机系统带来过多的负担,即使在配置较低的电脑上也能流畅运行。例如,在一些老旧的办公电脑上,FastStoneCapture可以快速启动并进行截图操作,而不会出现明显的卡顿现象。它的界面简洁干净,操作相对简</div>
                    </li>
                    <li><a href="/article/1892371689220665344.htm"
                           title="使用BLIP模型生成图像描述的可查询索引" target="_blank">使用BLIP模型生成图像描述的可查询索引</a>
                        <span class="text-muted">dgay_hua</span>
<a class="tag" taget="_blank" href="/search/python/1.htm">python</a><a class="tag" taget="_blank" href="/search/%E8%AE%A1%E7%AE%97%E6%9C%BA%E8%A7%86%E8%A7%89/1.htm">计算机视觉</a><a class="tag" taget="_blank" href="/search/%E5%BC%80%E5%8F%91%E8%AF%AD%E8%A8%80/1.htm">开发语言</a>
                        <div>在本篇文章中,我们将介绍如何使用预训练的SalesforceBLIP图像描述模型,生成一个可查询的图像描述索引。我们将使用ImageCaptionLoader来加载图像,并通过一系列步骤生成查询索引。使用示例代码进行演示,帮助读者理解和实践。技术背景介绍随着计算机视觉技术的发展,图像描述生成成为了重要的研究领域。通过对图像内容自动生成文字描述,可以大大提高对图像信息的检索和管理效率。Salesfo</div>
                    </li>
                    <li><a href="/article/1892368443945054208.htm"
                           title="为什么编程语言不能无误差的表示十进制数" target="_blank">为什么编程语言不能无误差的表示十进制数</a>
                        <span class="text-muted"></span>
<a class="tag" taget="_blank" href="/search/%E7%BC%96%E7%A8%8B/1.htm">编程</a>
                        <div>在编程中,尤其是涉及到数值计算时,十进制数的表示问题是一个常见的技术挑战。虽然我们日常生活中使用的是十进制数,但计算机内部却使用二进制来存储和处理数据。由于十进制和二进制之间存在根本性的差异,编程语言无法无误差地表示十进制数。这一问题不仅涉及到计算机的基本存储方式,还与浮点数的表示精度和计算机的内存管理机制密切相关。在实践中,这种表示误差会影响许多领域的计算,包括财务、科学计算和工程应用。本文将深</div>
                    </li>
                    <li><a href="/article/1892362230264033280.htm"
                           title="Python 基础-循环" target="_blank">Python 基础-循环</a>
                        <span class="text-muted">赔罪</span>
<a class="tag" taget="_blank" href="/search/Python/1.htm">Python</a><a class="tag" taget="_blank" href="/search/%E7%B3%BB%E7%BB%9F%E5%AD%A6%E4%B9%A0/1.htm">系统学习</a><a class="tag" taget="_blank" href="/search/python/1.htm">python</a><a class="tag" taget="_blank" href="/search/windows/1.htm">windows</a><a class="tag" taget="_blank" href="/search/%E6%9C%8D%E5%8A%A1%E5%99%A8/1.htm">服务器</a>
                        <div>目录简介breakcontinue小结简介要计算1+2+3,我们可以直接写表达式:>>>1+2+36要计算1+2+3+...+10,勉强也能写出来。但是,要计算1+2+3+...+10000,直接写表达式就不可能了。为了让计算机能计算成千上万次的重复运算,我们就需要循环语句。Python的循环有两种,一种是for...in循环,依次把list或tuple中的每个元素迭代出来,看例子:names=[</div>
                    </li>
                    <li><a href="/article/1892348487345958912.htm"
                           title="STMicroelectronics 系列:STM32F1 系列_(8).STM32F1系列的USART接口及编程" target="_blank">STMicroelectronics 系列:STM32F1 系列_(8).STM32F1系列的USART接口及编程</a>
                        <span class="text-muted">kkchenkx</span>
<a class="tag" taget="_blank" href="/search/%E5%8D%95%E7%89%87%E6%9C%BA%E5%BC%80%E5%8F%91/1.htm">单片机开发</a><a class="tag" taget="_blank" href="/search/stm32/1.htm">stm32</a><a class="tag" taget="_blank" href="/search/%E5%B5%8C%E5%85%A5%E5%BC%8F%E7%A1%AC%E4%BB%B6/1.htm">嵌入式硬件</a><a class="tag" taget="_blank" href="/search/%E5%8D%95%E7%89%87%E6%9C%BA/1.htm">单片机</a>
                        <div>STM32F1系列的USART接口及编程1.USART接口概述USART(UniversalSynchronousAsynchronousReceiverTransmitter)是一种串行通信接口,可以支持异步和同步通信模式。在STM32F1系列单片机中,USART接口用于实现与外部设备的串行数据通信,例如与其他单片机、计算机、传感器等设备进行数据交换。USART接口可以配置为多种通信模式,包括U</div>
                    </li>
                    <li><a href="/article/1892308524982136832.htm"
                           title="51单片机介绍" target="_blank">51单片机介绍</a>
                        <span class="text-muted">三日沐水</span>
<a class="tag" taget="_blank" href="/search/%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%85%A8%E5%A5%97%E5%AD%A6%E4%B9%A0%E6%95%99%E7%A8%8B/1.htm">嵌入式全套学习教程</a><a class="tag" taget="_blank" href="/search/51%E5%8D%95%E7%89%87%E6%9C%BA/1.htm">51单片机</a><a class="tag" taget="_blank" href="/search/%E5%B5%8C%E5%85%A5%E5%BC%8F%E7%A1%AC%E4%BB%B6/1.htm">嵌入式硬件</a><a class="tag" taget="_blank" href="/search/%E5%8D%95%E7%89%87%E6%9C%BA/1.htm">单片机</a>
                        <div>1、单片机基础知识1.1、单板机将CPU芯片、存储器芯片、I/O接口芯片和简单的I/O设备(小键盘、LED显示器)等装配到一块印刷电路板上,再配上监控程序(固化在ROM中),就构成了一台单板微型计算机(简称单板机)。1.2、单片机在一片集成电路芯片上集成微处理器、存储器、I/O接口电路,从而构成了单芯片微型计算机,即单片机。Intel公司推出了MCS-51系列单片机:集成8位CPU、4K字节ROM</div>
                    </li>
                    <li><a href="/article/1892307279949131776.htm"
                           title="Linux sftp 使用详解" target="_blank">Linux sftp 使用详解</a>
                        <span class="text-muted"></span>
<a class="tag" taget="_blank" href="/search/linux/1.htm">linux</a>
                        <div>简介SFTP(安全文件传输协议)是一种通过网络在计算机之间传输文件的安全方法。它是SSH协议的一部分,这意味着它在文件传输过程中提供加密通信。SFTP通常用于安全文件管理、远程文件访问和远程文件编辑。常用命令sftpuser@host:通过SFTP连接到远程服务器ls:列出当前远程目录中的文件cd:更改远程目录pwd:显示当前远程目录lcd:更改本地目录lpwd:显示当前本地目录put:将文件从本</div>
                    </li>
                                <li><a href="/article/96.htm"
                                       title="怎么样才能成为专业的程序员?" target="_blank">怎么样才能成为专业的程序员?</a>
                                    <span class="text-muted">cocos2d-x小菜</span>
<a class="tag" taget="_blank" href="/search/%E7%BC%96%E7%A8%8B/1.htm">编程</a><a class="tag" taget="_blank" href="/search/PHP/1.htm">PHP</a>
                                    <div>  
如何要想成为一名专业的程序员?仅仅会写代码是不够的。从团队合作去解决问题到版本控制,你还得具备其他关键技能的工具包。当我们询问相关的专业开发人员,那些必备的关键技能都是什么的时候,下面是我们了解到的情况。 
  
关于如何学习代码,各种声音很多,然后很多人就被误导为成为专业开发人员懂得一门编程语言就够了?!呵呵,就像其他工作一样,光会一个技能那是远远不够的。如果你想要成为</div>
                                </li>
                                <li><a href="/article/223.htm"
                                       title="java web开发 高并发处理" target="_blank">java web开发 高并发处理</a>
                                    <span class="text-muted">BreakingBad</span>
<a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/Web/1.htm">Web</a><a class="tag" taget="_blank" href="/search/%E5%B9%B6%E5%8F%91/1.htm">并发</a><a class="tag" taget="_blank" href="/search/%E5%BC%80%E5%8F%91/1.htm">开发</a><a class="tag" taget="_blank" href="/search/%E5%A4%84%E7%90%86/1.htm">处理</a><a class="tag" taget="_blank" href="/search/%E9%AB%98/1.htm">高</a>
                                    <div>java处理高并发高负载类网站中数据库的设计方法(java教程,java处理大量数据,java高负载数据) 一:高并发高负载类网站关注点之数据库 没错,首先是数据库,这是大多数应用所面临的首个SPOF。尤其是Web2.0的应用,数据库的响应是首先要解决的。 一般来说MySQL是最常用的,可能最初是一个mysql主机,当数据增加到100万以上,那么,MySQL的效能急剧下降。常用的优化措施是M-S(</div>
                                </li>
                                <li><a href="/article/350.htm"
                                       title="mysql批量更新" target="_blank">mysql批量更新</a>
                                    <span class="text-muted">ekian</span>
<a class="tag" taget="_blank" href="/search/mysql/1.htm">mysql</a>
                                    <div>mysql更新优化: 
一版的更新的话都是采用update set的方式,但是如果需要批量更新的话,只能for循环的执行更新。或者采用executeBatch的方式,执行更新。无论哪种方式,性能都不见得多好。 
三千多条的更新,需要3分多钟。 
查询了批量更新的优化,有说replace into的方式,即: 
 
 
replace into tableName(id,status) values</div>
                                </li>
                                <li><a href="/article/477.htm"
                                       title="微软BI(3)" target="_blank">微软BI(3)</a>
                                    <span class="text-muted">18289753290</span>
<a class="tag" taget="_blank" href="/search/%E5%BE%AE%E8%BD%AFBI+SSIS/1.htm">微软BI SSIS</a>
                                    <div>1) 
Q:该列违反了完整性约束错误;已获得 OLE DB 记录。源:“Microsoft SQL Server Native Client 11.0” Hresult: 0x80004005 说明:“不能将值 NULL 插入列 'FZCHID',表 'JRB_EnterpriseCredit.dbo.QYFZCH';列不允许有 Null 值。INSERT 失败。”。 
A:一般这类问题的存在是 </div>
                                </li>
                                <li><a href="/article/604.htm"
                                       title="Java中的List" target="_blank">Java中的List</a>
                                    <span class="text-muted">g21121</span>
<a class="tag" taget="_blank" href="/search/java/1.htm">java</a>
                                    <div>        List是一个有序的 collection(也称为序列)。此接口的用户可以对列表中每个元素的插入位置进行精确地控制。用户可以根据元素的整数索引(在列表中的位置)访问元素,并搜索列表中的元素。 
        与 set 不同,列表通常允许重复</div>
                                </li>
                                <li><a href="/article/731.htm"
                                       title="读书笔记" target="_blank">读书笔记</a>
                                    <span class="text-muted">永夜-极光</span>
<a class="tag" taget="_blank" href="/search/%E8%AF%BB%E4%B9%A6%E7%AC%94%E8%AE%B0/1.htm">读书笔记</a>
                                    <div>   1.  K是一家加工厂,需要采购原材料,有A,B,C,D 4家供应商,其中A给出的价格最低,性价比最高,那么假如你是这家企业的采购经理,你会如何决策? 
    
     传统决策: A:100%订单  B,C,D:0% 
  
  &nbs</div>
                                </li>
                                <li><a href="/article/858.htm"
                                       title="centos 安装 Codeblocks" target="_blank">centos 安装 Codeblocks</a>
                                    <span class="text-muted">随便小屋</span>
<a class="tag" taget="_blank" href="/search/codeblocks/1.htm">codeblocks</a>
                                    <div>1.安装gcc,需要c和c++两部分,默认安装下,CentOS不安装编译器的,在终端输入以下命令即可yum install gccyum install gcc-c++ 
  
2.安装gtk2-devel,因为默认已经安装了正式产品需要的支持库,但是没有安装开发所需要的文档.yum install gtk2* 
3. 安装wxGTK 
   yum search w</div>
                                </li>
                                <li><a href="/article/985.htm"
                                       title="23种设计模式的形象比喻" target="_blank">23种设计模式的形象比喻</a>
                                    <span class="text-muted">aijuans</span>
<a class="tag" taget="_blank" href="/search/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/1.htm">设计模式</a>
                                    <div>1、ABSTRACT FACTORY—追MM少不了请吃饭了,麦当劳的鸡翅和肯德基的鸡翅都是MM爱吃的东西,虽然口味有所不同,但不管你带MM去麦当劳或肯德基,只管向服务员说“来四个鸡翅”就行了。麦当劳和肯德基就是生产鸡翅的Factory    工厂模式:客户类和工厂类分开。消费者任何时候需要某种产品,只需向工厂请求即可。消费者无须修改就可以接纳新产品。缺点是当产品修改时,工厂类也要做相应的修改。如:</div>
                                </li>
                                <li><a href="/article/1112.htm"
                                       title="开发管理 CheckLists" target="_blank">开发管理 CheckLists</a>
                                    <span class="text-muted">aoyouzi</span>
<a class="tag" taget="_blank" href="/search/%E5%BC%80%E5%8F%91%E7%AE%A1%E7%90%86+CheckLists/1.htm">开发管理 CheckLists</a>
                                    <div>开发管理 CheckLists(23) -使项目组度过完整的生命周期 
开发管理 CheckLists(22) -组织项目资源 
开发管理 CheckLists(21) -控制项目的范围开发管理 CheckLists(20) -项目利益相关者责任开发管理 CheckLists(19) -选择合适的团队成员开发管理 CheckLists(18) -敏捷开发 Scrum Master 工作开发管理 C</div>
                                </li>
                                <li><a href="/article/1239.htm"
                                       title="js实现切换" target="_blank">js实现切换</a>
                                    <span class="text-muted">百合不是茶</span>
<a class="tag" taget="_blank" href="/search/JavaScript/1.htm">JavaScript</a><a class="tag" taget="_blank" href="/search/%E6%A0%8F%E7%9B%AE%E5%88%87%E6%8D%A2/1.htm">栏目切换</a>
                                    <div>js主要功能之一就是实现页面的特效,窗体的切换可以减少页面的大小,被门户网站大量应用思路: 
   1,先将要显示的设置为display:bisible  否则设为none
    2,设置栏目的id  ,js获取栏目的id,如果id为Null就设置为显示
    3,判断js获取的id名字;再设置是否显示
 
  
代码实现: 
  
html代码: 
  <di</div>
                                </li>
                                <li><a href="/article/1366.htm"
                                       title="周鸿祎在360新员工入职培训上的讲话" target="_blank">周鸿祎在360新员工入职培训上的讲话</a>
                                    <span class="text-muted">bijian1013</span>
<a class="tag" taget="_blank" href="/search/%E6%84%9F%E6%82%9F/1.htm">感悟</a><a class="tag" taget="_blank" href="/search/%E9%A1%B9%E7%9B%AE%E7%AE%A1%E7%90%86/1.htm">项目管理</a><a class="tag" taget="_blank" href="/search/%E4%BA%BA%E7%94%9F/1.htm">人生</a><a class="tag" taget="_blank" href="/search/%E8%81%8C%E5%9C%BA/1.htm">职场</a>
                                    <div>        这篇文章也是最近偶尔看到的,考虑到原博客发布者可能将其删除等原因,也更方便个人查找,特将原文拷贝再发布的。“学东西是为自己的,不要整天以混的姿态来跟公司博弈,就算是混,我觉得你要是能在混的时间里,收获一些别的有利于人生发展的东西,也是不错的,看你怎么把握了”,看了之后,对这句话记忆犹新。  &</div>
                                </li>
                                <li><a href="/article/1493.htm"
                                       title="前端Web开发的页面效果" target="_blank">前端Web开发的页面效果</a>
                                    <span class="text-muted">Bill_chen</span>
<a class="tag" taget="_blank" href="/search/html/1.htm">html</a><a class="tag" taget="_blank" href="/search/Web/1.htm">Web</a><a class="tag" taget="_blank" href="/search/Microsoft/1.htm">Microsoft</a>
                                    <div>1.IE6下png图片的透明显示: 
<img src="图片地址" border="0" style="Filter.Alpha(Opacity)=数值(100),style=数值(3)"/> 
或在<head></head>间加一段JS代码让透明png图片正常显示。 
 
2.<li>标</div>
                                </li>
                                <li><a href="/article/1620.htm"
                                       title="【JVM五】老年代垃圾回收:并发标记清理GC(CMS GC)" target="_blank">【JVM五】老年代垃圾回收:并发标记清理GC(CMS GC)</a>
                                    <span class="text-muted">bit1129</span>
<a class="tag" taget="_blank" href="/search/%E5%9E%83%E5%9C%BE%E5%9B%9E%E6%94%B6/1.htm">垃圾回收</a>
                                    <div>  CMS概述 
并发标记清理垃圾回收(Concurrent Mark and Sweep GC)算法的主要目标是在GC过程中,减少暂停用户线程的次数以及在不得不暂停用户线程的请夸功能,尽可能短的暂停用户线程的时间。这对于交互式应用,比如web应用来说,是非常重要的。 
  
CMS垃圾回收针对新生代和老年代采用不同的策略。相比同吞吐量垃圾回收,它要复杂的多。吞吐量垃圾回收在执</div>
                                </li>
                                <li><a href="/article/1747.htm"
                                       title="Struts2技术总结" target="_blank">Struts2技术总结</a>
                                    <span class="text-muted">白糖_</span>
<a class="tag" taget="_blank" href="/search/struts2/1.htm">struts2</a>
                                    <div>  
 
 必备jar文件 
   
 早在struts2.0.*的时候,struts2的必备jar包需要如下几个: 
commons-logging-*.jar   Apache旗下commons项目的log日志包 
freemarker-*.jar          </div>
                                </li>
                                <li><a href="/article/1874.htm"
                                       title="Jquery easyui layout应用注意事项" target="_blank">Jquery easyui layout应用注意事项</a>
                                    <span class="text-muted">bozch</span>
<a class="tag" taget="_blank" href="/search/jquery/1.htm">jquery</a><a class="tag" taget="_blank" href="/search/%E6%B5%8F%E8%A7%88%E5%99%A8/1.htm">浏览器</a><a class="tag" taget="_blank" href="/search/easyui/1.htm">easyui</a><a class="tag" taget="_blank" href="/search/layout/1.htm">layout</a>
                                    <div>在jquery easyui中提供了easyui-layout布局,他的布局比较局限,类似java中GUI的border布局。下面对其使用注意事项作简要介绍: 
     如果在现有的工程中前台界面均应用了jquery easyui,那么在布局的时候最好应用jquery eaysui的layout布局,否则在表单页面(编辑、查看、添加等等)在不同的浏览器会出</div>
                                </li>
                                <li><a href="/article/2001.htm"
                                       title="java-拷贝特殊链表:有一个特殊的链表,其中每个节点不但有指向下一个节点的指针pNext,还有一个指向链表中任意节点的指针pRand,如何拷贝这个特殊链表?" target="_blank">java-拷贝特殊链表:有一个特殊的链表,其中每个节点不但有指向下一个节点的指针pNext,还有一个指向链表中任意节点的指针pRand,如何拷贝这个特殊链表?</a>
                                    <span class="text-muted">bylijinnan</span>
<a class="tag" taget="_blank" href="/search/java/1.htm">java</a>
                                    <div>
public class CopySpecialLinkedList {

	/**
	 * 题目:有一个特殊的链表,其中每个节点不但有指向下一个节点的指针pNext,还有一个指向链表中任意节点的指针pRand,如何拷贝这个特殊链表?
拷贝pNext指针非常容易,所以题目的难点是如何拷贝pRand指针。
假设原来链表为A1 -> A2 ->... -> An,新拷贝</div>
                                </li>
                                <li><a href="/article/2128.htm"
                                       title="color" target="_blank">color</a>
                                    <span class="text-muted">Chen.H</span>
<a class="tag" taget="_blank" href="/search/JavaScript/1.htm">JavaScript</a><a class="tag" taget="_blank" href="/search/html/1.htm">html</a><a class="tag" taget="_blank" href="/search/css/1.htm">css</a>
                                    <div><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"  "http://www.w3.org/TR/html4/loose.dtd">    <HTML>    <HEAD>&nbs</div>
                                </li>
                                <li><a href="/article/2255.htm"
                                       title="[信息与战争]移动通讯与网络" target="_blank">[信息与战争]移动通讯与网络</a>
                                    <span class="text-muted">comsci</span>
<a class="tag" taget="_blank" href="/search/%E7%BD%91%E7%BB%9C/1.htm">网络</a>
                                    <div>      两个坚持:手机的电池必须可以取下来 
               光纤不能够入户,只能够到楼宇 
 
      建议大家找这本书看看:<&</div>
                                </li>
                                <li><a href="/article/2382.htm"
                                       title="oracle flashback query(闪回查询)" target="_blank">oracle flashback query(闪回查询)</a>
                                    <span class="text-muted">daizj</span>
<a class="tag" taget="_blank" href="/search/oracle/1.htm">oracle</a><a class="tag" taget="_blank" href="/search/flashback+query/1.htm">flashback query</a><a class="tag" taget="_blank" href="/search/flashback+table/1.htm">flashback table</a>
                                    <div>在Oracle 10g中,Flash back家族分为以下成员: 
Flashback Database 
Flashback Drop 
Flashback Table 
Flashback Query(分Flashback Query,Flashback Version Query,Flashback Transaction Query) 
下面介绍一下Flashback Drop 和Flas</div>
                                </li>
                                <li><a href="/article/2509.htm"
                                       title="zeus持久层DAO单元测试" target="_blank">zeus持久层DAO单元测试</a>
                                    <span class="text-muted">deng520159</span>
<a class="tag" taget="_blank" href="/search/%E5%8D%95%E5%85%83%E6%B5%8B%E8%AF%95/1.htm">单元测试</a>
                                    <div>zeus代码测试正紧张进行中,但由于工作比较忙,但速度比较慢.现在已经完成读写分离单元测试了,现在把几种情况单元测试的例子发出来,希望有人能进出意见,让它走下去. 
本文是zeus的dao单元测试: 
1.单元测试直接上代码 
  
package com.dengliang.zeus.webdemo.test;


import org.junit.Test;
import o</div>
                                </li>
                                <li><a href="/article/2636.htm"
                                       title="C语言学习三printf函数和scanf函数学习" target="_blank">C语言学习三printf函数和scanf函数学习</a>
                                    <span class="text-muted">dcj3sjt126com</span>
<a class="tag" taget="_blank" href="/search/c/1.htm">c</a><a class="tag" taget="_blank" href="/search/printf/1.htm">printf</a><a class="tag" taget="_blank" href="/search/scanf/1.htm">scanf</a><a class="tag" taget="_blank" href="/search/language/1.htm">language</a>
                                    <div>printf函数 
/*
	2013年3月10日20:42:32
	地点:北京潘家园
	功能:
	目的:
		测试%x %X %#x %#X的用法
 */

# include <stdio.h>

int main(void)
{

	printf("哈哈!\n");  // \n表示换行

	int i = 10;
	printf</div>
                                </li>
                                <li><a href="/article/2763.htm"
                                       title="那你为什么小时候不好好读书?" target="_blank">那你为什么小时候不好好读书?</a>
                                    <span class="text-muted">dcj3sjt126com</span>
<a class="tag" taget="_blank" href="/search/life/1.htm">life</a>
                                    <div>dady, 我今天捡到了十块钱, 不过我还给那个人了 
good girl! 那个人有没有和你讲thank you啊 
没有啦....他拉我的耳朵我才把钱还给他的, 他哪里会和我讲thank you 
  
爸爸, 如果地上有一张5块一张10块你拿哪一张呢.... 
当然是拿十块的咯... 
爸爸你很笨的, 你不会两张都拿 
  
爸爸为什么上个月那个人来跟你讨钱, 你告诉他没</div>
                                </li>
                                <li><a href="/article/2890.htm"
                                       title="iptables开放端口" target="_blank">iptables开放端口</a>
                                    <span class="text-muted">Fanyucai</span>
<a class="tag" taget="_blank" href="/search/linux/1.htm">linux</a><a class="tag" taget="_blank" href="/search/iptables/1.htm">iptables</a><a class="tag" taget="_blank" href="/search/%E7%AB%AF%E5%8F%A3/1.htm">端口</a>
                                    <div>1,找到配置文件 
vi /etc/sysconfig/iptables   
  
2,添加端口开放,增加一行,开放18081端口 
-A INPUT -m state --state NEW -m tcp -p tcp --dport 18081 -j ACCEPT 
  
3,保存 
ESC
:wq! 
  
4,重启服务 
service iptables </div>
                                </li>
                                <li><a href="/article/3017.htm"
                                       title="Ehcache(05)——缓存的查询" target="_blank">Ehcache(05)——缓存的查询</a>
                                    <span class="text-muted">234390216</span>
<a class="tag" taget="_blank" href="/search/%E6%8E%92%E5%BA%8F/1.htm">排序</a><a class="tag" taget="_blank" href="/search/ehcache/1.htm">ehcache</a><a class="tag" taget="_blank" href="/search/%E7%BB%9F%E8%AE%A1/1.htm">统计</a><a class="tag" taget="_blank" href="/search/query/1.htm">query</a>
                                    <div>缓存的查询 
目录 
1.    使Cache可查询 
1.1     基于Xml配置 
1.2     基于代码的配置 
2     指定可搜索的属性 
2.1     可查询属性类型 
2.2 &</div>
                                </li>
                                <li><a href="/article/3144.htm"
                                       title="通过hashset找到数组中重复的元素" target="_blank">通过hashset找到数组中重复的元素</a>
                                    <span class="text-muted">jackyrong</span>
<a class="tag" taget="_blank" href="/search/hashset/1.htm">hashset</a>
                                    <div>  如何在hashset中快速找到重复的元素呢?方法很多,下面是其中一个办法: 
 
 


 int[] array = {1,1,2,3,4,5,6,7,8,8};
         
        Set<Integer> set = new HashSet<Integer>();
         
        for(int i = 0</div>
                                </li>
                                <li><a href="/article/3271.htm"
                                       title="使用ajax和window.history.pushState无刷新改变页面内容和地址栏URL" target="_blank">使用ajax和window.history.pushState无刷新改变页面内容和地址栏URL</a>
                                    <span class="text-muted">lanrikey</span>
<a class="tag" taget="_blank" href="/search/history/1.htm">history</a>
                                    <div>后退时关闭当前页面 
<script type="text/javascript"> 
 jQuery(document).ready(function ($) { 
        if (window.history && window.history.pushState) {</div>
                                </li>
                                <li><a href="/article/3398.htm"
                                       title="应用程序的通信成本" target="_blank">应用程序的通信成本</a>
                                    <span class="text-muted">netkiller.github.com</span>
<a class="tag" taget="_blank" href="/search/%E8%99%9A%E6%8B%9F%E6%9C%BA/1.htm">虚拟机</a><a class="tag" taget="_blank" href="/search/%E5%BA%94%E7%94%A8%E6%9C%8D%E5%8A%A1%E5%99%A8/1.htm">应用服务器</a><a class="tag" taget="_blank" href="/search/%E9%99%88%E6%99%AF%E5%B3%B0/1.htm">陈景峰</a><a class="tag" taget="_blank" href="/search/netkiller/1.htm">netkiller</a><a class="tag" taget="_blank" href="/search/neo/1.htm">neo</a>
                                    <div>应用程序的通信成本  
什么是通信 
一个程序中两个以上功能相互传递信号或数据叫做通信。  
什么是成本 
这是是指时间成本与空间成本。 时间就是传递数据所花费的时间。空间是指传递过程耗费容量大小。  
都有哪些通信方式 
 
 全局变量 
 线程间通信 
 共享内存 
 共享文件 
 管道 
 Socket 
 硬件(串口,USB) 等等 
  
全局变量 
全局变量是成本最低通信方法,通过设置</div>
                                </li>
                                <li><a href="/article/3525.htm"
                                       title="一维数组与二维数组的声明与定义" target="_blank">一维数组与二维数组的声明与定义</a>
                                    <span class="text-muted">恋洁e生</span>
<a class="tag" taget="_blank" href="/search/%E4%BA%8C%E7%BB%B4%E6%95%B0%E7%BB%84/1.htm">二维数组</a><a class="tag" taget="_blank" href="/search/%E4%B8%80%E7%BB%B4%E6%95%B0%E7%BB%84/1.htm">一维数组</a><a class="tag" taget="_blank" href="/search/%E5%AE%9A%E4%B9%89/1.htm">定义</a><a class="tag" taget="_blank" href="/search/%E5%A3%B0%E6%98%8E/1.htm">声明</a><a class="tag" taget="_blank" href="/search/%E5%88%9D%E5%A7%8B%E5%8C%96/1.htm">初始化</a>
                                    <div>/**  *   */ package test20111005; /**  * @author FlyingFire  * @date:2011-11-18 上午04:33:36  * @author :代码整理  * @introduce :一维数组与二维数组的初始化  *summary:  */ public c</div>
                                </li>
                                <li><a href="/article/3652.htm"
                                       title="Spring Mybatis独立事务配置" target="_blank">Spring Mybatis独立事务配置</a>
                                    <span class="text-muted">toknowme</span>
<a class="tag" taget="_blank" href="/search/mybatis/1.htm">mybatis</a>
                                    <div>在项目中有很多地方会使用到独立事务,下面以获取主键为例      
(1)修改配置文件spring-mybatis.xml    <!-- 开启事务支持 -->    <tx:annotation-driven transaction-manager="transactionManager" />       &n</div>
                                </li>
                                <li><a href="/article/3779.htm"
                                       title="更新Anadroid SDK Tooks之后,Eclipse提示No update were found" target="_blank">更新Anadroid SDK Tooks之后,Eclipse提示No update were found</a>
                                    <span class="text-muted">xp9802</span>
<a class="tag" taget="_blank" href="/search/eclipse/1.htm">eclipse</a>
                                    <div>使用Android SDK Manager 更新了Anadroid SDK Tooks 之后, 
打开eclipse提示 This Android SDK requires Android Developer Toolkit version 23.0.0 or above, 点击Check for Updates  
检测一会后提示 No update were found  </div>
                                </li>
                </ul>
            </div>
        </div>
    </div>

<div>
    <div class="container">
        <div class="indexes">
            <strong>按字母分类:</strong>
            <a href="/tags/A/1.htm" target="_blank">A</a><a href="/tags/B/1.htm" target="_blank">B</a><a href="/tags/C/1.htm" target="_blank">C</a><a
                href="/tags/D/1.htm" target="_blank">D</a><a href="/tags/E/1.htm" target="_blank">E</a><a href="/tags/F/1.htm" target="_blank">F</a><a
                href="/tags/G/1.htm" target="_blank">G</a><a href="/tags/H/1.htm" target="_blank">H</a><a href="/tags/I/1.htm" target="_blank">I</a><a
                href="/tags/J/1.htm" target="_blank">J</a><a href="/tags/K/1.htm" target="_blank">K</a><a href="/tags/L/1.htm" target="_blank">L</a><a
                href="/tags/M/1.htm" target="_blank">M</a><a href="/tags/N/1.htm" target="_blank">N</a><a href="/tags/O/1.htm" target="_blank">O</a><a
                href="/tags/P/1.htm" target="_blank">P</a><a href="/tags/Q/1.htm" target="_blank">Q</a><a href="/tags/R/1.htm" target="_blank">R</a><a
                href="/tags/S/1.htm" target="_blank">S</a><a href="/tags/T/1.htm" target="_blank">T</a><a href="/tags/U/1.htm" target="_blank">U</a><a
                href="/tags/V/1.htm" target="_blank">V</a><a href="/tags/W/1.htm" target="_blank">W</a><a href="/tags/X/1.htm" target="_blank">X</a><a
                href="/tags/Y/1.htm" target="_blank">Y</a><a href="/tags/Z/1.htm" target="_blank">Z</a><a href="/tags/0/1.htm" target="_blank">其他</a>
        </div>
    </div>
</div>
<footer id="footer" class="mb30 mt30">
    <div class="container">
        <div class="footBglm">
            <a target="_blank" href="/">首页</a> -
            <a target="_blank" href="/custom/about.htm">关于我们</a> -
            <a target="_blank" href="/search/Java/1.htm">站内搜索</a> -
            <a target="_blank" href="/sitemap.txt">Sitemap</a> -
            <a target="_blank" href="/custom/delete.htm">侵权投诉</a>
        </div>
        <div class="copyright">版权所有 IT知识库 CopyRight © 2000-2050 E-COM-NET.COM , All Rights Reserved.
<!--            <a href="https://beian.miit.gov.cn/" rel="nofollow" target="_blank">京ICP备09083238号</a><br>-->
        </div>
    </div>
</footer>
<!-- 代码高亮 -->
<script type="text/javascript" src="/static/syntaxhighlighter/scripts/shCore.js"></script>
<script type="text/javascript" src="/static/syntaxhighlighter/scripts/shLegacy.js"></script>
<script type="text/javascript" src="/static/syntaxhighlighter/scripts/shAutoloader.js"></script>
<link type="text/css" rel="stylesheet" href="/static/syntaxhighlighter/styles/shCoreDefault.css"/>
<script type="text/javascript" src="/static/syntaxhighlighter/src/my_start_1.js"></script>





</body>

</html>