JavaScript如何检查页面是否重新加载或刷新

283

我想检查当有人尝试刷新页面时。

例如,当我打开页面时,什么也不会发生,但当我刷新页面时,它应该显示一个警报。


1
不太可能没有服务器端代码。你需要它做什么?也许如果你提供更大的背景,我们可以建议更好的替代方案。 - Shadow The Spring Wizard
也许你可以使用 cookie 来实现这样的功能,比如存储时间,在重新加载时比较时间差异。 - Felix Kling
我想让类似Facebook链接的格式变为#!/anythinge,但只在页面重新加载时移除#! - Ahmed
1
@Ahmed 我也在尝试做同样的事情。下面的解决方案有没有对你有用? - Paul Fitzgerald
4
window.performance.navigation.type 已经被弃用,请参考我的答案 - Илья Зеленько
15个回答

274

⚠️⚠️⚠️ window.performance.navigation.type已被弃用,请参见Илья Зеленько的答案


更好的方法是使用大多数现代浏览器支持的navigator对象来知道页面是否已经重新加载。

它使用了Navigation Timing API

//check for Navigation Timing API support
if (window.performance) {
  console.info("window.performance works fine on this browser");
}
console.info(performance.navigation.type);
if (performance.navigation.type == performance.navigation.TYPE_RELOAD) {
  console.info( "This page is reloaded" );
} else {
  console.info( "This page is not reloaded");
}

来源: 导航计时API


1
谢谢伙计,这是一个准确的解决方案,可以检测页面是通过右键单击/刷新浏览器重新加载还是通过URL重新加载。 - Roque Mejos
4
注意,Chrome 最近改变了这个行为。当用户单击当前地址栏并按回车键时,performance.navigation.type 的值将为 1,而不是应该为 0。我在版本 56 中进行了测试,但不确定原因。 - Jackwin tung
30
performance.navigation.type == performance.navigation.TYPE_RELOAD 更易于阅读,而不是 == 1。此外,如果您检查 performance.navigation,您会发现有4种不同的导航类型,例如 TYPE_BACK_FORWARDTYPE_NAVIGATE - Vitalij Kornijenko
11
window.performance.navigation.type 已经被废弃,请参考我的回答 - Илья Зеленько
1
第二个if和else不应该在第一个if里面吗? - Matthias
显示剩余9条评论

112

新标准 2018-now (PerformanceNavigationTiming)

window.performance.navigation属性在导航计时2级规范中已被弃用。请使用PerformanceNavigationTiming接口。

PerformanceNavigationTiming.type

这是一个实验性技术。请在生产之前仔细查看浏览器兼容性表格

在JavaScript中检查页面是否被重新加载或刷新

const pageAccessedByReload = (
  (window.performance.navigation && window.performance.navigation.type === 1) ||
    window.performance
      .getEntriesByType('navigation')
      .map((nav) => nav.type)
      .includes('reload')
);

alert(pageAccessedByReload);

2021-11-09 支持

支持表格

type 是只读属性,返回一个字符串,表示导航的类型。这个值必须是以下之一:

  • navigate — 通过点击链接、在浏览器地址栏输入 URL、提交表单或者初始化脚本操作(不包括 reload 和 back_forward,如下所列)开始的导航。

  • reload — 通过浏览器的刷新操作或者 location.reload() 方法进行的导航。

  • back_forward — 通过浏览器的历史遍历操作进行的导航。

  • prerender — 通过预渲染提示启动的导航。

该属性为只读。

下面的示例说明了该属性的用法。

function print_nav_timing_data() {
  // Use getEntriesByType() to just get the "navigation" events
  var perfEntries = performance.getEntriesByType("navigation");

  for (var i=0; i < perfEntries.length; i++) {
    console.log("= Navigation entry[" + i + "]");
    var p = perfEntries[i];
    // dom Properties
    console.log("DOM content loaded = " + (p.domContentLoadedEventEnd - p.domContentLoadedEventStart));
    console.log("DOM complete = " + p.domComplete);
    console.log("DOM interactive = " + p.interactive);
 
    // document load and unload time
    console.log("document load = " + (p.loadEventEnd - p.loadEventStart));
    console.log("document unload = " + (p.unloadEventEnd - p.unloadEventStart));
    
    // other properties
    console.log("type = " + p.type);
    console.log("redirectCount = " + p.redirectCount);
  }
}

22
感谢您指出已弃用的API,但是对于苹果公司在iOS上仍缺乏支持直到2020年,我给予-100分。 - kinakuta
4
谢谢指出。这是完整的兼容解决方案链接:https://jsfiddle.net/j9o1khcw/2/ - garzj
1
@0nline,我尝试了你的解决方案,但是对我来说没有起作用,供你参考。 - kennysong
这个在2022年的Safari上能用吗?我没有Safari浏览器。 - Anshuman Kumar
1
@Илья 感谢您指出这一点。这对我非常有帮助。我有一个问题。我尝试了各种方法,但始终只返回了一个 getEntriesByType('navigation') 输入项。为什么您要使用 .map 而不是直接使用第一个输入项?在某些情况下是否可能获取多个输入项?我很想了解更多,请解释一下。 - Ashutosh Biswas
显示剩余2条评论

42

第一步是检查{{link1:sessionStorage}}是否存在预定义的值,如果存在,则向用户发出警报:

if (sessionStorage.getItem("is_reloaded")) alert('Reloaded!');

第二步是将sessionStorage设置为某个值(例如true):
sessionStorage.setItem("is_reloaded", true);

会话值保留直到页面关闭,因此仅在使用新标签页重新加载站点时才起作用。您也可以以同样的方式保持重新加载计数。


40
需要注意的两件事: 1)只能在会话和本地存储中存储字符串值。因此,true 会被转换为 "true"。 2)会话存储会持续到用户关闭浏览器窗口,因此您无法区分页面重新加载和在同一浏览器会话中导航离开并返回您的站点之间的区别。 - Hector
SessionStorage可以在浏览器内部进行修改吗?如果我错了,请纠正我。有人可以添加/删除密钥,从而规避您的逻辑/代码。 - f0rfun
请注意,如果您关闭选项卡并从ctrl + shift + T还原它,则sessionStorage将恢复。 在需要清除会话令牌的公共场所,这可能潜在地存在安全漏洞。 - kuzroman
这里是关于编程的相关内容,请将页面刷新与页面重载的区别考虑在内。 - btx
@kuzroman,看起来一切都正常,即使在关闭后重新打开也是如此。 - 27px
为了避免任何讨论,在第二步之前清除变量。sessionStorage.removeItem("is_reloaded"),然后再设置它 sessionStorage.setItem("is_reloaded", true); - undefined

17

在第一次访问页面时存储一个cookie。刷新时检查您的cookie是否存在,如果存在,则弹出警报。

function checkFirstVisit() {
  if(document.cookie.indexOf('mycookie')==-1) {
    // The cookie doesn't exist. Create it now
    document.cookie = 'mycookie=1';
  }
  else {
    // Not the first visit, so alert
    alert('You refreshed!');
  }
}

在您的body标签中:

<body onload="checkFirstVisit()">

14
回头客怎么办? - Red Taz
6
就像@Rob2211说的那样,这仅检查页面是否被访问过,并且只要在Cookie仍然有效时重新访问该页面,就可能产生误报。不要使用这种方法来检查刷新。 - Brannon
1
@Brannon - Cookie是没有过期值创建的,会在浏览器关闭时被销毁。 - techfoobar
2
@techfoobar 很好的发现。如果用户在cookie被销毁之前重新访问网站,这是否仍会造成问题? - Brannon
4
是的,如果浏览器保持开启状态并且用户在一段时间后重新访问同一网站,那么这次访问将不被视为新访问。 - techfoobar
显示剩余3条评论

15
我编写了这个函数来同时检查旧的window.performance.navigation和新的performance.getEntriesByType("navigation")方法:
function navigationType(){

    var result;
    var p;

    if (window.performance.navigation) {
        result=window.performance.navigation;
        if (result==255){result=4} // 4 is my invention!
    }

    if (window.performance.getEntriesByType("navigation")){
       p=window.performance.getEntriesByType("navigation")[0].type;

       if (p=='navigate'){result=0}
       if (p=='reload'){result=1}
       if (p=='back_forward'){result=2}
       if (p=='prerender'){result=3} //3 is my invention!
    }
    return result;
}

结果描述:

0:点击链接、在浏览器地址栏中输入URL、表单提交、点击书签、通过脚本操作初始化。

1:点击刷新按钮或使用Location.reload()

2:与浏览器历史记录(后退和前进)一起工作。

3:预渲染活动,如<link rel="prerender" href="//example.com/next-page.html">

4:任何其他方法。


这在Safari中不起作用。返回的数组为空。 - char m

9

如果

event.currentTarget.performance.navigation.type

返回

0 => 用户刚刚输入了一个URL
1 => 页面重新加载
2 => 点击了返回按钮。


我遇到了这个错误,你能解释一下吗?Uncaught TypeError: Cannot read property 'currentTarget' of undefined - Janatbek Orozaly
2 => TYPE_BACK_FORWARD 该页面是通过浏览历史记录访问的。https://developer.mozilla.org/zh-CN/docs/Web/API/PerformanceNavigation - Tiago Freitas Leal
performance.navigation.type已经被弃用,请参见我的答案 - Илья Зеленько

8

我在JavaScript检测页面刷新中找到一些信息。他的第一个建议是使用隐藏字段,这些字段往往会在页面刷新时被保存。

function checkRefresh() {
    if (document.refreshForm.visited.value == "") {
        // This is a fresh page load
        document.refreshForm.visited.value = "1";
        // You may want to add code here special for
        // fresh page loads
    } else {
        // This is a page refresh
        // Insert code here representing what to do on
        // a refresh
    }
}
<html>

<body onLoad="JavaScript:checkRefresh();">
    <form name="refreshForm">
        <input type="hidden" name="visited" value="" />
    </form>

</body>

</html>


1
@Adeel:检查“Referer”也不可靠;许多代理和浏览器扩展会从请求中剥离它。 - Andy E
@VoronoiPotato 请尝试总结信息,而不仅仅发布链接。 - Dallin
@AndyE他在body加载时触发了javascript,我非常怀疑这会在dom加载之前执行... - VoronoiPotato
1
对我来说,它总是执行“if”条件,从不执行“else”部分,无论我是加载页面还是刷新页面。 - Parth Vora
在Chrome上我得到了Uncaught TypeError: Cannot read property 'visited' of undefined - vallentin
显示剩余2条评论

3

以下是几乎所有浏览器都支持的方法:

if (sessionStorage.getItem('reloaded') != null) {
    console.log('page was reloaded');
} else {
    console.log('page was not reloaded');
}

sessionStorage.setItem('reloaded', 'yes'); // could be anything

它使用 SessionStorage 来检查页面是第一次打开还是刷新。

1
使用ctrl/cmd+T重新打开标签页时无法工作。 - Nebulosar

2

这个实现对我有所帮助:

来源于MDN参考2022年版:导航时机Level 2规范

const navigationType = 
    (window.performance.getEntriesByType('navigation')
        [0] as PerformanceNavigationTiming).type;

const isPageReload = navigationType === 'reload';
const isNavigation = navigationType === 'navigate';
const isBackForwarad = navigationType === 'back_forward';
const isPrerender = navigationType === 'prerender';

这是TypeScript,OP希望用JavaScript来回答。 - undefined
1
@SilvioGuedes 不好意思,代码已更新。 - undefined
自2018年起,此代码已被弃用。 - undefined
@OlivierC 在MDN页面上没有关于它们的弃用通知,并且这篇文章似乎非常更新。请提供您信息的来源,谢谢! - undefined
@btx:确实,我错了,我把它和Performance.navigation搞混了。 如果你编辑你的信息,我会修改我的备注。 - undefined

1
一个简单的解决方案还没有被提到(不依赖于已弃用的window.performance.navigation):
  1. 使用 window.onbeforeunload 来在用户离开页面(可能是刷新页面)时将当前页面的时间和 URL 存储在本地存储中。

    window.onbeforeunload = function(e)
    {
        localStorage.setItem('reload-url', window.location.href);
    }
    
  2. 然后使用 window.onload 从本地存储中获取这些值。

    window.onload = function(e)
    {
        if (localStorage.getItem('reload-url') != null))
        {
            if (window.location.href == localStorage.getItem('reload-url'))
            {
                console.log('Reload');
            }
        }
    }
    
  3. 如果最近的 URL 与存储的 URL 匹配,并且存储的时间与当前时间匹配(可能有微小偏差),则说明用户进行了页面重新加载。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接