新闻资讯
vue动态组件与异步组件之间的辛路历程
首先说下项目需求:单页应用中点击菜单项后动态响应页面中的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 }) );
解决!
回复列表