前言最近接到一个基于vue和element-ui的通用背景框架页面的需求。具体要求如下:要求通用性高,需要在十多个子项目中使用,所以大部分地方都是可配置的。要求采用脚手架形式。可以通过npm安装实现多标签,可以通过浏览器url回显多标签。而tabs维护历史记录,可以回溯组件要求异步加载,减少首屏加载时间。显然,这是一个类似ERP的应用程序。做过JSP等背景的同学应该对多页标签不陌生。那么继续接下来说说实现。高通用性没什么难的,无非是有点麻烦。提取所有数据并将它们放入配置文件中。然后将其导入到框架页面中,并绑定到相应的位置。这里有一个困难的选择,就是如果把所有的数据都绑定到vue的数据上,由于数据量很大,会造成性能问题。如果分开的话,会让配置文件看起来比较复杂,增加后期用户的学习成本。这部分取决于具体的项目要求。由于我暂时对前端性能要求不是那么高,所以暂时采用全绑定数据的方案做成脚手架形式。起初,产品对此的需求将其做成组件形式。然后发布npm包,方便后期更新。你只需要更新npm。不需要每个项目都复制粘贴来替换,但是基于这个是一个框架页面,可配置项很多,需要实现tab多页面签名等考虑,最终还是选择了脚手架解决方案,虽然后面升级会麻烦一点(原来的解决方案是把frame页面放在一个文件夹里,然后直接替换文件夹),但是相对于component来说,还是比较好maintain,以后可以写一个更新的脚手架,毕竟现在发布一个npm工具的成本太低了。第一次开发脚手架。看了很多社区的帖子,发现现在的脚手架一般都是基于两种形式,一种是基于文件复制,一种是基于git-clone。经过比较,我觉得文件的复制有点复杂。其实我只是需要一个可以一键安装的工具,所以git-clone的形式比较适合我。下面是脚手架的代码。虽然只是简单的50、60行代码,但是查资料+下坑我花了一上午的时间。#!/usr/bin/envnodeconstshell=require('shelljs');constprogram=require('commander');constinquirer=require('inquirer');constora=require('ora');constfs=require('fs');constpath=require('path');constspinner=ora();constgitClone=require('git-clone')constchalk=require('chalk')程序.version('1.0.0','-v,--version').parse(process.argv);constquestions=[{type:'input',name:'name',message:'请输入项目名称',default:'my-project',验证:(name)=>{if(/^[a-z]+/.test(name)){returntrue;}else{return'项目名必须以小写字母开头';}}}]inquirer.prompt(questions).then((dir)=>{downloadTemplate(dir.name);})functiondownloadTemplate(dir){//判断目录是否已经存在letisHasDir=fs.existsSync(path.resolve(目录));if(isHasDir){spinner.fail('当前目录已经存在!');返回假;}spinner.start(`您选择的目录是:${chalk.red(dir)},正在加载数据,请稍候...`);//克隆模板文件gitClone(`https://github.com/noahlam/vue-multi-tab.git`,dir,null,function(err){//删除无用文件shell.rm('-rf',`${dir}/.git`)spinner.succeed('项目初始化成功!')//运行常用命令shell.cd(dir)spinner.start(`它正在帮助您安装依赖项...`);shell.exec('npmi')spinner.succeed('Dependencyinstalledsuccessfully!')shell.exec('npmrundev')})}如果你对这个脚手架有任何疑问或兴趣,可以直接访问代码选项卡-github上的cli实现多tab。如果要实现多tab,那vue-router基本没用,why?vue-router根据url切换单个组件,而tab需要同时在组件内部有多个子组件,所以路由无法胜任(至少我是这么认为的,如果你有更好的解决方案,请让我知道)多个tab的展示其实并不难,element有现成的tab组件,所以老哥写代码就像穿梭一样,撸起袖子干,啪啪啪,写完后测试了一下,没有问题,真的是不要太简单了,丢给产品预览:复制浏览器地址粘贴到别处,tab不能正确回显,跳转需要在选项卡,它必须能够返回。第一个问题比较简单。自己写一个基于hash的伪路由,把当前tab的id放在url上,然后回显的时候,根据url打开对应的tab。tip:如何实现路由请看我的另一篇博文自己实现一个前端路由。第二个问题大概是本文的重点。以下是对要求的详细说明。每个选项卡都可以在选项卡内跳转。这里的跳转和vue-router的跳转一般都有类似的,要能够push,replace,back,还要带参数。那么如何实现呢?首先维护一个打开的选项卡列表,然后在每个列表中维护一个使用过的组件(包括参数)的列表。这可能吗?当然不是,用户不可能实现这些跳转组件和传递参数的方法。我选择封装一个公共对象挂载在vue.prototype上。然后像vue.$router.xxxx(我叫vue.$tab)这样的东西可以在页面的任何地方使用。如果对具体的实现方法感兴趣,请点击文末链接前往我的Github仓库查看。在组件异步加载之前,只使用过基于vue-router的异步加载方式。但是,这个项目没有使用vue-router。怎么可能是异步的?翻了一下vue的官方文档,是这样写的:Vue.component('async-webpack-example',//这个`import`函数会返回一个`Promise`对象。()=>import('./my-async-component'))但是我试了一下,发现报错。这里不能用import,这里不能用require。谢谢!后来在segmentfault上看到这篇文章,用webpack的require.ensure可以实现//第一个字符串是组件名,第二个是组件路径,第三个是chunkName(不指定就是1.js,2.js....n.js命名)vue.component('home',(resolve)=>{require.ensure([],()=>resolve(require('@/Views/index.vue')),'home')})顺便在webpack中配置output下的chunkFilename:'[name].js',当然文件名格式可以根据你项目的需要,我会的使用最简单的结束语首先,当然这里是项目的github地址,其次是本文地址个人技术帖合集以上项目欢迎大家随意star和关注,不乱发
