带间隔的进度条

Progress bar with intervals

我正在尝试创建一个带有步骤和 play/pause 按钮的进度条。

我在创建 play/pause 按钮时遇到问题,但实际情况是加载进度条不应填充,只有在按下播放按钮后才会填充。

第二种我想不通的情况是进度条在运行时如果按下暂停按钮应该会在他当前所在的区间结束时停止。

例如,如果我们按下播放,如果在起点和第一个间隔之间按下暂停按钮,进度条开始填充,如果按下暂停按钮,它应该在第一个间隔结束时停止在第1个区间和第2个区间之间,应该继续填充到第2个区间结束等等

希望我说清楚了。

const checkpoints = [
  {
    perc: 25, 
    label: "25%\n<b>2018</b>"
  },
  {
    perc: 35, 
    label: "35%\n<b>2019</b>"
  },
  {
    perc: 45,
    label: "45%\n<b>2020</b>"
  },
  {
    perc: 55,
    label: "55%\n<b>2021</b>"
  },
  {
    perc: 100,
    label: "100%\n<b>2022</b>"
  }
];
const step = 1;
const timeInterval = 100;
const playLabel = 'PLAY';
const pauseLabel = 'PAUSE';

//on document ready..
$(document).ready(()=>{
  
  //shows checkpoints under the progressbar
  for(checkpoint of checkpoints){
    $('#rulers')
      .append(`<p class='ruler' style='width:${checkpoint.perc}%;'>${checkpoint.label}</p>`);
  }
        
  //attaches click event handler to #playpause button
  $('#playpause').on('click', (event)=>{ toggleButton( $(event.currentTarget) ) });
});

function toggleButton(playPauseButton){
  const status = $(playPauseButton).attr('data-status');  
  //if the button was in pause state (and having the Play label)
  if (status == "pausing"){        
    $(playPauseButton)        
      //toggles it to status 'playing'
      .attr('data-status', 'playing')
      //toggles it to "Pause" label
      .text(pauseLabel);    
    //begins incrementing the progressbar
    const intervals = checkpoints.map(cp => cp.perc);
    setProgressWithCheckpoints(intervals, step, timeInterval);
  }
  //if the button was in playing state (and having the Pause label)
  else if(status == 'playing'){
    $(playPauseButton)
      //toggles it to status 'pausing'
      .attr('data-status', 'pausing')
      //toggles it to "Play" label
      .text(playLabel);
    //if the progressbar is still running to complete its task,
    if( isStillRunning() === true ){
      //sets the playpause button as disabled so that you can't click it
      $(playPauseButton).prop('disabled', true);
    }
  }
}

//set the progressbar at perc
function setProgress(perc){    
  $(".progress .progress-bar")
    .css('width', `${perc}%`)
    .attr('aria-valuenow', perc)
  $(".progress .progress-bar span")
    .text(`${perc}%`);    
}

//get progressbar %
function getProgress(){
  const valueNow = $(".progress .progress-bar")
                    .attr('aria-valuenow');
  return parseInt(valueNow);
}

//return true/false if the progress is still running
function isStillRunning(){
  if ( $('#playpause').attr('data-stillrunning') == 'yes' )
    return true;
  return false;
}

//sets the state stillrunning to yes
function setStillRunning(){
  $('#playpause').attr('data-stillrunning', 'yes');
}

//sets the state stillrunning to no and enables the button (in case it was disabled)
function setNotStillRunning(){
  $('#playpause')
    .attr('data-stillrunning', 'no')
    .prop('disabled', false);
    
   if ( $('#playpause').attr('data-status') == 'playing' )
    toggleButton(  $('#playpause') );
}
.progress{  
  margin: 50px 20px 20px 0;
}

.progress{  
  display: flex;
  width: 100%;  
  height: 2rem;
  overflow: hidden;
  border: solid 1px lightgray;
  width: 100%;
}

.progress-bar{
  color: white;
  vertical-align: middle;
  font-weight: 600;  
  padding-top: 6px;
}

.progress-bar span{
  padding-left: 10px;
}

#rulers {
  position: relative;
  height: 3em;
  border-bottom: solid 1px lightgray;
}

#rulers .ruler{
  position: absolute;
  text-align: right;
  margin-top: 0;
  white-space: pre-line;
  border-right: solid 2px darkgray;
  padding-right: 4px;
  box-sizing: border-box;
}

#playpause {
  display: block;
  cursor: pointer;
  margin-top: 20px;
  padding: 2px 10px;
  font-size: 18px;
}

#playpause:disabled{
  cursor: not-allowed;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="progress">
  <div
    class="progress-bar"
    role="progressbar"
    aria-valuenow="0"
    aria-valuemin="0"
    aria-valuemax="100"
    style="width: 0%;background: green;">
    <span></span>
  </div>
</div>

<div id="rulers">
</div>

<button id="playpause" data-status="pausing">PLAY</button>

这是代码笔的 link:https://codepen.io/Wildfactor/pen/WNMwbEP

这是具有一些已定义检查点的进度条的实现。

定义的检查点保存每个检查点的百分比值及其在标尺中显示的标签。

按下播放按钮后,按钮标签切换为“暂停”,进度条将开始前进。如果点击暂停按钮,进度将前进到下一个检查点并停止。

如果进度到达100%,暂停按钮还没有被按下,进度会停止,按钮会恢复到暂停状态。

当进度为 运行 直到下一个检查点并且按下按钮暂停时,在进度条到达检查点之前无法按播放按钮。

const checkpoints = [
  {
    perc: 25, 
    label: "25%\n<b>2018</b>"
  },
  {
    perc: 35, 
    label: "35%\n<b>2019</b>"
  },
  {
    perc: 45,
    label: "45%\n<b>2020</b>"
  },
  {
    perc: 55,
    label: "55%\n<b>2021</b>"
  },
  {
    perc: 100,
    label: "100%\n<b>2022</b>"
  }
];
const step = 1;
const timeInterval = 100;
const playLabel = 'PLAY';
const pauseLabel = 'PAUSE';

//on document ready..
$(document).ready(()=>{
  
  //shows checkpoints under the progressbar
  for(checkpoint of checkpoints){
    $('#rulers')
      .append(`<p class='ruler' style='width:${checkpoint.perc}%;'>${checkpoint.label}</p>`);
  }
        
  //attaches click event handler to #playpause button
  $('#playpause').on('click', (event)=>{ toggleButton( $(event.currentTarget) ) });
});

function toggleButton(playPauseButton){
  const status = $(playPauseButton).attr('data-status');  
  //if the button was in pause state (and having the Play label)
  if (status == "pausing"){        
    $(playPauseButton)        
      //toggles it to status 'playing'
      .attr('data-status', 'playing')
      //toggles it to "Pause" label
      .text(pauseLabel);    
    //begins incrementing the progressbar
    const intervals = checkpoints.map(cp => cp.perc);
    setProgressWithCheckpoints(intervals, step, timeInterval);
  }
  //if the button was in playing state (and having the Pause label)
  else if(status == 'playing'){
    $(playPauseButton)
      //toggles it to status 'pausing'
      .attr('data-status', 'pausing')
      //toggles it to "Play" label
      .text(playLabel);
    //if the progressbar is still running to complete its task,
    if( isStillRunning() === true ){
      //sets the playpause button as disabled so that you can't click it
      $(playPauseButton).prop('disabled', true);
    }
  }
}

//set the progressbar at perc
function setProgress(perc){    
  $(".progress .progress-bar")
    .css('width', `${perc}%`)
    .attr('aria-valuenow', perc)
  $(".progress .progress-bar span")
    .text(`${perc}%`);    
}

//get progressbar %
function getProgress(){
  const valueNow = $(".progress .progress-bar")
                    .attr('aria-valuenow');
  return parseInt(valueNow);
}

//return true/false if the progress is still running
function isStillRunning(){
  if ( $('#playpause').attr('data-stillrunning') == 'yes' )
    return true;
  return false;
}

//sets the state stillrunning to yes
function setStillRunning(){
  $('#playpause').attr('data-stillrunning', 'yes');
}

//sets the state stillrunning to no and enables the button (in case it was disabled)
function setNotStillRunning(){
  $('#playpause')
    .attr('data-stillrunning', 'no')
    .prop('disabled', false);
    
   if ( $('#playpause').attr('data-status') == 'playing' )
    toggleButton(  $('#playpause') );
}

function setProgressWithCheckpoints(intervals, step, ms){
  
   setStillRunning();
  
  const valueNow = getProgress();     
  const nextIntervals =
    intervals.filter((interval) => interval > valueNow);      
  const nextInterval =
    (nextIntervals.length > 0) ? nextIntervals[0] : null;

  const newValue = Math.min(nextInterval, valueNow+step);    
  setProgress(newValue);

  const playpauseStatus = $('#playpause').attr('data-status');

  //if progress got to 100% OR
  //   nextInterval got reached while the play button is in pause state
  if(newValue >= 100 || (nextInterval == newValue && playpauseStatus == 'pausing')){
     //ends the calling and set the button as notStillRunning
     setNotStillRunning();
  }
  //else
  else
    //call again the progress function
    setTimeout(()=>{setProgressWithCheckpoints(intervals, step, ms)}, ms);  
}
.progress{  
  margin: 50px 20px 20px 0;
}

.progress{  
  display: flex;
  width: 100%;  
  height: 2rem;
  overflow: hidden;
  border: solid 1px lightgray;
  width: 100%;
}

.progress-bar{
  color: white;
  vertical-align: middle;
  font-weight: 600;  
  padding-top: 6px;
}

.progress-bar span{
  padding-left: 10px;
}

#rulers {
  position: relative;
  height: 3em;
  border-bottom: solid 1px lightgray;
}

#rulers .ruler{
  position: absolute;
  text-align: right;
  margin-top: 0;
  white-space: pre-line;
  border-right: solid 2px darkgray;
  padding-right: 4px;
  box-sizing: border-box;
}

#playpause {
  display: block;
  cursor: pointer;
  margin-top: 20px;
  padding: 2px 10px;
  font-size: 18px;
}

#playpause:disabled{
  cursor: not-allowed;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="progress">
  <div
    class="progress-bar"
    role="progressbar"
    aria-valuenow="0"
    aria-valuemin="0"
    aria-valuemax="100"
    style="width: 0%;background: green;">
    <span></span>
  </div>
</div>

<div id="rulers">
</div>

<button id="playpause" data-status="pausing">PLAY</button>