HTML简单音乐播放器「建议收藏」

HTML简单音乐播放器「建议收藏」HTML代码:<!DOCTYPEhtml><htmllang=”en”><head><metacharset=”UTF-8″><metaname=”viewport”content=”width=device-width,initial-scale=1.0″><metahttp-e…

大家好,又见面了,我是你们的朋友全栈君。

在这里插入图片描述

HTML代码:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>html音乐播放器</title>
<link rel="stylesheet" href="font/iconfont.css">
<link rel="stylesheet" href="css/style.css">
</head>
<body>
<div id="player">
<!-- 歌曲信息模块 -->
<div id="player-content1">
<!-- 歌曲名 -->
<div class="music-name"></div>
<!-- 歌手名 -->
<div class="artist-name"></div>
<!-- 歌曲时间 -->
<div class="time">
<!-- 当前播放的时间 -->
<div class="current-time"></div>
<!-- 歌曲总时长 -->
<div class="total-time"></div>
</div>
<!-- 进度条 -->
<div id="s-area">
<!-- 鼠标移动到进度条上,显示的时间信息 -->
<div id="ins-time"></div>
<!-- 鼠标移动到进度条上,进度条变暗部分-->
<div id="s-hover"></div>
<!-- 表示当前歌曲播放进度的蓝色进度条 -->
<div id="seek-bar"></div>
</div>
</div>
<!-- 控制模块 -->
<div id="player-content2">
<!-- 左侧歌曲封面旋转模块 -->
<div class="music-imgs">
<!-- 封面图 -->
<div class="img"></div>
<!-- 歌曲缓冲时的提示文字 -->
<div id="buffer-box">缓冲…</div>
</div>
<!-- 右侧歌曲操作模块 -->
<div class="player-controls">
<!-- 上一首按钮 -->
<div class="btn prev iconfont">&#xe603;</div>
<!-- 暂停/播放 按钮 -->
<div class="btn play-pause icon-jiediankaishi iconfont"></div>
<!-- 下一首按钮 -->
<div class="btn next iconfont">&#xe602;</div>
</div>
</div>
</div>
<script src="js/jquery-3.4.1.min.js"></script>
<script src="js/index.js"></script>
</body>
</html>

CSS部分讲解:

里面有几处用到了CSS3动画:

动画一:点击 播放/暂停 按钮, 歌曲信息模块向上/向下移动
在这里插入图片描述

/* 歌曲信息模块 */
#player-content1{ 

position: absolute;
top:0px;
left:15px;
width:320px;
height:90px;
padding:0 20px 0 130px;
background: rgb(209, 226, 245);
border-top-left-radius: 10px;
border-top-right-radius: 10px;
/* transition过渡动画:设置top属性过渡,过渡时间0.3s,速度曲线为ease(逐渐变慢) */
transition:top 0.3s ease; 
}
#player-content1.active{ 

top:-85px;
}

通过JS部分的代码,动态给歌曲信息模块(id为player-content1)的DOM元素添加/移除active类名
设置CSS3动画过渡属性: transition:top 0.3s ease;来生成过渡时间0.3s,速度逐渐变慢的:
上移动画效果:top:0px; ——>top:-85px;
下移动画效果: top:-85px; ——>top:0px;

同理,左侧图片的旋转,移动,阴影等动画效果:
在这里插入图片描述
1. 封面图上移/下移 出现阴影/阴影消失 的动画效果:

/* 左侧封面图模块 */
.music-imgs{ 

position: absolute;
top: -40px;
width: 100px;
height: 100px;
margin-left: 30px;
-webkit-transform: rotateZ(0);
transform: rotateZ(0);
transition: 0.3s ease all;
box-shadow: 0 0 0 10px #fff;
border-radius: 50%;
overflow: hidden;
}
/* 左侧封面图模块添加了active类名 */
.music-imgs.active{ 

top: -50px;
box-shadow: 0 0 0 4px #e8f5ff, 0 30px 50px -15px #afb7c1;
}

通过JS控制给封面图模块(类名为music-imgs)添加/移除active类名
结合transition: 0.3s ease all;
来生成:圆形封面图上移并且下方出现阴影的效果

2. 封面图旋转的动画效果

/* 左侧封面图模块下的 图片div */
.music-imgs .img{ 

display: block;
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: url('../img/bg.jpg');
}
/* 封面图模块添加了active类名后,图片div的样式添加 */
.music-imgs.active .img{ 

z-index: 1;
-webkit-animation: rotateAlbumArt 3s linear 0s infinite forwards;
animation: rotateAlbumArt 3s linear 0s infinite forwards;
}
@-webkit-keyframes rotateAlbumArt
{ 

0%{ 
 -webkit-transform: rotateZ(0); transform: rotateZ(0); }
100%{ 
 -webkit-transform: rotateZ(360deg); transform: rotateZ(360deg); }
}
@keyframes rotateAlbumArt
{ 

0%{ 
 -webkit-transform: rotateZ(0); transform: rotateZ(0); }
100%{ 
 -webkit-transform: rotateZ(360deg); transform: rotateZ(360deg); }
}

这里用到了css3的animation属性

  • animation属性:比较类似于 flash 中的逐帧动画;
  • 在 CSS3 中是由属性keyframes来完成逐帧动画的;

animation: rotateAlbumArt 3s linear 0s infinite forwards;
rotateAlbumArt: 绑定的keyframe名称
3s:动画变化时间为3s
linear: 动画从头到尾的速度是相同的
0s: 动画开始之前的延迟时间,这里为0s,即不延迟
infinite: 设置动画无限循环播放
forwards: 表示动画结束后,元素直接使用当前样式。

@keyframes rotateAlbumArt
{ 

0%{ 
 -webkit-transform: rotateZ(0); transform: rotateZ(0); }
100%{ 
 -webkit-transform: rotateZ(360deg); transform: rotateZ(360deg); }
}

设置开始帧(0%):沿着Z轴旋转度数为0
设置结束帧(100%):沿着Z轴旋转度数为360

推荐:前端实现动画的方法总结

全部CSS代码如下:

*{ 

margin: 0;
padding: 0;
box-sizing: border-box;
}
#player{ 

position: relative;
top: 100px;
left:200px;
}
/* 歌曲信息模块 */
#player-content1{ 

position: absolute;
top:0px;
left:15px;
width:320px;
height:90px;
padding:0 20px 0 130px;
background: rgb(209, 226, 245);
border-top-left-radius: 10px;
border-top-right-radius: 10px;
/* transition过渡动画:设置top属性过渡,过渡时间0.3s,速度曲线为ease(逐渐变慢) */
transition:top 0.3s ease; 
}
#player-content1.active{ 

top:-85px;
}
.music-name, .artist-name{ 

height: 20px;
margin-top:5px;
font-size:14px;
}
.artist-name{ 

font-size:12px;
color: #656565
}
.time{ 

font-size:12px;
height:15px;
margin: 5px 0;
}
.current-time{ 

float: left;
}
.total-time{ 

float: right;
}
.current-time,.total-time{ 

color: transparent;
font-size: 11px;
background-color: #e8f5ff;
border-radius: 10px;
transition: 0.3s ease all;
}
.time.active .current-time, .time.active .total-time{ 

color: rgb(54, 127, 196);
background-color: transparent;
}
#s-area, #seek-bar{ 

position: relative;
height: 4px;
border-radius: 4px;
}
#s-area{ 

background-color:#e8f5ff;
cursor: pointer;
}
#ins-time{ 

position: absolute;
top: -29px;
color: #fff;
font-size: 12px;
white-space: pre;
padding: 5px 6px;
border-radius: 4px;
display:none;
}
#s-hover{ 

position: absolute;
top: 0;
bottom: 0;
left: 0;
opacity: 0.2;
z-index: 2;
}
#ins-time, #s-hover{ 

background-color: #4b4d5c;
}
#seek-bar{ 

content: '';
position: absolute;
top: 0;
bottom: 0;
left: 0;
width: 0;
background-color: rgb(54, 127, 196);
transition: 0.2s ease width;
}
#player-content2{ 

position: relative;
width:350px;
height:90px;
background: #fff;
border-radius: 20px;
box-shadow: 0 30px 80px #656565;
}
/* 左侧封面图模块 */
.music-imgs{ 

position: absolute;
top: -40px;
width: 100px;
height: 100px;
margin-left: 30px;
-webkit-transform: rotateZ(0);
transform: rotateZ(0);
transition: 0.3s ease all;
box-shadow: 0 0 0 10px #fff;
border-radius: 50%;
overflow: hidden;
}
/* 左侧封面图模块添加了active类名 */
.music-imgs.active{ 

top: -50px;
box-shadow: 0 0 0 4px #e8f5ff, 0 30px 50px -15px #afb7c1;
}
.music-imgs:before{ 

content: '';
position: absolute;
top: 50%;
right: 0;
left: 0;
width: 20px;
height: 20px;
margin: -10px auto 0 auto;
background-color: #d6dee7;
border-radius: 50%;
box-shadow: inset 0 0 0 2px #fff;
z-index: 2;
}
/* 左侧封面图模块下的 图片div */
.music-imgs .img{ 

display: block;
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
/* 封面图模块添加了active类名后,图片div的样式添加 */
.music-imgs.active .img{ 

z-index: 1;
-webkit-animation: rotateAlbumArt 3s linear 0s infinite forwards;
animation: rotateAlbumArt 3s linear 0s infinite forwards;
}
@-webkit-keyframes rotateAlbumArt
{ 

0%{ 
 -webkit-transform: rotateZ(0); transform: rotateZ(0); }
100%{ 
 -webkit-transform: rotateZ(360deg); transform: rotateZ(360deg); }
}
@keyframes rotateAlbumArt
{ 

0%{ 
 -webkit-transform: rotateZ(0); transform: rotateZ(0); }
100%{ 
 -webkit-transform: rotateZ(360deg); transform: rotateZ(360deg); }
}
#buffer-box
{ 

position: absolute;
top: 50%;
right: 0;
left: 0;
height: 13px;
color: #1f1f1f;
font-size: 13px;
font-family: Helvetica;
text-align: center;
font-weight: bold;
line-height: 1;
padding: 6px;
margin: -12px auto 0 auto;
background-color: rgba(255, 255, 255, 0.19);
opacity: 0;
z-index: 2;
}
.music-imgs .img, #buffer-box
{ 

transition: 0.1s linear all;
}
.music-imgs.buffering .img
{ 

opacity: 0.25;
}
.music-imgs.buffering .img.active
{ 

opacity: 0.8;
filter: blur(2px);
-webkit-filter: blur(2px);
}
.music-imgs.buffering #buffer-box
{ 

opacity: 1;
}
.player-controls{ 

position: absolute;
top:20px;
left:150px;
}
.player-controls .btn{ 

float: left;
width:60px;
height:60px;
line-height: 60px;
font-size:24px;
color:#D6DEE7;
}

JS部分讲解

缓冲效果:
当我把歌曲链接改成错误的时候:
在这里插入图片描述
缓冲部分JS:

// 定时器检测是否需要缓冲
function checkBuffering(){ 

clearInterval(buffInterval);
buffInterval = setInterval(function()
{ 
 
// 这里如果音频播放了,则nTime为当前时间毫秒数,如果没播放则为0;如果时间间隔过长,也将缓存
if( (nTime == 0) || (bTime - nTime) > 1000  ){ 
 
musicImgs.addClass('buffering');  // 添加缓存样式类
} else{ 

musicImgs.removeClass('buffering'); // 移除缓存样式类
}
bTime = new Date();
bTime = bTime.getTime();
},100);
}

全部JS代码(内含详细注释):

$(function(){ 

var playerContent1 = $('#player-content1');// 歌曲信息模块部分dom元素
var musicName = $('.music-name');          // 歌曲名部分dom元素 
var artistName = $('.artist-name');        // 歌手名部分dom元素
var musicImgs = $('.music-imgs');          // 左侧封面图dom元素
var playPauseBtn = $('.play-pause');       // 播放/暂停按钮 dom元素
var playPrevBtn = $('.prev');              // 上一首按钮 dom元素
var playNextBtn = $('.next')               // 下一首按钮 dom元素
var time = $('.time');                     // 时间信息部分 dom元素
var tProgress = $('.current-time');        // 当前播放时间文本部分 dom元素
var totalTime = $('.total-time');          // 歌曲总时长文本部分 dom元素
var sArea = $('#s-area');                  // 进度条部分
var insTime = $('#ins-time');              // 鼠标移动至进度条上面,显示的信息部分
var sHover = $('#s-hover');                // 鼠标移动至进度条上面,前面变暗的进度条部分
var seekBar = $('#seek-bar');              // 播放进度条部分
// 一些计算所需的变量
var seekT, seekLoc, seekBarPos, cM, ctMinutes, ctSeconds, curMinutes, curSeconds, durMinutes, durSeconds, playProgress, bTime, nTime = 0
var musicImgsData = ['img/bg.jpg','img/bg1.jpg','img/bg2.jpg']    // 图片地址数组
var musicNameData = ['出山','盗将行','归去来兮'];                   // 歌曲名数组
var artistNameData = ['花粥/王胜娚','花粥/马雨阳','花粥']            // 创作歌手数组
var musicUrls=['mp3/music1.mp3','mp3/music2.mp3','mp3/music3.mp3'];// 歌曲mp3数组
var currIndex = -1;              // 当前播放索引
var buffInterval = null          // 初始化定时器 判断是否需要缓冲
var len = musicNameData.length;  // 歌曲长度
// 点击 播放/暂停 按钮,触发该函数
// 作用:根据audio的paused属性 来检测当前音频是否已暂停 true:暂停 false:播放中
function playPause(){ 

if(audio.paused){ 

playerContent1.addClass('active'); // 内容栏上移
musicImgs.addClass('active');      // 左侧图片开始动画效果
playPauseBtn.attr('class','btn play-pause icon-zanting iconfont') // 显示暂停图标
checkBuffering(); // 检测是否需要缓冲
audio.play();     // 播放
}else{ 

playerContent1.removeClass('active'); // 内容栏下移
musicImgs.removeClass('active');      // 左侧图片停止旋转等动画效果
playPauseBtn.attr('class','btn play-pause icon-jiediankaishi iconfont'); // 显示播放按钮
clearInterval(buffInterval);          // 清除检测是否需要缓冲的定时器
musicImgs.removeClass('buffering');    // 移除缓冲类名
audio.pause(); // 暂停
}  
}
// 鼠标移动在进度条上, 触发该函数 
function showHover(event){ 

seekBarPos = sArea.offset();    // 获取进度条长度
seekT = event.clientX - seekBarPos.left;  //获取当前鼠标在进度条上的位置
seekLoc = audio.duration * (seekT / sArea.outerWidth()); //当前鼠标位置的音频播放秒数: 音频长度(单位:s)*(鼠标在进度条上的位置/进度条的宽度)
sHover.width(seekT);  //设置鼠标移动到进度条上变暗的部分宽度
cM = seekLoc / 60;    // 计算播放了多少分钟: 音频播放秒速/60
ctMinutes = Math.floor(cM);  // 向下取整
ctSeconds = Math.floor(seekLoc - ctMinutes * 60); // 计算播放秒数
if( (ctMinutes < 0) || (ctSeconds < 0) )
return;
if( (ctMinutes < 0) || (ctSeconds < 0) )
return;
if(ctMinutes < 10)
ctMinutes = '0'+ctMinutes;
if(ctSeconds < 10)
ctSeconds = '0'+ctSeconds;
if( isNaN(ctMinutes) || isNaN(ctSeconds) )
insTime.text('--:--');
else
insTime.text(ctMinutes+':'+ctSeconds);  // 设置鼠标移动到进度条上显示的信息
insTime.css({ 
'left':seekT,'margin-left':'-21px'}).fadeIn(0);  // 淡入效果显示
}
// 鼠标移出进度条,触发该函数
function hideHover()
{ 

sHover.width(0);  // 设置鼠标移动到进度条上变暗的部分宽度 重置为0
insTime.text('00:00').css({ 
'left':'0px','margin-left':'0px'}).fadeOut(0); // 淡出效果显示
}
// 鼠标点击进度条,触发该函数
function playFromClickedPos()
{ 

audio.currentTime = seekLoc; // 设置音频播放时间 为当前鼠标点击的位置时间
seekBar.width(seekT);        // 设置进度条播放长度,为当前鼠标点击的长度
hideHover();                 // 调用该函数,隐藏原来鼠标移动到上方触发的进度条阴影
}
// 在音频的播放位置发生改变是触发该函数
function updateCurrTime()
{ 

nTime = new Date();      // 获取当前时间
nTime = nTime.getTime(); // 将该时间转化为毫秒数
// 计算当前音频播放的时间
curMinutes = Math.floor(audio.currentTime  / 60);
curSeconds = Math.floor(audio.currentTime  - curMinutes * 60);
// 计算当前音频总时间
durMinutes = Math.floor(audio.duration / 60);
durSeconds = Math.floor(audio.duration - durMinutes * 60);
// 计算播放进度百分比
playProgress = (audio.currentTime  / audio.duration) * 100;
// 如果时间为个位数,设置其格式
if(curMinutes < 10)
curMinutes = '0'+curMinutes;
if(curSeconds < 10)
curSeconds = '0'+curSeconds;
if(durMinutes < 10)
durMinutes = '0'+durMinutes;
if(durSeconds < 10)
durSeconds = '0'+durSeconds;
if( isNaN(curMinutes) || isNaN(curSeconds) )
tProgress.text('00:00');
else
tProgress.text(curMinutes+':'+curSeconds);
if( isNaN(durMinutes) || isNaN(durSeconds) )
totalTime.text('00:00');
else
totalTime.text(durMinutes+':'+durSeconds);
if( isNaN(curMinutes) || isNaN(curSeconds) || isNaN(durMinutes) || isNaN(durSeconds) )
time.removeClass('active');
else
time.addClass('active');
// 设置播放进度条的长度
seekBar.width(playProgress+'%');
// 进度条为100 即歌曲播放完时
if( playProgress == 100 )
{ 

playPauseBtn.attr('class','btn play-pause icon-jiediankaishi iconfont'); // 显示播放按钮
seekBar.width(0);              // 播放进度条重置为0
tProgress.text('00:00');       // 播放时间重置为 00:00
musicImgs.removeClass('buffering').removeClass('active');  // 移除相关类名
clearInterval(buffInterval);   // 清除定时器
selectTrack(1);  // 添加这一句,可以实现自动播放
}
}
// 定时器检测是否需要缓冲
function checkBuffering(){ 

clearInterval(buffInterval);
buffInterval = setInterval(function()
{ 
 
// 这里如果音频播放了,则nTime为当前时间毫秒数,如果没播放则为0;如果时间间隔过长,也将缓存
if( (nTime == 0) || (bTime - nTime) > 1000  ){ 
 
musicImgs.addClass('buffering');  // 添加缓存样式类
} else{ 

musicImgs.removeClass('buffering'); // 移除缓存样式类
}
bTime = new Date();
bTime = bTime.getTime();
},100);
}
// 点击上一首/下一首时,触发该函数。 
//注意:后面代码初始化时,会触发一次selectTrack(0),因此下面一些地方需要判断flag是否为0
function selectTrack(flag){ 

if( flag == 0 || flag == 1 ){ 
  // 初始 || 点击下一首
++ currIndex;
if(currIndex >=len){ 
      // 当处于最后一首时,点击下一首,播放索引置为第一首
currIndex = 0;
}
}else{ 
                    // 点击上一首
--currIndex;
if(currIndex<=-1){ 
    // 当处于第一首时,点击上一首,播放索引置为最后一首
currIndex = len-1;
}
}
if( flag == 0 ){ 

playPauseBtn.attr('class','btn play-pause icon-jiediankaishi iconfont'); // 显示播放图标
}else{ 

musicImgs.removeClass('buffering');   
playPauseBtn.attr('class','btn play-pause icon-zanting iconfont') // 显示暂停图标
}
seekBar.width(0);           // 重置播放进度条为0
time.removeClass('active');
tProgress.text('00:00');    // 播放时间重置
totalTime.text('00:00');    // 总时间重置
// 获取当前索引的:歌曲名,歌手名,图片,歌曲链接等信息
currMusic = musicNameData[currIndex];
currArtist = artistNameData[currIndex];
currImg = musicImgsData[currIndex];
audio.src = musicUrls[currIndex];
nTime = 0;
bTime = new Date();
bTime = bTime.getTime();
// 如果点击的是上一首/下一首 则设置开始播放,添加相关类名,重新开启定时器
if(flag != 0){ 

audio.play();
playerContent1.addClass('active');
musicImgs.addClass('active');
clearInterval(buffInterval);
checkBuffering();
}
// 将歌手名,歌曲名,图片链接,设置到元素上
artistName.text(currArtist);
musicName.text(currMusic);
musicImgs.find('.img').css({ 
'background':'url('+currImg+')'})
}
// 初始化函数
function initPlayer() { 

audio = new Audio();  // 创建Audio对象
selectTrack(0);       // 初始化第一首歌曲的相关信息
audio.loop = false;   // 取消歌曲的循环播放功能
playPauseBtn.on('click',playPause); // 点击播放/暂停 按钮,触发playPause函数
// 进度条 移入/移出/点击 动作触发相应函数
sArea.mousemove(function(event){ 
 showHover(event); }); 
sArea.mouseout(hideHover);
sArea.on('click',playFromClickedPos);
// 实时更新播放时间
$(audio).on('timeupdate',updateCurrTime); 
// 上下首切换
playPrevBtn.on('click',function(){ 
 selectTrack(-1);} );
playNextBtn.on('click',function(){ 
 selectTrack(1);});
}
// 调用初始化函数
initPlayer();
});

代码太多了,我就不一个个拆开来了。注释已经写了很多了。
你们加油!
放上github源代码地址:https://github.com/zoyoy1203/musicPlayer
试了下,百度网盘放不了 (¬_¬)ノ
HTML简单音乐播放器「建议收藏」HTML简单音乐播放器「建议收藏」

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/148287.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)
blank

相关推荐

  • ssm整合思路与配置详解_接口整合配置

    ssm整合思路与配置详解_接口整合配置swagger2于17年停止维护,现在最新的版本为17年发布的Swagger3(OpenApi3)

    2022年10月30日
  • tcp 校验和_tcp如何保证有序

    tcp 校验和_tcp如何保证有序1.tcp校验和接收方在接收数据时检验数据包在传输过程中是否改变的验证方式发送方将数据体取反码,检验和也取反码相加,高于4bit的和低于4bit的相加,得到的就是校验和,保存在tcp头的校验和字段,接收方将数据取反码,校验和取反码,相加为1111则数据包没有异常,否则丢弃数据包。参考此文2.为什么Internet协议:IP,ICMP,IGMP,UDP,TCP收到有…

    2022年10月29日
  • USB转232和485的区别

    1串口串口,即串行通信接口,与之相对应的另一种接口叫并口,并行接口。两者的区别是,传输一个字节(8个位)的数据时,串口是将8个位排好队,逐个地在1条连接线上传输,而并口则将8个位一字排开,分别在8条连接线上同时传输,也就是进行数据传输的接口串口是一种物理接口形式,(硬件)通常指COM接口,当然这些接口有着很多标准接口标准:串口通信的接口标准有很多,而我们所了解的RS-23…

  • characterEncodingFilter作用[通俗易懂]

    characterEncodingFilter作用[通俗易懂]characterEncoding表示编码方式,enabled表示是否启用编码,分别从初始化参数中取值。web.xml中的配置如下:如果使用的字符编码Filter、request中取出的字符可能是

  • 常用的Java工具,16个

    常用的Java工具,16个在Java中,工具类定义了一组公共方法,这篇文章将介绍Java中使用最频繁及最通用的Java工具类。以下工具类、方法按使用流行度排名,参考数据来源于Github上随机选取的5万个开源项目源码。一.org.apache.commons.io.IOUtilscloseQuietly:关闭一个IO流、socket、或者selector且不抛出异常,通常放在finally块toString:转换IO流、Uri、byte[]为Stringcopy:IO流数据复制,从输入流写到输出流中,最大支持2GB

  • protel99se精彩教程[通俗易懂]

    protel99se精彩教程[通俗易懂]网上盛行的那个protel99se精彩教程中,PCB通用封装在哪?

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号