序:
我接下来写的vue项目高阶操作文章,每篇都按照需求分析+操作的模式来写。
需求分析:
大家都知道vue主要是用于搭建 单页Web应用(single page web application,SPA),根据实践,需要多页面的场景有以下几种:
- 首屏优化,这是SPA应用的固有的问题,(后面会用一章专门讲这个),而利用多页面就是将首屏(登录页等)独立出来一个html,首次加载时只加载这个依赖很少的html。
- 分模块开发,例如需要增加有不同权限的后台某个功能,按照以前需要新建一个项目,而利用多页面就是增加多一个出入口的事。
- 某些页面独立出来,例如有某个页面含有很多与第三方(微信等)交互的功能,这就需要后台配合生成签名等操作,这样就会导致 后台到第三方到客户端的各种重复调转,有些还需要通过url传各种参数,麻烦而且不安全,利用多页面就是将此页面独立出来打包成一个html静态页面,直接放到后端让后台直接完成第三方对接逻辑。
以上需求针对的是本人公司遇到的一些问题。当然还有很多,大家根据自己实际使用。
代码操作:
基础知识
- vue-cli 提供了一个pages字段作为页面的配置(vue.config.js)。https://cli.vuejs.org/zh/config/#pages
平常我们vue-cli 搭建的项目都是单页面应用,pages的默认配置就如上图,而我们如果需要配置多页面就直接按照上面的配置注释来提供入口文件和出口页面即可。如下:
- /vue.config.js
module.exports = {
pages: {
index: {
entry: 'src/main.js',
template: 'public/index.html',
filename: 'index.html',
title: 'Index Page',
},
page2: {
entry: 'src/page2_main.js',
filename: 'page2.html',
title: 'page2Page',
},
}
}
- src/page2_main.js
import Vue from 'vue';
import App from 'src/page2_app.vue';
Vue.config.productionTip = false;
new Vue({ render: h => h(App) }).$mount('#page2');
- src/page2_app.vue
<template>
<div id="page2">
页面2
</div>
</template>
<script>
export default {
}
</script>
- 运行,和以前一样:npm run serve
打开 localhost:8080/page.html 就可以看到page2的效果。 - 打包 npm run build
会在包里打出一个 page2.html
总结:就这么简单,如果你只需要两个页面,那么上面的完全可以满足你的需求(以上代码需要注意路径的问题。)
不过,当你需要很多个页面的时候,以上配置就显得有点麻烦了,有很多操作都需要重复,下面的干货就登场了。
自动化生成多页面配置和入口文件。
思路:多页面需要的两个条件:1、pages字段的配置json 2、入口文件(例:main.js)
写一个函数用node.js的库自动化实现此两个条件即可。
- vue.config.js
const glob = require('glob');
const fs = require('fs');
module.exports = {
publicPath: '',
// 自动多页面配置
pages: getPages()
}
// 生成多页面的配置数据
function getPages() {
const pages = {};
// 寻找到目标文件遍历
glob.sync('./src/pages/*/*.vue').forEach(function (pageUrl) {
const ext = path.extname(pageUrl);
const pageCode = path.basename(pageUrl, ext);
// 文件名不能重复的验证(pageCode 在这里取的是文件名)
if(pages[pageCode]){
console.error( `文件名不能重复使用:${pageCode}。\n`);
process.exit(1);
}
// 生成入口文件,放在跟目录的entry目录中
const entryFile = `./entry/${pageCode}.js`;
fs.exists(entryFile, async function (exists) { // 这里没有对文件目录进行判断,所以需要先建一个'entry'文件夹,否则会报错
if(exists) return;
// 创建文件及写入文件内容
const appTpl = '.' + pageUrl;
let entryData = ''
// 判断是否有路由文件
await fs.exists(`./src/pages/${pageCode}/router.js`,function(exists){
if(exists){
entryData = `import Vue from 'vue';\nimport '../src/base-main.js'\nimport App from '${appTpl}';\nVue.config.productionTip = false;\nimport router from '../src/pages/${pageCode}/router.js'\n\nnew Vue({ router , render: h => h(App) }).$mount('#${pageCode}'); `;
fs.writeFile(entryFile, entryData, function(err){
// err.code === 'ENOENT'
if(err) console.log(err);
});
}
if(!exists){
entryData = `import Vue from 'vue';\nimport '../src/base-main.js'\nimport App from '${appTpl}';\nVue.config.productionTip = false;\nnew Vue({ render: h => h(App) }).$mount('#${pageCode}'); `;
fs.writeFile(entryFile, entryData, function(err){
// err.code === 'ENOENT'
if(err) console.log(err);
});
}
})
});
// 自定义页面数据,用于增加附加数据,例如title等。
const pagesJson = require('./src/page.json');
const pageData = pagesJson[pageCode] || {};
Object.assign(pageData, {
url: pageUrl,
code: pageCode
});
// 配置多页面
pages[pageCode] = {
entry: entryFile, // 入口文件
template: './public/index.html',// 模板文件
filename: pageCode + '.html', // 打包后的文件路径
minify: true, // 是否压缩
chunks: ['chunk-vendors', 'chunk-common', 'app', pageCode], // 引入资源文件
chunksSortMode: 'manual', // 控制 chunk 的排序。none | auto(默认)| dependency(依赖)| manual(手动)| {function}
pageData: pageData
};
});
return pages;
}
- 目录结构
上面函数就是在启动项目的时候,自动去检测src/pages 下有vue文件的子目录,自动生成对应的入口文到 entry文件,并返回 对应的pages配置json到vue.config.js,从而实现了多页面。 - 特殊文件介绍
src/base-main.js 公用的入口文件,会合并到各个页面的入口文件中,用于放所有页面都需要的公有依赖。
import Vue from 'vue'
Vue.config.productionTip = false
import Vant from 'vant';
import 'vant/lib/index.css';
Vue.use(Vant)
import requests from '@s/basejs/new-axios.js'
Vue.prototype.rq = requests
// 通用工具库
import {tools} from '@s/basejs/tools.js'
Vue.prototype.tools = tools;
import '@s/basecss/common.css' // 通用css
// 全局过滤器
import * as filters from '@s/basejs/filters.js'
Object.keys(filters).forEach(key => {
Vue.filter(key, filters[key])
})
生成的入口文件(有路由):entry/index.js
import Vue from 'vue';
import '../src/base-main.js'
import App from '../src/pages/index/index.vue';
Vue.config.productionTip = false;
import router from '../src/pages/index/router.js'
new Vue({ router , render: h => h(App) }).$mount('#index');
生成的入口文件(无路由):entry/home1.js
import Vue from 'vue';
import '../src/base-main.js'
import App from '../src/pages/home1/home1.vue';
Vue.config.productionTip = false;
new Vue({ render: h => h(App) }).$mount('#home1');
页面附加数据 src/page.json
{
"home1": {
"title": "home1",
"code" : "home1"
},
"home2": {
"title": "home2",
"code" : "home2"
},
"index": {
"title": "个人中心",
"code" : "index"
}
}
注意:因为函数是在项目运行时执行的,如果要增加多一个多页面(即是在src/pages下增加多一个有vue文件的目录),需要重新执行 npm run serve 才能生效多页面配置和生成新的入口文件。
好了,这就是自动化多页面的全部内容了。这是我自动化插件的第一次实践,从此打开了我写插件的大门,让我知道写插件不是后端的专属,前端也可以利用一些插件提高自己的编码效率和架构思想,并为我之后的自动化vue lib库工厂项目做了思想上的基础。
这篇文章如果刚好对你有帮助,帮忙点个赞呗。有什么问题也可以留言讨论。
很高兴你能读到我的文章,我是醉梦者,让我们一起进步成长,慢慢变成自己想要的成为的自己