简体   繁体   English

Javascript,SetInterval和SetTimeOut函数导致跳转滚动

[英]Javascript, SetInterval and SetTimeOut functions cause jumpy scrolling

I am using a Squarespace website with a specific template that uses an index page and sub pages as the contents of the index page. 我正在使用带有特定模板的Squarespace网站,该模板使用索引页面和子页面作为索引页面的内容。 (The pages are scrollable one after the other). (这些页面可以一个接一个地滚动)。 I guess anchors are being used by Squarespace to scroll to relevant page from the index page. 我想Squarespace正在使用锚点从索引页面滚动到相关页面。

I added a javascript to show the current time and update it every second (moment.js and moment-timezone). 我添加了一个javascript来显示当前时间并每秒更新一次(moment.js和moment-timezone)。 I am updating the time every second with SetInterval(function_name,1000); 我每秒用SetInterval(function_name,1000)更新时间;

The time is updating correctly every second. 时间每秒都在正确更新。 However, this causes the particular page where I am updating the time to keep coming into focus when trying to scroll up or down (it happens every second). 但是,这会导致我正在更新时间的特定页面在尝试向上或向下滚动时保持聚焦(它每秒都会发生)。 So If i try to scroll up or down from that particular page where the time is updating, it keep scrolling automatically back to that page every second!!. 因此,如果我尝试从更新时间的特定页面向上或向下滚动,它会每秒自动滚动回到该页面!!

It seems there is an event triggering every second which causes this. 似乎有一个事件触发每一秒导致这一点。 The actual function that I am calling every second is the following: 我每秒呼叫的实际功能如下:

function showLocalTime() {
    var momentLondon = moment().tz("Europe/London").format('HH:mm:ss z');
    // The location label HTML
    var locationHTML = '<strong>Location</strong><br>';
    // The HTML string for london, England
    var londonHTML = 'London, England';
    $( "p:contains('London, England')" ).html(locationHTML + londonHTML + ' (' + momentLondon + ')');
}

Therefore, All I am doing is changing the innerHTML of a particular HTML element to show the current time. 因此,我所做的只是更改特定HTML元素的innerHTML以显示当前时间。

I am calling the above function as follows: 我调用上面的函数如下:

<script>
  $(function() {
    document.addEventListener("DOMSubtreeModified", function(){
    return;});
    window.setInterval(showLocalTime, 1000); // update it periodically
  });
</script>

However, as I said, the repeated call to the above function through SetInterval causes the webpage to keep autoscrolling to this section of the website (Contacts Page) every second!!. 但是,正如我所说,通过SetInterval重复调用上述函数会导致网页每秒自动滚动到网站的这一部分(联系人页面)!!

I can see that there is an event DOMSubtreeModified being triggered every time I call the above function. 我可以看到每次调用上面的函数时都会触发一个事件DOMSubtreeModified。 I added a custom listener to DOMSubtreeModified event, but still I am still getting the same issue. 我为DOMSubtreeModified事件添加了一个自定义侦听器,但我仍然遇到同样的问题。

It could be that this is due to some sort of redraw event? 可能是因为某种重绘事件? Anyway, I cannot seem to locate the issue and I am unable to overcome this problem. 无论如何,我似乎无法找到问题,我无法克服这个问题。

Any help would be appreciated!! 任何帮助,将不胜感激!!

Thanks 谢谢

The problem 问题

You are removing and adding two DOM nodes ( <strong> and <br> ) every second with $.html() . 您每秒使用$.html()删除并添加两个DOM节点( <strong><br> $.html() And this action triggers the mentioned DOMSubtreeModified event, check the test below: 并且此操作会触发提到的DOMSubtreeModified事件,请检查以下测试:

 go.onclick = function() { document.addEventListener('DOMSubtreeModified', function() { alert('Modified'); }); test.innerHTML = '<strong>Location</strong><br>'; }; 
 <button id=go>Test</button> <p id=test></p> 

Solution

Instead of setting html and concatenating strings with: 而不是设置html和串联字符串:

.html(locationHTML + londonHTML + ' (' + momentLondon + ')');

You should create a DOM node ( <span> element as example) to change only necessary things using the textContent attribute: 您应该创建一个DOM节点( <span>元素作为示例),以使用textContent属性仅更改必要的内容:

 go.onclick = function() { wrapper.removeChild(go); document.addEventListener('DOMSubtreeModified', function() { alert('Modified'); }); setInterval(function() { test.textContent = new Date; }, 1000); }; 
 <p id=wrapper> <button id=go>Test</button> <span id=test></span> </p> 

In your case, it will be the momentLondon value. 在你的情况下,它将是momentLondon价值。 (Final example at the end) (最后的例子)

Performance 性能

Since your function will run every second, you should save the maximun execution time as you can. 由于您的函数每秒都会运行,因此您应该尽可能地保存最大执行时间。

1 .You can declare constant variables outside the function scope like: 1.你可以在函数范围之外声明常量变量,如:

var locationHTML = '<strong>Location</strong><br>';
var londonHTML = 'London, England';

function showLocalTime() {
    // locationHTML ...
    // londonHTML   ...
    // ...
}

2 .Also, if a function will always give the same expected result: 2.另外,如果函数总是给出相同的预期结果:

 $("p:contains('London, England')")

You can run it only once outside your function scope, and store the result in a variable: 您只能在函数范围之外运行一次,并将结果存储在变量中:

var $p = $("p:contains('London, England')");

function showLocalTime() {
    // $p ...
    // ...
}

Final result 最后结果

With all that in mind, your code will end up like this: 考虑到所有这些,您的代码最终会像这样:

<script>
$(function() {
    // constants
    var locationHTML = '<strong>Location</strong><br>';
    var londonHTML = 'London, England';
    var $p = $("p:contains('London, England')");

    // prepare your DOM outside showLocalTime
    $p.html(locationHTML + londonHTML + ' (<span></span>)');
    var span = $p.find('span')[0];

    // do only necessary things within setInterval
    setInterval(function showLocalTime() {
        span.textContent = moment().tz('Europe/London').format('HH:mm:ss z');
    }, 1000);
});
</script>

Hope it helps. 希望能帮助到你。

I would move the showLocalTime function into the immediately invoked anonymous function, and call it before the setTimeOut call, that way it displays time at load as well as after 1 second. 我将showLocalTime函数移动到立即调用的匿名函数中,并在setTimeOut调用之前调用它,这样它在加载时以及1秒后显示时间。

I made this fiddle of your code to see if I could reproduce your auto scrolling issue, this code does not cause that on JSFiddle. 我制作了你的代码的小提琴,看看我是否可以重现你的自动滚动问题,这个代码不会导致JSFiddle。

Here is the JSFiddle: https://jsfiddle.net/workingClassHacker/xhrfoznj/10/ 这是JSFiddle: https ://jsfiddle.net/workingClassHacker/xhrfoznj/10/

Here is the code: 这是代码:

$(function() {
   var londonP = $("p:contains('London, England')");
   var showLocalTime = function() {
       timeDisplay.textContent = moment().tz("Europe/London").format('HH:mm:ss z');
   }
   londonP.html('<strong>Location</strong><br/>London, England (<span></span>)');
   var timeDisplay = londonP.find('span')[0];
   showLocalTime();
   setInterval(showLocalTime, 1000);
});

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM