Vue.js CLI 中的多个页面

multiple pages in Vue.js CLI

我无法弄清楚如何在 Vue CLI 项目中拥有多个页面。现在我的主页有一些组件,我想创建另一个页面,但我不知道该怎么做。我是否应该在默认情况下 index.html 所在的位置创建多个 html 文件?在以 css js img 文件夹和 html 文件作为页面的简单文件结构中,我知道创建另一个 html 文件意味着制作另一个页面。但是我不明白这是如何与 Vue CLI 项目一起工作的。

我在 Vue 文档中看到了 vue-router 和 "pages" 之类的东西,但我不太了解它们。我有什么选择?有没有详细解释的指南,因为我找不到,更不用说详细了。如果您能提供帮助,将非常高兴!谢谢!

请注意将用户指向应该被接受的答案
在发布我的初始答案时,我并不知道在 VueJS 中实际构建 MPA 的可能性。我的回答没有解决所问的问题,因此我建议看看下面 PJ.Wanderson 提供的答案, 应该是公认的答案

初始答案
Vue.js 项目是 SPA(单页应用程序)。你整个工程只有一个.html文件,就是你说的index.html文件。您要创建的 "pages",在 vue.js 中称为组件。它们将被插入 index.html 文件并在浏览器中呈现。 vue.js 组件包含 3 个部分:

<template>

</template>

<script>
export default {

}
</script>

<style>

</style>
  • 模板:它包含您的页面应显示的所有 html(这是放置页面 html 的位置)
  • 脚本:它包含将在 page/component
  • 上执行的所有 JavaScript 代码
  • 样式:它包含 CSS 将设置特定 component/page
  • 的样式

您可以查看本教程以快速入门Vue.js 2 Quickstart Tutorial 2017

它解释了 vue.js 项目结构以及各种文件如何相互关联

第一:始终阅读官方文档。使用 Vue 你可以构建一个 SPA,一个 MPA 也没有问题。只需按照指南操作即可:

您应该使用 Vue CLI 3 创建一个新项目。创建项目后,将其设置为手动配置。确保您选择 SPA 选项。然后,Vue 将使用 MPA 方法创建一个不错的“开始”项目。之后,只需在 vue.config.js.

上重复配置

更新#1

似乎 Vue Cli 的一些更新改变了构建 MPA 应用程序的方式,所以:

  • 创建新应用程序vue create test
  • 选择手动配置

创建的样板将用于 SPA。因此进行以下更改:

  • src 下创建一个名为 pages 的文件夹(可选)

  • 在此文件夹中创建您自己的页面:主页、关于等

  • 将 src 中的 App.vue 和 main.js 复制并粘贴到您的新文件夹 - Home 等中

  • 根据您的喜好将 App.vue 格式化到此文件夹中。

  • 创建一个vue.config.js并设置如下:https://cli.vuejs.org/config/#pages

下面,我用三张图片展示了这一点:

  • 第一:全新的应用程序
  • 第二个:同一个应用程序,我在上面进行了更改
  • 第三个:来自此应用的 vue.config.js

不需要创建pages文件夹,这只是为了理解。

Link 到 GitHub:Building a MPA App

编辑:Vue 内置了这个。跳到底部了解更多。

原回答:

有两种方法可以解释您的问题,从而回答您的问题。

第一种解读为:"how can I support routing to different pages within the same single-page app, e.g. localhost:8080/about and localhost:8080/report etc?"。答案是使用路由器。它相当简单并且运行良好。

第二种解释是:"my app is complex, and I have multiple single-page applications, e.g. one app for the 'website' part, one app for consumers to log in and do work, one app for admins, etc - how can vue do this, without making three entirely separate repositories?"

后者的答案是具有多个单页应用程序的单个存储库。这个演示看起来正是您所追求的:

https://github.com/Plortinus/vue-multiple-pages/

具体看:https://github.com/Plortinus/vue-multiple-pages/blob/master/vue.config.js

更新的答案:

原来vuejs内置了多个顶级页面的思想。我的意思是,这是有道理的 - 尽管关于 "no, it's for single page apps"!

有很多不正确的答案,但它会非常普遍

您想要 vue.config.js 文件中的 pages 选项:

https://cli.vuejs.org/config/#pages

如果您的项目在根目录中没有该文件,请创建它,vuejs 会发现它。

定义每个页面有长有短。我在这里使用了缩写形式:

module.exports = {
  pages: {
    index: 'src/pages/index/main.ts',
    experiment: 'src/pages/experiment/main.ts'
  }
}

您不必将您的工作放在 "pages" 下。它可以是“/src/apps/index/index.ts”或其他任何东西。

移动代码并更改一些导入后:

import HelloWorld from './components/HelloWorld'

import HelloWorld from '@/components/HelloWorld'

该应用程序可以运行 - 但我的存储库中的 "experiment" 应用程序必须像这样加载:

http://localhost:8080/experiment.html

非常丑陋,甚至更糟,因为它使用导致 URL 的路由器:

http://localhost:8080/experiment.html/about

幸好解决了。更新 vue.config.js 文件以包含 devServer 选项(确保这是在导出对象的顶层:

devServer: {
  historyApiFallback: {
    rewrites: [
      { from: /\/index/, to: '/index.html' },
      { from: /\/experiment/, to: '/experiment.html' }
    ]
  }
}

然后还修改 router.ts 文件以附加额外的路径(在我的例子中 "experiment/":

export default new Router({
  mode: 'history',
  base: process.env.BASE_URL + 'experiment/',
  ...

然后 URL 会很好地解析,例如:http://localhost:8080/experiment/about

这可能与问题无关,但请耐心等待,也许我的回答可以帮助到一些人。 我用的是webpack+vue,弄明白了怎么搭建多页应用。这是我的 webpack.config.js:

const path = require('path');
const fs = require('fs')
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const VueLoaderPlugin = require('vue-loader/lib/plugin');
const TerserPlugin = require('terser-webpack-plugin');
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const OptimizeCSSAssetsPlugin = require("optimize-css-assets-webpack-plugin");

module.exports = {
    entry: {
        app: './src/app.js',
        mgmt: ['./src/modules/mgmt/mgmt.js'],
        login: './src/modules/login/login.js'
    },
    output: {
        path: path.resolve(__dirname, 'dist'),
        // publicPath: '/ahezime/',
        filename: (chunkData) => {
            console.log('chuckData.chunk.name => ', chunkData.chunk.name)
            return chunkData.chunk.name === 'app' ? './[name].bundle.js' : './[name]/[name].bundle.js';
        }
    },
    optimization: {
        minimizer: [
            new TerserPlugin(),
            new OptimizeCSSAssetsPlugin({})
        ]
    },
    plugins: [
        new MiniCssExtractPlugin({
            filename: "[name].css",
            chunkFilename: "[id].css"
        }),
        new CleanWebpackPlugin(['dist']),
        new VueLoaderPlugin(),
        new HtmlWebpackPlugin({
            title: 'app',
            template: './src/app.html',
            // inject: false,
            chunks: ['app'],
            filename: './index.html'
        }),
        new HtmlWebpackPlugin({
            title: 'mgmt',
            template: './src/modules/mgmt/mgmt.html',
            // inject: false,
            chunks: ['mgmt'],
            filename: './mgmt/index.html'
        }),
        new HtmlWebpackPlugin({
            title: 'login',
            template: './src/modules/login/login.html',
            // inject: false,
            chunks: ['login'],
            filename: './login/index.html'
        })
    ],
    module: {
        rules: [
            {
                test: /\.m?js$/,
                exclude: /(node_modules|bower_components)/,
                use: {
                    loader: 'babel-loader',
                    options: {
                        presets: ['@babel/preset-env'],
                        plugins: ['@babel/plugin-proposal-object-rest-spread']
                    }
                }
            }
        ],
        rules: [
            {
                test: /\.vue$/,
                exclude: /node_modules/,
                loader: 'vue-loader'
            },
            {
                test: /\.css$/,
                use: [
                    'vue-style-loader',
                    'style-loader',
                    'css-loader',
                    'sass-loader'
                ]
            },
            {
                test: /\.scss?$/,
                use: ['style-loader', 'css-loader', 'sass-loader']
            },
            {
                test: /\.(png|svg|jpg|gif)$/,
                use: [
                    'file-loader'
                ]
            },
            {
                test: /\.(woff|woff2|eot|ttf|otf)$/,
                use: [
                    'file-loader'
                ]
            }
        ]
    }
};

这是我的目录结构:

https://i.stack.imgur.com/uFvKx.png

并且可以跳转页面:

<template>
    <div>
        <h1>App</h1>
        <div>
            <a href="./login">Please click me, and let take you into the login page!!!</a>
        </div>
        <span>Before computed: {{ message }} </span>
        <br>
        <span>Afer computed: {{ computedMessage() }} </span>
    </div>
</template>

<script>
    export default {
        data() {
            return {
                message: 'Hello World!'
            }
        },
        computed: {
            reversedMessage: function() {
                return this.message.split('').reverse().join('')
            }
        },
        methods: {
            computedMessage: function() {
                return this.message.split('').reverse().join('')
            }
        }
    }
</script>