vue render函数如何实现异步

项目是用的vue-cli/webpack模板。

项目中有一个tab分页,其中每页内容和用户点击的栏目有关。

tab下显示内容区域,我写了一个组件:

<script>
  export default {
    props: ['content'],
    render (h) {
      let comp = require('../page/' + this.content + '.vue')
      return h(comp, {})
    }
  }
</script>

这样可以使用,但这样最终会把所有的业务代码全部打包到app.js中,页面一加载所有的模块的都加载了。

我参考了下 vue-router 的懒加载,改成了 import 形式:

<script>
  export default {
    props: ['content'],
    render (h) {
//      let comp = require('../page/' + this.content + '.vue')
      let comp = () => import('../page/' + this.content + '.vue')
      return h(comp, {})
    }
  }
</script>

这样修改发现,comp返回的是 promise,直接 render 就是死循环了。

查到 webpack.ensure 方法,改成如下方式:

<script>
  export default {
    props: ['content'],
    render (h) {
      require.ensure([], (require) => {
        let comp = require('../page/' + this.content + '.vue')
        return h(comp, {})
      })
    }
  }
</script>

貌似 render 函数,不支持异步形式。

请问这个需要如何来处理?同时,是否需要额外配置 webpack呢?

阅读 11.3k
2 个回答

To convert any .vue component from being a sync. to an async component the rule is as followed according to their API. (Not including SSR which as first answer says, is not possible until vue 2.4):

Anywhere in VueJS that accepts a Component (usually from a component property) will also take a function that returns a Promise<Component>

This means if you have:

import SomeComponent from "./SomeComponent.vue";
export default function install(Vue){
    Vue.component("some-component", Vue.extend(SomeComponent));
};

That it can also be async by changing it to:

const SomeComponent = () => import("./SomeComponent.vue");
export default function install(Vue){
    Vue.component("some-component", SomeComponent);
};

The above example will only resolve the component async if it is scanned and resolved in the view template. So if you have that component wrapped in a v-if and the expression does not evaluate to true, then the component async code will never be fetched.

The same applies to local component registration:

import SomeComponent from "./SomeComponent.vue";

export default {
    component: {
        SomeComponent
    }
}

to be async you convert to:

const SomeComponent = () => import("./SomeComponent.vue");

export default {
    component: {
        SomeComponent
    }
}

render()函数确实不行(当前版本2.6),可使用 component标签变通一下,例子中整个组件就是一个动态引用一下component, 事实上直接写在父级需要动态引用的地方就行

<template>
  <component :is="viewName"></component>
</template>

<script>
export default {
  props:['content'],
  computed: {
    viewName() {
      // let name = this.$route.params.name;
      return () => import('@/views/'+this.content+'.vue')
    }
  }
};
</script>

非要使用render()函数的话,把上述编译一下,得到一个变通的render函数, 注意tag参数在官方文档里好像没有说明,可以自已编译一下

<script>
  export default {
    props: ['content'],
    render (h) {
      let comp = () => import('../page/' + this.content + '.vue');
      return h(comp, {tag: "component"})
    }
  }
</script>

注:
上述render函数其实就是 <component :is="comp" /> 标签的渲染方法
之前根据官方文档来渲染这个标签,按以下方式无效:

createElement('component', {
    props:{
      is: ()=>import('../foo/bar.vue');
    }
});
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题