我正在创建具有可滚动内容(溢出:滚动)的类似列表框的小部件。 可以通过鼠标悬停或键盘(使用向上/向下箭头)选择任何项目。
问题是:
当通过键盘选择项目时,新选择的项目必须滚动到 View 中。由于该滚动,项目在鼠标光标下移动,这会带来不需要的鼠标事件。
如何防止项目在通过 scrollIntoView(或类似)滚动时获取鼠标事件?
var VK_DOWN = 40;
$('#scrollable div').mouseenter(function() {
$(this).addClass('selected');
});
$('#scrollable div').mouseleave(function() {
$(this).removeClass('selected');
});
$(document).keydown(function(e) {
if (e.which == VK_DOWN) {
e.preventDefault();
//select next item
var selected = $('div.selected');
selected.removeClass('selected');
selected = selected.next().addClass('selected');
//scroll to selected item (if necessary)
if (selected.position().top + 20 > 300) {
selected[0].scrollIntoView(false);
}
} //vk_down
});
#scrollable {
height: 300px;
overflow: scroll;
overflow-x: hidden;
}
#scrollable div {
background: lightgray;
border-bottom:2px solid white;
height: 20px;
cursor: default;
}
.selected {
background: red !important;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="scrollable">
<div>1</div>
<div>2</div>
<div>3</div>
<div>4</div>
<div>5</div>
<div>6</div>
<div>7</div>
<div>8</div>
<div>9</div>
<div>10</div>
<div>11 click this item, then press "down arrow" few times.</div>
<div>12</div>
<div>13</div>
<div>14</div>
<div>15</div>
<div>16</div>
<div>17</div>
<div>18</div>
<div>19</div>
<div>20</div>
<div>21</div>
<div>22</div>
<div>23</div>
<div>24</div>
<div>25</div>
<div>26</div>
<div>27</div>
<div>28</div>
<div>29</div>
<div>30</div>
<div>31</div>
<div>32</div>
<div>33</div>
<div>34</div>
<div>35</div>
<div>36</div>
<div>37</div>
<div>38</div>
<div>39</div>
<div>40</div>
</div>
http://jsfiddle.net/sck0cbjn/1/
我的第一个想法是在 scrollIntoView() 之前设置标志“ItsMeScrolling”(滚动后删除标志),并在每次设置标志时忽略鼠标事件。 这没有用 - 在鼠标事件发生时,标志从未设置。
最佳答案
解决方案非常简单:
如果鼠标事件是有意的,鼠标光标会移动。 所以如果我们得到一个没有光标移动的事件,它必须是由滚动引起的。
http://jsfiddle.net/sck0cbjn/7/
var VK_DOWN = 40;
var lastCursorPos = {
x: 0,
y: 0
};
$('#scrollable div').mousemove(function(e) {
var currentCursorPos = {
x: e.screenX,
y: e.screenY
};
if (currentCursorPos.x == lastCursorPos.x &&
currentCursorPos.y == lastCursorPos.y) {
console.log("cursor didn't move so this event was not intended.");
return;
}
lastCursorPos = {
x: e.screenX,
y: e.screenY
};
$('#scrollable div').removeClass('selected');
$(this).addClass('selected');
});
$('#scrollable div').mouseleave(function(e) {
$(this).removeClass('selected');
lastCursorPos = {
x: e.screenX,
y: e.screenY
};
});
$(document).keydown(function(e) {
if (e.which == VK_DOWN) {
e.preventDefault();
//select next item
var selected = $('div.selected');
selected.removeClass('selected');
selected = selected.next().addClass('selected');
//scroll to selected item (if necessary)
if (selected.position().top + 20 > 300) {
selected[0].scrollIntoView(false);
}
} //vk_down
});
#scrollable {
height: 300px;
overflow: scroll;
overflow-x: hidden;
}
#scrollable div {
background: lightgray;
border-bottom: 2px solid white;
height: 20px;
cursor: default;
}
.selected {
background: red !important;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="scrollable">
<div>1</div>
<div>2</div>
<div>3</div>
<div>4</div>
<div>5</div>
<div>6</div>
<div>7</div>
<div>8</div>
<div>9</div>
<div>10</div>
<div>11 click this item, then press "down arrow" few times.</div>
<div>12</div>
<div>13</div>
<div>14</div>
<div>15</div>
<div>16</div>
<div>17</div>
<div>18</div>
<div>19</div>
<div>20</div>
<div>21</div>
<div>22</div>
<div>23</div>
<div>24</div>
<div>25</div>
<div>26</div>
<div>27</div>
<div>28</div>
<div>29</div>
<div>30</div>
<div>31</div>
<div>32</div>
<div>33</div>
<div>34</div>
<div>35</div>
<div>36</div>
<div>37</div>
<div>38</div>
<div>39</div>
<div>40</div>
</div>
当心: 将光标从一个元素移动到另一个元素(之间没有间隙)时,您将得到: mouseleave 和 mouseenter 事件具有相同的坐标!
关于javascript - 通过 javascript 滚动内容时不需要的鼠标事件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26179043/