当前位置: 首页 > news >正文

随机生成千山万水动画

<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="utf-8"> <title>千山万水</title> <style> body { margin: 0; padding: 0; } #container { margin: 0; padding: 0; position:absolute; top:0; left:0; width:100%; height:100vh; overflow:hidden; background-color: #fff; box-shadow: 0 0 20px rgba(0, 0, 0, 0.5); background-color:#ff3333; } canvas { margin: 0; padding: 0; position:absolute; top:0; left:-100px; } svg{ margin: 0; padding: 0; position:absolute; top:0; left:0; } </style> </head> <body> <!-- 千山万水 --> <div id="container"></div> </body> <script> // 使用SVG绘制山脉 // 画布高度和页面高度相同 let canvasHeight=window.innerHeight; console.log(`canvasHeight=${canvasHeight}`); //---------------------------- function generateMountainsCurvePoints (pointCount=9,mtWidthBase=30,mtWidthVariation=120,mtHeightBase=100,mtHeightVariation=200) { // 生成随机的山脉曲线点 // 山脉曲线点数组 let mountainCurvePoints=[]; // 起点 let currentX=0; let currentY=canvasHeight; // 随机生成山脉曲线点 for (let i = 0; i < pointCount; i++) { mountainCurvePoints.push([currentX,currentY]); //生成随机偏移量 //x偏移量限定区间100-200 let xOffset=Math.random()*mtWidthVariation+mtWidthBase; currentX+=xOffset; //y值随机变幻区间 currentY=Math.random()*mtHeightVariation+mtHeightBase; currentY=canvasHeight-currentY; } // 终点 mountainCurvePoints.push([currentX+100,canvasHeight]); // 返回结果数组 return mountainCurvePoints; } //---------------------------- // 绘制山脉 function drawMountains (canvasId,mountainCurvePoints,mtLineColor='rgb(255,0,0,1)',mtFillColor='rgb(255,0,0,1)',mtLineWidth=1) { console.log(canvasId); // 获取Canvas元素 const canvas = document.getElementById(canvasId); const ctx = canvas.getContext('2d'); // 设置Canvas布大小mountainCurvePoints最后一个点的x坐标决定 // 画布宽度由mountainCurvePoints最后一个点的x坐标决定 canvas.width = mountainCurvePoints[mountainCurvePoints.length-1][0]; console.log(`canvas.width=${canvas.width}`); canvas.height = canvasHeight; // 设置背景颜色 ctx.fillStyle='rgba(255,0,0,0)'; ctx.fillRect(0,0,canvas.width,canvas.height); // 绘制山脉曲线,使用随机颜色 ctx.strokeStyle=`${mtLineColor}`; ctx.lineWidth=mtLineWidth; ctx.lineCap='round'; ctx.lineJoin='round'; ctx.beginPath(); ctx.moveTo(mountainCurvePoints[0][0], mountainCurvePoints[0][1]); for (let i = 0; i < mountainCurvePoints.length-1; i++) { // ctx.lineTo(mountainCurvePoints[i][0], mountainCurvePoints[i][1]); //绘制圆滑曲线 const p0x=mountainCurvePoints[Math.max(i-1,0)][0]; const p0y=mountainCurvePoints[Math.max(i-1,0)][1]; const p1x=mountainCurvePoints[i][0]; const p1y=mountainCurvePoints[i][1]; const p2x=mountainCurvePoints[i+1][0]; const p2y=mountainCurvePoints[i+1][1]; const p3x=mountainCurvePoints[Math.min(i+2,mountainCurvePoints.length-1)][0]; const p3y=mountainCurvePoints[Math.min(i+2,mountainCurvePoints.length-1)][1]; //计算控制点 const tension=0.15; const cp1x=p1x+(p2x-p0x)*tension; const cp1y=p1y+(p2y-p0y)*tension; const cp2x=p1x+(p3x-p1x)*tension; const cp2y=p1y+(p3y-p1y)*tension; ctx.bezierCurveTo(cp1x, cp1y, cp2x, cp2y, p2x, p2y); } //闭合曲线 ctx.closePath(); ctx.stroke(); //填充颜色 ctx.fillStyle=`${mtFillColor}`; ctx.fill(); } //---------------------------- function drawMountainsSVG (canvasId,mountainCurvePoints,mtLineColor='rgb(255,0,0,1)',mtFillColor='rgb(255,0,0,1)',mtLineWidth=1) { // 绘制山脉 //创建SVG元素svg const svg = document.createElementNS('http://www.w3.org/2000/svg','svg'); // 设置SVG元素的属性 svg.setAttribute('width',mountainCurvePoints[mountainCurvePoints.length-1][0]); svg.setAttribute('height',canvasHeight); svg.setAttribute('id',canvasId); // 设置SVG元素的属性 svg.setAttribute('viewBox',`0 0 ${mountainCurvePoints[mountainCurvePoints.length-1][0]} ${canvasHeight}`); // 创建path元素 const path = document.createElementNS('http://www.w3.org/2000/svg','path'); // 构造path文本字符串 let pathText=`M ${mountainCurvePoints[0][0]} ${mountainCurvePoints[0][1]} `; // 按照mountainCurvePoints的坐标点,绘制山脉曲线 for (let i = 0; i < mountainCurvePoints.length; i++) { //构造path文本字符串 pathText+=`L ${mountainCurvePoints[i][0]} ${mountainCurvePoints[i][1]} `; } // 闭合曲线 pathText+='Z'; // 设置path元素的属性 path.setAttribute('d',pathText); // 绘制山脉曲线,使用随机颜色 path.setAttribute('stroke',`${mtLineColor}`); path.setAttribute('stroke-width',`${mtLineWidth}`); path.setAttribute('stroke-linecap','round'); path.setAttribute('stroke-linejoin','round'); //添加linearGradient线性渐变填充 const linearGradient = document.createElementNS('http://www.w3.org/2000/svg','linearGradient'); linearGradient.setAttribute('id',`linearGradientFill${canvasId}`); linearGradient.setAttribute('x1','0%'); linearGradient.setAttribute('y1','0%'); linearGradient.setAttribute('x2','0%'); linearGradient.setAttribute('y2','100%'); const stop1 = document.createElementNS('http://www.w3.org/2000/svg','stop'); stop1.setAttribute('stop-color',`${mtFillColor}`); stop1.setAttribute('offset','0%'); linearGradient.appendChild(stop1); const stop2 = document.createElementNS('http://www.w3.org/2000/svg','stop'); stop2.setAttribute('stop-color',`orange`); stop2.setAttribute('offset','100%'); linearGradient.appendChild(stop2); // 添加linearGradient元素到svg元素 svg.appendChild(linearGradient); path.setAttribute('fill',`url(#linearGradientFill${canvasId})`); // 填充颜色 // path.setAttribute('fill',`${mtFillColor}`); // 添加path元素到svg元素 svg.appendChild(path); // 添加svg元素到container元素 document.getElementById('container').appendChild(svg); } //---------------------------- // 动画:canvas水平平移动画循环 function moveMt(canvasId,speed=10,stopGate=1000000) { // 获取Canvas元素 let mt = document.getElementById(canvasId); // 通过修改left属性实现水平平移动,left的属性无法直接获取,需要通过getComputedStyle()方法获取当前left值,, // 所能直接修改left属性,实现水平平移动 let mtLeft=parseInt(getComputedStyle(mt).left); // console.log("canvas left:"+mtLeft); mt.style.left=mtLeft-speed+"px"; //动画循环 let animationId=requestAnimationFrame(()=>{ moveMt(canvasId,speed); }); // 触发结束循环的条件是left绝对值大于等于当前画布的宽度 // console.log(`stopGate=${stopGate}`); if(mtLeft<=-stopGate){ console.log(`${canvasId} 结束循环`); cancelAnimationFrame(animationId); } } //---------------------------- // 绘制山脉 let pointCount=10000; let mtWidthVariation=50; let mtHeightVariation=145; mtps0=generateMountainsCurvePoints(pointCount=pointCount,mtWidthBase=30,mtWidthVariation=mtWidthVariation,mtHeightBase=870,mtHeightVariation=mtHeightVariation); mtps1=generateMountainsCurvePoints(pointCount=pointCount,mtWidthBase=30,mtWidthVariation=mtWidthVariation,mtHeightBase=800,mtHeightVariation=mtHeightVariation); mtps2=generateMountainsCurvePoints(pointCount=pointCount,mtWidthBase=30,mtWidthVariation=mtWidthVariation,mtHeightBase=720,mtHeightVariation=mtHeightVariation); mtps3=generateMountainsCurvePoints(pointCount=pointCount,mtWidthBase=30,mtWidthVariation=mtWidthVariation,mtHeightBase=630,mtHeightVariation=mtHeightVariation); mtps4=generateMountainsCurvePoints(pointCount=pointCount,mtWidthBase=30,mtWidthVariation=mtWidthVariation,mtHeightBase=530,mtHeightVariation=mtHeightVariation); mtps5=generateMountainsCurvePoints(pointCount=pointCount,mtWidthBase=30,mtWidthVariation=mtWidthVariation,mtHeightBase=420,mtHeightVariation=mtHeightVariation); mtps6=generateMountainsCurvePoints(pointCount=pointCount,mtWidthBase=30,mtWidthVariation=mtWidthVariation,mtHeightBase=320,mtHeightVariation=mtHeightVariation); mtps7=generateMountainsCurvePoints(pointCount=pointCount,mtWidthBase=30,mtWidthVariation=mtWidthVariation,mtHeightBase=200,mtHeightVariation=mtHeightVariation); //---------------------------- //SVG模式绘制山脉 let mtFillColorList=['#ff4444','#ff5555','#ff6666','#ff7777','#ff8888','#ff9999','#ffaaaa','#ffbbbb','#ffcccc','#ffdddd','#ffeeee','#ffffff']; drawMountainsSVG("canvas0",mtps0,mtLineColor=mtFillColorList[0],mtFillColor=mtFillColorList[0],mtLineWidth=0); drawMountainsSVG("canvas1",mtps1,mtLineColor=mtFillColorList[1],mtFillColor=mtFillColorList[1],mtLineWidth=0); drawMountainsSVG("canvas2",mtps2,mtLineColor=mtFillColorList[2],mtFillColor=mtFillColorList[2],mtLineWidth=0); drawMountainsSVG("canvas3",mtps3,mtLineColor=mtFillColorList[3],mtFillColor=mtFillColorList[3],mtLineWidth=0); drawMountainsSVG("canvas4",mtps4,mtLineColor=mtFillColorList[4],mtFillColor=mtFillColorList[4],mtLineWidth=0); drawMountainsSVG("canvas5",mtps5,mtLineColor=mtFillColorList[5],mtFillColor=mtFillColorList[5],mtLineWidth=0); drawMountainsSVG("canvas6",mtps6,mtLineColor=mtFillColorList[6],mtFillColor=mtFillColorList[6],mtLineWidth=0); drawMountainsSVG("canvas7",mtps7,mtLineColor=mtFillColorList[7],mtFillColor=mtFillColorList[7],mtLineWidth=0); /* //canvas模式绘制山脉 let mtFillColorList=['#ff3333','#ff4444','#ff5555','#ff6666','#ff7777','#ff8888','#ff9999','#ffaaaa','#ffbbbb','#ffcccc']; drawMountains("canvas0",mtps0,mtLineColor=mtFillColorList[0],mtFillColor=mtFillColorList[0],mtLineWidth=0); drawMountains("canvas1",mtps1,mtLineColor=mtFillColorList[1],mtFillColor=mtFillColorList[1],mtLineWidth=0); drawMountains("canvas2",mtps2,mtLineColor=mtFillColorList[2],mtFillColor=mtFillColorList[2],mtLineWidth=0); drawMountains("canvas3",mtps3,mtLineColor=mtFillColorList[3],mtFillColor=mtFillColorList[3],mtLineWidth=0); drawMountains("canvas4",mtps4,mtLineColor=mtFillColorList[4],mtFillColor=mtFillColorList[4],mtLineWidth=0); drawMountains("canvas5",mtps5,mtLineColor=mtFillColorList[5],mtFillColor=mtFillColorList[5],mtLineWidth=0); drawMountains("canvas6",mtps6,mtLineColor=mtFillColorList[6],mtFillColor=mtFillColorList[6],mtLineWidth=0); drawMountains("canvas7",mtps7,mtLineColor=mtFillColorList[7],mtFillColor=mtFillColorList[7],mtLineWidth=0); */ //---------------------------- // 调用动画函数 moveMt("canvas0",speed=1); moveMt("canvas1",speed=2); moveMt("canvas2",speed=3); moveMt("canvas3",speed=4); moveMt("canvas4",speed=5); moveMt("canvas5",speed=6); moveMt("canvas6",speed=7); moveMt("canvas7",speed=8); </script> </html>

精简圆滑曲线版:

<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="utf-8"> <title>千山万水</title> <style> body { margin: 0; padding: 0; } #container { margin: 0; padding: 0; position:absolute; top:0; left:0; width:100%; height:100vh; overflow:hidden; background-color: #fff; box-shadow: 0 0 20px rgba(0, 0, 0, 0.5); background-color:#ff3333; } canvas { margin: 0; padding: 0; position:absolute; top:0; left:-100px; } svg{ margin: 0; padding: 0; position:absolute; top:0; left:0; } </style> </head> <body> <!-- 千山万水 --> <div id="container"></div> </body> <script> // 使用SVG绘制山脉 // 画布高度和页面高度相同 let canvasHeight=window.innerHeight; console.log(`canvasHeight=${canvasHeight}`); //---------------------------- function generateMountainsCurvePoints (pointCount=9,mtWidthBase=30,mtWidthVariation=120,mtHeightBase=100,mtHeightVariation=200) { // 生成随机的山脉曲线点 // 山脉曲线点数组 let mountainCurvePoints=[]; // 起点 let currentX=0; let currentY=canvasHeight; // 随机生成山脉曲线点 for (let i = 0; i < pointCount; i++) { mountainCurvePoints.push([currentX,currentY]); //生成随机偏移量 //x偏移量限定区间100-200 let xOffset=Math.random()*mtWidthVariation+mtWidthBase; currentX+=xOffset; //y值随机变幻区间 currentY=Math.random()*mtHeightVariation+mtHeightBase; currentY=canvasHeight-currentY; } // 终点 mountainCurvePoints.push([currentX+100,canvasHeight]); // 返回结果数组 return mountainCurvePoints; } //---------------------------- //---------------------------- function drawMountainsSVG (canvasId,mountainCurvePoints,mtLineColor='rgb(255,0,0,1)',mtFillColor='rgb(255,0,0,1)',mtLineWidth=1) { // 绘制山脉 //创建SVG元素svg const svg = document.createElementNS('http://www.w3.org/2000/svg','svg'); // 设置SVG元素的属性 svg.setAttribute('width',mountainCurvePoints[mountainCurvePoints.length-1][0]); svg.setAttribute('height',canvasHeight); svg.setAttribute('id',canvasId); // 设置SVG元素的属性 svg.setAttribute('viewBox',`0 0 ${mountainCurvePoints[mountainCurvePoints.length-1][0]} ${canvasHeight}`); // 创建path元素 const path = document.createElementNS('http://www.w3.org/2000/svg','path'); // 构造path文本字符串 let pathText=`M ${mountainCurvePoints[0][0]} ${mountainCurvePoints[0][1]} `; // 按照mountainCurvePoints的坐标点,绘制山脉曲线 for (let i = 0; i < mountainCurvePoints.length-1; i++) { //构造path文本字符串 // pathText+=`L ${mountainCurvePoints[i][0]} ${mountainCurvePoints[i][1]} `; // 绘制圆滑曲线,使用三次贝塞尔曲线 const p0 = mountainCurvePoints[i]; const p1 = mountainCurvePoints[i + 1]; const cp1 = { x: (p0[0] + p1[0]) / 2, y: p0[1] }; // 控制点1,通常在两个点之间垂直于线段的中点 const cp2 = { x: (p0[0] + p1[0]) / 2, y: p1[1] }; // 控制点2,通常在两个点之间垂直于线段的中点,但稍微偏移以避免直线连接 if (i === 0) { pathText += `M ${p0[0]} ${p0[1]}`; // Move to the first point } else { pathText += `C ${cp1.x} ${cp1.y}, ${cp2.x} ${cp2.y}, ${p1[0]} ${p1[1]} `; // Cubic Bezier curve to the next point } } // 闭合曲线 pathText+='Z'; // 设置path元素的属性 path.setAttribute('d',pathText); // 绘制山脉曲线,使用随机颜色 path.setAttribute('stroke',`${mtLineColor}`); path.setAttribute('stroke-width',`${mtLineWidth}`); path.setAttribute('stroke-linecap','round'); path.setAttribute('stroke-linejoin','round'); //添加linearGradient线性渐变填充 const linearGradient = document.createElementNS('http://www.w3.org/2000/svg','linearGradient'); linearGradient.setAttribute('id',`linearGradientFill${canvasId}`); linearGradient.setAttribute('x1','0%'); linearGradient.setAttribute('y1','0%'); linearGradient.setAttribute('x2','0%'); linearGradient.setAttribute('y2','100%'); const stop1 = document.createElementNS('http://www.w3.org/2000/svg','stop'); stop1.setAttribute('stop-color',`${mtFillColor}`); stop1.setAttribute('offset','0%'); linearGradient.appendChild(stop1); const stop2 = document.createElementNS('http://www.w3.org/2000/svg','stop'); stop2.setAttribute('stop-color',`orange`); stop2.setAttribute('offset','100%'); linearGradient.appendChild(stop2); // 添加linearGradient元素到svg元素 svg.appendChild(linearGradient); // 填充颜色 // path.setAttribute('fill',`${mtFillColor}`); path.setAttribute('fill',`url(#linearGradientFill${canvasId})`); // 添加path元素到svg元素 svg.appendChild(path); // 添加svg元素到container元素 document.getElementById('container').appendChild(svg); } //---------------------------- // 动画:canvas水平平移动画循环 function moveMt(canvasId,speed=10,stopGate=1000000) { // 获取Canvas元素 let mt = document.getElementById(canvasId); // 通过修改left属性实现水平平移动,left的属性无法直接获取,需要通过getComputedStyle()方法获取当前left值,, // 所能直接修改left属性,实现水平平移动 let mtLeft=parseInt(getComputedStyle(mt).left); // console.log("canvas left:"+mtLeft); mt.style.left=mtLeft-speed+"px"; //动画循环 let animationId=requestAnimationFrame(()=>{ moveMt(canvasId,speed); }); // 触发结束循环的条件是left绝对值大于等于当前画布的宽度 // console.log(`stopGate=${stopGate}`); if(mtLeft<=-stopGate){ console.log(`${canvasId} 结束循环`); cancelAnimationFrame(animationId); } } //---------------------------- // 绘制山脉 let pointCount=10000; let mtWidthVariation=50; let mtHeightVariation=145; mtps0=generateMountainsCurvePoints(pointCount=pointCount,mtWidthBase=30,mtWidthVariation=mtWidthVariation,mtHeightBase=870,mtHeightVariation=mtHeightVariation); mtps1=generateMountainsCurvePoints(pointCount=pointCount,mtWidthBase=30,mtWidthVariation=mtWidthVariation,mtHeightBase=800,mtHeightVariation=mtHeightVariation); mtps2=generateMountainsCurvePoints(pointCount=pointCount,mtWidthBase=30,mtWidthVariation=mtWidthVariation,mtHeightBase=720,mtHeightVariation=mtHeightVariation); mtps3=generateMountainsCurvePoints(pointCount=pointCount,mtWidthBase=30,mtWidthVariation=mtWidthVariation,mtHeightBase=630,mtHeightVariation=mtHeightVariation); mtps4=generateMountainsCurvePoints(pointCount=pointCount,mtWidthBase=30,mtWidthVariation=mtWidthVariation,mtHeightBase=530,mtHeightVariation=mtHeightVariation); mtps5=generateMountainsCurvePoints(pointCount=pointCount,mtWidthBase=30,mtWidthVariation=mtWidthVariation,mtHeightBase=420,mtHeightVariation=mtHeightVariation); mtps6=generateMountainsCurvePoints(pointCount=pointCount,mtWidthBase=30,mtWidthVariation=mtWidthVariation,mtHeightBase=320,mtHeightVariation=mtHeightVariation); mtps7=generateMountainsCurvePoints(pointCount=pointCount,mtWidthBase=30,mtWidthVariation=mtWidthVariation,mtHeightBase=200,mtHeightVariation=mtHeightVariation); //---------------------------- //SVG模式绘制山脉 let mtFillColorList=['#ff4444','#ff5555','#ff6666','#ff7777','#ff8888','#ff9999','#ffaaaa','#ffbbbb','#ffcccc','#ffdddd','#ffeeee','#ffffff']; drawMountainsSVG("canvas0",mtps0,mtLineColor=mtFillColorList[0],mtFillColor=mtFillColorList[0],mtLineWidth=0); drawMountainsSVG("canvas1",mtps1,mtLineColor=mtFillColorList[1],mtFillColor=mtFillColorList[1],mtLineWidth=0); drawMountainsSVG("canvas2",mtps2,mtLineColor=mtFillColorList[2],mtFillColor=mtFillColorList[2],mtLineWidth=0); drawMountainsSVG("canvas3",mtps3,mtLineColor=mtFillColorList[3],mtFillColor=mtFillColorList[3],mtLineWidth=0); drawMountainsSVG("canvas4",mtps4,mtLineColor=mtFillColorList[4],mtFillColor=mtFillColorList[4],mtLineWidth=0); drawMountainsSVG("canvas5",mtps5,mtLineColor=mtFillColorList[5],mtFillColor=mtFillColorList[5],mtLineWidth=0); drawMountainsSVG("canvas6",mtps6,mtLineColor=mtFillColorList[6],mtFillColor=mtFillColorList[6],mtLineWidth=0); drawMountainsSVG("canvas7",mtps7,mtLineColor=mtFillColorList[7],mtFillColor=mtFillColorList[7],mtLineWidth=0); //---------------------------- // 调用动画函数 moveMt("canvas0",speed=1); moveMt("canvas1",speed=2); moveMt("canvas2",speed=3); moveMt("canvas3",speed=4); moveMt("canvas4",speed=5); moveMt("canvas5",speed=6); moveMt("canvas6",speed=7); moveMt("canvas7",speed=8); </script> </html>
http://www.jsqmd.com/news/521924/

相关文章:

  • ESP32实战-构建离线精准计时系统:DS1302 RTC与MicroPython深度集成
  • StepperControl:专为28BYJ-48步进电机优化的轻量级Arduino控制库
  • 2026年3月成都火锅推荐,这些宝藏店铺不容错过!,有名的成都火锅源头厂家选哪家赋能企业生产效率提升与成本优化 - 品牌推荐师
  • T5模型微调实战:从零构建中文生成式问答系统
  • 产品经理效率工具:MT5中文表达多样化,快速生成PRD多版本描述
  • 接口高效调用,实现应用内无感促评
  • Docker安装教程(加汉化!超详细!!!)
  • AI赋能安全新生态 黎阳之光锚定国家政策筑造数智防线
  • 深度解析:5大核心技术如何实现智能内容解锁与付费墙绕过
  • 互联网大厂Java面试场景:谢飞机的奇妙面试之旅
  • SEO_快速诊断并修复网站SEO问题的实用方法
  • 2026成都离婚律所哪家好?高性价比离婚律师事务所盘点 - 深度智识库
  • 二维平面点集环绕方向判断
  • 杭州手表维修门店怎么选?从百达翡丽到欧米茄,高端腕表维修的专业标准与北上广深杭宁六城服务网络深度解析 - 时光修表匠
  • GDevelop-低代码做游戏【4小时入门视频教程】
  • CPFEM 高效 VUMAT 晶体塑性显示动力学模拟:二维与三维模型验证
  • 数学建模竞赛避坑指南:从SARS题目看残差分析的5个常见错误
  • 2002 Text 1
  • 自定义完成boot loader
  • ETF更名,哪家公募基金ETF更强?五家优质公募基金推荐
  • 2026三相四线电表厂家推荐:常州瑞信电子科技,有线远传电表/多用户智能电表/无线电表厂家精选 - 品牌推荐官
  • Windows11下Seay源码审计系统安装全攻略:从环境配置到实战测试
  • 找嵌入式硬件工程师合作项目
  • 合肥帮友惠-邦友恵客服咨询AI流量赋能,重塑智能体验新标杆 - 速递信息
  • 2026年知名的304潜水搅拌机厂家推荐:推流式潜水搅拌机/304冲压式潜水搅拌机批发销售 - 行业平台推荐
  • Git急救指南:误操作全场景挽救方案
  • Python调用大模型API入门实践
  • GriddyCode:3个理由告诉你为什么这款开源代码编辑器值得一试
  • 多径衰落信道下OFDM传输信道估计算法误码率比较
  • 从CCNA到HCIE,3月通关战报复盘