zoukankan      html  css  js  c++  java
  • Webpack + VueJS 学习、跳坑和总结

    这篇随笔会陆续地更新下去,用于汇集一些关于Webpack的初学跳坑总结还有VueJS的基础知识。

    Webpack部分

    ① 快速建立一个Webpack-Vue项目开发环境(4.39.1-2019/08/07)

    Step 1 安装 Webpack:

    1
    npm install webpack -g

    Step 2 Webpack 4 需要再安装 Webpack-Cli:

    1
    npm install webpack-cli -g

    Step 3 快速初始化一个Vue项目

    1
    npm init --yes

    安装Vue和Webpack-dev-server

    vue@2.6.10

    webpack-cli@3.3.6

    webpack-dev-server@3.7.2

    1
    npm install vue --save

    这里安装webpack-dev-server,目的是方便调试,其热加载工具可以侦测项目文件夹下的文件变动,相应地进行自动刷新,当然,还需要手动配置,后面会讲到。

    1
    npm install webpack-dev-server --save

    项目文件夹下安装,webpack,webpack-cli

    1
    npm install webpack --save

    webpack现在的版本需要这样安装webpack-cli

    1
    npm install -D webpack-cli --save

    安装vue-loader,同时还要安装vue-template-complier

    1
    npm install vue-loader vue-template-compiler --save

    Step 4 开始动工一个项目

    创建文件夹目录和文件,例如项目根目录叫做webpack-test,其下创建2个文件夹:dist/、src/,创建3个文件:index.html、packge.json、webpack.config.js,src/下创建main.js、templates/以及templates/main.vue,具体文件关系如下图:

    按照如下编辑文件内容:

     
    index.html
    COPY
    EXPAND
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title>webpack-test</title>
    </head>
    <body>
        <div id="app"></div>
    </body>
    <script src="./dist/build.js" type="text/javascript"></script>
    </html>
     
    index.html
    COPY
    EXPAND
     
    package.json
    COPY
    EXPAND
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    {
      "name": "webpack-test",
      "version": "1.0.0",
      "description": "webpack-test",
      "main": "index.js",
      "scripts": {
        "dev": "webpack-dev-server --open --hot --mode development",
        "build": "webpack --progress --hide-modules --mode production"
      },
      "keywords": [],
      "author": "",
      "license": "ISC",
      "dependencies": {
        "vue": "^2.6.10",
        "vue-loader": "^15.7.1",
        "vue-template-compiler": "^2.6.10",
        "webpack": "^4.39.1",
        "webpack-dev-server": "^3.7.2"
      },
      "devDependencies": {
        "webpack-cli": "^3.3.6"
      }
    }
     
    package.json
    COPY
    EXPAND
     
    webpack.config.js
    COPY
    EXPAND
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    const path = require("path");
    // vue-loader
    const VueLoaderPlugin = require("vue-loader/lib/plugin");
    const argvs = require("process").argv;
    module.exports = {
        entry: './src/main.js', // 项目的入口文件,webpack会从main.js开始,把所有依赖的js都加载打包
        output: {
            path: path.resolve(__dirname, './dist'), // Webpack 打包目标文件夹
            // publicPath: './dist', // webpack-dev-serve 访问路径
            // 判断是开发模式还是打包发布模式设置合理的文件路径
            publicPath: argvs[argvs.indexOf("--mode")+1] === "development" ? "/dist/" : "./dist/",
            filename: 'build.js' // 打包后的文件名
        },
        devServer: {
            historyApiFallback: true, // 404 则返回到 index.html
            overlay: true, // html 页面顶层显示报错提示信息
            // clientLogLevel: "none" // 减少浏览器控制台 log
        },
        resolve: {
            alias: {
                vue$: "vue/dist/vue.esm.js"
            }
        },
        module: {
            rules: [
                {
                    test: /.vue$/,
                    loader"vue-loader"
                }
            ]
        },
        plugins: [
            // 加载 vue-loader
            new VueLoaderPlugin()
        ]
    };
     
    webpack.config.js
    COPY
    EXPAND
     
    main.js
    COPY
    EXPAND
    1
    2
    3
    4
    5
    6
    7
    import Vue from "vue";
    import appMain from "./templates/main.vue";
    new Vue({
        "el": "#app",
        "template": "<app-main/>",
        "components": { appMain }
    })
     
    main.js
    COPY
    EXPAND
     
    main.vue
    COPY
    EXPAND
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    <template>
        <div class="main">
            <p v-text="txt">...</p>
        </div>
    </template>
    <script>
    export default {
        "name": "appMain",
        data () {
            return {
                txt: "Hello,Vue!"
            }
        }
    }
    </script>
     
    main.vue
    COPY
    EXPAND

    Step 5 webpack 使用

    先运行打包看看:

    1
    npm run build

    之后便在 dist/ 下打包好一个 build.js 文件

    开发模式,热加载,很方便,一旦它监测文件更改,便会热加载,解放了键盘刷新操作,很省心。

    1
    npm run dev

    之后会开启一个webpack-dev服务,然后默认浏览器跳转到 localhost 页面,不出意外,屏幕上已经打印出了 Hello, Vue! :

    ②Webpack添加Babel编译器(2019/08/08)

    @babel/core@7.5.5

    @babel/preset-env@7.5.5

    @babel/preset-react@7.0.0

    babel-loader@8.0.6

    Step 1 安装 BABEL

    1
    npm install @babel/core @babel/preset-env @babel/preset-react babel-loader --save

    等待安装完成后,webpack.config.js中添加babel-loader:

     
    webpack.config.js
    COPY
    EXPAND
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    const path = require("path");
    // vue-loader
    const VueLoaderPlugin = require("vue-loader/lib/plugin");
    const argvs = require("process").argv;
    module.exports = {
        entry: ['./src/main.js'], // 项目的入口文件,webpack会从main.js开始,把所有依赖的js都加载打包
        output: {
            path: path.resolve(__dirname, './dist'), // Webpack 打包目标文件夹
            // publicPath: './dist', // webpack-dev-serve 访问路径
            // 判断是开发模式还是打包发布模式设置合理的文件路径
            publicPath: argvs[argvs.indexOf("--mode")+1] === "development" ? "/dist/" : "./dist/",
            filename: 'build.js' // 打包后的文件名
        },
        devServer: {
            historyApiFallback: true, // 404 则返回到 index.html
            overlay: true, // html 页面顶层显示报错提示信息
            clientLogLevel: "none" // 减少浏览器控制台 log
        },
        resolve: {
            alias: {
                vue$: "vue/dist/vue.esm.js"
            }
        },
        module: {
            rules: [
                {
                    test: /.vue$/,
                    loader"vue-loader"
                },
                { // 此处添加 balbel-loader
                    test: /.js$/,
                    use: {
                        loader"babel-loader",
                        options: {
                            presets: ["@babel/env"]
                        }
                    }
                }
            ]
        },
        plugins: [
            // 加载 vue-loader
            new VueLoaderPlugin()
        ]
    };
     
    webpack.config.js
    COPY
    EXPAND

    Step 2 现在可以大胆地使用ES6的语法了,举例:

     
    main.vue
    COPY
    EXPAND
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    <template>
        <div class="main">
            <span v-for="(l, i) in letters" :key="i" v-text="l"></span>
        </div>
    </template>
    <script>
    export default {
        "name": "appMain",
        "computed": {
            letters () {
                const atA = "A".charCodeAt();
                const atZ = "Z".charCodeAt();
                let arr = [];
                for (let x=atZ+1; x>atA; arr[x--] = x);
                return arr.map( num => {
                    return unescape(`%${num.toString(16)}`)
                }).filter( item => {
                    return item;
                });
            }
        }
    }
    </script>
     
    main.vue
    COPY
    EXPAND

    如上vue实现的是遍历出26个英文字母,页面正常显示,查看控制台,babel确实起作用了,转成了ES5:

     

    ③单文件组件开发注意的几点:

    1.避免打包文件过大,乱成“一锅粥”。

    1) vue 单文件内的样式表部分可以全部写在打包文件夹目录之外的一个文件内,然后在index.html引入,否则在打包后出现下面的一些现象,显得代码臃肿:

    2) utils等js插件尽量用script标签引入,减少打包过程的时间和打包文件的体积;

    3) vue单文件的cssstyle标签内不要留有太多的注释,也是为了限制文件体积,参考 1);

    VueJS基础

    ①单文件组件开发中,子父组件传值问题(2019/08/08)

    子 → 父组件传值

    方法一:使用 vm.$emit( eventName, […args] )

    会在当前实例下触发一个事件,$emit的eventName后面的变量,将会传给Vue绑定的事件的回调函数里面,举个例子,譬如要实现一个多个选项的点击跳转功能:点击某个头像跳转到相应网址:

    子组件文件定义了头像的整个布局或结构,父组件文件中依赖数组遍历子组件,这时就需要被点击到的子组件传递给父组件其对应的渲染 data

     
    chCh.vue
    COPY
    EXPAND
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    // 子组件
    <template>
        <!-- 某个子组件被点击后,则会触发父组件的 goto 方法,同时传递渲染这个子组件的 obj -->
        <div class="ch-ch" :style="{'background-color': obj.color}" @click="$emit('goto', obj)">
            <div class="icon">
                <span v-text="obj.name.charAt(0)"></span>
            </div>
            <div class="label" v-text="obj.name"></div>
        </div>
    </template>
    <script>
    export default {
        "name": "chCh",
        "props": [ "obj" ]
    }
    </script>
    <style>
    .ch-ch { cursor: pointer; position: relative; display: flex; justify-content: center; align-items: center; margin: 1rem .5rem; width: 3.5rem; height: 3.5rem; border-radius: 50%; }
    .icon { display: flex; font-size: 2rem; font-weight: 600; color: #fff; }
    .label { position: absolute; bottom: -1.5rem; left: 0; width: 100%; text-align: center; }
    </style>
     
    chCh.vue
    COPY
    EXPAND
     
    faFa.vue
    COPY
    EXPAND
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    // 父组件
    <template>
        <div class="main">
            <!-- @goto === v-on:goto -->
            <ch-ch v-for="item in arr" :key="item.name" :obj="item" @goto="goto"></ch-ch>
        </div>
    </template>
    <script>
    import chCh from "./chCh.vue";
    export default {
        "name": "faFa",
        "components": { chCh },
        "methods": {
            // 被子组件触发的方法
            goto (data) {
                console.log(data.site)
                // window.location.href = data.site; // 跳转到某个网址
            }
        },
        data () {
            return {
                // 渲染数据
                arr: [
                    {
                        name"Mike"color"cornflowerblue"site"https://a.com"
                    }, {
                        name"Jhon"color"firebrick"site"https://b.com"
                    }, {
                        name"Frank"color"yellowgreen"site"https://c.com"
                    }
                ]
            }
        }
    }
    </script>
    <style>
    .main { display: flex; justify-content: center; }
    </style>
     
    faFa.vue
    COPY
    EXPAND

    方法二:子组件修改$parent.$data[...],父组件在watch中添加对[...]的watcher:

     
    chCh.vue
    COPY
    EXPAND
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    // 子组件
    <template>
        <div class="ch-ch" :style="{'background-color': obj.color}" @click="goto(obj)">
            <div class="icon">
                <span v-text="obj.name.charAt(0)"></span>
            </div>
            <div class="label" v-text="obj.name"></div>
        </div>
    </template>
    <script>
    export default {
        "name": "chCh",
        "props": [ "obj" ],
        "methods": {
            goto (data) {
                // 修改父组件的 $data 的值,触发 watcher
                this.$parent.obj = data;
            }
        }
    }
    </script>
    <style>
    .ch-ch { cursor: pointer; position: relative; display: flex; justify-content: center; align-items: center; margin: 1rem .5rem; width: 3.5rem; height: 3.5rem; border-radius: 50%; }
    .icon { display: flex; font-size: 2rem; font-weight: 600; color: #fff; }
    .label { position: absolute; bottom: -1.5rem; left: 0; width: 100%; text-align: center; }
    </style>
     
    chCh.vue
    COPY
    EXPAND
     
    faFa.vue
    COPY
    EXPAND
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    // 父组件
    <template>
        <div class="main">
            <ch-ch v-for="item in arr" :key="item.name" :obj="item"></ch-ch>
        </div>
    </template>
    <script>
    import chCh from "./chCh.vue";
    export default {
        "name": "faFa",
        "components": { chCh },
        "watch": {
            // 添加监测
            obj (new_val, old_val) {
                console.log(new_val.site)
            }
        },
        data () {
            return {
                // 渲染数据
                arr: [
                    {
                        name"Mike"color"cornflowerblue"site"https://a.com"
                    }, {
                        name"Jhon"color"firebrick"site"https://b.com"
                    }, {
                        name"Frank"color"yellowgreen"site"https://c.com"
                    }
                ], 
                //监测的对象
                obj: {}
            }
        }
    }
    </script>
    <style>
    .main { display: flex; justify-content: center; }
    </style>
     
    faFa.vue
    COPY
    EXPAND

    父 → 子组件传值的几种办法

    方法一:子组件暴露props,父组件使用v-bind,这个是最常用的方法之一。

    方法二:父组件在引用子组件的标签上加入ref="..."属性,然后通过this.$refs[...].$data[---],来传递数据

     
    faFa.vue
    COPY
    EXPAND
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    // 父组件
    <template>
        <div class="main">
            <ch-ch ref="child"></ch-ch>
        </div>
    </template>
    <script>
    import chCh from "./chCh.vue";
    export default {
        "name": "faFa",
        "components": { chCh },
        mounted () {
            console.log(this.obj = this.$refs["child"].obj)
        }
    }
    </script>
     
    faFa.vue
    COPY
    EXPAND

    ②添加过渡动画

    Step 1 从四个「点」两个阶段/状态添加CSS样式/动画:

    官方的一张图表:

    Transition Diagram

    由下面的3D flip card的例子(建议Chrome下运行)可知leave-to类名会影响到整个动画退出过程的样式:(其中的keyframes只起到定时隐藏或显现正反面内容的作用),注意leave-to/enter-to对animation过程的影响程度最长

    transition example-3d flip card

     
    test-main.vue
    COPY
    EXPAND
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    <template>
        <div class="test">
            <div class="card" :class="{'flip': isFlip}" @click="flip">
                <transition name="front">
                    <div class="front" v-if="!isFlip"></div>
                </transition>
                <transition name="back">
                    <div class="back" v-if="isFlip"></div>
                </transition>
            </div>
        </div>
    </template>
    <script>
    export default {
        name: "testMain",
        methods: {
            flip () {
                this.isFlip = !this.isFlip;
            }
        },
        data () {
            return {
                isFlip: false
            }
        }
    }
    </script>
    <style lang="css">
    .test {
        display: flex; justify-content: center; align-items: center;
        width: 400px; height: 400px;
        font-size: 2.5rem; font-weight: 600; color: #fff;
        background-color: #fff;
        perspective: 450px;
    }
    .card {
        position: relative;
        width: 200px; height: 200px;
        background-color: #fff; cursor: pointer;
        transform-style: preserve-3d;
        transition: transform 1300ms ease-in-out;
    }
    .card.flip {
        transform: rotateY(180deg)
    }
    .front, .back{
        display: flex; justify-content: center; align-items: center;
        position: absolute; width: 100%; height: 100%; 
    }
    .front {
        z-index: 1; 
        background-color: orange; 
        backface-visibility: hidden;
        -moz-backface-visibility: hidden;
        -webkit-backface-visibility: hidden;
    }
    .front::before { content: "Front"; }
    .back::before { content: "Back"; }
    .back {
        z-index: 0; width: 100%; height: 100%;
        transform: rotateY(180deg); 
        background-color: tomato;
    }
    @keyframes show_hide { from { visibility: visible; } to { visibility: hidden; } }
    .front-leave { background-color: red; }
    .front-leave-active { animation: show_hide 650ms 650ms; background-color: orange; }
    .front-leave-to { background-color: blue; color: green; }
    .front-enter { background-color: black; }
    .front-enter-active { animation: show_hide 650ms 650ms reverse; background-color: orange; }
    .front-enter-to { background-color: purple; }
    /* ---- */
    .back-enter { background-color: black; }
    .back-enter-active { animation: show_hide 650ms 650ms reverse; background-color: tomato; }
    .back-enter-to { background-color: purple; }
    .back-leave { background-color: red; }
    .back-leave-active { animation: show_hide 650ms 650ms; background-color: tomato; }
    .back-leave-to { background-color: blue; color: green; }
    </style>
     
    test-main.vue
    COPY
    EXPAND
  • 相关阅读:
    Linux环境下入侵工具Knark的分析及防范 java程序员
    六个步骤即可防范ARP地址欺骗类病毒 java程序员
    巧用命令行 揪出ARP欺骗病毒母机方法 java程序员
    poj3264Balanced Lineup(线段树RMQ)
    有了1A的把握再去提交
    poj2828Buy Tickets(线段树 单点更新+区间求和+区间第K值)
    poj2513Colored Sticks(无向图判欧拉路、回路+trie树)
    ACM数学(转)
    sdut2381Broken Keyboard
    sdut2383Decode the Strings(循环节)
  • 原文地址:https://www.cnblogs.com/Orcim/p/11316307.html
Copyright © 2011-2022 走看看