(一)vue + webpack搭建前端項(xiàng)目

vue和webpack大家項(xiàng)目的教程很多冒晰,可以選擇自定義搭建,也可以選擇直接用腳手架vue-cli椎例。這里我就不一一細(xì)說(shuō)了斤斧,直接甩已有的教程:https://segmentfault.com/a/1190000008602934
而我這里的webpack配置,是我搭建項(xiàng)目一直用的配置:
我的簡(jiǎn)單項(xiàng)目結(jié)構(gòu)如下:

項(xiàng)目結(jié)構(gòu).png

其中build中的各文件如下:
build.js

require('./check-versions')()// 檢查 Node 和 npm 版本
process.env.NODE_ENV = 'production'//指定生產(chǎn)環(huán)境
var ora = require('ora')// 一個(gè)很好看的 loading 插件
var rm = require('rimraf')//提供node版本的UNIX的rm -rf命令
var path = require('path')//使用Node自帶的文件路徑插件
var chalk = require('chalk')//控制臺(tái)高亮顯示的插件
var webpack = require('webpack')//使用 webpack
var config = require('../config')//使用 config/index.js
var webpackConfig = require('./webpack.prod.conf')// 加載 webpack.prod.conf
// 使用 ora 打印出 loading + log
var spinner = ora('building for production...')
spinner.start()
//https://www.npmjs.com/package/rimraf
rm(path.join(config.build.assetsRoot, config.build.assetsSubDirectory), err => {
    if (err) throw err//如果回調(diào)函數(shù)出現(xiàn)錯(cuò)誤就拋出異常
    //  開(kāi)始 webpack 的編譯
    webpack(webpackConfig, function (err, stats) {//編譯回調(diào)函數(shù)
        spinner.stop()
        if (err) throw err//編譯失敗就拋出異常
        process.stdout.write(stats.toString({//標(biāo)準(zhǔn)輸出流
            colors: true,
            modules: false,
            children: false,
            chunks: false,
            chunkModules: false
        }) + '\n\n')
        console.log(chalk.cyan('  Build complete.\n'))
        console.log(chalk.yellow(
            '  Tip: built files are meant to be served over an HTTP server.\n' +
            '  Opening index.html over file:// won\'t work.\n'
        ))
    })
})

check-versions.js

var chalk = require('chalk')// 用于在控制臺(tái)輸出高亮字體的插件
var semver = require('semver')// 語(yǔ)義化版本檢查插件
var packageConfig = require('../package.json')// 引入package.json
var shell = require('shelljs')//引入shelljs
// 開(kāi)辟子進(jìn)程執(zhí)行指令cmd并返回結(jié)果
function exec (cmd) {
    return require('child_process').execSync(cmd).toString().trim()
}
// node和npm版本需求
var versionRequirements = [
    {
        name: 'node',
        currentVersion: semver.clean(process.version),
        versionRequirement: packageConfig.engines.node
    },
]
if (shell.which('npm')) {
    versionRequirements.push({
        name: 'npm',
        currentVersion: exec('npm --version'),
        versionRequirement: packageConfig.engines.npm
    })
}
module.exports = function () {
    var warnings = []
    // 依次判斷版本是否符合要求
    for (var i = 0; i < versionRequirements.length; i++) {
        var mod = versionRequirements[i]
        if (!semver.satisfies(mod.currentVersion, mod.versionRequirement)) {
            warnings.push(mod.name + ': ' +
                chalk.red(mod.currentVersion) + ' should be ' +
                chalk.green(mod.versionRequirement)
            )
        }
    }
    if (warnings.length) {
        console.log('')
        // 如果有警告則將其輸出到控制臺(tái)
        console.log(chalk.yellow('To use this template, you must update following to modules:'))
        console.log()
        for (var i = 0; i < warnings.length; i++) {
            var warning = warnings[i]
            console.log('  ' + warning)
        }
        console.log()
        process.exit(1)
    }
}

dev.client.js

/* eslint-disable */
require('eventsource-polyfill')
var hotClient = require('webpack-hot-middleware/client?noInfo=true&reload=true')

hotClient.subscribe(function (event) {
    if (event.action === 'reload') {
        window.location.reload()
}
})

dev.server.js

require('./check-versions')()

var config = require('../config')
if(!process.env.NODE_ENV) {
    process.env.NODE_ENV = JSON.parse(config.dev.env.NODE_ENV)
}

var opn = require('opn')
var path = require('path')
var express = require('express')
var webpack = require('webpack')
var proxyMiddleware = require('http-proxy-middleware')
var webpackConfig = require('./webpack.dev.conf')

// default port where dev server listens for incoming traffic
var port = process.env.PORT || config.dev.port
// automatically open browser, if not set will be false
var autoOpenBrowser = !!config.dev.autoOpenBrowser
// Define HTTP proxies to your custom API backend
// https://github.com/chimurai/http-proxy-middleware
var proxyTable = config.dev.proxyTable

var app = express()
var compiler = webpack(webpackConfig)

var bodyParser = require('body-parser')
app.use(bodyParser.urlencoded({
    extended: false
}))
app.use(bodyParser.json())

var devMiddleware = require('webpack-dev-middleware')(compiler, {
    publicPath: webpackConfig.output.publicPath,
    quiet: true
})

var hotMiddleware = require('webpack-hot-middleware')(compiler, {
    log: false,
    heartbeat: 2000
})
// force page reload when html-webpack-plugin template changes
compiler.plugin('compilation', function(compilation) {
    compilation.plugin('html-webpack-plugin-after-emit', function(data, cb) {
        hotMiddleware.publish({
            action: 'reload'
        })
        cb()
    })
})

// proxy api requests
var proxy = require('express-http-proxy');
Object.keys(proxyTable).forEach(function(context) {
    var options = proxyTable[context]
    //  if (typeof options === 'string') {
    //    options = { target: options }
    //  }
    //  app.use(proxyMiddleware(options.filter || context, options))
    var apiProxy = proxy(typeof options === 'string' ? options : options.target, {});
    app.use(context, apiProxy);
})

// handle fallback for HTML5 history API
app.use(require('connect-history-api-fallback')())

// serve webpack bundle output
app.use(devMiddleware)

// enable hot-reload and state-preserving
// compilation error display
app.use(hotMiddleware)

// serve pure static assets
var staticPath = path.posix.join(config.dev.assetsPublicPath, config.dev.assetsSubDirectory)
app.use(staticPath, express.static('./static'))

var uri = 'http://localhost:' + port

var _resolve
var readyPromise = new Promise(resolve => {
    _resolve = resolve
})

console.log('> Starting dev server...')
devMiddleware.waitUntilValid(() => {
    console.log('> Listening at ' + uri + '\n')
    // when env is testing, don't need open it
    if(autoOpenBrowser && process.env.NODE_ENV !== 'testing') {
        opn(uri)
    }
    _resolve()
})

var server = app.listen(port)

module.exports = {
    ready: readyPromise,
    close: () => {
        server.close()
    }
}

utils.js

var path = require('path')
var config = require('../config')
var ExtractTextPlugin = require('extract-text-webpack-plugin')

exports.assetsPath = function (_path) {
    var assetsSubDirectory = process.env.NODE_ENV === 'production'
        ? config.build.assetsSubDirectory
        : config.dev.assetsSubDirectory
    return path.posix.join(assetsSubDirectory, _path)
}

exports.cssLoaders = function (options) {
    options = options || {}

    var cssLoader = {
        loader: 'css-loader',
        options: {
            minimize: process.env.NODE_ENV === 'production',
            sourceMap: options.sourceMap
        }
    }

    // generate loader string to be used with extract text plugin
    function generateLoaders (loader, loaderOptions) {
        var loaders = [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) {
            return ExtractTextPlugin.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) {
    var output = []
    var loaders = exports.cssLoaders(options)
    for (var extension in loaders) {
        var loader = loaders[extension]
        output.push({
            test: new RegExp('\\.' + extension + '$'),
            use: loader
        })
    }
    return output
}

vue-loader.conf.js

var utils = require('./utils')
var config = require('../config')
var isProduction = process.env.NODE_ENV === 'production'

module.exports = {
    loaders: utils.cssLoaders({
        sourceMap: isProduction
            ? config.build.productionSourceMap
            : config.dev.cssSourceMap,
        extract: isProduction
    }),
    transformToRequire: {
        video: 'src',
        source: 'src',
        img: 'src',
        image: 'xlink:href'
    }
}

webpack.base.conf.js

var path = require('path')    // 使用 NodeJS 自帶的文件路徑插件
var utils = require('./utils')    //封裝了一些方法的工具
var config = require('../config')   //使用 config/index.js

var vueLoaderConfig = require('./vue-loader.conf')   //使用vue-loader.conf

// 拼接我們的工作區(qū)路徑為一個(gè)絕對(duì)路徑
function resolve (dir) {
    return path.join(__dirname, '..', dir)
}

module.exports = {

    entry: {
        // 編譯文件入口
        app: './src/main.js'
    },

    output: {
        //使用chonfig/index.js中build的assetsRoot作為輸出根路徑
        path: config.build.assetsRoot,

        filename: '[name].js',    //編譯輸入的文件名

        publicPath: process.env.NODE_ENV === 'production'    // 正式發(fā)布環(huán)境下編譯輸出的發(fā)布路徑
            ? config.build.assetsPublicPath
            : config.dev.assetsPublicPath
    },

    resolve: {
        // 自動(dòng)補(bǔ)全的擴(kuò)展名,能夠使用戶(hù)在引入模塊時(shí)不帶擴(kuò)展
        extensions: ['.js', '.vue', '.json'],

        // 默認(rèn)路徑代理,例如 import Vue from 'vue$',會(huì)自動(dòng)到 'vue/dist/vue.esm.js'中尋找

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

    module: {

        rules: [
            {
                test: /\.vue$/,
                loader: 'vue-loader',
                options: vueLoaderConfig
            },
            {
                test: /\.js$/,
                loader: 'babel-loader',
                include: [resolve('src'), resolve('test')]
            },
            {
                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]')
                }
            }
        ]

    }


}

webpack.dev.conf.js

var utils = require('./utils') //封裝了一些方法的工具

var webpack = require('webpack') //使用 webpack

var config = require('../config') //使用 config/index.js

var merge = require('webpack-merge') //使用 webpack 配置合并插件

var baseWebpackConfig = require('./webpack.base.conf') // 加載 webpack.base.conf

var HtmlWebpackPlugin = require('html-webpack-plugin') // 使用 html-webpack-plugin 插件,這個(gè)插件可以幫我們自動(dòng)生成 html 并且注入到 .html 文件中

//https://www.npmjs.com/package/friendly-errors-webpack-plugin,可以識(shí)別某些類(lèi)別的Webpack錯(cuò)誤并進(jìn)行清理损敷,聚合和優(yōu)先排序
var FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin')

// add hot-reload related code to entry chunks
//將 Hol-reload 相對(duì)路徑添加到 webpack.base.conf 的 對(duì)應(yīng) entry 前
Object.keys(baseWebpackConfig.entry).forEach(function (name) {
    baseWebpackConfig.entry[name] = ['./build/dev-client'].concat(baseWebpackConfig.entry[name])
})

// 將我們 webpack.dev.conf.js 的配置和 webpack.base.conf.js 的配置合并
module.exports = merge(baseWebpackConfig, {
    module:{
        // 使用 styleLoaders
        rules: utils.styleLoaders({ sourceMap: config.dev.cssSourceMap })
    },

    // 使用 #cheap-module-eval-source-map 模式作為開(kāi)發(fā)輔助調(diào)試工具
    // 具體配置請(qǐng)參考https://doc.webpack-china.org/configuration/devtool/
    devtool: '#cheap-module-eval-source-map',
    plugins: [
        // definePlugin 接收字符串插入到代碼當(dāng)中, 需要的話可以寫(xiě)上 JS 的字符串
        new webpack.DefinePlugin({
            'process.env': config.dev.env
        }),

        // https://github.com/glenjamin/webpack-hot-middleware#installation--usage
        // HotModule 插件在頁(yè)面進(jìn)行變更的時(shí)候只會(huì)重回對(duì)應(yīng)的頁(yè)面模塊,不會(huì)重繪整個(gè) html 文件
        new webpack.HotModuleReplacementPlugin(),
        //https://doc.webpack-china.org/plugins/no-emit-on-errors-plugin/
        //在編譯出現(xiàn)錯(cuò)誤時(shí)深啤,使用 NoEmitOnErrorsPlugin 來(lái)跳過(guò)輸出階段拗馒。這樣可以確保輸出資源不會(huì)包含錯(cuò)誤。
        new webpack.NoEmitOnErrorsPlugin(),

        // https://github.com/ampedandwired/html-webpack-plugin
        // 將 index.html 作為入口墓塌,注入 html 代碼后生成 index.html文件
        //https://doc.webpack-china.org/plugins/html-webpack-plugin/ webpack插件列表(中文)
        new HtmlWebpackPlugin({
            filename: 'index.html',
            template: 'index.html',
            inject: true
        }),
        //看上面
        new FriendlyErrorsPlugin()
    ]
})

webpack.prod.conf.js

var path = require('path')
var utils = require('./utils')
var webpack = require('webpack')
var config = require('../config')
var merge = require('webpack-merge')   // 在大型項(xiàng)目中瘟忱,可能 webpack.config.js 會(huì)變得越來(lái)越臃腫奥额,這個(gè)時(shí)候可以利用做 webpack-merge 插件。將配置定義在一個(gè)目錄下面的不同文件中访诱,然后通過(guò) webpack-merge 來(lái)合并成最終的配置垫挨。
var baseWebpackConfig = require('./webpack.base.conf')

//可以將單個(gè)文件或整個(gè)目錄復(fù)制到構(gòu)建目錄中

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

// 一個(gè)可以插入 html 并且創(chuàng)建新的 .html 文件的插件

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

// 一個(gè) webpack 擴(kuò)展,可以提取一些代碼并且將它們和文件分離開(kāi)
// 如果我們想將 webpack 打包成一個(gè)文件 css js 分離開(kāi)触菜,那我們需要這個(gè)插件

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

//一個(gè)個(gè)優(yōu)化/最小化css資源的插件

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

var env = config.build.env

//合并 webpack.base.conf.js中的配置,里面具體的配置參考webpack.base.conf.js里面的注釋
var webpackConfig = merge(baseWebpackConfig, {


    module: {
        rules: utils.styleLoaders({
            sourceMap: config.build.productionSourceMap,
            extract: true
        })
    },

    devtool: config.build.productionSourceMap ? '#source-map' : false,

    output: {
        path: config.build.assetsRoot,   //指定生產(chǎn)環(huán)境輸出路徑
        filename: utils.assetsPath('js/[name].[chunkhash].js'),    //編譯輸出帶hash的文件名,可以指定hash長(zhǎng)度(chunkhash:6)
        chunkFilename: utils.assetsPath('js/[id].[chunkhash].js')    // 沒(méi)有指定輸出名的文件輸出的文件名
    },

    plugins: [

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

        // definePlugin 接收字符串插入到代碼當(dāng)中, 所以你需要的話可以寫(xiě)上 JS 的字符串

        new webpack.DefinePlugin({
            'process.env': env
        }),

        // 壓縮 js (同樣可以壓縮 css)

        new webpack.optimize.UglifyJsPlugin({
            compress: {
                warnings: false
            },
            sourceMap: true
        }),

        // extract css into its own file
        //將 css 文件分離出來(lái)

        new ExtractTextPlugin({
            filename: utils.assetsPath('css/[name].[contenthash].css')
        }),

        // Compress extracted CSS. We are using this plugin so that possible
        // duplicated CSS from different components can be deduped.
        //壓縮css代碼

        new OptimizeCSSPlugin({
            cssProcessorOptions: {
                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
        // 輸入輸出的 .html 文件

        new HtmlWebpackPlugin({
            filename: process.env.NODE_ENV === 'testing'
                ? 'index.html'
                : config.build.index,
            template: 'index.html',
            inject: true,     // 是否注入 html
            minify: {    // 壓縮的方式
                removeComments: true,    //移除帶html的注釋
                collapseWhitespace: true,    //移除空格
                removeAttributeQuotes: true   //移除屬性的引號(hào)

                // more options:
                // https://github.com/kangax/html-minifier#options-quick-reference
            },

            // necessary to consistently work with multiple chunks via CommonsChunkPlugin
            //https://doc.webpack-china.org/plugins/commons-chunk-plugin/

            chunksSortMode: 'dependency'    //資源按照依賴(lài)關(guān)系去插入
        }),

        // split vendor js into its own file//將引用的庫(kù)文件拆出來(lái)打包到一個(gè)[name].js文件中

        new webpack.optimize.CommonsChunkPlugin({
            name: 'vendor',
            minChunks: function (module, count) {

                // any required modules inside node_modules are extracted to vendor
                //任何一個(gè)從node_modules中引用的模塊都會(huì)被打包進(jìn)來(lái)

                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
        //https://doc.webpack-china.org/concepts/manifest/
        //把webpack的runtime和manifest這些webpack管理所有模塊交互的代碼打包到[name].js文件中,防止build之后vendor的hash值被更新

        new webpack.optimize.CommonsChunkPlugin({
            name: 'manifest',
            chunks: ['vendor']
        }),

        // copy custom static assets
        //復(fù)制自定義的靜態(tài)資源文件到dist/static文件夾中

        new CopyWebpackPlugin([
            {
                from: path.resolve(__dirname, '../static'),
                to: config.build.assetsSubDirectory,
                ignore: ['.*']
            }
        ])
    ]

})

// 開(kāi)啟 gzip 的情況下使用下方的配置

if (config.build.productionGzip) {
    // Gzip依賴(lài) compression-webpack-plugin 插件

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

// 向webpackconfig.plugins中加入下方的插件

    webpackConfig.plugins.push(
        // 使用 compression-webpack-plugin 插件進(jìn)行壓縮,https://doc.webpack-china.org/plugins/compression-webpack-plugin/

        new CompressionWebpackPlugin({
            asset: '[path].gz[query]',//目標(biāo)資源名稱(chēng)
            algorithm: 'gzip',//壓縮方式
            test: new RegExp(
                '\\.(' +
                config.build.productionGzipExtensions.join('|') +
                ')$'
            ),//所有匹配該正則的資源都會(huì)被處理九榔。默認(rèn)值是全部資源。
            threshold: 10240,//只有大小大于該值的資源會(huì)被處理涡相。單位是 bytes哲泊。默認(rèn)值是 0。
            minRatio: 0.8//只有壓縮率小于這個(gè)值的資源才會(huì)被處理催蝗。默認(rèn)值是 0.8切威。
        })
    )
}

//配置項(xiàng)目分析工具加載下方插件
if (config.build.bundleAnalyzerReport) {
    var BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
    webpackConfig.plugins.push(new BundleAnalyzerPlugin())
}
module.exports = webpackConfig

config中的文件如下:
dev.env.js

var merge = require('webpack-merge')
var prodEnv = require('./prod.env')

module.exports = merge(prodEnv, {
    NODE_ENV: '"development"'
})

index.js

var path = require('path')  //使用Node自帶的文件路徑插件
module.exports = {

    // 生產(chǎn)環(huán)境配置
    build: {
        // 使用 config/prod.env.js 中定義的編譯環(huán)境

        env: require('./prod.env'),
        index: path.resolve(__dirname, '../dist/index.html'),   // 編譯注入的 index.html 文件,必須是本地的絕對(duì)路徑
        assetsRoot: path.resolve(__dirname, '../dist'),   // 編譯輸出的靜態(tài)資源根路徑
        assetsSubDirectory: 'static',    // 編譯輸出的二級(jí)目錄
        assetsPublicPath: '/',    // 編譯發(fā)布上線路徑的根目錄,可配置為資源服務(wù)器域名或 CDN 域名
        productionSourceMap: true,    //生成用于生產(chǎn)構(gòu)建的源映射

        // Gzip off by default as many popular static hosts such as
        // Surge or Netlify already gzip all static assets for you.
        // Before setting to `true`, make sure to:
        // npm install --save-dev compression-webpack-plugin

        productionGzip: false,    // 是否開(kāi)啟 gzip

        productionGzipExtensions: ['js', 'css'],    // 需要使用 gzip 壓縮的文件擴(kuò)展名

        // Run the build command with an extra argument to
        // View the bundle analyzer report after build finishes:
        // `npm run build --report`
        // Set to `true` or `false` to always turn it on or off
        bundleAnalyzerReport: process.env.npm_config_report    //一個(gè)實(shí)用工具,用于分析項(xiàng)目的依賴(lài)關(guān)系https://www.npmjs.com/package/webpack-bundle-analyzer
    },

    // 開(kāi)發(fā)環(huán)境
    dev: {
        env:require('./dev.env'), // 使用 config/dev.env.js 中定義的編譯環(huán)境
        port: 8080,    // 運(yùn)行測(cè)試頁(yè)面的端口

        autoOpenBrowser: true,    //是否自動(dòng)打開(kāi)瀏覽器

        assetsSubDirectory: 'static',    // 編譯輸出的二級(jí)目錄

        assetsPublicPath: '/',    // 編譯發(fā)布上線路徑的根目錄丙号,可配置為資源服務(wù)器域名或 CDN 域名

        proxyTable: {
            //https://github.com/chimurai/http-proxy-middleware,配置方式
        },    // 需要 proxyTable 代理的接口(可跨域)http://vuejs-templates.github.io/webpack/proxy.html

        // CSS Sourcemaps off by default because relative paths are "buggy"
        // with this option, according to the CSS-Loader README
        // (https://github.com/webpack/css-loader#sourcemaps)
        // In our experience, they generally work as expected,
        // just be aware of this issue when enabling this option.

        cssSourceMap: false   // 是否開(kāi)啟 cssSourceMap
    }

}

prod.env.js

module.exports = {
    NODE_ENV: '"production"'
}

相關(guān)配置已經(jīng)介紹完了先朦,下面看主要的代碼:我想實(shí)現(xiàn)的想過(guò)很簡(jiǎn)單,就是運(yùn)行后出現(xiàn)下面的頁(yè)面:


頁(yè)面.png

我們先看組件庫(kù)中的幾個(gè)組件:
about.vue

<template>
    <div>about</div>
</template>
<script>
</script>
<style>
</style>

header.vue

<template>
    <div>
        <h1>共同的header</h1>
        <img src="../assets/imgs/vue.png">
    </div>
</template>
<script>
</script>
<style>
</style>

記得截個(gè)圖片放到imgs中去犬缨。
home.vue

<template>
    <div>
        <ol>
            <li v-for="todo in todos">
                {{ todo.text }}
            </li>
        </ol>
        <button @click="eClick()">事件</button>
    </div>
</template>

<script>
    export default {
        name: 'indexP',
        data () {
            return {
                todos: [
                    { text: 'Learn JavaScript' },
                    { text: 'Learn Vue' },
                    { text: 'Build something awesome' }
                ]
            }
        },
        methods:{
            eClick(){
                console.log(9999);
            }
        }
    }
</script>

router.js

import Vue from 'vue'
import Router from 'vue-router'
import indexPage from './components/header.vue'
import homePage from './components/home.vue'
import aboutPage from './components/about.vue'

Vue.use(Router)

export default new Router({
    routes:[
        {
            path:'/',
            component:homePage
        },{
            path:'/about',
            component:aboutPage
        }
    ]
})

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <div id="app">

    </div>
    <script src="./dist/build.js"></script>

</body>
</html>

App.vue

<template>
    <div id="app">
        <header-tab></header-tab>
        <h2>{{msg}}</h2>
        <div class="nav-box">
            <p class="nav-list">
                <router-link class="nav-item" to="/">首頁(yè)</router-link>
                <router-link class="nav-item" to="/about">關(guān)于</router-link>
            </p>
        </div>
        <div>
            <router-view></router-view>
        </div>
    </div>
</template>

<script>
    import HeaderTab from './components/header.vue'

    let data = () => {
        return {
            msg: 'Welcome to Your Vue.js App'
        }
    }

    export default {
        name: 'app',
        data:data,
        components:{
            HeaderTab
        }
    }

</script>

<style>
    h2{
        color:#f00;
    }
    #app {
        text-align: center;
        color: #2c3e50;
        margin-top: 60px;
    }
    h1, h2 {
        font-weight: normal;
    }
    ul {
        list-style-type: none;
        padding: 0;
    }
    li {
        text-align: left;
        margin: 0 10px;
    }
    a {
        color: #42b983;
    }
</style>

main.js

import Vue from 'vue'
import App from './App.vue'
import router from './router.js'

import './assets/styles/base.css'

Vue.config.debug = true

new Vue({
    router,
    el:'#app',
    render:h=>h(App)
})

base.css

h1{
    color: #999;
}

好了喳魏,寫(xiě)完之后,從控制臺(tái)進(jìn)入到你所建的文件下面怀薛,npm run dev就可以了刺彩。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市枝恋,隨后出現(xiàn)的幾起案子创倔,更是在濱河造成了極大的恐慌,老刑警劉巖焚碌,帶你破解...
    沈念sama閱讀 206,214評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件三幻,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡呐能,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門(mén)抑堡,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)摆出,“玉大人,你說(shuō)我怎么就攤上這事首妖≠寺” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 152,543評(píng)論 0 341
  • 文/不壞的土叔 我叫張陵有缆,是天一觀的道長(zhǎng)象踊。 經(jīng)常有香客問(wèn)我温亲,道長(zhǎng),這世上最難降的妖魔是什么杯矩? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,221評(píng)論 1 279
  • 正文 為了忘掉前任栈虚,我火速辦了婚禮,結(jié)果婚禮上史隆,老公的妹妹穿的比我還像新娘魂务。我一直安慰自己,他們只是感情好泌射,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,224評(píng)論 5 371
  • 文/花漫 我一把揭開(kāi)白布粘姜。 她就那樣靜靜地躺著,像睡著了一般熔酷。 火紅的嫁衣襯著肌膚如雪孤紧。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,007評(píng)論 1 284
  • 那天拒秘,我揣著相機(jī)與錄音号显,去河邊找鬼。 笑死翼抠,一個(gè)胖子當(dāng)著我的面吹牛咙轩,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播阴颖,決...
    沈念sama閱讀 38,313評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼活喊,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了量愧?” 一聲冷哼從身側(cè)響起钾菊,我...
    開(kāi)封第一講書(shū)人閱讀 36,956評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎偎肃,沒(méi)想到半個(gè)月后煞烫,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,441評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡累颂,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,925評(píng)論 2 323
  • 正文 我和宋清朗相戀三年滞详,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片紊馏。...
    茶點(diǎn)故事閱讀 38,018評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡料饥,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出朱监,到底是詐尸還是另有隱情岸啡,我是刑警寧澤,帶...
    沈念sama閱讀 33,685評(píng)論 4 322
  • 正文 年R本政府宣布赫编,位于F島的核電站巡蘸,受9級(jí)特大地震影響奋隶,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜悦荒,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,234評(píng)論 3 307
  • 文/蒙蒙 一唯欣、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧逾冬,春花似錦黍聂、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,240評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至嘀趟,卻和暖如春脐区,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背她按。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,464評(píng)論 1 261
  • 我被黑心中介騙來(lái)泰國(guó)打工牛隅, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人酌泰。 一個(gè)月前我還...
    沈念sama閱讀 45,467評(píng)論 2 352
  • 正文 我出身青樓媒佣,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親陵刹。 傳聞我的和親對(duì)象是個(gè)殘疾皇子默伍,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,762評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容