js判断页面是否是通过浏览器后退按钮返回打开的

852 阅读2分钟

利用浏览器的window.performance.navigation.type属性(已经废弃)

valuenamemeaning
0TYPE_NAVIGATEThe page was accessed by following a link, a bookmark, a form submission, a script, or typing the URL in the address bar.
1TYPE_RELOADThe page was accessed by clicking the Reload button or via the Location.reload() method.
2TYPE_BACK_FORWARDThe page was accessed by navigating into the history
3TYPE_RESERVEDAny other way.

PerformanceNavigation

valuenamemeaning
0TYPE_NAVIGATE当前页面是通过点击链接,书签和表单提交,或者脚本操作,或者在 url 中直接输入地址,type 值为 0
1TYPE_RELOAD点击刷新页面按钮或者通过Location.reload()方法显示的页面,type 值为 1
2TYPE_BACK_FORWARD页面通过历史记录和前进后退访问时。type 值为 2
255TYPE_RESERVED任何其他方式,type 值为 255

ios手机上返回上一页时候经常不触发vue等组件的mounted,从缓存读取的页码

window.addEventListener('pageshow', (e) => {
  if (e.persisted) { // 从缓存中读取
     // do somthing
   }
)

综合上面完整的代码,完美方案如下

兼容navigation的新旧判断,以及ios返回上一页不触发mounted只触发pageshow的判断


mounted()  {
   if (isMobile && isIOS) {
    window.addEventListener('pageshow', this.onPageShow)
  } else if (isNavigationBackOrForward()) {
    $emit('navigation-back-forward')
  }
}

onPageShow(e: PageTransitionEvent) {
  // 从缓存中打开
  if (e.persisted) {
    if (isNavigationBackOrForward()) {
      $emit('navigation-back-forward')
    }
  }
}

isNavigationBackOrForward() {
    if (!window.performance) {
      return false
    }

    if (window.performance.navigation?.type === 2) {
      return true
    }

    const entries = window.performance.getEntriesByType?.('navigation')

    if (!entries || !entries.length) {
      return false
    }
    return entries.find((entry: PerformanceEntry & { type?: string }) => entry.type === 'back_forward') || false
}

滚动到页面顶部

直接全部重写

router.scrollBehavior.js

  mounted() {
  // 不直接beforeMount中设置scrollTop,是因为web会先记住上次的位置再滚动
  window.addEventListener('beforeunload', this.handleScrollTop)
}

beforeDestroy() {
  window.removeEventListener('pageshow', this.handleScrollTop)
}

handleScrollTop() {
  // 参考 https://www.zhangxinxu.com/wordpress/2022/05/history-scrollrestoration/
  window.history.scrollRestoration = 'manual'
}

router.scrollBehavior.js文件如下

import { getMatchedComponents } from './utils'

if (process.client) {
 if ('scrollRestoration' in window.history) {
   
   window.history.scrollRestoration = 'manual'

   // reset scrollRestoration to auto when leaving page, allowing page reload
   // and back-navigation from other pages to use the browser to restore the
   // scrolling position.
   window.addEventListener('beforeunload', () => {
     debugger
     window.history.scrollRestoration = 'auto'
   })

   // Setting scrollRestoration to manual again when returning to this page.
   window.addEventListener('load', () => {
     debugger
     window.history.scrollRestoration = 'manual'
   })
 }
}

export default function (to, from, savedPosition) {
 // if the returned position is falsy or an empty object,
 // will retain current scroll position.
 let position = false

 // if no children detected and scrollToTop is not explicitly disabled
 const Pages = getMatchedComponents(to)
 if (
   Pages.length < 2 &&
   Pages.every(Page => Page.options.scrollToTop !== false)
 ) {
   // scroll to the top of the page
   position = { x: 0, y: 0 }
 } else if (Pages.some(Page => Page.options.scrollToTop)) {
   // if one of the children has scrollToTop option set to true
   position = { x: 0, y: 0 }
 }

 // savedPosition is only available for popstate navigations (back button)
 if (savedPosition) {
   position = savedPosition
 }


 // triggerScroll is only fired when a new component is loaded
 if (to.path === from.path && to.hash !== from.hash) {
   nuxt.$nextTick(() => nuxt.$emit('triggerScroll'))
 }

 return new Promise((resolve) => {
   // wait for the out transition to complete (if necessary)
   nuxt.$once('triggerScroll', () => {
     // coords will be used if no selector is provided,
     // or if the selector didn't match any element.
     if (to.hash) {
       let hash = to.hash
       // CSS.escape() is not supported with IE and Edge.
       if (typeof window.CSS !== 'undefined' && typeof window.CSS.escape !== 'undefined') {
         hash = '#' + window.CSS.escape(hash.substr(1))
       }
       try {
         if (document.querySelector(hash)) {
           // scroll to anchor by returning the selector
           position = { selector: hash }
         }
       } catch (e) {
         console.warn('Failed to save scroll position. Please add CSS.escape() polyfill (https://github.com/mathiasbynens/CSS.escape).')
       }
     }
     resolve(position)
   })
 })
}