为什么在此处调用keyup处理程序,我可以阻止它吗?

时间:2015-04-28 15:15:22

标签: javascript jquery html

考虑以下HTML5 + Javascript:

$(function() {	
    $('#edit').hide();
	
	$('#value')
		.css('cursor', 'pointer')
		.click(function() {
			$('#edit').show();
			$('#edit input').focus();
			$('#value').hide();
		});
	
	$('#edit input')
		.keyup(function(e) {
			if (e.keyCode == 13) {  // <enter>
				$('#value').show();
				$('#edit').hide();
			}
		});
  });
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="value">
	<a href="#">hello</a>
</div>
<div id="edit">
	<input type="text" value="hello" />
</div>

最初,所有这一切都是为了捕获文本hello上的点击事件,用输入框替换文本。当用户点击 Enter 时,新文本将通过AJAX保存到服务器,输入框再次替换为文本。

现在我添加了a标记,以便通过 Tab + 输入而不是仅使用鼠标进行导航(可访问性; yay!),但我发现,当这样做时,对focus()的调用会神奇地触发keyup()事件。 (我知道这一点,因为注释掉对focus()的调用会导致所需的行为。)

结果是标签和输入文本打开但随后立即关闭input框,就用户而言,根本没有发生任何事情。

为什么input的{​​{1}}处理程序是由完全不相关的元素上的keyup事件触发的?我怎样才能阻止这种情况发生?

工作方案

  1. 点击click
  2. hello消失了;文本框出现,里面有插入符号
  3. Enter
  4. 文本框消失; hello重新出现
  5. 破碎的场景

    1. 把重点放在文件
    2. Tab 直到hello成为焦点
    3. Enter
    4. hello消失了;文本框出现,里面有插入符号
    5. 文本框消失; hello再次出现......在我有机会做任何事之前。

6 个答案:

答案 0 :(得分:5)

所以问题是当你按下回车键时,释放密钥时会触发keyup事件。

这会创建如下所示的流程: 1,点击链接(按回车键) 2,链接隐藏 3,重点放在文本输入上(此时仍然按下回车键) 4,释放密钥(keyup事件被触发)

如果您将事件更改为keydown,则在链接上按Enter键不会与输入冲突,因为该输入没有焦点。

此外,在keyup事件中使用的keydown事件中使用相同的代码仍将执行完全相同的操作(即按Enter键和输入隐藏,链接显示)。

修改

https://jsfiddle.net/geyut7uv/

我能找到的唯一可靠的解决方案是创建一个&#34;拦截器&#34;变量&#34;禁用&#34; keydown事件。只有在点击了keydown时,我才将它附加到链接。这将通过输入检查keydown事件,如果用户按住该键,将立即触发该输入。

仅当触发输入键加密事件时才允许“阻止”&#34;变量传递。

理想情况下,我想删除所有全局范围变量,但我无法找到识别当前正在使用事件(keydown)的方法。

<div id="value">
    <a href="#">hello</a>
</div>
<div id="edit">
    <input type="text" value="hello" />
</div>

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script type="text/javascript">
$(function() {
    var enter_enabled = true;
    $('#edit').hide();

    $('#value')
    .css('cursor', 'pointer')
    .click(function() {
        $('#edit').show();
        $('#edit input').focus();
        $('#value').hide();
    }).keydown(function(e){
        enter_enabled = false;
    });

    $('#edit input')
    .keydown(function(e){
        if(e.keyCode == 13 && enter_enabled){
            $('#value').show();
            $('#edit').hide();
        }
    })
    .keyup(function(e){
        if(e.keyCode == 13){
            enter_enabled = true;
        }
    });
});
</script>

答案 1 :(得分:4)

这是另一种解决方案。功能的唯一区别在于输入仅在释放时显示并聚焦。它会监听keydown并阻止默认键盘点击,然后在keyup事件中执行交换,以便keyup不会进入输入字段。我已经在IE 11,Chrome和Firefox上试用了它,所有这些都在Windows上。

$(function() {
    $('#edit').hide();

    $('#value')
        .css('cursor', 'pointer')
        .click(function() {
            $('#edit').show();
            $('#edit input').focus();
            $('#value').hide();
         });

    $('#value a')
        .keydown(function(e) { // Prevent default enter click
            if (e.keyCode == 13) {
                e.preventDefault();
                e.stopPropagation();
            }
        }).keyup(function(e) {
            if (e.keyCode == 13) {
                e.preventDefault();
                e.stopPropagation();
                $('#edit').show();
                $('#edit input').focus();
                $('#value').hide();
            }
        });

    $('#edit input')
        .keyup(function(e) {
            if (e.keyCode == 13) {  // <enter>
                $('#value').show();
                $('#edit').hide();
            }
        });
});

答案 2 :(得分:2)

我走了使用旗帜updated fiddle-again的路线:

html保持不变,但js有所改变。我添加了一个'valueClicked'变量并将其设置为false;然后,使用它作为keyup中的条件,但是,在keyup条件检查之后,我重置了标志。

     $(function() { 
var valueClickedFromEnter = false;
$('#edit').hide();
function handleLinkClick(event)
{
         $('#edit').show();
        $('#edit input').focus();
        $('#value').hide();
        valueClickedFromEnter = 
            (event.keyCode && event.keyCode == 13);   
}
$('#value')
    .css('cursor', 'pointer')
    .keydown(handleLinkClick).click(handleLinkClick);

$('#edit input')
    .keyup(function(e) {            
        if (e.keyCode == 13 && !valueClickedFromEnter) {  // <enter>
            $('#value').show();
            $('#edit').hide();
        }
        valueClickedFromEnter = false;
    });

});

这个想法是,无论何时从Tab键到锚点,输入标志,检查键盘然后重置标志,以便在下一次输入时条件通过。然后,正常使用它,永远不会设置标志,因此条件仍然通过。

编辑:根据反馈,clientX和clientY不是跨浏览器解决方案。相反,我使用中间函数来处理锚标记的keydown和click事件,并传递事件对象。然后检查该对象的keycode属性,如果它是13,则切换标志。

额外的好处是使用另一个键,如空格键,也会导致链接切换,如果用户开始输入,它将进入输入。

答案 3 :(得分:0)

更新以修复长按问题。问题很简单,你有一个事件正在侦听keyup,你特意把焦点放在那个元素上,所以它在用户释放密钥时触发。

更新#2: 这个应该完全有效,具有讽刺意味的是,我不得不扭转我的初始更改,以便在元素隐藏时执行所有操作。

试试这个:

var enterPressed = false;
var enteredExclusion = false;
$(document).ready(function() {
$('#edit').hide();

$('#value')
    .css('cursor', 'pointer')
    .click(function() {
        $('#value').hide();
        $('#edit').show();
            $('#editabletext').focusin(function(e){
                enteredExclusion = true;
            }).focusout(function(e){
                enterPressed = false;
                enteredExclusion = false;
            }).focus();
    });

$('#editabletext')
    .keydown(function(e){
        if (e.keyCode == 13 && !enteredExclusion) {  // <enter>
            console.log('setting true');
            enterPressed = true;
        }
     })
    .keyup(function(e) {
        enteredExclusion = false;
        if (e.keyCode == 13 && (enterPressed  )) {
            $('#value').show();
            $('#edit').hide();
            console.log('setting false - keyup');
            enterPressed = false;
        }
    });
 });

HTML:

<div id="value">
    <a href="#">hello</a>
</div>
<div id="edit">
    <input id="editabletext" type="text" value="hello" />
</div>

答案 4 :(得分:0)

我决定在不可见时禁用input元素,而不是弄乱标志和诸如此类的东西。禁用的元素无法获得焦点,因此从理论上讲,您不会遇到一个问题,即当元素处于活动状态时,Enter键仍会出现。

当在input元素中按下Enter键时,我还明确地将焦点设置为锚点。这可以确保在禁用它之前不再关注该元素,这可能会导致问题。

请注意,我只在Windows 8.1上测试过这个版本(哦,和FF 36和IE 11),所以YMMV。

&#13;
&#13;
$(function() {
  $('#edit').hide();

  var keyupHandler = function(e) {
    if (e.keyCode === 13) { // <enter>
      $('#value').show().focus();
      $('#edit').hide().find('input').prop('disabled', true);
    }
  };

  var clickHandler = function(e) {
    $('#value').hide();
    $('#edit').show(500, function() {
      $(this).find('input').prop('disabled', false).focus();
    });
    e.preventDefault();
  };

  $('#value').on('click', clickHandler);
  $('#edit').on('keydown', 'input', keyupHandler);

});
&#13;
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="value">
  <a href="#">hello</a>
</div>
<div id="edit">
  <input type="text" value="hello" />
</div>
&#13;
&#13;
&#13;

答案 5 :(得分:-1)

发生的事情似乎如下:

1)用户按下对焦元素的输入 - &gt;这将触发click事件以及keyup事件。点击事件首先被触发。

2)将调用点击#value的处理程序。此处理程序显示#edit字段并将焦点设置在此字段上。

3)触发keyup事件。但由于焦点现在位于#edit,因此将触发此字段(!)

4)#edit上的键盘处理程序将被调用并再次隐藏#edit字段。