coderwhy老师vue.js b站视频教程笔记——第一部分

原创不易,转载请注明出处,谢谢!

第一部分:Vue基础语法——组件化开发——模块化开发——webpack


Day 01


01.(了解)vue.js课程介绍

  • Vue.js课程学习路线
  • Vue基础语法——组件化开发——Vue CLI——vue-router——vuex详解——网络封装——项目实战——项目部署——Vue.js原理相关

02.(理解)vue.js的特点和认识介绍

  • Vue是一个渐进式框架,什么是渐进式呢?

渐进式意味着你可以将Vue作为你应用的一部分嵌入其中,带来更丰富的交互体验。

或者如果你希望将更多的业务逻辑使用Vue实现,那么Vue的核心库以及其生态系统。

比如Core+Vue-router+Vuex,也可以满足你各种各样的需求。

03.(掌握)vue.js安装方式

  • 方式一:直接CDN

  • 方式二:下载和引入

开发环境 https://vuejs.org/js/vue.js

生产环境 https://vuejs.org/js/vue.min.js

  • 方式三:NPM安装

后续通过webpack和CLI的使用,我们使用该方式。

04.(掌握)HelloVuejs初体验

  • 原生改变元素内容和vue改变元素内容区别 
  • el:挂载管理的元素
<body>
    <!-- vue模式html -->
    <div id="app">{{message}}</div>
    <!-- 原生模式html -->
    <div id="dom"></div>

    <!-- vue改变元素内容,叫声明式编程 -->
    <script src="./js/vue.js"></script>
    <script>
        //let变量、const常量
        const app = new Vue({
            el: '#app', //用于挂载要管理的元素
            data: { //定义一些数据
                message: '你好啊vue'
            },
        })
    </script>
    <!-- 原生改变元素内容,叫命令式编程-->
    <script>
        document.querySelector('#dom').innerHTML = '你好啊dom';
    </script>
</body>

 05.(掌握)Vue列表的显示

  • 传统改变ul>li内容和vue的v-for遍历内容的区别
  • 响应式:app.movies.push("龙猫"),页面直接就显示新增内容,而传统的dom操作需要创建一个li,然后再加内容
<body>
    <!-- vue替代遍历列表内容 -->
    <div id="app">
        <ul>
            <li v-for="item in movies">{{item}}</li>
        </ul>
    </div>
    <script src="./js/vue.js"></script>
    <script>
        const app = new Vue({
            el: '#app',
            data: {
                message: '',
                movies: ["功夫", "千与千寻", "肖申克救赎", "泰坦尼克号"]
            }
        })
    </script>

    <!-- 传统dom遍历列表内容 -->
    <ul class="con">
        <li>{{movies[0]}}</li>
        <li>{{movies[1]}}</li>
        <li>{{movies[2]}}</li>
        <li>{{movies[3]}}</li>
    </ul>
    <script>
        document.querySelector('.con').querySelectorAll('li')[0].innerHTML = "功夫"
        document.querySelector('.con').querySelectorAll('li')[1].innerHTML = "千与千寻"
        document.querySelector('.con').querySelectorAll('li')[2].innerHTML = "肖申克救赎"
        document.querySelector('.con').querySelectorAll('li')[3].innerHTML = "泰坦尼克号"
    </script>
</body>

06.(掌握)小案例-计数器

  • 计数器代码:
<body>
    <div id="app">
        <h2>计数器:</h2>
        <button @click="sub">-</button>
        <span>{{count}}</span>
        <button @click="add">+</button>
    </div>

    <script src="./js/vue.js"></script>
    <script>
        const app = new Vue({
            el: '#app',
            data: {
                count: 0,
            },
            methods: {
                sub: function() {
                    this.count--   //this指向当前对象
                },
                add: function() {
                    this.count++
                }
            },
        })
    </script>
</body>

07.(理解)Vue的MVVM模式

  • MVVM:MVVM是Model-View-ViewModel的简写。它本质上就是MVC 的改进版。MVVM 就是将其中的View 的状态和行为抽象化,让我们将视图 UI 和业务逻辑分开。

08.理解Vue的options选项

  • 创建new Vue({})的时候,就传入了一个options对象
    • 需要掌握的选项(不止这些):
      el

      类型:string | HTMLElement(“|”是或的意思)

      作用:决定之后Vue实例会管理哪一个DOM

      data

      类型:Object | Function

      作用:Vue实例对应的数据对象

      methods

      类型:{[key:string]:Function}

      作用:定义属于Vue的一些方法,可以在其他地方调用,也可以在指令中使用。

  • 方法和函数的区别:
方法函数
英文单词methodfunction
定义方法(method)是通过对象调用的javascript函数。也就是说,方法也是函数,只是比较特殊的函数。函数(function)是一段代码,需要通过名字来进行调用。它能将一些数据(函数的参数)传递进去进行处理,然后返回一些数据(函数的返回值),也可以不返回数据。

09.(理解)什么是Vue的生命周期

10.Vue的生命周期函数有哪些

  • 生命周期:Vue实例有一个完整的生命周期,也就是说从开始创建、初始化数据、编译模板、挂在DOM、渲染-更新-渲染、卸载等一系列过程,我们成为Vue 实例的生命周期。
  • Vue部分源码:(可以说明Vue在new Vue的时候做了很多事情)
function Vue (options) {
  if (process.env.NODE_ENV !== 'production' &&
    !(this instanceof Vue)
  ) {
    warn('Vue is a constructor and should be called with the `new` keyword')
  }
  this._init(options)
}
Vue.prototype._init = function (options?: Object) {
    ......
}
  • 下边created和mounted会在new Vue()的时候执行:
    <script>
        const app = new Vue({
            el: '#app',
            data: {},
            methods: {},
            created: function() {
                console.log("created");    //控制台打印“create”
            },
            mounted: function() {
                console.log("mounted");    控制台打印“mounted”
            },
        })
    </script>
  • Vue生命周期图(重要★)

11.(了解)定义vue的template

  • 自定义用户代码片段,vscode:文件-首选项-用户片段-html.json,加入以下代码:
"vue": {
        "prefix": "vue", // 触发的关键字 输入vue按下tab键
        "body": [

            "    <div id=\"app\"></div>",
            "    <script>",
            "        const app = new Vue({",
            "           el:'#app',",
            "           data:{},",
            "           methods:{}",
            "        });",
            "    </script>",
        ],
        "description": "vue template"
    }

12.(掌握)插值操作-mustache语法

  • {{message}}

 <div id="app">
        <h2>{{message}}</h2>
        <h2>{{message}},龙猫</h2>
        <!-- mustache语法中,也可以直接写简单的表达式 -->
        <h2>{{firstName +' '+ lastName}}</h2>
        <h2>{{firstName}}{{lastName}}</h2>
        <h2>{{count*2}}</h2>
    </div>
    <script src="./js/vue.js"></script>
    <script>
        const app = new Vue({
            el: '#app',
            data: {
                message: '你好啊',
                firstName: 'mao',
                lastName: 'long',
                count: 100
            },
            methods: {}
        });
    </script>

13.(掌握)插值操作-其他指令的使用(v-once、v-html、v-text、pre)

  • v-once 只渲染一次,不会随着数据改变而改变,
 <h2 v-once>{{message}}</h2>
  •  v-html按照HTML格式进行解析,并且显示对应的内容
  • v-text作用和Mustache一致,通常情况下,接受一个string类型
  • v-pre用于跳过这个元素和它子元素的编译过程,用于显示原本的Mustache语法
  • v-cloak避免在某些情况下,我们浏览器可能会直接显然出未编译的Mustache标签
 <div id="app">
        <!-- 显示'<a href="http://www.baidu.com">百度</a>'-->
        {{url}}
        <!-- 显示:百度-->
        <div v-html="url"></div>
        <!-- v-text和{{}}几乎一样,不会解析html元素,还不如{{}},因为会覆盖内容-->
        <div v-text="url"></div>
        <!-- v-pre不会解析{{}},原封不动显示,用的不多 -->
        <div v-pre>{{message}}</div>
        <!-- vue解析之前,div有一个熟悉叫v-cloak,解析之后,没了,[v-cloak]{display:none} -->
        <div v-cloak>{{message}}</div>
    </div>
    <script src="./js/vue.js"></script>
    <script>
        setTimeout(() => {
            const app = new Vue({
                el: '#app',
                data: {
                    message: '你好',
                    url: '<a href="http://www.baidu.com">百度</a>'
                },
                methods: {}
            });
        }, 1000);
    </script>

14.(掌握)v-bind的基本使用

  • v-bind用于绑定属性,如a元素的href属性,img元素的src属性
  • v-bind的缩写是冒号:
<div id="app">
        <img :src="imgUrl" alt="">
        <img v-bind:src="imgUrl" alt="">
        <a :href="baiduUrl">百度一下</a>C
    </div>
    <script src="./js/vue.js"></script>
    <script>
        const app = new Vue({
            el: '#app',
            data: {
                message: '类名',
                imgUrl: 'https://cn.vuejs.org/images/logo.png',
                baiduUrl: 'https://www.baidu.com',
            },
            methods: {}
        });
    </script>

15.(掌握)v-bind动态绑定class(对象语法)

  • 对象语法的含义是:class后面跟的是一个对象

用法一:直接通过{}绑定一个类

Hello World

用法二:也可以通过判断,传入多个值

Hello World

用法三:和普通的类同时存在,并不冲突 注:如果isActive和isLine都为true,那么会有title/active/line三个类

Hello World

用法四:如果过于复杂,可以放在一个methods或者computed中 注:classes是一个计算属性

Hello World

<head>
    <style>
        .active {
            color: red;
        }
        .line {
            font-size: 60px;
        }
    </style>
</head>
<body>
    <div id="app">
        <div :class="{active:isActive,line:isLine}">{{message}}</div>
        <div :class="getClasses()">{{message}}</div>
    </div>
    <script src="./js/vue.js"></script>
    <script>
        const app = new Vue({
            el: '#app',
            data: {
                message: '类名',
                isActive: true,
                isLine: true
            },
            methods: {
                getClasses: function() {
                    return {
                        active: this.isActive,
                        line: this.isLine
                    }
                }
            }
        });
    </script>
</body>

16.(掌握)v-bind动态绑定class(数组语法)

  • 数组语法的含义是:class后面跟的是一个数组。
  • Hello World

17.作业v-bind和v-for结合

  • 两种方法实现v-for不同行点击效果,第二种好
<body>
    <div id="app">
        <ul>
            :class="{active:isActive[index]}"方法:
            <li v-for="(item,index) in movies" :class="{active:isActive[index]}" @click = "changeColor(index)">{{item}}</li>
            index==this.num?"active":''方法:
            <li v-for="(item,index) in movies" :class="getClass(index)" @click = "changeNum(index)">{{item}}</li>
            
        </ul>
    </div>
    <script src="../js/vue.js"></script>
    <script>
        var app=new Vue({
           el:'#app',
           data:{
               movies:['龙猫','千与千寻','功夫','天空之城'],
            //    classes:['c1','c2','c3','c4'],
            isActive:[true,false,false,false],
            num:0
           },
           methods:{
            changeColor:function(index){
                // console.log(index);
                this.isActive = [false,false,false,false]
                this.isActive[index] = true;
            },
            changeNum:function(index){
                this.num = index;
            },
            getClass:function(index){
                return index==this.num?"active":''
            }
           }
        });
    </script>
</body>

18.v-bind动态绑定style(对象语法)

  • key:value,value如果不是一个变量,需要加单引号''
<div id="app">
        <h2 :style="{color:'red',fontSize:'100px',backgroundColor:color}">{{message}}</h2>
        <h2 :style="getStyles()">{{message}}</h2>
    </div>
    <script src="../js/vue.js"></script>
    <script>
        var app=new Vue({
           el:'#app',
           data:{
               message:'龙猫',
               color:'blue'
           },
           methods:{
            getStyles:function(){
                return {color:'red',fontSize:'100px',backgroundColor:this.color}
            }
           }
        });
    </script>

19.v-bind动态绑定style(数组语法)

  •  

         (用得很少)

20.(掌握)计算属性computed的基本使用

  • 计算属性一般用在对数据进行某种变换对时候,对数据重新定义一个属性
 <div id="app">
        <h2>{{firstName +' '+lastName}}</h2>
        <h2>{{firstName}} {{lastName}}</h2>
        <h2>{{getFullName()}}</h2>
        <!-- 计算属性一般用在对数据进行某种变换对时候,对数据重新定义一个属性 -->
        <h2>{{fullName}}</h2>
    </div>
    <script src="../js/vue.js"></script>
    <script>
        var app=new Vue({
           el:'#app',
           data:{
               firstName:'sen',
               lastName:'wang'
           },
           methods:{
            getFullName:function(){
                return this.firstName+' '+this.lastName
            }
           },
        //    因为说计算属性,名字最好只像属性
           computed:{
               fullName:function(){
                   return this.firstName+' '+this.lastName
               }
           }
        });
    </script>

21.(掌握)计算属性的复杂操作

  • computed用于计算属性,一般写名词eg:计算几本书的总价
<div id="app">
        <h2>{{getSumPrice()}}</h2>
        <h2>{{SumPrice}}</h2>
    </div>
    <script src="../js/vue.js"></script>
    <script>
        var app=new Vue({
           el:'#app',
           data:{
               books:[
                   {id:1101 ,name:"哈姆雷特" ,price:102},
                   {id:1102 ,name:"计算机原理" ,price:102},
                   {id:1103 ,name:"操作系统" ,price:102},
                   {id:1104 ,name:"web前端" ,price:102},
               ],
           },
           methods:{
            //    有错误,不知道为什么
            getSumPrice:function(){  
                let sum = 0
                for( let i = 0;i<this.books.length;i++){
                    sum += this.books[i].price;
                }
                return sum
            }
           },
           computed:{
            SumPrice:function(){
            //    for( let i = 0;i<this.books.length;i++){
            //         this.sumPrice += this.books[i].price;
            //     }
            //     return this.sumPrice;
            // 或者使用es6语法:
            let sum = 0
              for(let book of this.books){
                  sum += book.price
              }
              return sum;  
            }
           }
        });
    </script>

22.课堂回顾(略)


Day 02


01.理解计算属性的setter和getter

  • 默认使用get方法,没有用set方法
  • set方法只有在设置属性的时候才会调用,如:app.fullName2 = 'sss'
    <div id="app">
        <h2>{{fullName}}</h2>
        <h2>get方法:{{fullName2}}</h2>
    </div>
    <script src="../js/vue.js"></script>
    <script>
        var app=new Vue({
           el:'#app',
           data:{
               firstName:'sen',
               lastName:'wang',  
           },
           methods:{},
           computed:{
            fullName:function(){
                return this.firstName +' '+ this.lastName;
            },
            fullName2:{
                set:function(newValue){
                    console.log('---',newValue);
                    const names = newValue.split(' ');
                    this.firstName = names[0];
                    this.lastName = names[1];
                },
                get:function(){
                    return this.firstName +' '+ this.lastName
                }
            }
           }
        });
    </script>

02.计算属性computed和methods对比

  • computed只调用一次函数性能高(内部有一个缓存),methods会多次调用函数
 <div id="app">
        <!-- 1.直接拼接 -->
        <h2>{{firstName}}{{lastName}}</h2>
        <!-- 2.通过定义methods -->
        <h2>{{getFullName()}}</h2>
        <h2>{{getFullName()}}</h2>
        <h2>{{getFullName()}}</h2>
        <h2>{{getFullName()}}</h2>
        <!-- 3.通过定义computed -->
        <h2>{{fullName}}</h2>
        <h2>{{fullName}}</h2>
        <h2>{{fullName}}</h2>
        <h2>{{fullName}}</h2>
    </div>
    <script src="../js/vue.js"></script>
    <script>
        var app=new Vue({
           el:'#app',
           data:{
               firstName:'sen',
               lastName:'wang'
           },
           methods:{
            getFullName:function(){
                console.log('getFullName');//输出(调用)4次
                return this.firstName +' '+ this.lastName
            }
           },
           computed:{
               fullName:function(){
                console.log('fullName');//只输出(调用)1次
                return this.firstName +' '+ this.lastName
               }
           }
        });
    </script>

03.(掌握)块级作用域let和var

  •  JavaScript 闭包。它使得函数拥有私有变量变成可能。
 <script>
        // 1.var定义的变量在块级外边也可以访问
        {
            var name = "longmao"
            console.log(name);
        }
        console.log(name);
        
        if(true){
            var name2 = 'why'
        }
        console.log(name2);
</script>
  • 闭包案例
  • 没有使用闭包之前,单击每个按钮打印点击了第i个按钮会全部打印最后1个i的值
  • 使用闭包之后,相当于函数套函数,打印的是5个带参数的函数,在点击的时候再传递参数
var btns = document.querySelectorAll('button');
        for(i=0;i<btns.length;i++){
            // btns[i].onclick = function(){
            //     console.log('第'+i+'个按钮被点击了');
            // }
            //使用闭包可以解决此问题,闭包可以看作打印了5个函数,每个函数的num都是一个参数,点击的时候再传递参数
            (function(num){
                btns[i].onclick = function(){
                console.log('第'+num+'个按钮被点击了');
                }
            })(i)
        }
  • let块级作用域解决冲突
    <button>按钮1</button>
    <button>按钮2</button>
    <button>按钮3</button>

    <script>
        var btns = document.querySelectorAll('button');
        for(let i=0;i<btns.length;i++){
            btns[i].onclick = function(){
                console.log('第'+i+'个按钮被点击了');
            }
        }
// //使用let:
//         {//i = 0
//             btns[i].onclick = function(){
//                 console.log('第'+i+'个按钮被点击了');
//             }
//         }
//         {//i = 1
//             btns[i].onclick = function(){
//                 console.log('第'+i+'个按钮被点击了');
//             }
//         }
//         {//i = 3
//             btns[i].onclick = function(){
//                 console.log('第'+i+'个按钮被点击了');
//             }
//         }
// //使用var i=3
//         {//i = 3
//             btns[i].onclick = function(){
//                 console.log('第'+i+'个按钮被点击了');
//             }
//         }
//         {//i = 3
//             btns[i].onclick = function(){
//                 console.log('第'+i+'个按钮被点击了');
//             }
//         }
//         {//i = 3
//             btns[i].onclick = function(){
//                 console.log('第'+i+'个按钮被点击了');
//             }
//         }
    </script>

04.三种方案对比

  1. var错误的方式
  2. var+闭包方式
  3. let方式

05.(掌握)const的使用和注意点

  • ES6开发中,优先使用const,只有需要改变某个标识符时才用let
<script>
const name = 'why';
name = 'what';//报错
</script>
  • const obj = { },可以修改obj内部的属性,但是不能修改obj外部的指向:
    <script>
        const name = 'why';
        // name = 'what';//报错

        const obj = {
            name:'龙猫',
            age:2,
            move:function(){
                console.log(this.name);
            }
        };
        // obj = {}//报错
        obj.name = '千寻';
        obj.move();//打印的是“千寻”,因为内部的属性可以修改,但是不能改变obj的指向
    </script>

06.(掌握)ES6对象字面量增强写法

  • ES5和ES6的区别:
  1.         let name = 'why';
            let age = 18;
            let obj1 = {
                name:name,
                age:age,
                eat:function(){
                    console.log("吃1");
                }
            }
            console.log(obj1);
            obj1.eat();
            //ES6
            let obj2 = {
                name,age,
                eat(){
                    console.log("吃2");
                }
            }
            console.log(obj2);
            obj2.eat();

07.空

08.(掌握)v-on的基本使用和语法糖

  • 语法糖v-on:和@等价

09.(掌握)v-on的参数传递问题

  • 方法加()的问题
  1. 如果方法中没有传递参数,可以省略括号(也可以不省略)

    +

  2. 如果方法中有参数传递,必须加括号

    +

  3. 如果方法中有多个参数:

 <div id="app">
        <!-- 1.事件调用方法没有参数 -->
        <button @click = "btn1Click">按钮1不带参数,正常执行</button>
        <button @click = "btn1Click()">按钮1()不带参数,正常执行</button>
        <!-- 2.事件调用方法有参数 -->
        <button @click = "btn2Click('参数')">按钮2(name)带参数,正常返回</button>
        <button @click = "btn2Click()">按钮2()带括号但是不传递参数,返回undefined</button>
        <button @click = "btn2Click">按钮2不带括号也不传递参数,返回MouseEvent对象</button>
        <!-- 3.传递多个参数 -->
        <button @click = "btn3Click('参数3',$event)">按钮3,方法定义时需要参数和event</button>
    </div>
    <script src="../js/vue.js"></script>
    <script>
        var app=new Vue({
           el:'#app',
           data:{},
           methods:{
            btn1Click(){
                console.log("按钮1");
            },
            btn2Click(name){
                console.log(name);
            },
            //默认不写参数的时候,执行的是event对象:
            // btn2Click(event){
            //     console.log(event);
            // }
            btn3Click(name,event){
                console.log(name,event);
            }
           }
        });
    </script>

10.(掌握)v-on修饰符的使用

  1. vue中阻止事件冒泡: 按钮
  2. vue中阻止submit默认行为.prevent,如
  3. vue中键盘按下修饰符@keyup.enter = "keyUp"
  4. vue中只运行一次修饰符.once,如按钮2
<div id="app">
        <!-- 1..stop修饰符 -->
        <div @click = "divClick">
            <button @click.stop = "btnClick">按钮</button>
        </div>
        <!-- 2..prevent事件修饰符的使用  -->
        <form action="baidu">
            <input type="submit" value="提交" @click.prevent = "submitClick">
        </form>
        <!-- 3.监听键帽的按下 -->
        <input type="text" @keyup.enter = "keyUp">
        <!-- 4..once修饰符 -->
        <button @click.once = "btn2Click">按钮2</button>
    </div>
    <script src="../js/vue.js"></script> 
    <script>
        var app=new Vue({
           el:'#app',
           data:{},
           methods:{
               btnClick(){
                   console.log("btnClick");
               },
               divClick(){
                   console.log("divClick");
               },
               submitClick(){
                   console.log("submitClick");
               },
               keyUp(){
                   console.log("keyUp");
               },
               btn2Click(){
                   console.log("btn2Click");
               }
           }
        });
    </script>

11.(掌握)v-if和v-if-else和v-else的使用 

  • 区别如下,不太建议在这写,建议在computed里边写判断
<div id="app">
        <h2 v-if="score>90">优秀</h2>
        <h2 v-else-if="score>80">良好</h2>
        <h2 v-else-if="score>60">中等</h2>
        <h2 v-else>差</h2>
        <h1>{{resultMessage}}</h1>
    </div>
    <script src="../js/vue.js"></script>
    <script>
        var app=new Vue({
           el:'#app',
           data:{
               score:88
           },
           methods:{},
           computed:{
            resultMessage(){
                let showMessage = '';
                if(this.score>90){
                    showMessage = "优秀"
                }else if(this.score>80){
                    showMessage = "良好"
                }else if(this.score>60){
                    showMessage = "中等"
                }else{
                    showMessage = "差"
                }
                return showMessage;
            }
           }
           
        });
    </script>

12.(掌握)v-if登陆切换的小案例

<div id="app">
        <span v-if="isShow">
            <label for="username">用户名登录</label>
            <input type="text" placeholder="请输入用户名" id="username">
        </span>
        <span v-else>
            <label for="email">邮箱登录</label>
            <input type="text" placeholder="请输入邮箱" id="email">
        </span>
        <button @click="changeLoggin">登录切换</button>
    </div>
    <script src="./js/vue.js"></script>
    <script>
        const app = new Vue({
            el: '#app',
            data: {
                isShow: true
            },
            methods: {
                changeLoggin() {
                    this.isShow = !this.isShow
                }
            }
        });
    </script>

13.(理解)登录切换的input复用问题

  • 问题:点击切换的时候,input的内容没有清空
    • 原理:div--虚拟dom(放内存里)--显示内容
    • 出于性能考虑,因为没有改变label和input元素标签,会继续复用虚拟dom的label和input元素标签
  • 解决:各加一个key属性,
    • key = "username"
    • key = "email"
        <span v-if="isShow">
            <label for="username">用户名登录</label>
            <input type="text" placeholder="请输入用户名" id="username" key="username">
        </span>
        <span v-else>
            <label for="email">邮箱登录</label>
            <input type="text" placeholder="请输入邮箱" id="email" key = "email">
        </span>
        <button @click="changeLoggin">登录切换</button>

14.(掌握)v-show的使用和v-if的区别

  • v-show:false相当于加了一个行内样式display:none属性
  • v-if:false相当于删除dom
    <div id="app">
        <!-- v-if为false时,相当于删除dom,适合使用频率低的时候 -->
        <h2 v-if="isShow" id="if">{{message}}</h2>
        <!-- v-show为false时,相当于display:none,适合使用频率高的时候 -->
        <h2 v-show="isShow" id="show">{{message}}</h2>
    </div>
    <script src="./js/vue.js"></script>
    <script>
        const app = new Vue({
            el: '#app',
            data: {
                message: "hello",
                isShow: true
            },
            methods: {}
        });
    </script>

15.(掌握)v-for遍历数组和对象

  • 遍历数组
    <div id="app">
        <ul>
            <li v-for="(item,index) in names">{{index+1}},{{item}}</li>
        </ul>
    </div>
    <script src="./js/vue.js"></script>
    <script>
        const app = new Vue({
            el: '#app',
            data: {
                names: ['why', 'wangsen', 'james', 'curry']
            },
            methods: {}
        });
    </script>
  • 遍历对象
    <div id="app">
        <!-- 1.笨方法 -->
        <ul>
            <li>{{obj.name}}</li>
            <li>{{obj.age}}</li>
            <li>{{obj.height}}</li>
        </ul>
        <!-- 2.遍历方法,只获取value -->
        <ul>
            <li v-for="item in obj">{{item}}</li>
        </ul>
        <!-- 3.获取(value,key) -->
        <ul>
            <li v-for="(item,key) in obj">{{key}}:{{item}}</li>
        </ul>
        <!-- 4.获取(value,key,index)index用的很少 -->
        <ul>
            <li v-for="(item,key,index) in obj">{{key}}:{{item}}--{{index}}</li>
        </ul>
    </div>
    <script src="./js/vue.js"></script>
    <script>
        const app = new Vue({
            el: '#app',
            data: {
                obj: {
                    name: 'wangsen',
                    age: 18,
                    height: 1.88
                }
            },
            methods: {}
        });
    </script>

16.(理解)v-for绑定和非绑定key的区别

  • 数组插入app.letters.splice(2,0,'F') ,第二个字母边插入F
  • 正常情况是虚拟dom里插入F,然后渲染。但是实际不是,实际是把E改成F,把D改成C,E改成D,最后加一个E,性能比较低,这叫diff算法
  • 所以官方推荐我们使用v-for时,给对应元素加:key属性,这样diff算法就可以正确识别此节点,找到正确的位置插入
  • :key="item"不用index是因为插入之后,index会变,不是一一对应,性能不好
    <div id="app">
        <ul>
            <!-- :key="item"不用index是因为插入之后,index会变,不是一一对应,性能不好-->
            <li v-for="(item,index) in letters" :key="item">{{index}},{{item}}</li>
        </ul>
    </div>
    <script src="./js/vue.js"></script>
    <script>
        const app = new Vue({
            el: '#app',
            data: {
                letters: ['A', 'B', 'C', 'D', 'E']
            },
            methods: {}
        });
    </script>

17.(掌握)数组中哪些是响应式的

数组方法是否响应式作用

this.letter.push('sss')

响应式

数组后边添加元素,可以做到响应式

this.letters.pop()

响应式

删除数组最后一个

this.letters.shift()

响应式

删除数组中的第一个

this.letters.unshift('aaa', 'bbb')

响应式

在数组前边添加元素,可以传多个参数是因为是可变参数...str

this.letter.sort()

响应式

排序,响应式

this.letters.reverse()

响应式数组反转

this.letters.splice(2, 1, 'm  ')

响应式

可以做增删改,从第二个开始,删除1个,增加‘m’

this.letters[0] = 'bbbb'

不能做到响应式,可以this.letters.splice(0, 1, 'bbbb');替代

Vue.set(this.letters, 0, 'bbbb')

响应式vue的方法实现元素替换

18.(掌握)作业的回顾和实现

  • 四行一列的数据,点击谁,谁变红
  • 重点:currentIndex的引入(此类问题都是这么解决),就是获取当前点击的index的数字
    <div id="app">
        <ul>
            <li v-for="(item,index) in movies" @click="changeClass(index)" :class="{active:currentIndex==index}">{{item}}</li>
            <!-- <li v-for="(item,index) in movies" @click="changeClass(index)" :class="{active:currentIndex==0}">{{item}}</li>
            <li v-for="(item,index) in movies" @click="changeClass(index)" :class="{active:currentIndex==1}">{{item}}</li>
            <li v-for="(item,index) in movies" @click="changeClass(index)" :class="{active:currentIndex==2}">{{item}}</li>
            <li v-for="(item,index) in movies" @click="changeClass(index)" :class="{active:currentIndex==3}">{{item}}</li> -->
        </ul>
    </div>
    <script src="./js/vue.js"></script>
    <script>
        const app = new Vue({
            el: '#app',
            data: {
                currentIndex: 0,
                movies: ['海王', '海贼王', '加勒比海盗', '海尔兄弟']
            },
            methods: {
                changeClass(index) {
                    this.currentIndex = index;
                }
            }
        });
    </script>

19.(掌握)购物车案例-界面搭建

  • v-for把书籍遍历
        <table>
            <thead>
                <tr>
                    <th></th>
                    <th>书籍名称</th>
                    <th>出版日期</th>
                    <th>价格</th>
                    <th>购买数量</th>
                    <th>操作</th>
                </tr>
            </thead>
            <tbody>
                <tr v-for="(item,index) in bookList">
                    <td>{{item.id}}</td>
                    <td>{{item.name}}</td>
                    <td>{{item.date}}</td>
                    <td>
                        <span>{{getFinallPrice(item.price)}}</span>
                    <td>
                        <button @click="subCount(index)">-</button>
                        <span>{{item.count}}</span>
                        <button @click="addCount(index)">+</button>
                    </td>
                    <td>
                        <button @click="remove(index)">移除</button>
                    </td>
                </tr>
            </tbody>
        </table>
        <h2>总价格:{{sumPrice}}</h2>

20.(掌握)购物车案例-过滤器filter的使用

  • 没有使用过滤器和使用过滤器都能达到目的:
<!--没有使用过滤器-->
<span>{{getFinallPrice(item.price)}}</span>
<script>
...
    methods: {
        getFinallPrice(price) {
            return '¥' + price.toFixed(2)
        }
    },
</script>

<!--使用过滤器-->
<span>{{item.price | showPrice}}</span>

<script>
...
    methods: {
    },
    filters: {
        showPrice(price) {
            return '¥' + price.toFixed(2)
        }
    },
</script>

21.(掌握)购物车案例-改变购买数量

  • :disabled="item.count==1"剩下1个点时候,减少按钮不能再点击(变灰)
<th>
    <button @click = "sub(index)" :disabled="item.count==1">-        </button>
    <span>{{item.count}}</span>
    <button @click = "add(index)">+</button>
</th>
...
methods:{
        sub(index){
            this.books[index].count--      
        },
        add(index){
            this.books[index].count++
        },
}

22.(掌握)购物车案例-移除按钮-最终价格

  • 移除全部书之后,购物车变成“购物车为空”,利用v-if和v-else
  • 计算总价使用计算属性:
    两种方法DOM中区别调用
    computed

    总价为{{sumPrice}}

    会自动调用sumPrice方法
    methods

    总价为{{sumPrice()}}

    也会自动调用sumPrice方法,但是不太合适
    totalPrice() {
                //计算总价的方法1:
                // let totalprice = 0;
                // for (item of this.bookList) {
                //     totalprice += item.price * item.count;
                // }
                // return totalprice
                //计算总价的方法2(高级函数):
                return this.bookList.reduce(function(preValue, book) {
                    return preValue + book.price * book.count
                }, 0)
            }

<div v-if="books.length!=0">
    <table>books</table>
</div>
<div v-else>购物车为空</div>

Day 03


01.(掌握)JavaScript高阶函数的使用

  • 计算总价的三种方法(of 最好):
sumPrice(){
            //1.普通的for循环
            // let sumprice = 0;
            // for(let i=0;i<this.books.length;i++){
            //     sumprice += this.books[i].price * this.books[i].count;
            // }
            // return sumprice
            // 2. in循环
            // let sumprice = 0;
            // for(let i in this.books){
            //     sumprice += this.books[i].price * this.books[i].count;
            // }
            // return sumprice
            // 3.of循环
            let sumprice = 0;
            for(let item of this.books){
                sumprice += item.price * item.count;
            }
            return sumprice
        }
编程范式命令式编程声明式编程
编程范式

面向对象编程

(第一公民:对象)

函数式编程

(第一公民:函数)

  • 高阶函数:函数所需要的参数也是函数
  • filter / map / reduce高级方法(数组):
    1. filter的使用,用于过滤数值,不改变数值

nums = [12 , 333 , 34 , 55 , 133 ]

let new3Nums = nums.filter(function(n) {

            return n < 100

})

console.log(new3Nums)    //打印[12 , 34 , 55 ]

                   2.map的使用,一般用于数值操作,不过滤数值

let new4Nums = new3Nums.map(function(n) {

            return n * 2

})

console.log(new4Nums);    //打印[24 , 68 , 110 ]

                  3.reduce应用,用于数组求和:

let total2 = new4Nums.reduce(function(total, num) {

            return total + num;

})

console.log(total2);    //打印24+68+110的和

                 4.命令式和高级函数对比代码:

        const nums = [10, 20, 44, 66, 888, 123, 55, 75, 111];
//1.取出所有小于100的数字
        let newNums = [];
        for (let n of nums) {
            if (n < 100) {
                newNums.push(n)
            }
        }
        console.log(newNums);
//2.将所有小于100的数字进行转化:全部*2
        let new2Nums = [];
        for (let n of newNums) {
            new2Nums.push(n * 2);
        }
        console.log(new2Nums);
//3.将所有num2Nums数字相加,得到最终结果
        let total = 0
        for (let n of new2Nums) {
            total += n;
        }
        console.log(total);
//4.filter,根据条件筛选,不能改变值
        let new3Nums = nums.filter(function(n) {
            return n < 100
        })
        console.log(new3Nums);
//5.map,不做筛选,改变值
        let new4Nums = new3Nums.map(function(n) {
            return n * 2
        })
        console.log(new4Nums);
// 6.reduce
        let total2 = new4Nums.reduce(function(total, num) {
            return total + num;
        })
        console.log(total2);
//7.一行代码搞定,函数式编程
        let total3 = nums.filter(function(n) {
            return n < 100
        }).map(function(n) {
            return n * 2
        }).reduce(function(total, num) {
            return total + num;
        })
        console.log(total3);
//8.一行代码搞定——箭头函数
        let total4 = nums.filter(n => n < 100).map(n => n * 2).reduce((total, num) => total + num);
        console.log(total3);

02.(掌握)v-model的使用和原理

  • v-model指令来实现表单元素和数据的双向绑定
  • v-bind指令是单向绑定,只能从数据传到表单,表单的值改变不能改变message的值
1.双向绑定,可以接收和改变message:
        <input type="text" v-model="message">
        <h2>message:{{message}}</h2>
2.单向绑定,只能接收不能改变message:
        <input type="text" :value="message">
3.人为单向绑定,只改变不接收,2+3合起来就是v-model
        <input type="text" v-on:input="valueChange">
4.手动双向绑定:
        <input type="text" :value="message" @input="message=$event.target.value">
    </div>
    <script src="./js/vue.js"></script>
    <script>
        const app = new Vue({
            el: '#app',
            data: {
                message: '龙猫'
            },
            methods: {
                valueChange(event) {
                    this.message = event.target.value;
                }
            }
        });
    </script>

03.(掌握)v-model结合radio类型使用

  • 二选一的时候和value有关
  • 单选多时候是boolean
        <label for="male">
            <input type="radio" id="male"  value="男" v-model="sex">男
        </label>
        <label for="female">
            <input type="radio" id="female"  value="女" v-model="sex">女
        </label>
        <h2>你选择的性别是:{{sex}}</h2>

        <h1>单选框:</h1>
        <label for="agree">
            <input type="checkbox" id="agree" v-model="isAgree">同意
        </label>
        <h2>你选择的是:{{isAgree}}</h2>
        <button :disabled="!isAgree">下一步</button>
......
        data:{
               sex:'男',
               isAgree:false
         
        },

04.(掌握)v-model结合checkbox类型

  • 多选多时候绑定的是数组
        <h1>多选框:</h1>
            <input type="checkbox" value="篮球" v-model="hobbies">篮球
            <input type="checkbox" value="钢琴" v-model="hobbies">钢琴
            <input type="checkbox" value="跳舞" v-model="hobbies">跳舞
        <h2>你的爱好是:{{hobbies}}</h2>

...
        var app=new Vue({
           el:'#app',
           data:{
               hobbies:[],
           },
        });

05.(掌握)v-model结合select类型使用

  • 多选的时候加multiple
    <div id="app">
        <h2>选择一个:</h2>
        <select name="abc" id="" v-model="fruit">
            <option value="苹果" >苹果</option>
            <option value="香蕉" >香蕉</option>
            <option value="梨" >梨</option>
            <option value="榴莲" >榴莲</option>
        </select>
        <h2>{{fruit}}</h2>

        <h2>选择多个:</h2>
        <select name="abc" id="" v-model="fruits" multiple>
            <option value="苹果" >苹果</option>
            <option value="香蕉" >香蕉</option>
            <option value="梨" >梨</option>
            <option value="榴莲" >榴莲</option>
        </select>
        <h2>{{fruits}}</h2>
    </div>
    <script src="../js/vue.js"></script>
    <script>
        var app=new Vue({
           el:'#app',
           data:{
            fruit:'榴莲',
            fruits:[]
           },
        });
    </script>

06.(掌握)input中的值的绑定

  • v-for实现多选
        <h1>v-for:</h1>
        <label v-for="item in originHobbies" :for="item">
            <input type="checkbox" :value="item" v-model="hobbies">{{item}}
        </label>
        <h2>{{hobbies}}</h2>

        var app=new Vue({
           el:'#app',
           data:{
               hobbies:[],
               originHobbies:["篮球","钢琴","跳舞","瑜伽","游泳"],
           },
        });

07.(掌握)v-model修饰符的使用

  1. .lazy回车之后才会改变message值
  2. .number让输入的值由字符串改为number类型
  3. trim去除两端多余空格
 <div id="app">
        <h1>1.修饰符lazy</h1>
        <input type="text" v-model.lazy="message">
        <h2>{{message}}</h2>

        <h1>2.修饰符number</h1>
        <input type="number" v-model.number="age">
        <h2>{{typeof age}},{{age}}</h2>

        <h1>3.trim去除空格</h1>
        <input type="text" v-model.trim="name">
        <h2>{{name}}</h2>
    </div>
    <script src="../js/vue.js"></script>
    <script>
        var app=new Vue({
           el:'#app',
           data:{
               message:'',
               age:18,
               name:''
           },
           methods:{}
        });
    </script>

08.(掌握)组件化的使用和实现步骤

09. (掌握)组件化的基本使用过程

  1. 创建组件构造器对象
  2. 注册组件
  3. 使用组件
    <div id="app">
        <h2>我是内容</h2>
        <p>我是内容1111</p>
        <p>我是内容2222</p>

        <h2>我是内容</h2>
        <p>我是内容1111</p>
        <p>我是内容2222</p> 
<!-- 3.使用组件 -->
        <my-cpn></my-cpn>
        <my-cpn></my-cpn>

    </div>
    <script src="../js/vue.js"></script>
    <script>
//1.创建组件构造器对象
        const cpnC = Vue.extend({
            template:
            `<div>
            <h2>我是内容</h2>
            <p>我是内容3333</p>
            <p>我是内容4444</p>
            </div>`
        });
//2.注册组件
        Vue.component('my-cpn',cpnC);
        var app=new Vue({
           el:'#app',
           data:{},
           methods:{}
        });
    </script>

10.(掌握)全局组件和局部组件

  • Vue CLI3.x 构建Vue项目的
  • 使用组件必须在app元素内

  • 全局组件和局部组件
  • 全局组件:Vue.component('my-cpn',cpnC); app1和app2都可以使用
  • 局部组件:components:{ my_cpn:cpnC }, /只能在对应的app下面使用,my_cpn使用组件的标签名, 是在vue实例中创建的,开发中用局部组件比较多。
  • 注意:组件名不能大写
    <div id="app">
        <!-- <my-cpn></my-cpn> -->
        <my_cpn></my_cpn>
    </div>
    <div id="app2">
        <!-- <my-cpn></my-cpn> -->
        局部组件不能在这里使用:
        <!-- <my_cpn></my_cpn> -->
    </div>
    <script src="../js/vue.js"></script>
    <script>
        //1.全局组件
        const cpnC = Vue.extend({
            template:`
            <div>
                <div>我是标题</div>
                <p>我是内容</p>
            </div>
            `
        })
        //全局组件,可以在多个vue的实例下面使用 
        //Vue.component('my-cpn',cpnC);

        var app=new Vue({
           el:'#app',
           data:{},
           components:{
               //局部组件,只能在对应的app下面使用,my_cpn使用组件的标签名
               my_cpn:cpnC
           },
           methods:{}
        });
        var app2=new Vue({
           el:'#app2',
           data:{},
           methods:{}
        });
    </script>

11.(掌握)父组件和子组件的区分

  • 父组件也可以套子组件(套娃):Vue.extend({... conponents:{cpn1:cpnC1}})
  • new Vue({});也可以看成是最顶层的组件(root),里边也可以有template属性
    <div id="app">
        <cpn2></cpn2>
<!-- 下边这个会报错,因为要么全局注册,要么组件中注册过局部的 -->
        <cpn1></cpn1>
    </div>
    <script src="../js/vue.js"></script>
    <script>
        const cpnC1 = Vue.extend({
            template:`
            <div>
               <h2>我说标题1</h2>
               <p>我说内容1</p> 
            </div>`
        });
        const cpnC2 = Vue.extend({
            template:`
            <div>
               <h2>我说标题2</h2>
               <p>我说内容2</p> 
               <cpn1></cpn1>
            </div>`,
            components:{
                cpn1:cpnC1
            }
        });
        var app=new Vue({
           el:'#app',
           data:{
           },
           components:{
               cpn2:cpnC2
           },
           methods:{}
        });
    </script>

12.(掌握)注册组件的语法糖写法

  • 语法糖省去了调用Vue.extend()带步骤,可以直接使用一个对象代替

<div id="app">
        <cpnc1></cpnc1>
        <cpnc2></cpnc2>
    </div>
    <script src="../js/vue.js"></script>
    <script>
        //1.创建组件的构造器
        // const cpn1 = Vue.extend()
        //2.注册组件(语法糖):
        Vue.component('cpnc1',{
            template:`
                <div>
                    <h2>我是标题1</h2>
                    <p>我是内容1</p>
                </div>`
        })
        var app=new Vue({
           el:'#app',
           data:{},
           components:{
            cpnc2:{
                template:`
                    <div>
                        <h2>我是标题2</h2>
                        <p>我是内容2</p>
                    </div>`
                }
            },
           methods:{}
        });
    </script>

13.(掌握)组件模板抽离的写法

  • 模板分离的第一种写法:
  • 模板分离的第二种写法:    ,第二个比较好,用得多
<div id="app">
        <cpn1></cpn1>
        <cpn2></cpn2>
    </div>
    <!-- 1.模板分离的写法 -->
    <script type="text/x-template" id="cpnC1">
        <div>
            <h2>模板分离1</h2>
            <p>我是内容1</p>
        </div>
    </script>
<!--2.模板分离的第二种写法 -->
    <template id="cpnC2">
        <div>
            <h2>模板分离2</h2>
            <p>我是内容2</p>
        </div>
    </template>
    <script src="../js/vue.js"></script>
    <script>
        Vue.component('cpn1',{
            template:'#cpnC1'
        })
        Vue.component('cpn2',{
            template:'#cpnC2'
        })
        var app=new Vue({
           el:'#app',
           data:{},
           methods:{}
        });
    </script>

 14.(理解)为什么组件data必须是函数

  • 组件内部不能访问vue实例中的内容的:

    {{title}}

    ......data:{title:"我是标题"}
  • 如果想访问,必须加data(){return {}}: Vue.component('cpn1',{
                template:'#cpnC1',
                data(){
                    return {
                        title:"我是标题",
                        con:"我是内容"
                    }
                }
            })
    <div id="app">
        <cpn1></cpn1>
    </div>
    <template id="cpnC1">
        <div>
            <!-- 下边title不能访问实例数据 -->
            <h2>{{title}}</h2>
            <p>{{con}}</p>
        </div>
    </template>
    <script src="../js/vue.js"></script>
    <script>
        Vue.component('cpn1',{
            template:'#cpnC1',
            data(){
                return {
                    title:"我是标题",
                    con:"我是内容"
                }
            }
        })
        var app=new Vue({
           el:'#app',
           data:{
//以下这种写法错误
            //title:"我是标题"
           },
           methods:{}
        });
    </script>
  • let obj1 = abc();和let obj2 = abc();并不是一个对象,指向的地址也不一样,因此,data(){return {count:0}}每次返回的count(局部变量)是不同对象的count,互不冲突,如果用data():{count:obj},就会冲突:

    <div id="app">
        <!-- 组件实例对象 -->
        <cpn1></cpn1>
        <cpn1></cpn1>
        <cpn1></cpn1>
    </div>
    <template id="cpnC1">
        <div>
           <button @click="sub">-</button>
           <span>{{count}}</span>
           <button @click="add">+</button>
        </div>
    </template>
    <script src="../js/vue.js"></script>
    <script>
        //1.创建组件
        Vue.component('cpn1',{
            template:'#cpnC1',
            data(){
            //每次调用的时候,return一个新的对象,这样避免的用同一个count导致的冲突
            //注:这里return的对象是局部变量,每次是不一样的,如果外边定义个obj穿过来,就会导致冲突了(使用同一个count)
                return {
                    count:0
                }
            },
            methods:{
                sub(){
                    this.count--
               },
               add(){
                   this.count++
               }
            }
        })
        var app=new Vue({
           el:'#app',
           data:{},
        });
    </script>

15.(掌握)父子组件通信-父传子

  • 父传子:通过props向子组件传递数据(properties属性)
  • 子传父:自定义emit事件
  • 理解:属性向下传,方法向上传
  • 说明:new Vue({})相当于根组件

  1. 父传子 (props的值有多种类型:对象、数据、字符串、布尔、数值等等)
    <div id="app">
        <cpn :cmovies="movies" :cmessage="message"></cpn>
    </div>
    <template id="cpnC1">
        <div>
            <ul>
                <li v-for="item in cmovies">{{item}}</li>
            </ul>
            <p>{{cmessage}}</p>
        </div>
    </template>
    <script src="../js/vue.js"></script>
    <script>
        const cpn = {
            template:'#cpnC1',
            // props:['cmovies','cmessage'],//开发中数组的写法比较少
            //props不止是数组,还可以是对象、字符串、布尔、数组点等,如:
            props:{
                //1.类型限制
                // cmovies:Array,
                // cmessage:String
                //2.提供一些默认值
                cmovies:{
                    type:Array,
                    default(){  //类型是对象或者数组时,默认值必须是一个函数
                        return []
                    }
                },
                cmessage:{
                    type:String,
                    default:'aaa',
                    required:true   //使用组件的时候,必须传cmessage属性
                }
            },
            data(){
                return {}
            },
            methods:{
            }

        }
        var app=new Vue({
           el:'#app',
           data:{
               movies:['龙猫','千与千寻','天空之城'],
               message:'你好'
           },
           components:{
            // cpn:cpn
            cpn //增强写法
           },
        });
    </script>

16.(掌握)父子组件通信-props驼峰标识

  • props里边要用驼峰命名(cInfo),外边使用组件的时候,要用-号(c-info)
  • 知识点补充:js大小写敏感,html大小写不敏感
  • 父组件传递数据的过程:1,父组件data中准备数据,2,子组件的构造器添加props,包括需要用到的变量,在template中使用这些变量,3,在vue实例中把这两项绑定起来
    <div id="app">
        <cpn :c-info="info" :child-my-message="childmymessage"></cpn>
        <!-- 下面这个写只输出默认值{} -->
        <!-- <cpn></cpn> -->
    </div>
    <template id="cpn">
        <div>
            <h2>{{cInfo.name}}</h2>
            <h2>{{cInfo.age}}</h2>
            <h2>{{cInfo.height}}</h2>
            <h2>{{childMyMessage}}</h2>
        </div>
    </template>
    <script src="../js/vue.js"></script>
    <script>
        const cpn = {
            template:'#cpn',
            props:{
               cInfo:{
                   type:Object,
                   default(){
                       return {}
                   }
               },
               childMyMessage:{
                   type:String
               } 
            }
        }

        var app=new Vue({
           el:'#app',
           data:{
            info:{
                name:"龙猫",
                age:2,
                height:2.88
            },
            childmymessage:"aaaa",
           },
           components:{
               cpn
           },
           methods:{}
        });
    </script>

17.(掌握)父子组件通信-子传父(自定义事件)

  • 使用场景:1,购物网站列表中选择手机,会向父级发消息说点击了谁,然后父级再回转手机的数据;
  • 传递过程:1,子组件中通过$emit()来触发事件,2,父组件中v-on来监听子组件事件

  • 注:父组件中的方法不要写参数,默认在子组件模版中已经定义了,不能写cpnClick(item),只能写cpnClick

 <!-- 父组件模板 -->
    <div id="app">
        <!-- 不能写cpnClick(item) 相当于之前的@click="btnClick"默认会传递event事件,这里默认传item -->
        <cpn1 @item-click="cpnClick"></cpn1>
    </div>
    <!-- 子组件模板 -->
    <template id="cpn">
        <div>
            <button v-for="item in categories" @click="btnClick(item)">{{item.name}}</button>
        </div>
    </template>
    <script src="../js/vue.js"></script>
    <script>
        //1.子组件
        const cpn1 = {
            template:'#cpn',
            data(){
                return {
                    categories:[
                        {id:'aaa',name:'热门推荐'},
                        {id:'bbb',name:'手机数码'},
                        {id:'ccc',name:'家用家电'},
                        {id:'ddd',name:'电脑办公'},
                ]
                }
            },
            methods:{
                btnClick(item){
                    // 自定义事件item-click,相当于之前的reset-map
                    //传递过程:1,子组件中通过$emit()来触发事件,2,父组件中v-on来监听子组件事件
                    this.$emit('item-click',item)
                }
            }
        }
        //2.父组件
        var app=new Vue({
           el:'#app',
           data:{

           },
           components:{
            cpn1
           },
           methods:{
            cpnClick(item){
                console.log(item);
            }
           }
        });
    </script>
  • 计数器小案例,把子组件中的count传递给父组件total:
    <div id="app">
        <cpn @cpn-sub="changeTotal" @cpn-add="changeTotal"></cpn>
        <h2>{{total}}</h2>
    </div>
    <template id="cpn">
        <div>
            <button @click="sub">-</button>
            <button @click="add">+</button>
        </div>
    </template>
    <script src="../js/vue.js"></script>
    <script>
        const cpn = {
            template:'#cpn',
            data(){
                return {
                     count:0
                }
            },
            methods:{
                sub(){
                    this.count--;
                    this.$emit('cpn-sub',this.count)
                },
                add(){
                    this.count++;
                    this.$emit('cpn-add',this.count)
                }
            }
        }
        var app=new Vue({
           el:'#app',
           data:{
               total:0
           },
           components:{
            cpn
           },
           methods:{
            changeTotal(count){
                this.total = count
            }
           }
        });
    </script>

18.(了解)项目展示

  • template和JavaScript代码相互分离

19.(了解)知识回顾


04day


01.(掌握)父子组件通信-结合双向绑定案例 

  • 子组件使用v-model案例
  • v-model相当于v-bind:value和@input="$event.target.value"的结合,也就是set方法
    <div id="app">
            <cpn :number1="num1" 
            :number2="num2" 
            @num1-change="changeNum1"
            @num2-change="changeNum2"
            ></cpn>
    </div>
    <template id="cpn">
        <div>
            <h2>props:{{number1}}</h2>
            <h2>data:{{dnumber1}}</h2>
            <!-- <input type="text" v-model="dnumber1"> -->
            <input type="text" :value="dnumber1" @input ="num1Input">
            <h2>props:{{number2}}</h2>
            <h2>data:{{dnumber2}}</h2>
            <!-- <input type="text" v-model="dnumber2"> -->
            <input type="text" :value="dnumber2" @input ="num2Input">
        </div>
    </template>
    <script src="../js/vue.js"></script>
    <script>
        var app=new Vue({
           el:'#app',
           data:{
               num1:1,
               num2:0
           },
           components:{
            cpn:{
                template:'#cpn',
                props:{
                number1:{
                    type:Number
                },
                number2:{
                    type:Number
                },
                },
                data(){
                    return {
                        dnumber1:this.number1,
                        dnumber2:this.number2
                    }
                },
                methods:{
                    num1Input(){
                        //1.input中的value复制到dnumber1中
                        this.dnumber1 = event.target.value;
                        //2.为了让父组件可以修改值,发出一个事件
                        this.$emit('num1-change',this.dnumber1);
                        //3.让number2和dnumber2的值是1的100倍
                        this.dnumber2 = this.dnumber1 * 100;
                        this.$emit('num2-change',this.dnumber2)

                    },
                    num2Input(){
                        this.dnumber2 = event.target.value;
                        this.$emit('num2-change',this.dnumber2);
                        //3.让number2和dnumber2的值是1的100倍
                        this.dnumber1 = this.dnumber2 / 100;
                        this.$emit('num1-change',this.dnumber1)

                    },
                }
            },
            
           },
           methods:{
            changeNum1(value){
                this.num1 = parseInt(value);
            },
            changeNum2(value){
                this.num2 = parseInt(value);
            }
           }
        });
    </script>

02.(掌握)上边代码的图示:

03.(了解)结合双向绑定案例-watch实现

  • watch可以监听某一个属性的改变
  • watch是实时监听属性变化,computed是计算属性,计算完后有一个缓存。而methods监听触发事件的。
  • watch是监听变化的,不变化不触发
    <div id="app">
            <cpn :number1="num1" 
            :number2="num2" 
            @num1-change="changeNum1"
            @num2-change="changeNum2"
            ></cpn>
    </div>
    <template id="cpn">
        <div>
            <h2>props:{{number1}}</h2>
            <h2>data:{{dnumber1}}</h2>
            <!-- <input type="text" v-model="dnumber1"> -->
            <input type="text" v-model="dnumber1">
            <h2>props:{{number2}}</h2>
            <h2>data:{{dnumber2}}</h2>
            <!-- <input type="text" v-model="dnumber2"> -->
            <input type="text" v-model="dnumber2">
        </div>
    </template>
    <script src="../js/vue.js"></script>
    <script>
        var app=new Vue({
           el:'#app',
           data:{
               num1:1,
               num2:0
           },
           components:{
            cpn:{
                template:'#cpn',
                props:{
                    number1:Number,
                    number2:Number,
                },
                data(){
                    return {
                        dnumber1:this.number1,
                        dnumber2:this.number2
                    }
                },
                watch:{
                    dnumber1(newValue){
                        this.dnumber2 = newValue * 100;
                        this.$emit('num1-change',newValue)
                    },
                    dnumber2(newValue){
                        this.dnumber1 = newValue / 100;
                        this.$emit('num2-change',newValue)
                    },
                },
            },
            
           },
           methods:{
            changeNum1(value){
                this.num1 = parseInt(value);
            },
            changeNum2(value){
                this.num2 = parseInt(value);
            }
           }
        });
    </script>

04.(掌握)父组件访问子组件-$children-$refs

  • 父组件访问子组件两种方式
  • 注意:refs是渲染结束后才能拿到,不能在初始化的时候访问
第一种(用得少)第二种(用的非常多)
$children$refs       (refs:reference引用的意思)
结果是个数组,下标志拿数据方式不太好,因为子组件数量可能会变化,下标的索引值会变结果是个对象,可以给每个组件添加一个ref属性设置唯一性
    <div id="app">
        <cpn ref="aaa"></cpn>
        <cpn ref="bbb"></cpn>
        <cpn ref="ccc"></cpn>
        <button @click="btnClick">按钮</button>
    </div>
    <template id="cpn">
        <div>我是子组件</div>
    </template>
    <script src="../js/vue.js"></script>
    <script>
        var app=new Vue({
           el:'#app',
           data:{},
           methods:{
            btnClick(){
                // 一、$children结果是个数组,用得很少
                //1,取子组件的方法,下标志拿数据方式不太好,因为子组件数量可能会变化
                this.$children[0].showMessage();//0代表第一个子组件
                // //2,取子组件的数据
                console.log(this.$children[0].name); 
                // //3,或者循环遍历
                for(let item of this.$children){
                    item.showMessage();
                    console.log(item.name);    
                }
                //二、$refs结果是个对象,用的非常多
                   this.$refs.aaa.showMessage();    
                   console.log(this.$refs.aaa.name);    
            }
           },
           components:{
               cpn:{
                   template:'#cpn',
                   data(){
                       return {
                           name:"我是子组件的内容"
                       }
                   },
                   methods:{
                       showMessage(){
                           console.log('message');
                       }
                   }
               }
           }
        });
    </script>

05.(了解)子访问父-parent-root

  •  this.$parent和this.$root用得也非常少
    <div id="app">
        <cpn></cpn>
    </div>
    <template id="cpn">
        <div>
            <h2>我是子组件</h2>
            <button @click="btnClick">按钮</button>
        </div>
    </template>
    <script src="../js/vue.js"></script>
    <script>
        var app=new Vue({
           el:'#app',
           data:{
               message:'父组件message'
           },
           components:{
               cpn:{
                   template:'#cpn',
                   methods:{
                    btnClick(){
                        //1,this.$parent返回的不是组件(VueComponent),而是实例(Vue),用的非常少
                       console.log(this.$parent.name);
                       //2,this.$root可以访问父,也可以访问父亲父父亲,返回实例对象
                       console.log(this.$root);
                   }
                   }
               }
           },
           methods:{}
        });
    </script>

06.(掌握)slot插槽的基本使用

  • 插槽就是预留的空间,一般抽取共性,保留插槽
  • 使用案例:

  • 使用过程:template里加入,也可以设置默认值按钮
    <div id="app">
        <cpn><button>按钮</button></cpn>
        <cpn><span>span标签</span></cpn>
        <cpn></cpn>
        <cpn></cpn>
    </div>
    <template id="cpn">
        <div>
            <!-- 这种定义的组件不具有扩展性,如仅对第一个<cpn></cpn>组件的<p>后加一个span或者button标签-->
            <h2>我是组件标题</h2>
            <p>我是组件内容</p>
            <!-- 下边插槽内加<button>按钮</button>可以设置插槽默认值 -->
            <slot><button>按钮</button></slot>
        </div>
    </template>
    <script src="../js/vue.js"></script>
    <script>
        var app=new Vue({
           el:'#app',
           data:{
           },
           components:{
               cpn:{
                   template:'#cpn',
               }
           },
           methods:{}
        });
    </script>

07.(掌握)具名插槽的使用

  • 当有多个slot,想改变某一个值的时候,如京东导航栏,模板设置name:中间,父组件标题:
    <div id="app">
        <!-- 1.不替换 -->
        <cpn></cpn>
        <!-- 2.只会把没有名字的替换掉 -->
        <cpn><span>标题</span></cpn>
        <!-- 3.只会替换center的slot -->
        <cpn><span slot="center">标题</span></cpn>
    </div>
    <template id="cpn">
        <div> 
           <slot name="left"><span>左边</span></slot>
           <slot name="center"><span>中间</span></slot>
           <slot name="right"><span>右边</span></slot>
           <slot><span>右边</span></slot>
        </div>
    </template>
    <script src="../js/vue.js"></script>
    <script>
        var app=new Vue({
           el:'#app',
           data:{
           },
           components:{
               cpn:{
                   template:'#cpn',
               }
           },
           methods:{}
        });
    </script>

08.(理解)编译作用域的概念

  • 不关心组件,只关心在那个app里,只会使用vue实例里边的isShow

    <div id="app">
        <cpn v-show="isShow"></cpn>
    </div>
    <template id="cpn">
        <div>
            <h2>我是标题</h2>
            <p>我是内容</p>
        </div>
    </template>
    <script src="../js/vue.js"></script>
    <script>
        var app=new Vue({
           el:'#app',
           data:{
               isShow:true    //使用的是这里的isShow
           },
           components:{
            cpn:{
                template:'#cpn',
                data(){
                    return {
                        isShow:false
                    }
                }
               }
           },
           methods:{}
        });
    </script>

09.(掌握)作用域插槽的使用

  • 需求:在渲染之前,把组件的数据传给vue实例(渲染之后一般用this.$refs.name)
  • 即,父组件对子组件的展示方式不满意,想以另外一种方式展示
  • 总结:父组件替换插槽的标签,但是内容由子组件来提供
    <div id="app">
        <!-- 1.不改变template,直接显示 -->
        <cpn></cpn>
        <!-- 2.不想用列表的方式,想用-连接字符串 -->
        <cpn>
            <template slot-scope="slot">
                <!-- <span v-for="item in slot.data">{{item}} - </span> -->
                <span>{{slot.data.join('-')}}</span>
            </template>
        </cpn>

    </div>

    <template id="cpn">
        <div>
            <slot :data="pLanguages">
                <ul>
                    <li v-for="item in pLanguages">{{item}}</li>
                </ul>
            </slot>
        </div>
    </template>
    <script src="../js/vue.js"></script>
    <script>
        var app=new Vue({
           el:'#app',
           data:{},
           components:{
            cpn:{
                template:'#cpn',
                data(){
                    return {
                        pLanguages:['Javascript','c++','Java','Python','go','swift','c#']
                    }
                }
            }
           },
           methods:{}
        });
    </script>

10.(了解)前端代码复杂带来的问题

  • 如小明在a.js文件中定义var flag = true;小红在b.js定义var flag = false;当小明在c.js使用if(flag){}时可能会传小红的flag
  • 解决方法匿名函数,即闭包。闭包的核心理念是用函数的变量作用域控制来完成javascript所缺失的块作用域功能:
  • 闭包的缺点导致的代码的复用性不高,如下边的sum函数在别的js文件中访问不到,因此闭包也不行
(function(){
    var flag = true;
    function sum(num1,num2){
        return num1+num2
    }
})()

11.(理解)前端模块化雏形和CommonJS

  • 只能用模块化解决(如下a.js),就可以在c.js使用if(moduleA.flag){},下边这种就是模块化思想,但是已经不用了
  • 常见的模块化规范:CommonJS,AMD,CMD,ES6的Modules
var moduleA = (function(){
    var obj = {};
    var name = '小明';
    var age = 18;
    function sum(num1,num2){
        return num1 + num2
    }
    var flag = true;
    // if(flag){
    //     console.log(sum(10,20));
    // }
    obj.name = name;
    obj.age = age;
    obj.flag = flag;
    obj.sum = sum;
    obj.myFunction = function(value){
        console.log(value)
    }

    return obj
})()
  • CommonJS了解
//a.js导出
module.exports = {
    name:ws,
    flag:true,
    sum(a,b){
        return a+b
    }
}


//b.js导入,导入名字要和导出的名字一样
let {name, sum, flag} = require('./a.js');
//上边等同于下边
let mod = require('./a.js');
let name = mod.name;
let flag = mod.flag;
let sum = mod.sum;

12.(掌握)ES6模块化的导入和导出

  • 可以使用type="module"把js变成块级作用域,解决变量冲突问题:
  • 但是这样带来了新的问题,其他模块想使用该块内的变量,访问不到:
//index.html
//    <script src="./aaa.js" type="module"></script>
//    <script src="./bbb.js" type="module"></script>
//    <script src="./ccc.js" type="module"></script>

//aaa.js//小明
var name = 'xiaoming';
var age = 18;
var flag = true;
function sum(a , b){
    return a+b
}
if(flag){
    console.log(sum(11,2));
}

//bbb.js//小红
var name = 'xiaohong';
var age = 19;
var flag = false;

//ccc.js 报错,flag未定义
if(flag){
    console.log('flag');
}
  • 解决方案:模块导出(3种方法)
  1. 方法1,先定义变量、函数或class,再导出:export { flag,sum,Person}

  2. 方法2,直接导出:export var num1 = 100001;   export function sum(a,b){return a+b};  export class Person{run(){console.log("在奔跑")}}

  3. 方法3,export default name;  import myName from "./aaa.js",用于导入者自己可以修改名字,但是export default只能在一个js中使用一次

  4. 前两种导入方法一样:import {flag , sum,num1 , Person} from "./aaa.js"或import * as obj from "./aaa.js"  然后obj.flag可以取值

//index.html
    //<script src="./aaa.js" type="module"></script>
    //<script src="./bbb.js" type="module"></script>
    //<script src="./ccc.js" type="module"></script>

//aaa.js
var name = 'xiaoming';
var age = 18;
var flag = true;
function sum(a , b){
    return a+b
}
if(flag){
    console.log(sum(11,2));
}
//1.导出方式一:
export{
    flag,sum
}
//2.导出方式二:
export var num1 = 100001;
export var height = 1.88;
export class Person{
    run(){
        console.log("在奔跑");
    }
}
//3.导出方式三:
var address = '北京市';
export default address;

//ccc.js
import {flag , sum} from "./aaa.js"
if(flag){
    console.log('flag');
    console.log(sum(111,222));
}
import {num1 , height ,Person} from "./aaa.js"
console.log(num1);
console.log(height);
let ws = new Person();
ws.run();
import myAdd from "./aaa.js"
console.log(myAdd);
import * as obj from "./aaa.js"
console.log(obj.height);

13.(理解)webpack的介绍和安装

  • webpack就是一个模块打包工具

  • webpack打包现在用的比较多,而gulp用的比较少了,grunt更没人用了
  • 什么时候用gulp和webpack

  • webpack和node、npm关系:

  • 注意:Mac安装webpack要先获取权限,使用sudo -s然后输入计算机密码,最后npm install webpack@3.6.0 -g

14.(掌握)webpack的基本使用过程

  • 使用目的代码打包到dist文件夹中,方法一的过程(方法二是配置webpack.config.js,见15):
  1. 全局安装webpack(npm install webpack@3.6.0 -g),终端定位到项目的根目录中
  2. webpack ./src/main.js ./dist/bundle.js 意思是把main.js打包到dist文件夹下的bundle.js文件中,至于main.js里边的依赖会由webpack自动处理
  3. index.html中引用bundle.js,,执行index.html
  4. 代码:
//index.html
//<script src="./dist/bundle.js"></script>

//main.js
//1.common.js导入
let {sum ,mul} = require('./mathUtils.js');
console.log(sum(11,3));
console.log(mul(22,10));
//2.ES6导入
import {name , age , height} from './info';
console.log(name);
console.log(age);
console.log(height);

//mathUtils.js
function sum(num1,num2){
    return num1 + num2
}
function mul(num1,num2){
    return num1 * num2
}
//1.common.js导出
module.exports = {
    sum,
    mul
}

//info.js
//2.ES6导出
export const name = 'xiaoming';
export const age = 18;
export const height = 1.88;

15.(掌握)webpack.config.js和package.json的配置

  • 代码打包的方法二:
  1. (第一层映射)新建webpack.config.js文件(如下),输入打包的参数(如入口、出口);2.运行命令:webpack
  2. (第二层映射)执行npm init 命令,在package.js文件加"build":"webpack"    //本句加完之后,能用npm run build替代webpack命令
//webpack.config.js文件
const path = require('path');//'path'是node的系统模块
module.exports = {
    entry:'./src/main.js',
    output:{
        path:path.resolve(__dirname,'dist'),
        filename:'bundle.js'
    }
}
  • 注意:const path = require('path') ,括号内的path是node的系统模块,__dirname是node上下文自带的全局变量
  • 运行webpack一般需要依赖node环境的项目,都会有package.json文件(项目的信息,如下),该文件的配置命令:npm init 
//package.js文件
{
  "name": "meetwebpack",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "build":"webpack"    //本句加完之后,能用npm run build替代webpack命令
  },
  "author": "",
  "license": "ISC"
}
  • 刚刚的webpack是全局安装的(npm install webpack@3.6.0 -g),但是开发的时候每个项目都要有自己的本地的webpack(npm install webpack@3.6.0 --save-dev),因为二者版本可能不一样

——只要是在终端敲webpack,用的都是全局的,想使用本地的必须./node_modules/.bin/webpack 

——所以定义"build":"webpack" 的好处是执行npm run build时,优先找本地的webpack

16.(掌握)webpack中使用css文件的配置(loader)

  • loader干什么的?:因为webpack除了要打包js以外,还要对css、图片、ES6、Vue等进行打包,这时候webpack就不支持了,需要对webpack扩展loader就可以了
    • loader使用过程:1.安装loader:npm install --save-dev css-loader@2.0.2   2.webpack.config.js配置module.exports={}  3.安装css-loader(可以去webpack官网看安装命令和配置说明):npm install style-loader --save-dev
    • css-loader只负责加载,不负责解析,需要再安装style-loade(样式添加到dom中)

const path = require('path');
module.exports = {
    entry: './src/main.js',
    output: {
        path: path.resolve(__dirname, 'dist'),
        filename: 'bundle.js',
        publicPath: '../dist/' //涉及到url的东西,都会再前边拼接dist/
    },
    module: {
        rules: [{
            test: /\.css$/i,
            use: ["style-loader", "css-loader"],
        }, {
            test: /\.less$/i,
            loader: [
                // compiles Less to CSS
                "style-loader",
                "css-loader",
                "less-loader",
            ],
        }, {
            test: /\.(png|jpg|gif)$/i,
            use: [{
                loader: 'url-loader',
                options: {
                    //当加载的图片小于limit时,会将图片编译成base64位字符串形式
                    //当加载的图片大于limit时,需要使用file-loader模块进行加载
                    limit: 8192,
                },
            }, ],
        }
     ],
    },
}

04day


01.(掌握)webpack-less文件的打包less-loader

  • 1.预处理:写*.less文件,引入到main.js(目的是打包less格式的样式文件)  
  • 2, npm install --save-dev less-loader@4.1.0 less@3.9.0 
  • 3,配置webpack.config.js(详见03-16)
  • 4.npm run build

02.(掌握)webpack图片文件的打包url-loader

  • 1.预处理:css加背景图,引入到main.js 
  • 2.npm install --save-dev url-loader@1.1.2 (图片小于limit尺寸)或者npm install file-loader@3.0.1 --save-dev(图片大于limit)
  • 3,配置webpack.config.js(详见03-16),output中添加publicPath: '../dist/' ,涉及到url的东西,都会再前边拼接dist/
  • 4.npm run build

03.(掌握)webpack ES6转ES5的babel-loader

  • 需求:由于打包后的文件还是ES6,并没有转成ES5,有些浏览器并不能运行,所以用babel-loader
  • 1.npm install --save-dev babel-loader@7 babel-core babel-preset-es2015 ; 2.配置webpack.config.js:
{
                test: /\.m?js$/,
                exclude: /(node_modules|bower_components)/,
                use: {
                  loader: 'babel-loader',
                  options: {
                    presets: ['es2015']
                  }
                }
 }

04.(掌握)webpack-使用vue的配置过程

  • import {name,age} from './js/info.js'有路径,而import Vue from 'vue',没写路径,就从node_modules library root里边拿;
  • npm install vue --save 不需要加-dev因为加dev是开发时依赖,而vue时整个项目就要依赖;
  • 项目里直接使用vue的过程:
1.npm install vue --save
2.webpack.config.js配置:
resolve:{
      //alias别名
      alias:{
        'vue$':'vue/dist/vue.esm.js' //这个指定的有compiler,默认用的是vue.runtime.js
      }
    }
3.npm install vue-loader@13.0.0 vue-template-compiler@2.5.21 --save-dev
4.开始使用new Vue({})
4,npm run build

05.(掌握)创建Vue时template和el的关系

  • 实际开发时index.html里只写
    里边不写内容;
  • 而如main.js中的new Vue({el..template})如果同时存在el和template,会自动用template内容替换

06.(掌握)Vue的终极使用方法

  • 第一次抽离,index.html只保留
    ,在main.js中写组件:
import Vue from 'vue';
// import { Cpn }  from './vue/app.js'
const Cpn = {
    template:`
    <div>
        <h2>{{message}}</h2>
        <button @click="btnClick">按钮</button>
        <h2>{{name}}</h2>
    </div>
    `,
    data(){
        return{
            message:'hello world',
            name:'coderwhy'
        }
    },
    methods:{
        btnClick(){
            console.log("btnClick");
        }
    }
};
  • 第二次抽离,const Cpn对象全部抽到app.js中。下边这个Vue是一个根组件,运行只会template会替换el,new Vue({ el:'#app'})之前的组件都是再
    里使用,由于现在index.html不让写东西里,就写到这里用,new Vue本身也是一个根组件,只要是组件都有template属性。
//app.js
import Vue from 'vue';
 import { Cpn }  from './vue/app.js'
//下边这个Vue是一个根组件,运行只会template会替换el
new Vue({
    el:'#app',
    template:'<Cpn/>',   
    components:{
        Cpn
    }
})
  • 第三次抽离,app.js内容全部抽到App.vue中,main.js导入App.js模块实现template-script-style三者相分离:
//App.vue
<template>
     <div>
        <h2 class="title">{{message}}</h2>
        <button @click="btnClick">按钮</button>
        <h2>{{name}}</h2>
    </div>
</template>
<script>
export default {
    name:Cpn,
    data(){
        return{
            message:'hello world',
            name:'coderwhy'
        }
    },
    methods:{
        btnClick(){
            console.log("btnClick");
        }
    }
}
</script>

<style scoped>
.title{
    color: green;
}
</style>
  • import Cpn from './Cpn.vue' 的.vue想省略的话,需要需改webpack.config.js:resolve:{extensions:['.js' , '.css' , '.vue']}

07.(掌握)webpack-横幅Plugin的使用-版权声明

  • plugin是插件的意思,通常是用于对某个现有的架构进行扩展。 webpack中的插件,就是对webpack现有功能的各种扩展,比如打包优化,文件压缩等等。
  • loader和plugin区别 loader主要用于转换某些类型的模块,它是一个转换器。 plugin是插件,它是对webpack本身的扩展,是一个扩展器。
  • plugin的使用过程:
  • 步骤一:通过npm安装需要使用的plugins(某些webpack已经内置的插件不需要安装)
  • 步骤二:在webpack.config.js中的plugins中配置插件。 
  • 添加版权:const webpack = require('webpack');                   module.exports = {plugins:[new webpack.BannerPlugin('该版权归龙猫所有!')]}

08.(掌握)webpack-HtmlWebpackPlugin的使用

  • HTML打包目的是为了让index.html打包到dist文件夹中,过程:

1.安装 npm install html-webpack-plugin --save-dev 
2. 配置webpack.config.js:

const HtmlWebpackPlugin = require('html-webpack-plugin');
new HtmlWebpackPlugin({template:'index.html'}),加了参数后,为了让原index.html的

引进进来,webpack.config.js:
const path = require('path');
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
    entry: './src/main.js',
    output: {
        path: path.resolve(__dirname, 'dist'),
        filename: 'bundle.js',
        // publicPath: '../dist/' //涉及到url的东西,都会再前边拼接dist/
    },
    module: {
        rules: [{
                test: /\.css$/i,
                use: ["style-loader", "css-loader"],
            },
            {
                test: /\.less$/i,
                loader: [
                    // compiles Less to CSS
                    "style-loader",
                    "css-loader",
                    "less-loader",
                ],
            }, {
                test: /\.(png|jpg|gif)$/i,
                use: [{
                    loader: 'url-loader',
                    options: {
                        //当加载的图片小于limit时,会将图片编译成base64位字符串形式
                        //当加载的图片大于limit时,需要使用file-loader模块进行加载
                        limit: 8192,
                    },
                }, ],
            },
            {
                test: /\.js$/,
                // exclude: 排除
                // include: 包含
                exclude: /(node_modules|bower_components)/,
                use: {
                    loader: 'babel-loader',
                    options: {
                        presets: ['es2015']
                    }
                }
            },
            {
                test: /\.vue$/,
                use: ['vue-loader']
            }
        ],
    },
    resolve: {
        // alias: 别名
        extensions: ['.js', '.css', '.vue'],
        alias: {
            'vue$': 'vue/dist/vue.esm.js'
        }
    },
    plugins: [
        new webpack.BannerPlugin('版权最终归龙猫所有'),
        new HtmlWebpackPlugin({
            template: 'index.html' //为了让原index.html的<div id="app"><div>引进进来
        })
    ]
}

09.(掌握)webpack-UglifyjsWebpackPlugin的使用(压缩js文件)

  1. npm install uglifyjs-webpack-plugin@1.1.1 --save-dev
  2. const UglifyjsWebpackPlugin = require('uglifyjs-webpack-plugin')
  3. plugins: [  new UglifyjsWebpackPlugin()  ]

10.(掌握)webpack-dev-server搭建本地服务器(npm run dev)

过程:

1.npm install --save-dev webpack-dev-server@2.9.3     

2.配置webpack.config.js:

devServer:{

contentBase:'./dist',

inline:true,

}

3.配置package.js的script:"dev":"webpack-dev-server",或者script:"dev":"webpack-dev-server --open"默认打开

4.运行npm run dev

11.(掌握)webpack配置文件的分离

  • 需求:开发时和发布时依赖的配置文件不一样,后边脚手架用法哦了,提前了解
  • 分离过程:
  • 1.把webpack.config.js分离成base.config.js、prod.config.js、base.config.js   
  • 2.npm install webpack-merge@4.1.5 --save-dev 
  • 3.package.json配置:"build": "webpack --config ./build/prod.config.js" , "dev": "webpack-dev-server --open --config ./build/dev.config.js"

发布时base.config.js+prod.config.js  => npm run build

开发时base.config.js+dev.config.js  => npm run dev

//prod.config.js
const UglifyjsWebpackPlugin = require('uglifyjs-webpack-plugin')
const webpackMerge = require('webpack-merge')
const baseConfig = require('./base.config')

module.exports = webpackMerge(baseConfig,{
    plugins:[
      new UglifyjsWebpackPlugin()
    ]
})
//dev.config.js
const webpackMerge = require('webpack-merge')
const baseConfig = require('./base.config')

module.exports = webpackMerge(baseConfig,{
    devServer:{
      contentBase:'./dist',
      inline:true,
    }
})

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

q124467623

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值