javascript - 使用 Brad Birdsall 的 Swipe 2.0 在纯 JavaScript 中的 iOS 导航栏

标签 javascript ios canvas navigationbar

在纯 javascript 中,我想要一个带有水平和垂直滚动页面的导航栏。如果页面被“温和地”处理,我的代码似乎可以工作。但是,页面很容易变得错位,尤其是将页面向下拖动到橡皮筋区域并同时滚动时。

通过隐藏页面(使用 style.display='none')并重新显示页面或双击带有滚动条的页面,页面会自动重新对齐。

我已尽最大努力尝试模拟双击,但我的模拟双击没有与手动双击相同的效果。 (但我对 javascript 还很陌生,所以有可能我在那里遗漏了一些东西,或者可能是某个事件而不是 double 来纠正问题。)

我尝试在此处发布我的代码,但遇到了 30000 个字符的限制,我已将我的代码减少到 32K(包括 Brad 的 Swipe 2.0),因此我删除了 Swipe 2.0(可在 https://github.com/bradbirdsall/Swipe 获得)。我在我的网站上也发布了代码,包括 Swipe 2.0,地址为 http://www.datewise.com/testa.html .我认为在 jsfiddle 上发布代码没有意义,因为问题只能在 iPhone 上观察到(据我所知,iPhone 不会在 jsfiddle 上执行代码)。

据我所知,它必须在 iPhone 上运行才能发现问题 - 这是我一直在测试的唯一东西。要查看问题,请将手机置于纵向模式。在第一个屏幕上,选择一种颜色 - 例如,黄色,它将显示一个黄色页面 - 左右滚动并看到导航栏停留。小心地垂直向下滚动并返回到导航栏。到目前为止,一切都应该工作正常。

产生问题的一种简单方法是旋转手机横向,然后再旋转回纵向。虽然我可以在示例代码中处理旋转,但我不允许轻松可靠地显示问题。您也可以通过对 Angular 滚动进入此问题模式(这就是为什么我指定“小心地垂直滚动”。)然后,再次左右滚动。最后,双击导航栏下方,页面将自行修复。

要查看通过隐藏和重新显示解决的问题,请使用导航屏幕中的尖框,这只会更改 style.display 设置。然后,使用组合框导航回同一页面的彩色页面(同样只是更改 style.display 设置)。

我希望有一个解决方案似乎是通过在匿名函数“end: function(event)”的末尾模拟我的两个手动解决方案之一来说明双击或 style.display 的工作方式。您可以通过查找评论“已添加以尝试修复对齐问题”来查看我尝试的解决方案。

这是我的代码的副本:

<!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Transitional//EN' 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd'>
<html xmlns='http://www.w3.org/1999/xhtml'>
<head>

<title>AppTitle</title>
<style type='text/css'>
html, body, div, form {
  margin:0;
  padding:0;
  border:0;
  outline:0;
  font-size:100%;
  vertical-align:baseline;
  background:transparent;
}
.swipe {
  overflow: hidden;
  visibility: hidden;
  position: relative;
}
.swipe-wrap {
  overflow: hidden;
  position: relative;
}
.swipe-wrap > div {
  float:left;
  width:100%;
  position: relative;
}
</style>

<meta http-equiv='Content-Type' content='text/html; charset=utf-8' />
<meta name='viewport' content='width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no, target-densityDpi=device-dpi' />

<form id='form0' style='position:relative; z-index:100' ontouchmove='BlockMove(event);'>
   <div id='nav' style='z-index:100; position:fixed; width:"320px"; height="44px"; background:black;'>
      <canvas id='navCanvas' width='320px' height='44px'>
         Your browser does not support HTML5 Canvas.
      </canvas>
   </div>
</form>

<form id='form1' style='position:relative; z-index:1'>
    <div id='mySwipe' class='swipe'>
        <div class='swipe-wrap'>
            <div>
                <canvas id='canvas1' width='50' height='50'>
                    Your browser does not support HTML5 Canvas.
                </canvas>
            </div>
            <div>
                <canvas id='canvas2' width='50' height='50'>
                    Your browser does not support HTML5 Canvas.
                </canvas>
            </div>
            <div>
                <canvas id='canvas3' width='50' height='50'>
                    Your browser does not support HTML5 Canvas.
                </canvas>
            </div>

        </div>
    </div>
</form>
<form id='form3' style='position:relative' ontouchmove='BlockMove(event);'>
   <div id='homeForm'; style='position:relative; height:100%; width:100%; z-index:1' ontouchmove='BlockMove(event);'>
      <div id='d1' style='position:absolute; top:0; left:0; z-index:1'>
         <canvas id='homeCanvas' width='400' height='300' style='border:1px solid #d3d3d3'>
            Your browser does not support the HTML5 canvas tag.
         </canvas>
      </div>
      <div id='dHomeColorList' style='position:absolute; z-index:2'>
         <select name='homeColorList' id='homeColorList' onChange='homeColorChange()'
             style="font:'20px Arial, Helvetica, sans-serif'; width:140px">
            <option value='Please select'>Please select</option>
            <option value='0'>Yellow</option>
            <option value='1'>Pink</option>
            <option value='2'>Blue</option>
         </select>
      </div>
   </div>
</form>

</head>

<body onload='canvasApp()' onunload='closeMe()'>

<script type='text/javascript'>
   var eventHandlerNavBarLaunched = false;
   var fromSchedule='home', saveDisease, saveRequest;
   var FontGrp_Headers='bold 18px Arial, Helvetica, sans-serif';
   var FontGrp_SmallHeaders='bold 14px Arial, Helvetica, sans-serif';
   var currDisplayType='splash';
   var arrowLeft=0, arrowTop=0, arrowRight=0, arrowBottom=0;

function BlockMove(event) {
   event.preventDefault();
}

function apparentWidth() {
  return screen.availWidth;
}

function apparentHeight() {
   var rtnVal=screen.height;
   if (rtnVal <= 480) {
       rtnVal=480;
   } else if (rtnVal <= 568) {
      rtnVal=568;
   }
  return rtnVal;
}

function closeMe() {
   if (eventHandlerNavBarLaunched) {
      var navCanvas = document.getElementById('navCanvas');
      if (navCanvas.removeEventListener)
         navCanvas.removeEventListener('mouseup', navBarMouseUp, false);
      else if (navCanvas.detachEvent)
         navCanvas.detachEvent('on' + 'mouseup', navBarMouseUp);
      eventHandlerNavBarLaunched=false;
   }       
}

function placeColoredTxt(ctx, fontGroup, left, right, top, bottom, text1, color) {
   var currWidth, currHeight, x, y;
   currWidth=right-left;
   currHeight=bottom-top;
   ctx.font=fontGroup;
   ctx.textAlign='center';
   ctx.fillStyle=color;
   x=Math.floor(left+currWidth/2);
   y=Math.floor(4+top+currHeight/2);
   ctx.fillText(text1,x,y);
}

function canvasApp () {

   var theCanvas, ctx, myCanvas;
   var pageNo;
   var availableWidth, availableHeight;
   var availableWidth;
   var availableHeight;
   var mouseUp={};

   for (j=0; j<=3; j++) {
      drawScreen(j);
   } 

   window.mySwipe = Swipe(document.getElementById('mySwipe'));
   if (!eventHandlerNavBarLaunched) {
      var navCanvas = document.getElementById('navCanvas');
      addEvent(navCanvas, 'mouseup', navBarMouseUp);
      addEvent(navCanvas, 'unload', closeMe);
      eventHandlerNavBarLaunched = true;
   }

   showArea('home', '');

   if (typeof String.prototype.trim != 'function') { // detect native implementation
       String.prototype.trim = function () {
          return this.replace(/^\s+/, '').replace(/\s+$/, '');
      };
   }

   //---------------------------------------------------------------
   // canvasApp() functions
   function addEvent(target, eventType, eventHandler) {
      if (target.addEventListener)
         target.addEventListener(eventType, eventHandler, false);
      else if (target.attachEvent)
         target.attachEvent('on' + eventType, eventHandler);
   }

   function windowToCanvas(x, y, cnvs)
   {
      var bbox = cnvs.getBoundingClientRect();
      return {x:Math.floor(x-bbox.left * (cnvs.width / bbox.width)),
              y:Math.floor(y-bbox.top * (cnvs.height / bbox.height))
             }
   };

   function navBarMouseUp(e) {
      var loc=windowToCanvas(e.clientY, e.clientX, document.getElementById('navCanvas'));
      e.preventDefault();
      procMouseUp(loc);
   }

   function getMyCanvas(pageNo) {
      switch (pageNo) {
         case 0:
            theCanvas = document.getElementById('homeCanvas');
            ctx = theCanvas.getContext('2d');
            break;
         case 1:    
            theCanvas = document.getElementById('canvas1');
            ctx = theCanvas.getContext('2d');
            break;
         case 2:    
            theCanvas = document.getElementById('canvas2');
            ctx = theCanvas.getContext('2d');
            break;
         case 3:    
            theCanvas = document.getElementById('canvas3');
            ctx = theCanvas.getContext('2d');
            break;
      }
      return ctx;
   }

   function drawScreen(i) {
      var j, fillPage=false;
      pageNo = i;
      ctx = getMyCanvas(pageNo);

      availableWidth = apparentWidth();
      availableHeight= apparentHeight();

      if (i>0 && availableHeight<770) {
         availableHeight=770;
      }

      ctx.canvas.width=availableWidth;
      ctx.canvas.height=availableHeight;

      //ctx.canvas.style.marginLeft='-8px';
      ctx.canvas.style.marginLeft='0px';
      ctx.canvas.style.marginTop='-8px';
      ctx.canvas.style.padding='0 0 0 0';
      ctx.canvas.style.border ='0 0 0 0';
      ctx.canvas.width=availableWidth;
      ctx.canvas.height=availableHeight;

      switch (pageNo) {
         case 0:
            calcHomePage(ctx, availableHeight, availableWidth);
            break;
         case 1:
            ctx.fillStyle='#ff0';

            fillPage=true;

            break;
         case 2:
            ctx.fillStyle='#f0f';

            fillPage=true;

            break;
         case 3:
            ctx.fillStyle='#0ff';

            fillPage=true;

            break;         
      }
      if (fillPage) {
         ctx.rect(0,0,ctx.canvas.width,ctx.canvas.height);
         ctx.fill();

         ctx.fillStyle='#666';
         ctx.font = FontGrp_Headers;
         ctx.textAlign='center';
         for (j=100; j<availableHeight; j+=100) {
            ctx.fillText(j, availableWidth/2, j);
         }
      }
   }
}

function procMouseUp(loc) {
   var pressedButton = '', x, y;
   x = Math.round(loc.x, 0);
   y = Math.round(loc.y, 0);
   if (x>arrowTop & x<arrowBottom & y>arrowLeft & y<arrowRight) {
      switch(fromSchedule) {
         case 'ages':
         case 'Ages':
            switchArea('ages');
            drawNavigation('Home', 'Color Specific');
            break;
         case 'home':
         case 'Home':
            switchArea('home');
            break;
      }
   }
} 

function drawNavigation(fromScrn, currTitle) { // Draw the navigation bar
   var navElement = document.getElementById('navCanvas');
   var navCtx = navElement.getContext('2d');
   var grd;
   var btnLeft=45, btnTop=18, btnHeight=28, btnWidth=50, cornerRadius=5;
   var font = FontGrp_Headers;

   navElement.style.textAlign='center';
   navElement.style.alignmentBaseline='middle';
   navElement.style.zIndex=100;
   navElement.style.display='inline';
   availableWidth = apparentWidth();
   navCtx.canvas.width=availableWidth;
   width = availableWidth-60;

   grd = navCtx.createLinearGradient(0, 0, 0, 44);
   grd.addColorStop(0, '#000');
   grd.addColorStop(1, '#000');
   navCtx.fillStyle = grd;
   navCtx.fill();

   if (fromScrn.length > 0) {
      drawArrow(navCtx, fromScrn, btnTop, btnLeft, btnHeight, btnWidth, cornerRadius);
   }
   placeColoredTxt(navCtx, FontGrp_Headers, 100, availableWidth-20, 1, 44, currTitle, '#fff');
   fromSchedule = fromScrn;
}

function calcHomePage(ctx, availableHeight, availableWidth) {  // Calculate the appearance of the home page
   var child = document.getElementById('dHomeColorList');
   var left=140;

   var grd=ctx.createLinearGradient(0,0,ctx.canvas.height,ctx.canvas.width);
   grd.addColorStop(0,'#58a2e2');
   grd.addColorStop(1,'#1863c0');
   ctx.fillStyle=grd;
   ctx.rect(0,0,ctx.canvas.width,ctx.canvas.height);
   ctx.fill();

   ctx.fillStyle='#fff';
   ctx.fillRect(25,95,availableWidth - 50,availableHeight - 95-2);

   sectionTop = 130;
   line = sectionTop;
   spacing = 44;
   ctx.fillStyle='#000';
   ctx.font = FontGrp_Headers;
   ctx.textAlign='center';
   ctx.fillText('Color Schedules', availableWidth/2, line);
   line += (2/3) * spacing;
   ctx.textAlign='right';
   width = ctx.measureText('Colors').width-20;
   ctx.fillStyle ='#CCC';   

   ctx.fillText('Colors', 50+width, line);
   child.style.top = line-26 + 'px';
   child.style.left= left + 'px';
   line += spacing;   
}

function homeColorChange() {
   var child = document.getElementById('homeColorList');

   if (child.selectedIndex > 0) {
      showArea('ages', 'home');
      mySwipe.slide(child.value, 20); // Open Brad Birdsall's slider at page (child.value)
   }
   child.selectedIndex=0;
}

function switchArea(areaName) {
   var homePage = document.getElementById('homeForm');
   var navPage = document.getElementById('nav');
   var sliderPage = document.getElementById('mySwipe');

   switch (areaName) {
      case 'home':
         homePage.style.display='inline';
         navPage.style.display='none';
         sliderPage.style.display='none';
         window.scrollTo(0,0);
         break;
      case 'ages':
         homePage.style.display='none';
         navPage.style.display='inline';
         sliderPage.style.display='inline';
         window.scrollTo(0,0);
         break;
    }
} 

function showArea(areaName, txtTitle) {
   var currCtx, grd;

   switch (areaName) {
      case 'home':
         switchArea(areaName);
         break;
      case 'ages':
         switchArea(areaName);
         drawNavigation('Home', 'Color Specific');
         break;
      default:
         alert('Unrecognized command passed to showArea, areaName: [' + areadName + ']');
         break;
   }
}

function drawArrow(context, text, top, left, height, width, cornerRadius) {
   // Draw the pointed rectangle box on left side of the navigation bar
   var keyGradient = context.createLinearGradient(left, top, left, top + height);
   var drawingTop=top/2, drawingLeft=left/2;
   keyGradient.addColorStop(0,   'rgb(208, 208, 210)');
   keyGradient.addColorStop(1.0, 'rgb(162, 162, 166)');
   context.save();
   context.fillStyle=keyGradient;
   context.beginPath();
   context.moveTo(drawingLeft-(height/2), (height/2) + drawingTop);  //A
   context.lineTo(drawingLeft, height + drawingTop); //B

   if (cornerRadius>0) {
      context.lineTo(width + drawingLeft - cornerRadius, height + drawingTop); //C
      context.arcTo(width + drawingLeft, height + drawingTop, width + drawingLeft, height + drawingTop - cornerRadius, cornerRadius); //D
      context.lineTo(width + drawingLeft, drawingTop + cornerRadius); //E
      context.arcTo(width + drawingLeft, drawingTop, width + drawingLeft - cornerRadius, drawingTop, cornerRadius); //F
   } else {
      context.lineTo(width + drawingLeft, height + drawingTop); //CD
      context.lineTo(width + drawingLeft, drawingTop); //EF
   }
   context.lineTo(drawingLeft, drawingTop); //G
   context.closePath();
   context.stroke();
   context.fill();
   context.font=FontGrp_SmallHeaders;
   context.fillStyle='#fff';
   context.textAlign='center';
   context.fillText(text, left + (width)/2 - (height/4) - context.measureText(text).width/2, top + (height)/2 - context.measureText('M').width/2);
   context.restore();

   arrowTop=drawingTop;
   arrowLeft=(left/2)-(height/4);
   arrowBottom=drawingTop+height;
   arrowRight=arrowLeft+width;
}

/*
 *
 * Swipe 2.0
 *
 * Brad Birdsall
 * Copyright 2013, MIT License
 * <Get this code at https://github.com/bradbirdsall/Swipe>
 *
*/

</script>

</body>
</html>

这是我尝试放置双击模拟的 Swipe 2.0 的一部分:

   end: function(event) {

      // measure duration
      var duration = +new Date - start.time;

      // determine if slide attempt triggers next/prev slide
      var isValidSlide =
            Number(duration) < 250               // if slide duration is less than 250ms
            && Math.abs(delta.x) > 20            // and if slide amt is greater than 20px
            || Math.abs(delta.x) > width/2;      // or if slide amt is greater than half the width

      // determine if slide attempt is past start and end
      var isPastBounds =
            !index && delta.x > 0                            // if first slide and slide amt is greater than 0
            || index == slides.length - 1 && delta.x < 0;    // or if last slide and slide amt is less than 0

      // determine direction of swipe (true:right, false:left)
      var direction = delta.x < 0;

      // if not scrolling vertically
      if (!isScrolling) {

        if (isValidSlide && !isPastBounds) {

          if (direction) {

            move(index-1, -width, 0);
            move(index, slidePos[index]-width, speed);
            move(index+1, slidePos[index+1]-width, speed);
            index += 1;

          } else {

            move(index+1, width, 0);
            move(index, slidePos[index]+width, speed);
            move(index-1, slidePos[index-1]+width, speed);
            index += -1;

          }

          options.callback && options.callback(index, slides[index]);

        } else {

          move(index-1, -width, speed);
          move(index, 0, speed);
          move(index+1, width, speed);

        }

      }

      // kill touchmove and touchend event listeners until touchstart called again
      element.removeEventListener('touchmove', events, false)
      element.removeEventListener('touchend', events, false)

      //---------------------------------------------------------------
      // Added to try to fix alignment problem

       var obj = document.getElementById('form1');
       var clickEvt = document.createEvent('MouseEvents');
       clickEvt.initEvent("dblclick");
       obj.dispatchEvent(clickEvt);


      // End added code
      //---------------------------------------------------------------

    },

最佳答案

我解决了最初的问题 - 这是对 Swipe() 的一个非常简单的更改,与我之前提出的解决方案无关。有了这个修复,我可靠地产生问题的方式(将 iPhone 横向和向后旋转)总是会产生问题,这个修复总是可以纠正它,只需将页面向右或向左移动然后放开。

在 Swipe 的最底部是一些被注释掉的原型(prototype)。如果我将对 window.scrollTo() 的调用添加到在任何动画结束时调用的调用中并且出现问题,屏幕将捕捉到导航动画结束时的正确位置。具体来说,这是我的更改(取消注释 transitionEnd 函数并添加对 scrollTo() 的调用):

var elem = document.getElementById('mySwipe');
window.mySwipe = Swipe(elem, {
  // startSlide: 4,
  // auto: 3000,
  // continuous: true,
  // disableScroll: true,
  // stopPropagation: true,
  // callback: function(index, element) {},
   transitionEnd: function(index, element) {window.scrollTo(0, 0);}
});

这是一个完整的示例:http://www.datewise.com/testa1.html

关于javascript - 使用 Brad Birdsall 的 Swipe 2.0 在纯 JavaScript 中的 iOS 导航栏,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17646711/

相关文章:

javascript - 计算页面上不在此元素中的其他元素的(总)高度

javascript - 如何在nodejs服务器上使用tensorflow js?

ios - MKTileOverlay:如何重新加载特定图 block 或区域

JavaScript postMessage 和多个可传输对象

javascript - 淡入图像

javascript - JQuery 自动完成(城市/州) - 需要帮助使脚本更加健壮

javascript - 关闭浏览器标签的脚本

ios - 在新窗口中快速打开 URL

ios - 必须按同一按钮两次才能调用函数 Swift 4

javascript - JS如何在没有任何插件的情况下渲染音频波形?