当前位置: 首页 > news >正文

vue 多页面应用例子_用vue构建多页面应用

为什么要用多页面应用?

研究了下vue搭建多页面应用,个人感觉多页面应用的优势主要就是在打包的时候每个页面都是单独打包,除了公用的vendor/mainfest文件,每个页面都只引用自己的样式表和脚本文件。在一个模块更新的时候,也不会影响到其他模块(如下图)。即提高了页面加载速度,也有利于运营维护。另外有SEO需求的话,单页面应用的改造是比较麻烦的,多页面入口则容易的多。关于单页面和多页面详细对比分析详见:https://www.cnblogs.com/xyyt/p/9116827.html

如上图,只是修改了index模块下的页面,重新打包,只有index相关的css/js文件及mainfest,其他文件都没有改动。

上边的说明还不好理解?

现实生活中的集团和子公司的例子来模拟说明多页面应用是再形象不过——一个集团相当于一个大项目,集团下边每个子公司都负责一块儿独立的业务(相当于每个页面入口)。集团提供了办公场地、办公设备、人员招聘等公共资源,每个子公司又可以根据自己的需要调整自己内部组织结构,置办自己独有的一些内部资源。每个子公司都相互独立运行,一个子公司的变动不会影响到其他子公司。就算后边某个子公司发展足够好可以从集团独立出来,或者经营不善面临解散,也只是子公司内部及集团层面有调整,对其他子公司没任何影响,多页面应用的优势也就是这样。

怎么搭建多页面应用?

首先,你需要会使用vue-cli脚手架创建一个基于webpack模板的单页面应用项目,需要注意的地方请留意下面代码后边的注释:

# 全局安装 vue-cli

npminstall --global vue-cli

# 创建一个基于 webpack 模板的新项目

vue init webpack my-project

# 这里需要进行一些配置,默认回车即可

This willinstall Vue 2.x version of the template.

For Vue1.x use: vue init webpack#1.0 my-project? Project name my-project?Project description A Vue.js project? Author runoob

?Vue build standalone? Use ESLint to lint your code? Yes//如不需要eslint,此处输入N回车

? Pick an ESLint preset Standard//如不需要eslint,此处输入N回车

? Setup unit tests with Karma + Mocha? Yes//如不需要单元测试,此处输入N回车

? Setup e2e tests with Nightwatch? Yes//如不需要端对端测试,此处输入N回车

vue-cli · Generated "my-project".

To get started:

cd my-project

npminstallnpm run dev

Documentation can be found at https://vuejs-templates.github.io/webpack

然后,进入项目,安装并运行,确保单页面应用能正常访问:

cd my-project

npm install

npm run dev

DONE Compiled successfullyin4388ms> Listening at http://localhost:8080

注意:目前最新的模板是没有开启自动打开浏览器访问的,可以去config/index.js中开启——autoOpenBrowser: true

最后,就要进入正题了,开始进行多页面改造了。

单页面应用改造多页面应用:

1.准备工作_安装glob组件:

glob是webpack安装时依赖的一个第三方模块,该模块允许你使用 *等符号, 例如lib/*.js就是获取lib文件夹下的所有js后缀名的文件。

npm install glob -save-dev

2. 配置文件改造:

需要改动的文件如下:

下面就按照顺序贴出完整的代码内容,在做修改或者添加代码的位置做了中文注释。

utils.js——修改1处

'use strict'const path= require('path')

const config= require('../config')

const ExtractTextPlugin= require('extract-text-webpack-plugin')

const packageConfig= require('../package.json')

exports.assetsPath= function(_path) {

const assetsSubDirectory= process.env.NODE_ENV === 'production'

?config.build.assetsSubDirectory

: config.dev.assetsSubDirectoryreturnpath.posix.join(assetsSubDirectory, _path)

}

exports.cssLoaders= function(options) {

options= options ||{}

const cssLoader={

loader:'css-loader',

options: {

minimize: process.env.NODE_ENV=== 'production',

sourceMap: options.sourceMap

}

}

const postcssLoader={

loader:'postcss-loader',

options: {

sourceMap: options.sourceMap

}

}//generate loader string to be used with extract text plugin

functiongenerateLoaders (loader, loaderOptions) {

const loaders= options.usePostCSS ?[cssLoader, postcssLoader] : [cssLoader]if(loader) {

loaders.push({

loader: loader+ '-loader',

options: Object.assign({}, loaderOptions, {

sourceMap: options.sourceMap

})

})

}//Extract CSS when that option is specified

//(which is the case during production build)

if(options.extract) {returnExtractTextPlugin.extract({

use: loaders,

fallback:'vue-style-loader'})

}else{return ['vue-style-loader'].concat(loaders)

}

}//https://vue-loader.vuejs.org/en/configurations/extract-css.html

return{

css: generateLoaders(),

postcss: generateLoaders(),

less: generateLoaders('less'),

sass: generateLoaders('sass', { indentedSyntax: true}),

scss: generateLoaders('sass'),

stylus: generateLoaders('stylus'),

styl: generateLoaders('stylus')

}

}//Generate loaders for standalone style files (outside of .vue)

exports.styleLoaders = function(options) {

const output=[]

const loaders=exports.cssLoaders(options)for (const extension inloaders) {

const loader=loaders[extension]

output.push({

test:new RegExp('\\.' + extension + '$'),

use: loader

})

}returnoutput

}/*这里是添加的部分 ---------------------------- 开始*/

//glob是webpack安装时依赖的一个第三方模块,还模块允许你使用 *等符号, 例如lib/*.js就是获取lib文件夹下的所有js后缀名的文件

var glob = require('glob')//页面模板

var HtmlWebpackPlugin = require('html-webpack-plugin')//取得相应的页面路径,因为之前的配置,所以是src文件夹下的pages文件夹

var PAGE_PATH = path.resolve(__dirname, '../src/pages')//用于做相应的merge处理

var merge = require('webpack-merge')//多入口配置//通过glob模块读取pages文件夹下的所有对应文件夹下的js后缀文件,如果该文件存在//那么就作为入口处理

exports.entries = function() {var entryFiles = glob.sync(PAGE_PATH + '/*/*.js')var map ={}

entryFiles.forEach((filePath)=>{var filename = filePath.substring(filePath.lastIndexOf('\/') + 1, filePath.lastIndexOf('.'))

map[filename]=filePath

})returnmap

}//多页面输出配置//与上面的多页面入口配置相同,读取pages文件夹下的对应的html后缀文件,然后放入数组中

exports.htmlPlugin = function() {

let entryHtml= glob.sync(PAGE_PATH + '/*/*.html')

let arr=[]

entryHtml.forEach((filePath)=>{

let filename= filePath.substring(filePath.lastIndexOf('\/') + 1, filePath.lastIndexOf('.'))

let conf={//模板来源

template: filePath,//文件名称

filename: filename + '.html',//页面模板需要加对应的js脚本,如果不加这行则每个页面都会引入所有的js脚本

chunks: ['manifest', 'vendor', filename],

inject:true}if (process.env.NODE_ENV === 'production') {

conf=merge(conf, {

minify: {

removeComments:true,

collapseWhitespace:true,

removeAttributeQuotes:true},

chunksSortMode:'dependency'})

}

arr.push(newHtmlWebpackPlugin(conf))

})returnarr

}/*这里是添加的部分 ---------------------------- 结束*/exports.createNotifierCallback= () =>{

const notifier= require('node-notifier')return (severity, errors) =>{if (severity !== 'error') returnconst error= errors[0]

const filename= error.file && error.file.split('!').pop()

notifier.notify({

title: packageConfig.name,

message: severity+ ': ' +error.name,

subtitle: filename|| '',

icon: path.join(__dirname,'logo.png')

})

}

}

webpack.base.conf.js——修改1处

'use strict'const path= require('path')

const utils= require('./utils')

const config= require('../config')

const vueLoaderConfig= require('./vue-loader.conf')functionresolve (dir) {return path.join(__dirname, '..', dir)

}

module.exports={

context: path.resolve(__dirname,'../'),/*修改部分*/entry:utils.entries(),/*修改部分end*/output: {

path: config.build.assetsRoot,

filename:'[name].js',

publicPath: process.env.NODE_ENV=== 'production'

?config.build.assetsPublicPath

: config.dev.assetsPublicPath

},

resolve: {

extensions: ['.js', '.vue', '.json'],

alias: {'vue$': 'vue/dist/vue.esm.js','@': resolve('src'),'@comp': resolve('src/components'),'@static': resolve('static'),

}

},

module: {

rules: [

{

test:/\.vue$/,

loader:'vue-loader',

options: vueLoaderConfig

},

{

test:/\.js$/,

loader:'babel-loader',

include: [resolve('src'), resolve('test'), resolve('node_modules/webpack-dev-server/client')]

},

{

test:/\.(png|jpe?g|gif|svg)(\?.*)?$/,

loader:'url-loader',

options: {

limit:10000,

name: utils.assetsPath('img/[name].[hash:7].[ext]')

}

},

{

test:/\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/,

loader:'url-loader',

options: {

limit:10000,

name: utils.assetsPath('media/[name].[hash:7].[ext]')

}

},

{

test:/\.(woff2?|eot|ttf|otf)(\?.*)?$/,

loader:'url-loader',

options: {

limit:10000,

name: utils.assetsPath('fonts/[name].[hash:7].[ext]')

}

}

]

},

node: {//prevent webpack from injecting useless setImmediate polyfill because Vue

//source contains it (although only uses it if it's native).

setImmediate: false,//prevent webpack from injecting mocks to Node native modules

//that does not make sense for the client

dgram: 'empty',

fs:'empty',

net:'empty',

tls:'empty',

child_process:'empty'}

}

webpack.dev.conf.js——修改2处

'use strict'const utils= require('./utils')

const webpack= require('webpack')

const config= require('../config')

const merge= require('webpack-merge')

const path= require('path')

const baseWebpackConfig= require('./webpack.base.conf')

const CopyWebpackPlugin= require('copy-webpack-plugin')

const HtmlWebpackPlugin= require('html-webpack-plugin')

const FriendlyErrorsPlugin= require('friendly-errors-webpack-plugin')

const portfinder= require('portfinder')

const HOST=process.env.HOST

const PORT= process.env.PORT &&Number(process.env.PORT)

const devWebpackConfig=merge(baseWebpackConfig, {

module: {

rules: utils.styleLoaders({ sourceMap: config.dev.cssSourceMap, usePostCSS:true})

},//cheap-module-eval-source-map is faster for development

devtool: config.dev.devtool,//these devServer options should be customized in /config/index.js

devServer: {

clientLogLevel:'warning',

historyApiFallback: {

rewrites: [

{ from:/.*/, to: path.posix.join(config.dev.assetsPublicPath, 'index.html') },

],

},

hot:true,

contentBase:false, //since we use CopyWebpackPlugin.

compress: true,

host: HOST||config.dev.host,

port: PORT||config.dev.port,

open: config.dev.autoOpenBrowser,

overlay: config.dev.errorOverlay? { warnings: false, errors: true}

:false,

publicPath: config.dev.assetsPublicPath,

proxy: config.dev.proxyTable,

quiet:true, //necessary for FriendlyErrorsPlugin

watchOptions: {

poll: config.dev.poll,

}

},

plugins: [newwebpack.DefinePlugin({'process.env': require('../config/dev.env')

}),newwebpack.HotModuleReplacementPlugin(),new webpack.NamedModulesPlugin(), //HMR shows correct file names in console on update.

newwebpack.NoEmitOnErrorsPlugin(),//https://github.com/ampedandwired/html-webpack-plugin

/*注释掉的文件*/

//new HtmlWebpackPlugin({//filename: 'index.html',//template: 'index.html',//inject: true//}),

/*注释掉的文件end*/

//copy custom static assets

newCopyWebpackPlugin([

{

from: path.resolve(__dirname,'../static'),

to: config.dev.assetsSubDirectory,

ignore: ['.*']

}

])

].concat(utils.htmlPlugin())//追加的代码

})

module.exports= new Promise((resolve, reject) =>{

portfinder.basePort= process.env.PORT ||config.dev.port

portfinder.getPort((err, port)=>{if(err) {

reject(err)

}else{//publish the new Port, necessary for e2e tests

process.env.PORT =port//add port to devServer config

devWebpackConfig.devServer.port =port//Add FriendlyErrorsPlugin

devWebpackConfig.plugins.push(newFriendlyErrorsPlugin({

compilationSuccessInfo: {

messages: [`Your application is running here: http://${devWebpackConfig.devServer.host}:${port}`],

},

onErrors: config.dev.notifyOnErrors?utils.createNotifierCallback()

: undefined

}))

resolve(devWebpackConfig)

}

})

})

webpack.prod.conf.js——修改2处

'use strict'const path= require('path')

const utils= require('./utils')

const webpack= require('webpack')

const config= require('../config')

const merge= require('webpack-merge')

const baseWebpackConfig= require('./webpack.base.conf')

const CopyWebpackPlugin= require('copy-webpack-plugin')

const HtmlWebpackPlugin= require('html-webpack-plugin')

const ExtractTextPlugin= require('extract-text-webpack-plugin')

const OptimizeCSSPlugin= require('optimize-css-assets-webpack-plugin')

const UglifyJsPlugin= require('uglifyjs-webpack-plugin')

const env= require('../config/prod.env')

const webpackConfig=merge(baseWebpackConfig, {

module: {

rules: utils.styleLoaders({

sourceMap: config.build.productionSourceMap,

extract:true,

usePostCSS:true})

},

devtool: config.build.productionSourceMap? config.build.devtool : false,

output: {

path: config.build.assetsRoot,

filename: utils.assetsPath('js/[name].[chunkhash].js'),

chunkFilename: utils.assetsPath('js/[id].[chunkhash].js')

},

plugins: [//http://vuejs.github.io/vue-loader/en/workflow/production.html

newwebpack.DefinePlugin({'process.env': env

}),newUglifyJsPlugin({

uglifyOptions: {

compress: {

warnings:false}

},

sourceMap: config.build.productionSourceMap,

parallel:true}),//extract css into its own file

newExtractTextPlugin({

filename: utils.assetsPath('css/[name].[contenthash].css'),//Setting the following option to `false` will not extract CSS from codesplit chunks.

//Their CSS will instead be inserted dynamically with style-loader when the codesplit chunk has been loaded by webpack.

//It's currently set to `true` because we are seeing that sourcemaps are included in the codesplit bundle as well when it's `false`,

//increasing file size: https://github.com/vuejs-templates/webpack/issues/1110

allChunks: true,

}),//Compress extracted CSS. We are using this plugin so that possible

//duplicated CSS from different components can be deduped.

newOptimizeCSSPlugin({

cssProcessorOptions: config.build.productionSourceMap? { safe: true, map: { inline: false} }

: { safe:true}

}),//generate dist index.html with correct asset hash for caching.

//you can customize output by editing /index.html

//see https://github.com/ampedandwired/html-webpack-plugin

/*注释的代码*/

//new HtmlWebpackPlugin({//filename: config.build.index,//template: 'index.html',//inject: true,//minify: {//removeComments: true,//collapseWhitespace: true,//removeAttributeQuotes: true more options: https://github.com/kangax/html-minifier#options-quick-reference//}, necessary to consistently work with multiple chunks via CommonsChunkPlugin//chunksSortMode: 'dependency'//}),

/*注释的代码end*/

//keep module.id stable when vendor modules does not change

newwebpack.HashedModuleIdsPlugin(),//enable scope hoisting

newwebpack.optimize.ModuleConcatenationPlugin(),//split vendor js into its own file

newwebpack.optimize.CommonsChunkPlugin({

name:'vendor',

minChunks (module) {//any required modules inside node_modules are extracted to vendor

return(

module.resource&&

/\.js$/.test(module.resource) &&module.resource.indexOf(

path.join(__dirname,'../node_modules')

)=== 0)

}

}),//extract webpack runtime and module manifest to its own file in order to

//prevent vendor hash from being updated whenever app bundle is updated

newwebpack.optimize.CommonsChunkPlugin({

name:'manifest',

minChunks: Infinity

}),//This instance extracts shared chunks from code splitted chunks and bundles them

//in a separate chunk, similar to the vendor chunk

//see: https://webpack.js.org/plugins/commons-chunk-plugin/#extra-async-commons-chunk

newwebpack.optimize.CommonsChunkPlugin({

name:'app',

async:'vendor-async',

children:true,

minChunks:3}),//copy custom static assets

newCopyWebpackPlugin([

{

from: path.resolve(__dirname,'../static'),

to: config.build.assetsSubDirectory,

ignore: ['.*']

}

])

].concat(utils.htmlPlugin())//追加的代码

})if(config.build.productionGzip) {

const CompressionWebpackPlugin= require('compression-webpack-plugin')

webpackConfig.plugins.push(newCompressionWebpackPlugin({

asset:'[path].gz[query]',

algorithm:'gzip',

test:newRegExp('\\.(' +config.build.productionGzipExtensions.join('|') +

')$'),

threshold:10240,

minRatio:0.8})

)

}if(config.build.bundleAnalyzerReport) {

const BundleAnalyzerPlugin= require('webpack-bundle-analyzer').BundleAnalyzerPlugin

webpackConfig.plugins.push(newBundleAnalyzerPlugin())

}

module.exports= webpackConfig

3. 页面改造:

1)src目录下新建pages文件夹,用来存放页面。

2)新建index文件夹作为主页(也可以定义为home).

3)将src目录下的App.vue和main.js以及根目录下的index.html文件统统放到index文件夹中,并将main.js改为index.js(html文件即为打包好直接访问的页面模板,决定了访问的文件路径,最好跟页面文件夹一致,js文件为页面入口,需要与html文件一致;vue文件名不限制,只需要在js文件中正确引入就可以了)。

一个页面文件夹中文件的格式分别如下:

App.vue

login

相关文章:

  • 6.7 二分查找
  • oracle手工收集awr报告_oracle手工生成AWR报告方法
  • 《杜拉拉升职记》//TODO
  • php缓存accestoken_php微信开发(1):缓存access_token的方法
  • git 更新代码到本地
  • python subprocess使用_python subprocess使用-阿里云开发者社区
  • tomcat日志神器--kibana
  • python计算相同生日概率_用python计算下一个生日前的天数
  • java保证多线程的执行顺序
  • php 文本显示一部分_使用简单,功能全面的 PHP 命令行应用库
  • jzoj4196 二分图计数 解题报告(容斥原理)
  • 华为上半年手机销量_国产手机上半年销量出炉:小米华为所向无敌
  • Python2与Python3区别
  • 计算混响时间的意义_计算你房间的混响时间
  • cordova打开文件_cordova插件之下载文件并打开
  • [译]CSS 居中(Center)方法大合集
  • “大数据应用场景”之隔壁老王(连载四)
  • 【个人向】《HTTP图解》阅后小结
  • 30秒的PHP代码片段(1)数组 - Array
  • 8年软件测试工程师感悟——写给还在迷茫中的朋友
  • ECS应用管理最佳实践
  • egg(89)--egg之redis的发布和订阅
  • E-HPC支持多队列管理和自动伸缩
  • iOS小技巧之UIImagePickerController实现头像选择
  • Js基础——数据类型之Null和Undefined
  • Js实现点击查看全文(类似今日头条、知乎日报效果)
  • Mysql5.6主从复制
  • Odoo domain写法及运用
  • Python代码面试必读 - Data Structures and Algorithms in Python
  • React中的“虫洞”——Context
  • Spring Cloud(3) - 服务治理: Spring Cloud Eureka
  • use Google search engine
  • 爱情 北京女病人
  • 从伪并行的 Python 多线程说起
  • 给第三方使用接口的 URL 签名实现
  • 给新手的新浪微博 SDK 集成教程【一】
  • 解决jsp引用其他项目时出现的 cannot be resolved to a type错误
  • 实战:基于Spring Boot快速开发RESTful风格API接口
  • 学习笔记TF060:图像语音结合,看图说话
  • 一起来学SpringBoot | 第三篇:SpringBoot日志配置
  • Spark2.4.0源码分析之WorldCount 默认shuffling并行度为200(九) ...
  • #### go map 底层结构 ####
  • #多叉树深度遍历_结合深度学习的视频编码方法--帧内预测
  • #在线报价接单​再坚持一下 明天是真的周六.出现货 实单来谈
  • (145)光线追踪距离场柔和阴影
  • (4) PIVOT 和 UPIVOT 的使用
  • (C语言)编写程序将一个4×4的数组进行顺时针旋转90度后输出。
  • (Java岗)秋招打卡!一本学历拿下美团、阿里、快手、米哈游offer
  • (分类)KNN算法- 参数调优
  • (考研湖科大教书匠计算机网络)第一章概述-第五节1:计算机网络体系结构之分层思想和举例
  • (十)DDRC架构组成、效率Efficiency及功能实现
  • (算法)N皇后问题
  • (一)80c52学习之旅-起始篇
  • (转)清华学霸演讲稿:永远不要说你已经尽力了
  • *(长期更新)软考网络工程师学习笔记——Section 22 无线局域网