在纯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上运行才能看到问题-这是我一直在测试的唯一内容。要查看问题,请以纵向模式握住手机。在第一个屏幕上,选择一种颜色-例如,黄色,它将显示一个黄页-向左和向右滚动,并查看导航栏。小心地,精确地垂直向下滚动并返回导航栏。到目前为止,一切应该正常。
解决问题的一种简单方法是旋转手机横向,然后再回到纵向。虽然我可以处理示例代码中的旋转问题,但我并没有允许轻松可靠地显示问题。您也可以通过对角滚动来进入此问题模式(这就是为什么我指定要“小心地垂直垂直滚动”。)然后,再次左右滚动。最后,双击导航栏下的页面,页面将自动修复。
要查看隐藏并重新显示的问题已解决,请在导航屏幕中使用尖头框,这只会更改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的最底部,有一些注释掉的原型。如果我在任何动画结束时都添加了对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