首先说下项目需求:单页应用中点击菜单项后动态响应页面中的tab标签(非浏览器的tab标签),tab标签对应一个页面,这将使得页面的显示由菜单主导,一般想法是点击菜单后动态显示组件,可组件怎么显示呢?
查阅vue官方文档,有个自带的动态组件
<component v-bind:is="需要动态显示的组件名"></component>
要使动态组件不随tab切换而变动(实际上每改变一次is都会new一个组件),还得加上keep-alive
<keep-alive>
<component v-bind:is="需要动态显示的组件名"></component>
</keep-alive>
咋一看好像需求成了,可认真一看<component>中的is需要指向已打包的组件(一般就是明确用import导入的组件),那要是组件多起来,不仅要很多import,还得在vue当前组件的components中写入好些组件映射,麻烦!最主要的是项目大起来,这么写的后果会使得webpack打包的项目体积增大,对于一个单页应用,开发者和用户都不希望看到一个页面加载太长时间吧。
接着看官方文档,后面有个新概念——异步组件,看着是个好东西,官方推荐写法:
Vue.component(
'组件名',
() => ({
// 需要加载的组件 (应该是一个 `Promise` 对象)
component: import('组件相对路径'),
// 异步组件加载时使用的组件
loading: loading,
// 加载失败时使用的组件
error: error,
// 展示加载时组件的延时时间。默认值是 200 (毫秒)
delay: 200,
// 如果提供了超时时间且组件加载也超时了,
// 则使用加载失败时使用的组件。默认值是:`Infinity`
timeout: 3000
})
);
马上着手并入自己的代码中,想当然的把import中的组件路径改为一个变量,加上去后编译就报错了,原来import不能这么玩,必须尽可能的明确路径。
粗略的认为,这个“异步组件”之路又不可行了,接着我考虑是否可以用ajax方式自行加载vue文件并解析呢?开始实干,接入http ajax库 axios (顺便照着网上的博文封装了一个http.js),正式加载组件,代码样本如下:
this.$http.axiosGet("./static/pages/Home2.vue")
.then((result) => {
var comContent = result.data; //加载获得的组件内容
Vue.component("组件名", {template: comContent});
//或者使用Vue.extend
})
.catch(err => {
console.log(err)
}
);
这下又踩坑了,一般的纯template组件,完全没问题,可vue组件文件中还有<script>代码啊,代码不执行咋办?难道我在加载完后在外部给它设置data等相关属性或函数,那加载的这块岂不是得写得非常非常非常臃肿?(这种方式我在bootstrap + jquery + vue模式中使用过,vue仅仅作为简单的数据绑定容器,全面使用vue后,肯定不能再这么干了)。
好吧,继续走在坑洼的道路上,难道就没有其它方式了?答案肯定是有的,记得我在对vue做技术评估时,初次尝试vue组件的便利,使用了一款开源组件加载器:httpVueLoader.js 按理说这也是一款神器,在不使用vuecli的情况下在简单的html文件中动态加载vue文件并能实现其中的<script>和<style>,非常了不起! 。。。。。。来转折了,但是呢,不兼容依据webpack写的组件,比如import语法,“export default” 还得改为 “module.exports=”,所有import导入组件全得改为在当前组件的依赖组件components中使用httpVueLoader加载,要是全部这么写,倒是没啥问题,要是正如vuex vueRouter呢,没这么整过,反正想着应该不够友好。如果仅仅是简单的使用vue给组件模板赋值显示,httpVueLoader.js也是一个很好的选择!
放弃 httpVueLoader.js 这条路后呢?有些人说:坚持就是胜利,就应该一条路走到黑,不过吧,毕竟写程序需要理智,不能脑袋抽风!虽然走了三条路,三条路都被我一一排查、验证和否定,但……,就没有我疏漏的地方?我再次反复观看官方文档,既然官方推荐这样做,肯定是有道理的,那么,又回到我走过的第一条路吧。
既然import不能使用变量是因为import中必须尽可能的明确组件路径地址这条硬性限制,我是否可以将import中的内容改为 "组件路径”+组件名的方式呢,经过验证,是可行的,最终用法如下:
Vue.component(
comName,
() => ({
//import应该尽可能的缩小path范围,不然会出错
component: import('../../static/pages/' + comName),
loading: asynLoading,
error: asynError,
delay: 200,
timeout: 3000
})
);
解决!
再次,感谢 https://m.jb51.net/article/143925.html 这篇博文作者对webpack import做了细致分析!