最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • nuxt-link预加载的原理

    正文概述 掘金(戬翀)   2021-03-02   1542

    nuxt-link 是 nuxtjs 提供的一个组件,基于 vue-router 的 router-link 做了一层封装,实现了预加载的功能。本文来简单聊聊这个“预加载”的原理。

    一点准备工作

    如果直接打开 nuxt 项目中 nuxt-link的源码,会发现里面使用了很多类似于 <%...%> 这样的模板语法。这其实是 lodash.template 提供的模板语法。如果觉得影响阅读,可以按照 nuxt 的文档,新建一个 nuxt 应用,然后构建一次,再找到 .nuxt/components/nuxt-link.client.js,这个就是编译过后的 nuxt-link 代码。

    前置条件

    要想触发 nuxt-link 的预加载,需要同时满足以下几个条件:

    1. nuxt-linkprefetch 属性值是 true

      默认值是 nuxt 配置里的 router.prefetchLinksprefetchLinks 的默认值是 true ,所以 prefetch 的默认值也是 true

    2. nuxt-linknoPrefetch 属性值是 false。默认值是 false

    3. nuxt-link 组件出现在可见区域内。

    4. nuxt-linkto 属性指向的页面是同一个应用的页面。

    5. 有网络链接并且不是 2g 网络。

    1、2 两点控制是否启动预加载功能(默认是开启预加载),3、4、5是决定什么时候执行预加载的逻辑。

    原理

    接下来梳理一下预加载的大致流程。为了说明原理,nuxt-link 源码里有些条件分支会省略,但不影响理解。下面会以 /cart 这个链接作为 nuxt-link 的跳转地址来做说明。/cart 页面对应的文件路径是 /pages/cart/index.vue

    <nuxt-link to="/cart">购物车</nuxt-link>
    

    事件监听

    nuxt-linkmounted 阶段,如果设置了开启预加载,即 this.prefetch && !this.noPrefetch,就会开始监听 nuxt-link 元素是否进入了可视区域。

    当元素进入了可视区域,就会调用 prefetchLink 方法进行预加载。

    监听过程中使用了 window.requestIdleCallback 和 window.IntersectionObserver 这两个 API。

    预加载

    核心的逻辑在 prefetchLink() 函数里:

    prefetchLink () {
      if (!this.canPrefetch()) {
        return
      }
      // Stop observing this link (in case of internet connection changes)
      observer.unobserve(this.$el)
      const Components = this.getPrefetchComponents()
    
      for (const Component of Components) {
        const componentOrPromise = Component()
        if (componentOrPromise instanceof Promise) {
          componentOrPromise.catch(() => {})
        }
        Component.__prefetched = true
      }
    }
    

    首先要获取需要预加载的组件。

    getPrefetchComponents() 方法里,使用了 vue-routerrouter.resolve 方法,找到将要跳转的页面对应的页面入口,即 Components

    getPrefetchComponents () {
      const ref = this.$router.resolve(this.to, this.$route, this.append)
      const Components = ref.resolved.matched.map(r => r.components.default)
    
      return Components.filter(Component => typeof Component === 'function' && !Component.options && !Component.__prefetched)
    },
    

    在浏览器开发工具里打印一下 Components,看到以下信息:

    nuxt-link预加载的原理

    可以看到 Components 里的每个元素都是一个函数,点击 [[FunctionLocation]] 的值,router.js,可以跳到函数定义的位置。然后你就会发现打开的这个 router.js 其实就是我们的项目构建完之后得到的 .nuxt/router.js

    通过 _30f4c240() 这个函数的定义可以发现它的核心功能其实就是引入了 /cart 对应的页面文件。如果调用这个方法,就会在浏览器开发者工具的 network 面板看到浏览器请求了 /_nuxt/pages/cart/index.js 这个文件,即加载了 /cart 这个页面对应的代码。具体的加载过程属于 webpack 的功能,这里不做说明。

    // .nuxt/router.js
    const _30f4c240 = () => interopDefault(import('../src/pages/cart/index.vue' /* webpackChunkName: "pages/cart/index" */))
    

    在获取到上面的加载函数之后,prefetchLink 就会调用这些函数,达到预加载的效果。之后,还会设置一个 __prefetch 的标识,防止重复加载。

    以上就是 nuxt-link 预加载的大致过程。

    延伸

    nuxt-link 的源码里,还能找到一些有趣的点:

    自定义预加载

    有些时候我们没有使用 nuxt-link 来做页面跳转,但又想预加载这个页面,就可以这样做:

    myPrefetch(path) {
      const ref = this.$router.resolve(path, this.$route, false);
      const Components = ref.resolved.matched.map((r) => r.components.default);
    
      Components
        .filter((Component) => typeof Component === 'function' && !Component.options && !Component.__prefetched)
        .forEach((Component) => {
          const componentOrPromise = Component();
          if (componentOrPromise instanceof Promise) {
            componentOrPromise.catch(() => {});
          }
          Component.__prefetched = true;
        });
    },
    

    可以使用以下方法简化一下 Components 的获取:

    const Components = this.$router.getMatchedComponents(path)
    

    navigator.connection

    可以使用 navigator.connection 来判断网络状态,但是要注意兼容性。

    quicklink

    react 项目里,可以使用 quicklink 实现预加载的功能。


    起源地下载网 » nuxt-link预加载的原理

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元