用JavaScript实现网红太空人表盘(绝对详细、绝对原创),附源码下载

  • Post author:
  • Post category:java


引言:网上最近太空人表盘很火,之前看到有个兄弟用svg写的,但是我也不会这个啊,我就琢磨着用canvas写了一个,效果感觉还不错,拿出来大家唠唠!

效果图:

思路



  1. 分两个画布来绘制,画布1用来放置不动的东西(背景、表盘、文字信息);



  2. 画布2用来绘制太空人的转动和时间的更新(经常要重新绘制);



  3. 太空人的转动的话就是用很多图片来切换,达到转动的效果。


绘制表盘

圆形构造函数

//构造函数
	 function Circle(o){
		this.x=0,//圆心X坐标
		this.y=0,//圆心Y坐标
		this.r=0,//半径
		this.startAngle=0,//开始角度
		this.endAngle=0,//结束角度
		this.anticlockwise=false;//顺时针,逆时针方向指定
		this.stroke=false;//是否描边
		this.fill=false;//是否填充
		this.scaleX=1;//缩放X比例
		this.scaleY=1;//缩放Y比例
		this.rotate=0;
		
		this.init(o);
	 }
	 //初始化
	 Circle.prototype.init=function(o){
		for(var key in o){
			this[key]=o[key];
		}
	}
		 //绘制
	 Circle.prototype.render=function(context){
		var ctx=context;//获取上下文
		ctx.save();
		ctx.beginPath();
		ctx.translate(this.x,this.y);
		if(this.fill){
			ctx.moveTo(0,0);
		}
		//ctx.moveTo(this.x,this.y);
		ctx.scale(this.scaleX,this.scaleY);//设定缩放
		ctx.arc(0,0,this.r,this.startAngle,this.endAngle);//画圆
		if(this.lineWidth){//线宽
			ctx.lineWidth=this.lineWidth;
		}
		if(this.fill){//是否填充
			this.fillStyle?(ctx.fillStyle=this.fillStyle):null;
			ctx.fill();
		}
		if(this.stroke){//是否描边
			this.strokeStyle?(ctx.strokeStyle=this.strokeStyle):null;
			ctx.stroke();
		}	
		ctx.restore();
	 	
	 	return this;
	 }	

绘制代码

//绘制表盘
	SpaceMan.prototype.drawClock=function(){
		  var x=y=0,cilcle;
		  x=this.w/2;y=this.h/2;
		  
		  //绘制外面的大圆
		  cilcle = new Circle({
		 	x:x,//圆心X坐标
			y:y,//圆心X坐标
			r:250,//半径
			startAngle:0,//开始角度
			endAngle:2*Math.PI,//结束角度
			lineWidth:2,
			fill:true,
			fillStyle:'#444444'
		 });
		 this.renderArr.push(cilcle);
		 //绘制第2个圆
		 cilcle = new Circle({
		 	x:x,//圆心X坐标
			y:y,//圆心X坐标
			r:220,//半径
			startAngle:0,//开始角度
			endAngle:2*Math.PI,//结束角度
			lineWidth:2,
			fill:true,
			fillStyle:'#DFE6F0'
		 });
		 this.renderArr.push(cilcle);
		 
	}

此时页面的效果:


绘制分隔线


构造函数

//直线的构造
	function Line(o){
		this.x=0,//x坐标
		this.y=0,//y坐标
		this.startX=0,//开始点x位置
		this.startY=0, //开始点y位置
		this.endX=0,//结束点x位置
		this.endY=0;//结束点y位置
		this.thin=false;//设置变细系数
		
		this.init(o);
	}
	Line.prototype.init=function(o){
		for(var key in o){
			this[key]=o[key];
		}
	}
	Line.prototype.render=function(ctx){
		innerRender(this);
		
		function innerRender(obj){
			ctx.save()
			ctx.beginPath();
			ctx.translate(obj.x,obj.y);
			if(obj.thin){
				ctx.translate(0.5,0.5);
			}
			if(obj.lineWidth){//设定线宽
				ctx.lineWidth=obj.lineWidth;
			}
			if(obj.strokeStyle){
				ctx.strokeStyle=obj.strokeStyle;
			}
			//划线
		  	ctx.moveTo(obj.startX, obj.startY);
		  	ctx.lineTo(obj.endX, obj.endY);
		  	ctx.stroke();
		  	ctx.restore();
		}
	  	
	  	return this;
	}

绘制代码

//分隔线的 绘制
	SpaceMan.prototype.drawClockLine=function(){
		var x=y=0;
		var	line = new Line({
				x:x,
				y:y,
			 	startX:70,
			 	startY:120,
			 	endX:430,
			 	endY:120,
			 	strokeStyle:'#030609',
			 	lineWidth:3
			})
		this.renderArr.push(line);
		
		line = new Line({
				x:x,
				y:y,
			 	startX:220,
			 	startY:30,
			 	endX:220,
			 	endY:120,
			 	strokeStyle:'#030609',
			 	lineWidth:3
			})
		this.renderArr.push(line);
		
		line = new Line({
				x:x,
				y:y,
			 	startX:58,
			 	startY:360,
			 	endX:442,
			 	endY:360,
			 	strokeStyle:'#030609',
			 	lineWidth:3
			})
		this.renderArr.push(line);
		
		
		line = new Line({
				x:x,
				y:y,
			 	startX:180,
			 	startY:410,
			 	endX:180,
			 	endY:460,
			 	strokeStyle:'#030609',
			 	lineWidth:3
			})
		this.renderArr.push(line);
		
		line = new Line({
				x:x,
				y:y,
			 	startX:178,
			 	startY:410,
			 	endX:342,
			 	endY:410,
			 	strokeStyle:'#030609',
			 	lineWidth:3
			})
		this.renderArr.push(line);
		
		line = new Line({
			x:x,
			y:y,
		 	startX:340,
		 	startY:410,
		 	endX:340,
		 	endY:360,
		 	strokeStyle:'#030609',
		 	lineWidth:3
		})
		this.renderArr.push(line);
	}

此时效果


绘制文字

构造函数

//文字的构造函数
	function Text(o){
		this.x=0,//x坐标
		this.y=0,//y坐标
		this.disX=0,//x坐标偏移量
		this.disY=0,//y坐标偏移量
		this.text='',//内容
		this.font=null;//字体
		this.textAlign=null;//对齐方式
		
		this.init(o);
	}
	
	Text.prototype.init=function(o){
		for(var key in o){
			this[key]=o[key];
		}
	}
	Text.prototype.render=function(context){
		this.ctx=context;
		innerRender(this);
			
		function innerRender(obj){
			var ctx=obj.ctx;
			ctx.save()
			ctx.beginPath();
			ctx.translate(obj.x,obj.y);
			if(obj.angle){//根据旋转角度来执行旋转
				ctx.rotate(-obj.angle*Math.PI/180);
			}
			
			if(obj.font){
				ctx.font=obj.font;
			}
			if(obj.textAlign){
				ctx.textAlign=obj.textAlign;
			}
			if(obj.fill){//是否填充
				obj.fillStyle?(ctx.fillStyle=obj.fillStyle):null;
				ctx.fillText(obj.text,obj.disX,obj.disY);
			}
			if(obj.stroke){//是否描边
				obj.strokeStyle?(ctx.strokeStyle=obj.strokeStyle):null;
				ctx.strokeText(obj.text,obj.disX,obj.disY);
			}
		  	ctx.restore();
		}
	  	return this;
	}

绘制

//组装文字信息
	SpaceMan.prototype.drawText=function(){
		var content="",x=y=0;
		//天气
		x=230;y=60,content="空气良好";
		var	text = new Text({
			x:x,
			y:y,
			text:content,
			font:'bold 20px ans-serif',
			textAlign:'left',
			fill:true,
			fillStyle:'#44444'
		});	
		this.renderArr.push(text);	
		
		x=230;y=85,content="晴天";
		var	text = new Text({
			x:x,
			y:y,
			text:content,
			font:'20px ans-serif',
			textAlign:'left',
			fill:true,
			fillStyle:'#44444'
		});	
		this.renderArr.push(text);
		
		//气温
		x=230;y=110,content="23°C";
		var	text = new Text({
			x:x,
			y:y,
			text:content,
			font:'18px ans-serif',
			textAlign:'left',
			fill:true,
			fillStyle:'#44444'
		});	
		this.renderArr.push(text);
		
		//绘制最小温度
		x=285;y=110,content="18°";
		var	text = new Text({
			x:x,
			y:y,
			text:content,
			font:'18px ans-serif',
			textAlign:'left',
			fill:true,
			fillStyle:'#44444'
		});	
		this.renderArr.push(text);
		
		//绘制最大温度
		x=285;y=85,content="26°";
		var	text = new Text({
			x:x,
			y:y,
			text:content,
			font:'18px ans-serif',
			textAlign:'left',
			fill:true,
			fillStyle:'#44444'
		});	
		this.renderArr.push(text);
		
		
		//电量
		x=120;y=115,content="70%";
		var	text = new Text({
			x:x,
			y:y,
			text:content,
			font:'bold 35px ans-serif',
			textAlign:'left',
			fill:true,
			fillStyle:'#44444'
		});	
		this.renderArr.push(text);
		
		//心率
		x=65;y=305,content="80~128";
		var	text = new Text({
			x:x,
			y:y,
			text:content,
			font:'20px ans-serif',
			textAlign:'left',
			fill:true,
			fillStyle:'#44444'
		});	
		this.renderArr.push(text);
		
		x=130;y=345,content="92";
		var	text = new Text({
			x:x,
			y:y,
			text:content,
			font:'bold 30px ans-serif',
			textAlign:'left',
			fill:true,
			fillStyle:'#44444'
		});	
		this.renderArr.push(text);
		
		//步数
		x=370;y=345,content="7032";
		var	text = new Text({
			x:x,
			y:y,
			text:content,
			font:'bold 26px ans-serif',
			textAlign:'left',
			fill:true,
			fillStyle:'#44444'
		});	
		this.renderArr.push(text);
		
		//睡眠
		x=110;y=395,content="睡眠";
		var	text = new Text({
			x:x,
			y:y,
			text:content,
			font:'30px ans-serif',
			textAlign:'left',
			fill:true,
			fillStyle:'#44444'
		});	
		this.renderArr.push(text);
		
		x=190;y=400,content="8h30m";
		var	text = new Text({
			x:x,
			y:y,
			text:content,
			font:'BOLD 34px ans-serif',
			textAlign:'left',
			fill:true,
			fillStyle:'#44444'
		});	
		this.renderArr.push(text);
		
		//距离
		x=350;y=395,content="距离";
		var	text = new Text({
			x:x,
			y:y,
			text:content,
			font:'30px ans-serif',
			textAlign:'left',
			fill:true,
			fillStyle:'#44444'
		});	
		this.renderArr.push(text);
		
		x=210;y=445,content="9.22km";
		var	text = new Text({
			x:x,
			y:y,
			text:content,
			font:'BOLD 32px ans-serif',
			textAlign:'left',
			fill:true,
			fillStyle:'#44444'
		});	
		this.renderArr.push(text);
	}

效果如下:


绘制修饰图片

图片构造函数

//图片对象ImageDraw构造函数
	function ImageDraw(o,obj){
		this.id='',
		this.image=0,//图片对象(必填)
		this.sx=0,//图片切片开始x位置(显示整个图片的时候不需要填)
		this.sy=0,//图片切片开始y位置(显示整个图片的时候不需要填)
		this.sWidth=0, //图片切片开始宽度(显示整个图片的时候不需要填)
		this.sHeight=0,//图片切片开始高度(显示整个图片的时候不需要填)
		this.dx=0, //图片目标x位置(必填)
		this.dy=0, //图片目标y位置(必填)
		this.dWidth=0,//图片目标显示宽度(宽度不缩放时不必填)
		this.dHeight=0//图片目标高度高度(高度不缩放时不必填)
		
		this.init(o,obj);
	}
	ImageDraw.prototype.init=function(o,obj){
		this.lol=obj;
		for(var key in o){
			this[key]=o[key];
		}
		return this;
	}
	ImageDraw.prototype.render=function(context){
		draw(context,this);
		function draw(context,obj) {
			var ctx=context;
			ctx.save();
			
			if(!obj.image || getType(obj.dx)=='undefined' || getType(obj.dy)=='undefined'){
				throw new Error("绘制图片缺失参数");	
				return;
			} 
			ctx.translate(obj.dx,obj.dy);
			if(getType(obj.sx)!='undefined' && getType(obj.sy)!='undefined' && obj.sWidth && obj.sHeight && obj.dWidth && obj.dHeight){
				//裁剪图片,显示时候有缩放
				ctx.drawImage(obj.image, obj.sx, obj.sy, obj.sWidth, obj.sHeight, 0, 0, obj.dWidth, obj.dHeight);
			}else if(obj.dWidth && obj.dHeight){
				ctx.drawImage(obj.image, 0, 0, obj.dWidth, obj.dHeight);//原始图片,显示时候有缩放
			}else{
				ctx.drawImage(obj.image,0, 0);//原始图片,显示时候无缩放
			}
			ctx.restore();
		}
	}
	ImageDraw.prototype.isPoint=function(pos){
		//鼠标位置的x、y要分别大于dx、dy 且x、y要分别小于 dx+dWidth、dy+dHeight
		if(pos.x>this.dx && pos.y>this.dy && pos.x<this.dx+this.dWidth && pos.y<this.dy+this.dHeight ){//表示处于当前图片对象范围内
			return true;
		}
		return false;
	}

绘制

//组装图片对象信息
	SpaceMan.prototype.drawOtherImg=function(){
		//绘制电量
		var image = this.imgObj[66];
		var img,x=y=0,sWidth=200,sHeight=200,dx=170,dy=45,dWidth=50,dHeight=50;
		img = new ImageDraw({image:image,sx:x,sy:y,sWidth:sWidth,sHeight:sHeight, dx:dx, dy:dy ,dWidth:dWidth,dHeight:dHeight},this);
		this.renderArr.push(img);
		
		//绘制太阳
		image = this.imgObj[62];
		sWidth=200,sHeight=200,dx=340,dy=70,dWidth=50,dHeight=50;
		img = new ImageDraw({image:image,sx:x,sy:y,sWidth:sWidth,sHeight:sHeight, dx:dx, dy:dy ,dWidth:dWidth,dHeight:dHeight},this);
		this.renderArr.push(img);	
		//绘制最大温度
		image = this.imgObj[65];
		var img,x=y=0,sWidth=200,sHeight=200,dx=315,dy=70,dWidth=20,dHeight=20;
		img = new ImageDraw({image:image,sx:x,sy:y,sWidth:sWidth,sHeight:sHeight, dx:dx, dy:dy ,dWidth:dWidth,dHeight:dHeight},this);
		this.renderArr.push(img);
		
		//绘制最小温度
		image = this.imgObj[64];
		var img,x=y=0,sWidth=200,sHeight=200,dx=315,dy=90,dWidth=20,dHeight=20;
		img = new ImageDraw({image:image,sx:x,sy:y,sWidth:sWidth,sHeight:sHeight, dx:dx, dy:dy ,dWidth:dWidth,dHeight:dHeight},this);
		this.renderArr.push(img);
		
		//绘制心率
		image = this.imgObj[61];
		sWidth=200,sHeight=200,dx=70,dy=305,dWidth=60,dHeight=60;
		img = new ImageDraw({image:image,sx:x,sy:y,sWidth:sWidth,sHeight:sHeight, dx:dx, dy:dy ,dWidth:dWidth,dHeight:dHeight},this);
		this.renderArr.push(img);	
		
		//绘制步数
		image = this.imgObj[63];
		sWidth=200,sHeight=200,dx=320,dy=310,dWidth=50,dHeight=50;
		img = new ImageDraw({image:image,sx:x,sy:y,sWidth:sWidth,sHeight:sHeight, dx:dx, dy:dy ,dWidth:dWidth,dHeight:dHeight},this);
		this.renderArr.push(img);
	}

此时的效果


绘制太空人


代码

	//组装太空人图片对象信息
	SpaceMan.prototype.drawImg=function(){
		var image = this.imgObj[this.imageKey];
		var img,x=y=0,sWidth=534,sHeight=598,dx=190,dy=200,dWidth=120,dHeight=134;
		
		img = new ImageDraw({image:image,sx:x,sy:y,sWidth:sWidth,sHeight:sHeight, dx:dx, dy:dy ,dWidth:dWidth,dHeight:dHeight},this);
		this.renderArr2.push(img);		
	}

此时效果


绘制时间

入口代码

//绘制日期
	SpaceMan.prototype.drawDateTime=function(){
		this.drawHour();//绘制小时
		this.drawMinute();//绘制分钟
		this.drawSecond();//绘制秒钟
		
		this.drawWeekDay();//绘制周
		this.drawMonthDate();//绘制日
		this.drawMonthDate2();//绘制农历
	}

绘制小时

//绘制小时
	SpaceMan.prototype.drawHour=function(){
		var content=this.hour+"",x=y=0;
		//小时
		x=120;y=190,
		content=(content.length==1?(0+content):content);
		var	text = new Text({
			x:x,
			y:y,
			text:content,
			font:'bold 80px ans-serif',
			textAlign:'left',
			fill:true,
			fillStyle:'#44444'
		});	
		this.renderArr2.push(text);	
		this.hourObj=text;
		
		//绘制 :号
		x=220;y=175,
		content=":";
		text = new Text({
			x:x,
			y:y,
			text:content,
			font:'bold 60px ans-serif',
			textAlign:'left',
			fill:true,
			fillStyle:'#44444'
		});	
		this.renderArr2.push(text);	
		
	}

绘制分钟、秒钟

//绘制分钟
	SpaceMan.prototype.drawMinute=function(){
		var content=this.minute+"",x=y=0;
		//分
		x=235;y=190,
		content=(content.length==1?(0+content):content);
		var	text = new Text({
			x:x,
			y:y,
			text:content,
			font:'bold 80px ans-serif',
			textAlign:'left',
			fill:true,
			fillStyle:'#44444'
		});	
		this.renderArr2.push(text);	
		this.minuteObj=text;
	}
	//绘制秒钟
	SpaceMan.prototype.drawSecond=function(){
		var content=this.second+"",x=y=0;
		//秒
		x=340;y=190,
		content=(content.length==1?(0+content):content);
		var	text = new Text({
			x:x,
			y:y,
			text:content,
			font:'bold 35px ans-serif',
			textAlign:'left',
			fill:true,
			fillStyle:'#44444'
		});	
		this.renderArr2.push(text);	
		
		this.secondObj=text;
	}

绘制星期、日期

//绘制星期
	SpaceMan.prototype.drawWeekDay=function(){
		var x=y=0;
		x=350;y=270,
		content=this.weekArr[this.day];
		var	text = new Text({
			x:x,
			y:y,
			text:content,
			font:'20px ans-serif',
			textAlign:'left',
			fill:true,
			fillStyle:'#44444'
		});	
		this.renderArr2.push(text);	
		
		this.weekDayObj=text;
	}
	
	//绘制日
	SpaceMan.prototype.drawMonthDate=function(){
		var content=this.month+"-"+this.date,x=y=0;
		//小时
		x=400;y=270,
		content=(content.length==1?(0+content):content);
		var	text = new Text({
			x:x,
			y:y,
			text:content,
			font:'20px ans-serif',
			textAlign:'left',
			fill:true,
			fillStyle:'#44444'
		});	
		this.renderArr2.push(text);	
		
		this.monthDateObj=text;
	}

绘制农历

//绘制农历日
	SpaceMan.prototype.drawMonthDate2=function(){
		this.lunarObj = new LunarDay();
		var lunarDay = this.lunarObj.getLunarDay(this.year,this.month,this.date);
		var lunarDayArr = lunarDay.split(" ");
		var content= lunarDayArr[1],x=y=0;
		
		x=350;y=240;
		text = new Text({
			x:x,
			y:y,
			text:content,
			font:'20px ans-serif',
			textAlign:'left',
			fill:true,
			fillStyle:'#44444'
		});	
		this.renderArr2.push(text);	
		this.lunarDateObj=text;
	}

效果如下 :



到现在的话整体效果已经完成了,接下来就是要动起来



太空人转动



  1. 设置定时任务



  2. 每次更换一张图片绘制

代码

//太空人转动
	SpaceMan.prototype.humanRotate=function(){
		//不断的更新图片即可
		this.imageKey--;
		if(this.imageKey<this.startCount){
			this.imageKey=60;
		}
		var img = this.renderArr2[0];
		img.image = this.imgObj[this.imageKey];
		
		this.render2();
	}

效果


时间更新

更新秒

//秒钟转动
	SpaceMan.prototype.updateSecond=function(){
		this.second++;
		if(this.second==60){//到达60以后设置为0
			this.second=0;
			this.updateMinute();//更新分钟
		}
		var content = this.second+"";
			content=(content.length==1?(0+content):content);
		this.secondObj.text=content;
	}

更新分钟

//分钟更新
	SpaceMan.prototype.updateMinute=function(){
		this.minute++;
		if(this.minute==60){
			this.minute=0;
			this.updateHour();
		}
	
		var content = this.minute+"";
			content=(content.length==1?(0+content):content);
			
		this.minuteObj.text=content;
	}

更新小时

	
	//时钟更新
	SpaceMan.prototype.updateHour=function(){
		this.hour+=1;
		if(this.hour==24){
			this.hour=0;
			this.updateDate();
		}
		var content = this.hour+"";
			content=(content.length==1?(0+content):content);
		this.hourObj.text=content;
	}

更新日、农历日

//更新日
	SpaceMan.prototype.updateDate=function(){
		var that=this,dateUpdateFlag=false,lastMonthDayLength,angleDis;
		this.date+=1;//日期递增1
		this.updateWeekDay();//更新周几
		if(this.date>this.currentMonthDayLength){//大于本月最大天数就切换到1日
			this.date=1;
			this.updateMonth();//更新月份
		}
		
		this.monthDateObj.text = this.month+"-"+this.date;
		
		this.updateMonthDate2();
	}
	//月更新
	SpaceMan.prototype.updateMonth=function(){
		var that=this;
		this.month+=1;
		if(this.month>12){
			this.month=1;
		}
	}
	//农历日期更新
	SpaceMan.prototype.updateMonthDate2=function(){
		var lunarDay = this.lunarObj.getLunarDay(this.year,this.month,this.date);
		var lunarDayArr = lunarDay.split(" ");
		var content= lunarDayArr[1];
		this.lunarDateObj.text=content;
	}

更新星期

		//更新星期几
	SpaceMan.prototype.updateWeekDay=function(){
		this.day+=1;
		//大于6则重置
		if(this.day>6){
			this.day=0;
		}
		//数组中获取周几
		this.weekDayObj.text=this.weekArr[this.day];
	}

最终效果


兄弟们给个三连支持一下,谢谢哇!

源码下载



关注下方公众号,回复

121

下载代码




更多源码





♥ 基于canvas的手风琴特效(附源码)♥





♥ 抖音很火的华为太空人表盘(附源码)♥





♥ 基于JavaScript页面动态验证码(附源码)♥





♥ 基于JavaScript的拖动滑块拼图验证(附源码)♥





♥ 基于JavaScript的幸运大转盘(附源码)♥





♥ 抖音很火的罗盘时钟(附源码)♥





♥ 基于JavaScript的俄罗斯方块小游戏(附源码)♥





♥ 基于JavaScript的贪吃蛇游戏(附源码)♥





♥ 基于JavaScript的拼图游戏(附源码)♥





♥ 用JavaScript给女儿做的烟花特效(附源码)♥





♥ 老父亲给女儿做的下雪特效,满足女儿看雪的愿望(附源码)♥





♥ 雷达扫描特效(附源码)♥





♥ 香港黄金配角吴孟达去世,80后程序员以轮播图来悼念达叔,达叔一路走好!(附源码)♥





♥ 仿抖音刷新进度条(附源码)♥





♥ 仿头条方形刷新进度条(附源码)♥





♥ 仿360加速球、水波评分特效(附源码)♥





♥ 基于canvas的刮刮卡(附源码)♥





♥ 原生js写的左侧飞入拼图特效,你是喜欢美女单飞还是双飞(附源码)♥





♥ 用js写的旋转木马,在新年献给各位刚登基的皇帝,让你的后宫转起来!程序员就是可以为所欲为!(附源码)♥





♥ 用js写的轮播图,八位女明星,你翻谁的牌,程序员就是可以为所欲为!(附源码)♥





♥ 原生js实现美女拼图,把美女老婆抱回家,5个美女够不够!程序员就是可以为所欲为!(附源码)♥





♥ 用js仿探探拖拽卡片的效果、飞卡片的效果,感觉挺酷,最后有美女看哦!(附源码)♥





♥ 老婆说程序员不懂浪漫,程序员默默拿起了键盘,这就亲手带你去看流星雨,女人真会影响拔刀的速度(附源码)♥





♥ 学生成绩管理系统(jsp+jquery+java+mysql+tomcat)有源码,你的毕设我的心(附源码)♥




版权声明:本文为dkm123456原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。