网络编程 
首页 > 网络编程 > 浏览文章

jQuery开发仿QQ版音乐播放器

(编辑:jimmy 日期: 2024/12/27 浏览:3 次 )

本文通过Html+CSS+jQuery开发仿QQ版的音乐播放器,是前端技术的综合应用,所用素材来源于网络,仅供学习分享使用,如有不足之处,还请指正。

涉及知识点

在本例中用到的知识点如下,按jQuery和CSS进行区分:

jQuery 是一个 JavaScript 库, 极大地简化了 JavaScript 编程,常见知识点如下:

  1. 通过标签获取jQuery对象:var $audio =$("audio");
  2. 通过选择符获取jQuery对象并设置文本内容:$(".music_progrss_time").text(timeStr);
  3. 通过选择符,标签名获取对象并获取第i个子元素:$(".song_lyric ul li").eq(index);
  4. 通过ajax异步获取数据并刷新页面:$.ajax({});
  5. 通过类选择符获取元素并进行隐藏或显示:$(this).find(".list_menu").stop().fadeIn(100);
  6. 通过委托动态设置单击事件,主要针对动态生成元素:$(".content_list").delegate(".list_check", "click", function() {});
  7. 通过addClass添加类,removeClass删除类,toggleClass切换类,hasClass是否包含类
  8. 获取与对象同级的兄弟节点:$musicList.siblings();
  9. 触发相关事件:$(".music_next").trigger("click");

CSS通过使用 CSS 我们可以大大提升网页开发的工作效率!本例使用知识点如下:

  1. 设置距离左边的距离:margin-left: 20px; 设置距离右边的距离:margin-right: 20px;
  2. 设置透明度:opacity: 0.6; 值[0,1]从透明到全不透明
  3. 设置背景图片:background: url(../img/player_logo.png) no-repeat 0 0;设置背景颜色和透明度:background: rgba(255,255,255,0.5);
  4. 设置li的样式:list-style: none;
  5. 设置显示样式为行内块:display: inline-block;
  6. 设置圆角:border-radius: 5px;
  7. 设置相对位置:position: relative;
  8. 背景图片的起始坐标:background-position: 0 -75px;

示例效果图及结构划分

本例的示例效果图及结构划分如下所示:

jQuery开发仿QQ版音乐播放器

Html核心代码

Header部分代码:主要用于显示logo和登录显示,如下所示:

<div class="header">
 <h1 class="logo">
 <a href="#" rel="external nofollow" ></a> --by Alan.hsiang
 </h1>
 <ul class="register">
 <li>登录</li>
 <li>设置</li>
 </ul>
</div>

中间区域部分:主要包括坐边的列表和右边的歌曲相关,如下所示:

 <div class="content">
 <div class="content_in">
  <div class="content_left">
  <div class="content_toolbar">
   <span><i></i>收藏</span>
   <span><i></i>添加到</span>
   <span><i></i>下载</span>
   <span><i></i>删除</span>
   <span><i></i>清空列表</span>
  </div>
  <div class="content_list">
   <ul>
   <li class="list_title">
    <div class="list_check"><i></i></div>
    <div class="list_number"></div>
    <div class="list_name">歌曲</div>
    <div class="list_singer">歌手</div>
    <div class="list_time">时长</div>
   </li>
   </ul>
  </div>
  </div>
  <div class="content_right">
  <div class="song_info">
   <a href="javascript:;" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" class="song_info_pic">
   <img src="/UploadFiles/2021-04-02/">

底部区域代码,主要用于播放相关内容,如下所示:

 <div class="footer">
 <div class="footer_in">
  <a href="javascript:;" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" class="music_pre" title="上一首"></a>
  <a href="javascript:;" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" class="music_play" title="播放"></a>
  <a href="javascript:;" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" class="music_next" title="下一首"></a>
  <div class="music_progress_info">
  <div class="music_progress_top">
   <span class="music_progrss_name"></span>
   <span class="music_progrss_time"></span>
  </div>
  <div class="music_progress_bar">
   <div class="music_progress_line">
   <div class="music_progress_dot"></div>
   </div>
  </div>
  </div>
  <a href="javascript:;" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" class="music_mode" title="播放模式"></a>
  <a href="javascript:;" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" class="music_fav" title="收藏"></a>
  <a href="javascript:;" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" class="music_down" title="下载"></a>
  <a href="javascript:;" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" class="music_comment" title="评论"></a>
  <a href="javascript:;" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" class="music_only" title="纯净模式"></a>
  <div class="music_voice">
  <a href="javascript:;" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" class="music_voice_info" title="声音"></a>
  <div class="music_voice_bar">
   <div class="music_voice_line">
   <div class="music_voice_dot"></div>
   </div>
  </div>
  </div>
 </div>
 </div>

jQuery功能性核心代码

在本示例中,从功能上区分,主要分为播放模块,进度条模块,歌词模块,各个模块相互独立,所以进行了适当的封装。

播放模块【Play】主要包括歌曲的初始化,播放与暂停,上一首,下一首,播放同步,跳转等功能,核心代码如下:

(function(window){
 function Player($audio){
 return new Player.prototype.init($audio);
 }
 Player.prototype={
 constructor :Player,
 musicList:[],
 currIndex:-1,
 $audio:null,
 audio:null,
 init:function($audio){
  this.$audio=$audio;//jQuey包装对象
  this.audio=$audio.get(0);//原生audio对象
 },
 play:function(index,music){
  console.log(index,music);
  console.log(this.$audio);
  if(this.currIndex==index){
  //同一首音乐,则是暂停,播放之间切换

  if(this.audio.paused){
   this.audio.play();
  }else{
   this.audio.pause();
  }
  }else{
  //不是同一首,重新播放
  this.$audio.attr('src',music.link_url);
  this.audio.play();
  this.currIndex=index;
  }
 },
 preIndex:function(){
  var index=this.currIndex-1;
  if(index<0){
  index=this.musicList.length-1;
  }
  return index;
 },
 nextIndex:function(){
  var index=this.currIndex+1;
  if(index>this.musicList.length-1){
  index=0;
  }
  return index;
 },
 del:function(index){
  this.musicList.splice(index,1);
  if(index<this.currIndex){
  this.currIndex=this.currIndex-1;
  }
 },
 musicTimeUpdate:function(callBack){
  //需要一个回调函数作为参数
  var that=this;
  //监听audio播放事件
  this.$audio.on("timeupdate",function(){
  var duration=that.audio.duration;
  var currentTime=that.audio.currentTime;
  var timeStr=that.formatTime(currentTime,duration);
  //参数是一个回调函数
  callBack(duration,currentTime,timeStr);
  });
 },
 //定义一个格式化时间的方法
 formatTime:function (currentTime,duration){
  //总时长
  var endMin=parseInt(duration/60);
  var endSec=parseInt(duration%60);
  endMin=endMin<10"0"+endMin:endMin;
  endSec=endSec<10"0"+endSec:endSec;
  //当前时长
  var curMin=parseInt(currentTime/60);
  var curSec=parseInt(currentTime%60);
  curMin=curMin<10"0"+curMin:curMin;
  curSec=curSec<10"0"+curSec:curSec;
  return curMin+":"+curSec+" / "+endMin+":"+endSec;
 },
 musicSeekTo:function(value){
  var that=this;
  var duration=that.audio.duration;
  if(isNaN(duration))return;
  if(isNaN(value))return;
  that.audio.currentTime=duration*value ;
 },
 musicVoiceSeekTo:function(value){
  if(isNaN(value))return;
  if(value<=0 || value>=1) return;
  this.audio.volume=value;
 }
 };
 Player.prototype.init.prototype=Player.prototype;
 window.Player=Player;
})(window);

歌词模块【lyric】,主要包括歌词的加载,解析,同步等功能,核心代码如下:

(function(window){
 function Lyric(path){
 return new Lyric.prototype.init(path);
 }
 Lyric.prototype={
 constructor :Lyric,
 times:[],
 lyrics:[],
 index:-1,
 init:function(path){
  this.path=path;
 },
 loadLyric:function(callBack){
  var that=this;
  $.ajax({
  type: "get",
  dataType:"text",
  contentType: "application/text; charset=utf-8",
  url: that.path,
  success: function(data) {
   //console.log(data);
   that.parseLyric(data);
   callBack();
  },
  error: function(e) {
   console.log(e);
  }
  });
 },
 parseLyric:function(data){
  var that=this;
  //初始化歌词和时间
  that.times=[];
  that.lyrics=[];
  that.index=-1;
  //
  var array=data.split("\n");
  //console.log(array);
  var timeReg=/\[(\d*:\d*\.\d*)\]/;
  $.each(array, function(index,ele) {
  //console.log(ele);
  //
  var lyc=ele.split("]")[1];
  if(lyc==null || lyc.length==1){
   return true;//排除空字符串
  }
  that.lyrics.push(lyc);

  var res=timeReg.exec(ele);
  //console.log(res);
  if(res==null){
   return true; //排除空时间
  }
  var timeStr=res[1];
  var res2=timeStr.split(":");
  var min=parseInt(res2[0]) *60;
  var sec=parseFloat(res2[1]) ;
  var res3=parseFloat( Number(min+sec).toFixed(2));
  //console.log(res3);
  that.times.push(res3);
  });
  console.log(that.times.length +" , "+ that.lyrics.length);
 },
 currentLyric:function(currentTime){
  //console.log(currentTime);
  if(currentTime>this.times[0]){
  this.index++;
  this.times.shift();//删除第一个元素,并返回剩余的数组
  }
  return this.index;
 }
 };
 Lyric.prototype.init.prototype=Lyric.prototype;
 window.Lyric=Lyric;
})(window);

进度条模块【Progress】主要包括:进度条的初始化,单击,拖动,回调等功能,核心代码如下:

(function(window){
 function Progress($progressBar,$progressLine,$progressDot){
 return new Progress.prototype.init($progressBar,$progressLine,$progressDot);
 }
 Progress.prototype={
 constructor :Progress,
 isMove:false,
 init:function($progressBar,$progressLine,$progressDot){
  this.$progressBar=$progressBar;
  this.$progressLine=$progressLine;
  this.$progressDot=$progressDot;
 },
 progressClick:function(callBack){
  //console.log(this.$progressBar);
  var that=this;//此时的this表示Progress
  this.$progressBar.click(function(event){
  //此时的this表示progrssBar点击的对象
  var normalLeft = $(this).offset().left;//控件默认距左边的位置
  var eventLeft = event.pageX;//当前鼠标点击的距左边的位置
  that.$progressLine.css("width",eventLeft-normalLeft);
  that.$progressDot.css("left",eventLeft-normalLeft);
  //计算进度条的比例
  var value=(eventLeft-normalLeft)/$(this).width();
  callBack(value);
  });
 },
 progressMove:function(callBack){
  var that=this;//此时的this表示Progress
  var normalLeft =-1;
  var eventLeft=-1;
  var barWidth=this.$progressBar.width();
  this.$progressBar.mousedown(function(){
  that.isMove=true;
  normalLeft = $(this).offset().left;//控件默认距左边的位置

  $(document).mousemove(function(){
   //此时的this表示progrssBar点击的对象
   eventLeft = event.pageX;//当前鼠标点击的距左边的位置
   var v=eventLeft-normalLeft;
   if(v>=0 && v<=barWidth){
   //判断值的有效范围再赋值
   that.$progressLine.css("width",eventLeft-normalLeft);
   that.$progressDot.css("left",eventLeft-normalLeft);
   }
  });
  });
  $(document).mouseup(function(){
  $(document).off("mousemove");
  that.isMove=false;
  //计算进度条的比例
  var value=(eventLeft-normalLeft)/that.$progressBar.width();
  //鼠标抬起时触发,防止音乐断断续续
  callBack(value);
  });
 },
 setProgress:function(value){
  if(this.isMove)return;
  if(value<0 || value>100){
  return;
  }
  this.$progressLine.css("width",value+"%");
  this.$progressDot.css("left",value+"%");
 }
 };
 Progress.prototype.init.prototype=Progress.prototype;
 window.Progress=Progress;
})(window);

加载流程,包括初始化歌曲列表,歌词信息,注册事件,初始化进度条等功能,本例中的歌曲列表和歌词信息,均是通过ajax从本地文件中获取,核心代码如下:

$(function() {
 var $audio =$("audio");
 var player=new Player($audio);
 var progress=null;
 var voiceProgress=null;
 var lyric=null;
 //1.加载音乐
 getPlayerList();
 //2.注册事件
 initEvent();
 //3.初始化进度条,包括声音
 initProgress();

 //音乐播放同步
 player.musicTimeUpdate(function(duration,currentTime,timeStr){
 //同步时间
 $(".music_progrss_time").text(timeStr);
 //同步进度条
 var value=currentTime/duration *100;
 progress.setProgress(value);
 //实现歌词同步
 var oldIndex=lyric.index;
 var index=lyric.currentLyric(currentTime);
 if(oldIndex==index)return;
 var item=$(".song_lyric ul li").eq(index);
 item.addClass("cur");
 item.siblings().removeClass("cur");
 if(index<0) return;
 $(".song_lyric ul").css({
  marginTop:(-index+2)*40
 });
 })

 //获取列表函数
 function getPlayerList() {
 $.ajax({
  type: "get",
  url: "music_list.json",
  success: function(data) {
  //player.musicList=data;
  //console.log(data);
  var musicList = $(".content_list ul");
  $.each(data, function(index, ele) {
   var item = createMusicItem(index, ele);
   musicList.append(item);
  });
  //默认初始化第一首歌曲信息
  initMusicInfo(data[0]);

  //初始化歌词信息
  initMusicLyric(data[0]);
  },
  error: function(e) {
  console.log(e);
  }
 });
 }
 //定义一个方法,创建一条音乐
 function createMusicItem(index, music) {
 var $item = $("<li class=\"list_music\">\n" +
  "<div class=\"list_check\">\n" +
  "<i></i>\n" +
  "</div>\n" +
  "<div class=\"list_number\">\n" +
  (index + 1) +
  "</div>\n" +
  "<div class=\"list_name\">\n" +
  music.name +
  "<div class=\"list_menu\">\n" +
  "<a href=\"javascript:;\" title=\"播放\" class=\"list_menu_play\"></a>\n" +
  "<a href=\"javascript:\;\" title=\"添加\"></a>\n" +
  "<a href=\"javascript:;\" title=\"下载\"></a>\n" +
  "<a href=\"javascript:;\" title=\"分享\"></a>\n" +
  "</div>\n" +
  "</div>\n" +
  "<div class=\"list_singer\">\n" +
  music.singer +
  "</div>\n" +
  "<div class=\"list_time\">\n" +
  "<span>\n" +
  music.time +
  "</span>\n" +
  "<a href=\"javascript:;\" title=\"删除\" class=\"list_menu_del\"></a>\n" +
  "</div>\n" +
  "</li>");
 $item.get(0).index=index;
 $item.get(0).music=music;
 return $item;
 }

 //初始化音乐信息
 function initMusicInfo(music){
 //获取元素
 var $musicImg=$(".song_info_pic img");
 var $musicName=$(".song_info_name a");
 var $musicSinger=$(".song_info_singer a");
 var $musicAlbum=$(".song_info_album a");
 var $musicTopName=$(".music_progrss_name");
 var $musicTopTime=$(".music_progrss_time");
 var $musicBg=$(".mask_bg");
 //赋值
 $musicImg.attr("src",music.cover);
 $musicName.text(music.name);
 $musicSinger.text(music.singer);
 $musicAlbum.text(music.album);
 $musicTopName.text(music.name+" / "+ music.singer);
 $musicTopTime.text("00:00 / "+music.time);
 $musicBg.css("background","url('"+music.cover+"') no-repeat 0 0;");

 }

 //初始化歌词信息
 function initMusicLyric(music){
 lyric=new Lyric(music.link_lrc);
 var lyricContainer=$(".song_lyric ul");
 //清空信息
 lyricContainer.html("");
 //加载歌词
 lyric.loadLyric(function(){
  //加载完成后处理函数
  $.each(lyric.lyrics,function(index,ele){
  var item=$("<li>"+ele+"</li>");
  lyricContainer.append(item);
  });
 });
 }
 //注册事件
 function initEvent() {
 //监听歌曲的移入移出事件
 //通过委托动态监听事件
 $(".content_list").delegate(".list_music", "mouseover", function() {
  //移入事件:1.显示子菜单 2. 隐藏时长 ,显示删除按钮
  $(this).find(".list_menu").stop().fadeIn(100);
  $(this).find(".list_time a").stop().fadeIn(100);
  $(this).find(".list_time span").stop().fadeOut(100);
  //
  $(this).find(".list_name").addClass("list_music_hover");
 });
 $(".content_list").delegate(".list_music", "mouseleave", function() {
  //移出事件:1.隐藏子菜单 2. 显示时长 ,隐藏删除按钮
  $(this).find(".list_menu").stop().fadeOut(100);
  $(this).find(".list_time a").stop().fadeOut(100);
  $(this).find(".list_time span").stop().fadeIn(100);
  $(this).find(".list_name").removeClass("list_music_hover");
 });

 //以下绑定事件只针对静态语句
 // $(".list_music").hover(function(){
 // //移入事件:1.显示子菜单 2. 隐藏时长 ,显示删除按钮
 // $(this).find(".list_menu").stop().fadeIn(100);
 // $(this).find(".list_time a").stop().fadeIn(100);
 // $(this).find(".list_time span").stop().fadeOut(100);
 // },function(){
 // //移出事件:1.隐藏子菜单 2. 显示时长 ,隐藏删除按钮
 // $(this).find(".list_menu").stop().fadeOut(100);
 // $(this).find(".list_time a").stop().fadeOut(100);
 // $(this).find(".list_time span").stop().fadeIn(100);
 // });

 $(".content_list").delegate(".list_check", "click", function() {
  $(this).toggleClass("list_checked");
  var musicList = $(this).parents(".list_music");
  if($(this).hasClass("list_checked")) {
  musicList.find("div").css("color", "#fff");
  musicList.siblings().find("div").css("color", "rgba(255,255,255,0.5)");
  } else {
  musicList.find("div").css("color", "rgba(255,255,255,0.5)");
  }
 });
 // //监听复选框的点击事件
 // $(".list_check").click(function(){
 // $(this).toggleClass("list_checked");
 // });

 //监听点击播放事件
 $(".content_list").delegate(".list_menu_play", "click", function() {
  //切换播放图标
  $(this).toggleClass("list_menu_play2");
  //还原其他项的图标
  var $musicList = $(this).parents(".list_music");

//  console.log($musicList.get(0).index);
//  console.log($musicList.get(0).music);

  $musicList.siblings().find(".list_menu_play").removeClass("list_menu_play2");
  //底部图标同步
  if($(this).hasClass("list_menu_play2")) {
  $(".music_play").addClass("music_pause");
  $musicList.find("div").css("color", "#fff");
  $musicList.siblings().find("div").css("color", "rgba(255,255,255,0.5)");
  } else {
  $(".music_play").removeClass("music_pause");
  $musicList.find("div").css("color", "rgba(255,255,255,0.5)");
  }
  $musicList.find(".list_number").toggleClass("list_number_play");
  $musicList.siblings().find(".list_number").removeClass("list_number_play");
  //播放
  player.play($musicList.get(0).index,$musicList.get(0).music);
  //
  initMusicInfo($musicList.get(0).music);
  //同步歌词
  initMusicLyric($musicList.get(0).music);
 });

 //监听删除事件
 $(".content_list").delegate(".list_menu_del", "click", function() {
  var $item=$(this).parents(".list_music");
  $item.remove();
  player.del($item.get(0).index);
  if($item.get(0).index==player.currIndex){
  //如果删除的是当前播放的歌曲,则自动播放下一首
  $(".music_next").trigger("click");
  }
  //修改序号
  $(".list_music").each(function(index,ele){
  ele.index=index;
  $(ele).find(".list_number").text(index+1);
  });
 });
 //监听底部按钮
 //播放
 $(".music_play").click(function(){
  //判断是否有播放过音乐
  if(player.currIndex==-1){
  //表示没有播放过
  $(".list_music").eq(0).find(".list_menu_play").trigger("click");

  }else{
  //表示之前有播放过
  $(".list_music").eq(player.currIndex).find(".list_menu_play").trigger("click");
  }
 });
 //前一首
 $(".music_pre").click(function(){
  $(".list_music").eq(player.preIndex()).find(".list_menu_play").trigger("click");
 });
 //下一首
 $(".music_next").click(function(){
  $(".list_music").eq(player.nextIndex()).find(".list_menu_play").trigger("click");
 });
 //声音事件
 $(".music_voice_info").click(function(){
  //图标切换
  $(this).toggleClass("music_voice_info2");
  if($(this).hasClass("music_voice_info2")){
  //无声音
  player.musicVoiceSeekTo(0);
  }else{
  //有声音
  player.musicVoiceSeekTo(1);
  }
 });
 }
 //初始化进度条
 function initProgress(){
 //进度条
 var $progressBar=$(".music_progress_bar");
 var $progressLine=$(".music_progress_line");
 var $progressDot=$(".music_progress_dot");
 progress=new Progress($progressBar,$progressLine,$progressDot);
 progress.progressClick(function(value){
  console.log("进度点0001");
  player.musicSeekTo(value);
 });
 progress.progressMove(function(value){
  player.musicSeekTo(value);
 });
 //声音条
 var $musicVoiceBar=$(".music_voice_bar");
 var $musicVoiceLine=$(".music_voice_line");
 var $musicVoiceDot=$(".music_voice_dot");
 voiceProgress=new Progress($musicVoiceBar,$musicVoiceLine,$musicVoiceDot);
 voiceProgress.progressClick(function(value){
  console.log("声音点0001");
  player.musicVoiceSeekTo(value);
 });
 voiceProgress.progressMove(function(value){
  player.musicVoiceSeekTo(value);
 });
 }

});

如果歌曲发生改变,则背景图也跟着改变,如下所示:

jQuery开发仿QQ版音乐播放器

源码链接

以上就是jQuery开发仿QQ版音乐播放器的详细内容,更多关于jQuery开发音乐播放器的资料请关注其它相关文章!

上一篇:详解Vue之事件处理
下一篇:Element图表初始大小及窗口自适应实现