h5新特性之手把手教你canvas 2d图形绘制(未完,待续...)

1,026 阅读14分钟

前言:

说到canvas,对于前端工程师来说并不陌生,但真正会的并没有几个,因为一般情况下用的会很少。但如果真正用到就会第一时间去百度又要一个一个代码试半天,费时又费力。此文抱着学习的态度带你去探究canvas的2d图形绘制奥义,带你去领略它的神奇之处。

绘制斜线:

  1. html部分:
    <canvas id="canvas" width="500" height="500">您的浏览器不支持 HTML5 canvas 标签。</canvas>

注:请注意宽度和高度是没有单位的而且是内联的,如果通过style设置css并设置px单位会出现未知错误。

  1. css部分:
    body{
		width: 100vw;
		height: 100vh;
		display: flex;
	}
	#canvas{
		border: 1px solid #333;
		margin: auto;
	}
  1. js部分:
   window.onload = function() {
		var canvas = document.getElementById('canvas');//获取dom节点
		//console.log(canvas);
		var ctx=canvas.getContext("2d");//绘制2d图形

		ctx.moveTo(100,100);//定义起点坐标
		ctx.lineTo(400,400);//定义终点坐标 

		ctx.stroke();//执行绘制函数
	} 
  1. 效果展示:
    image

斜线颜色和宽度设置:

  1. html部分:
    <canvas id="canvas" width="500" height="500">您的浏览器不支持 HTML5 canvas 标签。</canvas>
  1. css部分:
    body{
		width: 100vw;
		height: 100vh;
		display: flex;
	}
	#canvas{
		border: 1px solid #333;
		margin: auto;
	}
  1. js部分:
    window.onload = function() {
		var canvas = document.getElementById('canvas');//获取dom节点
		//console.log(canvas);
		var ctx=canvas.getContext("2d");//绘制2d图形

		ctx.moveTo(100,100);//定义起点坐标
		ctx.lineTo(400,400);//定义终点坐标 
		ctx.lineWidth = 5;//线条宽度
		ctx.strokeStyle = '#058';//线条颜色

		ctx.stroke();//执行绘制函数
	}
  1. 效果展示:
    image

折线绘制:

前言:HTML部分和css部分不会做更改,后续会直接在前面的画布中作图,所以后续只会写js代码

  1. js部分:
    window.onload = function() {
		var canvas = document.getElementById('canvas');//获取dom节点
		//console.log(canvas);
		var ctx=canvas.getContext("2d");//绘制2d图形

		ctx.moveTo(100,100);//定义起点坐标
		ctx.lineTo(400,400);//定义终点坐标
		ctx.lineTo(100,400);//定义终点坐标  

		ctx.stroke();//执行绘制函数
	}
  1. 效果展示:
    image

不封闭的箭头:

  1. js部分:
    window.onload = function() {
		var canvas = document.getElementById('canvas');//获取dom节点
		//console.log(canvas);
		var ctx=canvas.getContext("2d");//绘制2d图形

		ctx.moveTo(200,200);//定义起点坐标
		ctx.lineTo(300,200);//定义终点坐标
		ctx.lineTo(300,150);//定义终点坐标
		ctx.lineTo(350,220);//定义终点坐标
		ctx.lineTo(300,290);//定义终点坐标
		ctx.lineTo(300,240);//定义终点坐标
		ctx.lineTo(200,240);//定义终点坐标

		ctx.stroke();//执行绘制函数
	}
  1. 效果展示:
    image

3个箭头:

  1. js部分:
	window.onload = function() {
		var canvas = document.getElementById('canvas');//获取dom节点
		//console.log(canvas);
		var ctx=canvas.getContext("2d");//绘制2d图形

		ctx.moveTo(100,150);//定义起点坐标
		ctx.lineTo(200,250);//定义终点坐标
		ctx.lineTo(100,350);//定义终点坐标

		ctx.moveTo(150,150);//定义起点坐标
		ctx.lineTo(250,250);//定义终点坐标
		ctx.lineTo(150,350);//定义终点坐标

		ctx.moveTo(200,150);//定义起点坐标
		ctx.lineTo(300,250);//定义终点坐标
		ctx.lineTo(200,350);//定义终点坐标

		ctx.stroke();//执行绘制函数
	}
  1. 效果展示:
    image

绘制不同颜色的3个箭头:

  1. js部分:
	window.onload = function() {
		var canvas = document.getElementById('canvas');//获取dom节点
		//console.log(canvas);
		var ctx=canvas.getContext("2d");//绘制2d图形
		ctx.lineWidth = 5;//线条宽度

		ctx.beginPath();//指定第一条路径
		ctx.moveTo(100,150);//定义起点坐标
		ctx.lineTo(200,250);//定义终点坐标
		ctx.lineTo(100,350);//定义终点坐标
		ctx.strokeStyle = 'red';//线条颜色
		ctx.stroke();//执行绘制函数

		ctx.beginPath();//指定第二条路径
		ctx.moveTo(150,150);//定义起点坐标
		ctx.lineTo(250,250);//定义终点坐标
		ctx.lineTo(150,350);//定义终点坐标
		ctx.strokeStyle = 'green';//线条颜色
		ctx.stroke();//执行绘制函数

		ctx.beginPath();//指定第三条路径
		ctx.moveTo(200,150);//定义起点坐标
		ctx.lineTo(300,250);//定义终点坐标
		ctx.lineTo(200,350);//定义终点坐标
		ctx.strokeStyle = 'blue';//线条颜色
		ctx.stroke();//执行绘制函数
	}
  1. 效果展示:
    image

带填充色的封闭的箭头:

  1. js部分:
    window.onload = function() {
		var canvas = document.getElementById('canvas');//获取dom节点
		//console.log(canvas);
		var ctx=canvas.getContext("2d");//绘制2d图形

		ctx.lineWidth = 2;//线条宽度
		ctx.strokeStyle = '#058';//线条颜色

		ctx.beginPath();//指定路径
		ctx.moveTo(200,200);//定义起点坐标
		ctx.lineTo(300,200);//定义终点坐标
		ctx.lineTo(300,150);//定义终点坐标
		ctx.lineTo(350,220);//定义终点坐标
		ctx.lineTo(300,290);//定义终点坐标
		ctx.lineTo(300,240);//定义终点坐标
		ctx.lineTo(200,240);//定义终点坐标
		ctx.closePath();//封闭路径

		ctx.fillStyle = 'yellow';//设置封闭图形的填充颜色
		ctx.fill();//填充颜色
		
		ctx.stroke();//执行绘制函数
	}

注:如果绘制路径不在ctx.beginPath()和ctx.closePath()中间,会出现一个几像素的缺口,只有在线条足够粗的时候才能看见。

  1. 效果展示:
    image

矩形绘制函数:

  1. js部分:
	window.onload = function() {
		var canvas = document.getElementById('canvas');//获取dom节点
		//console.log(canvas);
		var ctx=canvas.getContext("2d");//绘制2d图形

		//绘制矩形的绘制函数:
		function drawRectangle(ctx,x=0,y=0,width=100,height=100,borderW=1,borderC='#333',bgC='yellow') {
			//此函数我用es6语法加了默认参数最简单的调用就是传个绘制环境就好了drawRectangle(ctx);
			/*参数说明:ctx绘制环境;x,y起点坐标;width,height矩形的宽高;borderW,borderC边框宽度及颜色;bgC填充色。*/

			ctx.beginPath();//指定路径
			ctx.moveTo(x,y);//定义起点坐标
			ctx.lineTo(x+width,y);//定义终点坐标
			ctx.lineTo(x+width,y+height);//定义终点坐标
			ctx.lineTo(x,y+height);//定义终点坐标
			ctx.closePath();//封闭路径

			ctx.lineWidth = borderW;//线条宽度
			ctx.strokeStyle = borderC;//线条颜色
			ctx.fillStyle = bgC;//设置封闭图形的填充颜色

			ctx.fill();//填充颜色
			ctx.stroke();//执行绘制函数
		}
		drawRectangle(ctx,250,250);//传参绘制
	}
  1. 效果展示:
    image

用自带api创建矩形绘制函数:

  1. js部分:
    window.onload = function() {
		var canvas = document.getElementById('canvas');//获取dom节点
		//console.log(canvas);
		var ctx=canvas.getContext("2d");//绘制2d图形

		//绘制矩形的绘制函数:
		function drawRectangle(ctx,x=0,y=0,width=100,height=100,borderW=1,borderC='#333',bgC='yellow') {
			//此函数我用es6语法加了默认参数最简单的调用就是传个绘制环境就好了drawRectangle(ctx);
			/*参数说明:ctx绘制环境;x,y起点坐标;width,height矩形的宽高;borderW,borderC边框宽度及颜色;bgC填充色。*/

			ctx.lineWidth = borderW;//线条宽度
			ctx.strokeStyle = borderC;//线条颜色
			ctx.fillStyle = bgC;//设置封闭图形的填充颜色

			ctx.fillRect(x,y,width,height);
			ctx.strokeRect(x,y,width,height);

		}
		drawRectangle(ctx);//传参绘制
	}
  1. 效果展示:
    image

重叠透明的矩形:

  1. js部分:
	window.onload = function() {
		var canvas = document.getElementById('canvas');//获取dom节点
		//console.log(canvas);
		var ctx=canvas.getContext("2d");//绘制2d图形

		//绘制矩形的绘制函数:
		function drawRectangle(ctx,x=0,y=0,width=100,height=100,borderW=1,borderC='#333',bgC='yellow') {
			//此函数我用es6语法加了默认参数最简单的调用就是传个绘制环境就好了drawRectangle(ctx);
			/*参数说明:ctx绘制环境;x,y起点坐标;width,height矩形的宽高;borderW,borderC边框宽度及颜色;bgC填充色。*/

			ctx.lineWidth = borderW;//线条宽度
			ctx.strokeStyle = borderC;//线条颜色
			ctx.fillStyle = bgC;//设置封闭图形的填充颜色

			ctx.fillRect(x,y,width,height);
			ctx.strokeRect(x,y,width,height);

		}
		drawRectangle(ctx);//传参绘制
		drawRectangle(ctx,50,50,100,100,1,'#333','rgba(0,0,0,0.1)');//传参绘制
	}
  1. 效果展示:
    image

不同顶端形状的线条:

此属性只用于线条的开始处和结尾处

  1. js部分:
    window.onload = function() {
		var canvas = document.getElementById('canvas');//获取dom节点
		//console.log(canvas);
		var ctx=canvas.getContext("2d");//绘制2d图形

		ctx.lineWidth = 50;//线条宽度
		ctx.strokeStyle = '#058';//线条颜色

		ctx.beginPath();//指定路径
		ctx.moveTo(100,100);//定义起点坐标
		ctx.lineTo(400,100);//定义终点坐标
		ctx.lineCap = 'butt'; //默认
		ctx.stroke();//执行绘制函数

		ctx.beginPath();//指定路径
		ctx.moveTo(100,250);//定义起点坐标
		ctx.lineTo(400,250);//定义终点坐标
		ctx.lineCap = 'round'; //圆头
		ctx.stroke();//执行绘制函数

		ctx.beginPath();//指定路径
		ctx.moveTo(100,400);//定义起点坐标
		ctx.lineTo(400,400);//定义终点坐标
		ctx.lineCap = 'square'; //方头
		ctx.stroke();//执行绘制函数
	}
  1. 效果展示:
    image

画一个五角星:

画五角星之前先给大家复习一下数学知识,否则此例数学不好会看不懂:

  1. 图例1:

image
2. 图解

deg为三角形的度数
正弦:sin(deg) = y(对边)/r(斜边)
余弦:cos(deg) = x(领边)/r(斜边)
  1. 图例2:
    image
  2. 图解:
//大圆五角星顶点度数18的由来:
90-360/5=18
释义:大圆以供360度,大圆上一共5个点平均每个点相差72度,90度的点减去72则为第一个点的度数
//18度点x长度:
x=cos18*R //cos(deg) = x(领边)/r(斜边)
//18度点y长度:
y=-sin18*R //sin(deg) = y(对边)/r(斜边)
//小圆五角星顶点度数54的由来:
270+72*2-360=54
释义:小圆最底部点为270度,往右推2个点为第一个小圆的顶点,每个点相差72度,加起来之后减去360即为第一个点的度数
//54度点x长度:
x=cos54*r //cos(deg) = x(领边)/r(斜边)
//54度点y长度:
y=-sin54*r //sin(deg) = y(对边)/r(斜边)
  1. 具体代码:

前言:请注意js的sin和cos都是弧度制,必须转化为弧度制计算:弧度 = 度数/180*PI

    window.onload = function() {
		var canvas = document.getElementById('canvas');//获取dom节点
		//console.log(canvas);
		var ctx=canvas.getContext("2d");//绘制2d图形

		ctx.lineWidth = 5;//线条宽度
		ctx.strokeStyle = '#058';//线条颜色

		ctx.beginPath();//指定路径
		for (var i = 0; i < 5; i++) {
			ctx.lineTo(Math.cos((18+i*72)/180*Math.PI)*200+250,-Math.sin((18+i*72)/180*Math.PI)*200+250);//定义终点坐标
			ctx.lineTo(Math.cos((54+i*72)/180*Math.PI)*100+250,-Math.sin((54+i*72)/180*Math.PI)*100+250);//定义终点坐标
		}
		ctx.closePath();//封闭路径
		ctx.stroke();//执行绘制函数
	}
  1. 提升代码复用性:
    window.onload = function() {
		var canvas = document.getElementById('canvas');//获取dom节点
		//console.log(canvas);
		var ctx=canvas.getContext("2d");//绘制2d图形

		ctx.lineWidth = 5;//线条宽度
		ctx.strokeStyle = '#058';//线条颜色
		drawStar(ctx,100,200,250,250);

		function drawStar(ctx,r,R,x,y){
			ctx.beginPath();//指定路径
			for (var i = 0; i < 5; i++) {
				ctx.lineTo(Math.cos((18+i*72)/180*Math.PI)*R+x,-Math.sin((18+i*72)/180*Math.PI)*R+y);//定义终点坐标
				ctx.lineTo(Math.cos((54+i*72)/180*Math.PI)*r+x,-Math.sin((54+i*72)/180*Math.PI)*r+y);//定义终点坐标
			}
			ctx.closePath();//封闭路径
			ctx.stroke();//执行绘制函数
		}
	}
  1. 带旋转参数的五角星:
    //函数封装
		function drawStar(ctx,r,R,x,y,rot){
			//rot为旋转,x、y为偏移量,r为小圆的五角星坐标,R为大圆的五角星坐标
			ctx.beginPath();//指定路径
			for (var i = 0; i < 5; i++) {
				ctx.lineTo(Math.cos((18+i*72-rot)/180*Math.PI)*R+x,-Math.sin((18+i*72-rot)/180*Math.PI)*R+y);//定义终点坐标
				ctx.lineTo(Math.cos((54+i*72-rot)/180*Math.PI)*r+x,-Math.sin((54+i*72-rot)/180*Math.PI)*r+y);//定义终点坐标
			}
			ctx.closePath();//封闭路径
			ctx.stroke();//执行绘制函数
		}
  1. 效果展示:
    image

线条的连接:

1.js部分:

    window.onload = function() {
		var canvas = document.getElementById('canvas');//获取dom节点
		//console.log(canvas);
		var ctx=canvas.getContext("2d");//绘制2d图形

		ctx.lineWidth = 5;//线条宽度
		ctx.strokeStyle = '#058';//线条颜色
		// ctx.lineJoin = 'bevel';//斜接
		ctx.lineJoin = 'round';//圆角
		drawStar(ctx,60,200,250,250);

		//函数封装
		function drawStar(ctx,r,R,x,y,rot=0){
			//rot为旋转,x、y为偏移量,r为小圆的五角星坐标,R为大圆的五角星坐标
			ctx.beginPath();//指定路径
			for (var i = 0; i < 5; i++) {
				ctx.lineTo(Math.cos((18+i*72-rot)/180*Math.PI)*R+x,-Math.sin((18+i*72-rot)/180*Math.PI)*R+y);//定义终点坐标
				ctx.lineTo(Math.cos((54+i*72-rot)/180*Math.PI)*r+x,-Math.sin((54+i*72-rot)/180*Math.PI)*r+y);//定义终点坐标
			}
			ctx.closePath();//封闭路径
			ctx.stroke();//执行绘制函数
		}
	}
  1. 效果示例:
    image

画一片星空

前言:请将canvas的背景颜色设置为#000

  1. js部分:
	window.onload = function() {
		var canvas = document.getElementById('canvas');//获取dom节点
		//console.log(canvas);
		var ctx=canvas.getContext("2d");//绘制2d图形

		ctx.lineWidth = 1;//线条宽度
		ctx.strokeStyle = '#333';//线条颜色
		// ctx.lineJoin = 'bevel';//斜接
		ctx.lineJoin = 'round';//圆角
		for(var i=0;i<200;i++){
			var R = Math.random()*10+10;
			var r = R/2.0;
			var x = Math.random()*canvas.width;
			var y = Math.random()*canvas.height;
			var rot = Math.random()*360;
			drawStar(ctx,r,R,x,y,rot);
		}
		//函数封装
		function drawStar(ctx,r,R,x,y,rot=0){
			//rot为旋转,x、y为偏移量,r为小圆的五角星坐标,R为大圆的五角星坐标
			ctx.beginPath();//指定路径
			for (var i = 0; i < 5; i++) {
				ctx.lineTo(Math.cos((18+i*72-rot)/180*Math.PI)*R+x,-Math.sin((18+i*72-rot)/180*Math.PI)*R+y);//定义终点坐标
				ctx.lineTo(Math.cos((54+i*72-rot)/180*Math.PI)*r+x,-Math.sin((54+i*72-rot)/180*Math.PI)*r+y);//定义终点坐标
			}
			ctx.fillStyle = 'yellow';//设置封闭图形的填充颜色
			ctx.fill();//填充颜色
			ctx.closePath();//封闭路径
			ctx.stroke();//执行绘制函数
		}
	}
  1. 效果展示:

位置偏移后的bug:

偏移量是进行叠加的,在默认情况下: 1.js部分:

    window.onload = function() {
		var canvas = document.getElementById('canvas');//获取dom节点
		//console.log(canvas);
		var ctx=canvas.getContext("2d");//绘制2d图形

		//绘制矩形的绘制函数:
		function drawRectangle(ctx,x=0,y=0,width=100,height=100,borderW=1,borderC='#333',bgC='yellow') {
			//此函数我用es6语法加了默认参数最简单的调用就是传个绘制环境就好了drawRectangle(ctx);
			/*参数说明:ctx绘制环境;x,y起点坐标;width,height矩形的宽高;borderW,borderC边框宽度及颜色;bgC填充色。*/

			ctx.lineWidth = borderW;//线条宽度
			ctx.strokeStyle = borderC;//线条颜色
			ctx.fillStyle = bgC;//设置封闭图形的填充颜色


			ctx.translate(x,y);//图形位置偏移
			ctx.fillRect(0,0,width,height);
			ctx.strokeRect(0,0,width,height);

		}
		drawRectangle(ctx,100,100);//传参绘制
		drawRectangle(ctx,100,100,100,100,1,'#333','green');//传参绘制
	}
  1. 效果展示:

解决偏移量叠加的bug:

1.js部分:

    window.onload = function() {
		var canvas = document.getElementById('canvas');//获取dom节点
		//console.log(canvas);
		var ctx=canvas.getContext("2d");//绘制2d图形

		//绘制矩形的绘制函数:
		function drawRectangle(ctx,x=0,y=0,width=100,height=100,borderW=1,borderC='#333',bgC='yellow') {
			//此函数我用es6语法加了默认参数最简单的调用就是传个绘制环境就好了drawRectangle(ctx);
			/*参数说明:ctx绘制环境;x,y起点坐标;width,height矩形的宽高;borderW,borderC边框宽度及颜色;bgC填充色。*/

			ctx.save();//保存当前绘制状态
			ctx.lineWidth = borderW;//线条宽度
			ctx.strokeStyle = borderC;//线条颜色
			ctx.fillStyle = bgC;//设置封闭图形的填充颜色


			ctx.translate(x,y);//图形位置偏移
			ctx.fillRect(0,0,width,height);//绘制填充的形状
			ctx.strokeRect(0,0,width,height);//绘制边框的形状
			ctx.restore();//返回所有状态

		}
		drawRectangle(ctx,100,100);//传参绘制
		drawRectangle(ctx,100,100,50,50,1,'#333','green');//传参绘制
	}
  1. 效果展示:

五角星通过图形变换旋转和偏移

使用缩放时请将图形的外边框设置去掉,否则图形的外边框也会随着放大

  1. js部分:
    window.onload = function() {
		var canvas = document.getElementById('canvas');//获取dom节点
		//console.log(canvas);
		var ctx=canvas.getContext("2d");//绘制2d图形

		for(var i=0;i<200;i++){
			var R = Math.random()*10+10;
			var x = Math.random()*canvas.width;
			var y = Math.random()*canvas.height;
			var rot = Math.random()*360;
			drawStar(ctx,R,x,y,rot);
		}
		//执行具体的绘制参数:
		function drawStar(ctx,R,x,y,rot){
			ctx.save();//保存当前绘制状态
			ctx.translate(x,y);//移动图形的位置坐标
			ctx.rotate(rot/180*Math.PI);//旋转
			ctx.scale(0.5,0.5);//缩放
			ctx.fillStyle = 'yellow';//设置封闭图形的填充颜色
			// ctx.lineWidth = 1;//线条宽度
			// ctx.strokeStyle = '#333';//线条颜色
			// ctx.lineJoin = 'bevel';//斜接
			// ctx.lineJoin = 'round';//圆角

			starPath(ctx,R);//绘制
			ctx.fill();//填充颜色
			ctx.stroke();//执行绘制函数

			ctx.restore();//返回所有绘制状态
		}
		//封装五角星的绘制路径
		function starPath(ctx,R){
			//rot为旋转,x、y为偏移量,r为小圆的五角星坐标,R为大圆的五角星坐标
			ctx.beginPath();//指定路径
			for (var i = 0; i < 5; i++) {
				ctx.lineTo(Math.cos((18+i*72)/180*Math.PI)*R,-Math.sin((18+i*72)/180*Math.PI)*R);//定义终点坐标
				ctx.lineTo(Math.cos((54+i*72)/180*Math.PI)*R*0.5,-Math.sin((54+i*72)/180*Math.PI)*R*0.5);//定义终点坐标
			}
			ctx.closePath();//封闭路径
		}
	}
  1. 效果展示:

变换矩阵

transform变换矩阵如果十多个的话会产生级联,这个时候只需要调用setTransform,这个时候会先将其设置成最初无变化的单位矩阵,然后将单位矩阵进行变换

  1. js部分:
	window.onload = function() {
		var canvas = document.getElementById('canvas');//获取dom节点
		//console.log(canvas);
		var ctx=canvas.getContext("2d");//绘制2d图形

		for(var i=0;i<200;i++){
			var R = Math.random()*10+10;
			var x = Math.random()*canvas.width;
			var y = Math.random()*canvas.height;
			var rot = Math.random()*360;
			drawStar(ctx,R,x,y,rot);
		}
		//执行具体的绘制参数:
		function drawStar(ctx,R,x,y,rot){
			ctx.save();//保存当前绘制状态
			//transform(a,b,c,d,e,f);
			// a水平缩放[1],b水平倾斜[0],c垂直倾斜[0],d垂直缩放[1],e水平位移[0],f垂直位移[0],[]中括号中为默认值
			ctx.rotate(rot/180*Math.PI);//旋转
			ctx.transform(0.5,0,0,0.5,x,y);
			ctx.fillStyle = 'yellow';//设置封闭图形的填充颜色
			// ctx.lineWidth = 1;//线条宽度
			// ctx.strokeStyle = '#333';//线条颜色
			// ctx.lineJoin = 'bevel';//斜接
			// ctx.lineJoin = 'round';//圆角

			starPath(ctx,R);//绘制
			ctx.fill();//填充颜色
			ctx.stroke();//执行绘制函数

			ctx.restore();//返回所有绘制状态
		}
		//封装五角星的绘制路径
		function starPath(ctx,R){
			//rot为旋转,x、y为偏移量,r为小圆的五角星坐标,R为大圆的五角星坐标
			ctx.beginPath();//指定路径
			for (var i = 0; i < 5; i++) {
				ctx.lineTo(Math.cos((18+i*72)/180*Math.PI)*R,-Math.sin((18+i*72)/180*Math.PI)*R);//定义终点坐标
				ctx.lineTo(Math.cos((54+i*72)/180*Math.PI)*R*0.5,-Math.sin((54+i*72)/180*Math.PI)*R*0.5);//定义终点坐标
			}
			ctx.closePath();//封闭路径
		}
	}
  1. 效果展示:

参考文献:

  1. www.runoob.com/w3cnote/htm…

后记:

此篇文章,由于本人最近比较忙没有写完,后续有空了会继续完成的,如果可以的话点个赞,谢谢!