Vue教程-day04-2018年12月24日笔记

文章目录


image-20210829174459646

第63个视频 - 父子组件通信 - 结合双向绑定案例

image-20210829174336358

image-20210829174542239

代码:

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

<!--父组件模板-->
<div id="app">
  <h2>这是父组件的num1:{{num1}}</h2>
  <h2>这是父组件的num2:{{num2}}</h2>
  <cpn :number1="num1" :number2="num2"></cpn>
</div>


<!--子组件模板-->
<template id="cpn">
  <div>
    <hr>
    <h2>这是子组件的number1: {{number1}}</h2>
    <input type="text" v-model="number1">子组件双向绑定number1
    <h2>这是子组件的number2: {{number2}}</h2>
    <input type="text" v-model="number2">子组件双向绑定number2
  </div>
</template>

<script src="../js/vue.js"></script>
<script>

  // 子组件
  const cpn = {
    template: '#cpn',
    props: {
      number1: Number,
      number2: Number,
    },
  }

  // 父组件
  const app = new Vue({
    el: '#app',
    data: {
      message: '',
      num1: 1,
      num2: 0
    },
    components: {
      cpn
    }
  })
</script>
</body>
</html>

image-20210829180926359

解决的办法:

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

<!--父组件模板-->
<div id="app">
  <h2>这是父组件的num1:{{num1}}</h2>
  <h2>这是父组件的num2:{{num2}}</h2>
  <cpn :number1="num1" :number2="num2"></cpn>
</div>


<!--子组件模板-->
<template id="cpn">
  <div>
    <hr>
    <h2>这是子组件的number1: {{dnumber1}}</h2>
    <input type="text" v-model="dnumber1">子组件双向绑定number1
    <h2>这是子组件的number2: {{dnumber2}}</h2>
    <input type="text" v-model="dnumber2">子组件双向绑定number2
  </div>
</template>

<script src="../js/vue.js"></script>
<script>

  // 子组件
  const cpn = {
    template: '#cpn',
    props: {
      number1: Number,
      number2: Number,
    },
    data(){
      return {
        dnumber1: this.number1,
        dnumber2: this.number2
      }
    }
  }

  // 父组件
  const app = new Vue({
    el: '#app',
    data: {
      message: '',
      num1: 1,
      num2: 0
    },
    components: {
      cpn
    }
  })
</script>
</body>
</html>

王红元父子通信双向绑定的需求描述是:

  1. 父组件data有两个num1和num2,通过父传子,传给子的props
  2. 子的props和data动态绑定到子的input上,绑定到用户的输入上。
  3. 用户的输入,引起子的data变化,通过子传父,传递给父的data的num1和num2

整体是通过父传子和子传父,形成了一个闭环,形成了一个圈。

加上了数据的双向绑定。

王红元的父子通信双向绑定案例的逻辑是:

  1. 父的data传子的props
  2. 子的props传子的data
  3. 子的data双向绑定用户输入
  4. 子的data和method自定义事件传父的method和data。

王红元的父子通信双向绑定案例的逻辑示意图是:

父子通信和双向绑定

王红元父子通信双向绑定的示例代码:

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

<div id="app">
  <cpn :childnum1="fathernum1"
       :childnum2="fathernum2"
       @num1change="num1change"
       @num2change="num2change"></cpn>
</div>

<template id="cpn">
  <div>
    <h2>子组件props:{{childnum1}}</h2>
    <h2>子组件data:{{datanum1}}</h2>
    <input type="text" :value="datanum1" @input="num1Input">
    <h2>子组件props:{{childnum2}}</h2>
    <h2>子组件data:{{datanum2}}</h2>
    <input type="text" :value="datanum2" @input="num2Input">
  </div>
</template>

<script src="../js/vue.js"></script>
<script>
  // 子组件
  const cpn = {
    template: '#cpn',
    props: {
      childnum1: Number,
      childnum2: Number,
    },
    data() {
      return {
        datanum1: this.childnum1,
        datanum2: this.childnum2
      };
    },
    methods: {
      num1Input(event) {
        // 1. 将input当中的value,放到datanum1中
        this.datanum1 = event.target.value;
        // 2. 触发自定义事件,改变父组件的fathernum1,进而改变子组件的props中childnum1的值。
        this.$emit('num1change', this.datanum1);
        // 3. 根据子组件datanum1的值,改变子组件datanum2的值
        this.datanum2 = this.datanum1 * 100;
        // 4. 触发自定义事件,改变父组件的fathernum2,进而改变子组件的props中childnum2的值。
        this.$emit('num2change', this.datanum2);
      },
      num2Input(event) {
        // 1. 将input当中的value,放到datanum2中。
        this.datanum2 = event.target.value;
        // 2. 触发自定义事件,改变父组件的fathernum2,进而改变子组件的props中childnum2的值。
        this.$emit('num2change', this.datanum2);
        // 3. 根据子组件datanum2的值,改变子组件datanum2的值
        this.datanum1 = this.datanum2 / 100;
        // 4. 触发自定义事件,改变父组件的fathernum1,进而改变子组件的props中childnum1的值。
        this.$emit('num1change', this.datanum1);
      }
    }
  };

  // 父组件
  const app = new Vue({
    el: '#app',
    data: {
      message: '',
      fathernum1: 1,
      fathernum2: 2,
    },
    components: {
      cpn
    },
    methods: {
      num1change(value) {
        this.fathernum1 = parseFloat(value);
      },
      num2change(value) {
        this.fathernum2 = parseFloat(value);
      }
    }
  });
</script>
</body>
</html>
考试

问题:你描述一下王红元这个案例的需求?

答案:在父组件当中有两个数,这两个数要传到子组件的props中。

子组件中有data,基于props两个数,双向绑定到用户输入。

用户输入触发事件,修改父组件的数,修改子组件的第二个数,触发各自的事件。


第64个视频 - 结合双向绑定案例 - 画图分析

image-20210830132513766

这个视频中,没有讲什么内容。苗苗。

所以,这个视频,不用考试。

第65个视频 - 结合双向绑定案例 - watch实现

watch可以用于监听某些属性的改变。

watch和props、data是并列的。

watch是对象。

在对象里面可以写函数。

监听哪个属性,函数名字就写哪个名称。

这个函数一般有两个参数,newValue和oldValue。一般用得比较多的是newValue。

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
</head>
<body>
<div id="app">
  <cpn :number1="num1"
       :number2="num2"
       @num1change="num1change"
       @num2change="num2change"/>
</div>

<template id="cpn">
  <div>
    <h2>props: {{number1}}</h2>
    <h2>data: {{dnumber1}}</h2>
    <input type="text" v-model="dnumber1">
    <h2>props: {{number2}}</h2>
    <h2>data: {{dnumber2}}</h2>
    <input type="text" v-model="dnumber2">
  </div>
</template>

<script src="../js/vue.js"></script>
<script>
  const app = new Vue({
    el: '#app',
    data: {
      num1: 1,
      num2: 0
    },
    methods: {
      num1change(value) {
        this.num2 = parseFloat(value)
      },
      num2change(value) {
        this.num2 = parseFloat(value)
      }
    },
    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('num1change',newValue);
          },
          dnumber2(newValue){
            this.dnumber1 = newValue / 100;
            this.$emit('num2change',newValue);
          }
        }
      }
    }
  });
</script>

</body>
</html>
考试

问题:vue实例或者组件实例中,watch是什么意思?

答案:watch是和data、props一样级别的属性。是可以监听某个属性的改变。


第66个视频 - 父访问子 - children - refs

业务场景:某些情况,父组件希望能拿到子组件的对象,子组件对象中有某个方法,父组件想要调用一下。或者有些时候,子组件想要拿到父组件的对象,去做一些事情。

image-20210830200326704

通过对象,直接访问。

$children

$children的演示代码,如下所示:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
</head>
<body>
<div id="app">
  <cpn></cpn>
  <br>
  <cpn></cpn>
  <br>
  <cpn></cpn>
  <br>
  <button @click="btnClick">按钮</button>
</div>
<template id="cpn">
  <div>我是子组件</div>
</template>
<script src="../js/vue.js"></script>
<script>
  const app = new Vue({
    el: '#app',
    data: {
      message: ''
    },
    methods: {
      btnClick() {
        console.log(this.$children);
        // this.$children[0].showMessage();
        // console.log(this.$children[0].name);
        for (let c of this.$children) {
          console.log(c.name);
          c.showMessage()
        }
      }
    },
    components: {
      cpn: {
        template: '#cpn',
        data() {
          return {
            name: '我是景甜'
          };
        },
        methods: {
          showMessage() {
            console.log('王子文');
          }
        }
      }
    }
  });
</script>
</body>
</html>

image-20210830201305116

image-20210830201921261

请注意: c h i l d r e n 拿 到 的 子 组 件 对 象 是 一 个 数 组 , 因 为 父 组 件 中 可 能 有 多 个 子 组 件 。 实 际 开 发 中 , 我 们 一 般 不 会 使 用 children拿到的子组件对象是一个数组,因为父组件中可能有多个子组件。实际开发中,我们一般不会使用 children使children来拿子组件对象。就是因为$children拿到的是数组,我们如果用它,还要数好子组件的顺序。不好用。

$refs

默认$refs是一个空的对象。你必须在子组件上面加属性,例如ref=“aaa”,这时候,refs里面就有东西了。

这其实,给每个子组件加了一个key。

image-20210830202735399

代码:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
</head>
<body>
<div id="app">
  <cpn ref="aaa"></cpn>
  <br>
  <cpn ref="bbb"></cpn>
  <br>
  <cpn ref="ccc"></cpn>
  <br>
  <button @click="btnClick">按钮</button>
</div>
<template id="cpn">
  <div>我是子组件</div>
</template>
<script src="../js/vue.js"></script>
<script>
  const app = new Vue({
    el: '#app',
    data: {
      message: ''
    },
    methods: {
      btnClick() {
        console.log(this.$refs.aaa);
      }
    },
    components: {
      cpn: {
        template: '#cpn',
        data() {
          return {
            name: '我是景甜'
          };
        },
        methods: {
          showMessage() {
            console.log('王子文');
          }
        }
      }
    }
  });
</script>
</body>
</html>
考试

问题: c h i l d r e n 和 children和 childrenrefs的区别是什么?

答案: c h i l d r e n 是 数 组 类 型 的 , 数 组 中 的 每 一 项 , 就 是 一 个 子 组 件 对 象 。 children是数组类型的,数组中的每一项,就是一个子组件对象。 childrenrefs是对象类型的,需要配合给子组件上添加ref属性,作为惹$refs对象当中的key,每个key对应一个子组件对象。


第67个视频 - 子访问父 - parent - root

子访问父,这个用得更少了,开发当中是不建议这样用的。

$parent
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
</head>
<body>

<div id="app">
  <cpn></cpn>
</div>

<template id="cpn">
  <div>
    <h2>我是子组件</h2>
    <button @click="btnClick">子组件按钮</button>
    <ccpn></ccpn>
  </div>
</template>

<template id="ccpn">
  <div>
    <h2>我是ccpn组件</h2>
    <button @click="cbtnClick">ccpn按钮</button>
  </div>
</template>

<script src="../js/vue.js"></script>
<script>
  const app = new Vue({
    el: '#app',
    data: {
      message: ''
    },
    components: {
      cpn: {
        template: '#cpn',
        data(){
          return {
            name: '我是cpn的name'
          }
        },
        methods: {
          btnClick(){
            //访问父组件
            console.log(this.$parent);
          }
        },
        components: {
          ccpn: {
            template: '#ccpn',
            methods: {
              cbtnClick(){
                //访问父组件
                console.log(this.$parent.name);
              }
            }
          }
        }
      }
    }
  });
</script>
</body>
</html>

image-20210830204122335

为什么开发当中不建议这么用呢?

因为你如果子访问父的话,损失了子组件的复用性。

$root

使用$root,直接访问到vue实例。

考试

问题: c h i l d r e n 、 children、 childrenrefs、 p a r e n t 、 parent、 parentroot使用频率怎么样

答案: r e f s − 非 常 多 , refs-非常多, refschildren和 r o o t 会 用 但 是 不 多 , root会用但是不多, rootparent非常少,因为它是用于子组件访问父组件,损害了父组件的独立性。


第68个视频 - slot - 插槽的基本使用

image-20210830204920526

image-20210830204932239

image-20210830204956373

image-20210830205009517

image-20210830204901040

举例

image-20210830211924857

共性的东西,封装在组件中,异性的东西,写在slot中。

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

<div id="app">
  <cpn>
    <i>我是苗蔓</i>
    <div>我是div元素</div>
    <p>我是p元素</p>
  </cpn>
  <cpn><img src="http://ww1.sinaimg.cn/large/006clBEWly1gtz4ugj6gxj30c20c1jvm.jpg" alt=""></cpn>
  <cpn><img src="http://ww1.sinaimg.cn/large/006clBEWly1gtz4v81l3zj30ne0ne43m.jpg" alt=""></cpn>
  <cpn></cpn>
</div>

<template id="cpn">
  <div>
    <h2>我是组件</h2>
    <p>我是组件,哈哈哈哈</p>
    <slot><button>默认按钮</button></slot>
  </div>
</template>

<script src="../js/vue.js"></script>
<script>
  const app = new Vue({
    el: '#app',
    data: {
      message: ''
    },
    components: {
      cpn: {
        template: '#cpn',
      }
    }
  })
</script>

</body>
</html>
总结

1 - slot的基本使用

2 - slot的默认值

3 - 如果有多个元素,同时放到组件中,替换一个slot,这多个元素会一起放到元素当中的。

考试

问题:一个自定义组件叫cpn,cpn组件中有一个slot,那么该如何使用呢?

答案:在调用子组件的时候,写<cpn><替换元素></cpn>


第69个视频 - slot - 具名插槽的使用

直接上代码:

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

<div id="app">
  <cpn><span slot="center">我是张澍</span></cpn>
  <cpn><button slot="left">我是江疏影</button></cpn>
  <cpn><img slot="right" src="http://ww1.sinaimg.cn/large/006clBEWly1gtz5dckhsuj304g04gt92.jpg" alt=""></cpn>
</div>

<template id="cpn">
  <div>
    <slot name="left"><span>我是左边</span></slot>
    <slot name="center"><span>我是中间</span></slot>
    <slot name="right"><span>我是右边</span></slot>
  </div>
</template>

<script src="../js/vue.js"></script>
<script>
  const app = new Vue({
    el: '#app',
    data: {
      message: ''
    },
    components: {
      cpn: {
        template: '#cpn',
      }
    }
  })
</script>

</body>
</html>

直接看效果:

image-20210830214434636

考试

问题:怎么使用具名插槽呢?

答案:在定义子组件的时候,通过slot标签定义插槽,给slot标签设置name属性和值,设置具名插槽。

第二步,在父组件中使用子组件的时候,在子组件标签content位置,写替换元素,元素增加一个slot属性,属性名是子组件设置的name值。


第70个视频 - 编译作用域的概念

先要理解编译作用域,然后才能够理解作用域插槽。

image-20210830214758128

什么叫做编译作用域呢?

我们通过代码来理解一下。

一般程序员用github和stack overflow。看stack overflow时候,一般直接看代码,就知道它想说什么了。

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>

<div id="app">
  <cpn v-show="isShow"></cpn>
</div>

<template id="cpn">
  <div>
    <h2>我是子组件</h2>
    <p>我是子组件,哈哈哈</p>
    <button v-show="isShow">按钮</button>
  </div>
</template>

<script src="../js/vue.js"></script>
<script>
  const app = new Vue({
    el: '#app',
    data: {
      message: '',
      isShow: false
    },
    components: {
      cpn: {
        template: '#cpn',
        data(){
          return {
            isShow: false
          }
        }
      }
    }
  })
</script>
</body>
</html>
考试

问题:什么是编译作用域?

答案:在父组件中调用子组件,子组件标签上,使用v-show、v-if这些指令,用到的变量,都是父组件的实例中的变量,这就叫做作用域。

image-20210830220404849


第71个视频 - 作用域插槽的使用

作用域插槽是slot中比较难理解的点,官方文档说得也是不清不楚的。

先看看王红元老师的总结:

父组件替换插槽里面的标签,但是内容又是由子组件来决定的

image-20210830220646242

  • 子组件的插槽,可以占位,父组件可以替换插槽。
  • 子组件的插槽,可以设置默认值,父组件可以替换插槽。
  • 子组件的插槽,可以具名占位,父组件可以具名替换插槽。
  • 子组件的插槽,里面只有展示形式,父组件改变子组件的插槽展示形式。

【锚点】小总结
  • c h i l d r e n 、 children、 childrenrefs、 p a r e n t 、 parent、 parentroot,这里是父拿子的对象,子拿父的对象,是在实例当中操作。
  • slot的name,slot的data,这是父拿子的元素,是在template当中操作。

作用域插槽的演示代码
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
</head>
<body>
<div id="app">
  <cpn></cpn>
  <cpn>
    <!--目的是获取子组件当中的pLanguages-->
    <!--vue的2.5.x以下,必须使用template,2.5.x以上,可以不使用template,使用div -->
    <!--为了让代码有更强的适应性,我们还使用template-->
    <!--template的目的是,去拿子组件当中的data-->
    <template slot-scope="slot">
      <!--<span v-for="item in slot.data">{{item}} -</span>-->
      <span>{{slot.data.join(' - ')}}</span>
    </template>
  </cpn>
  <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>
  const app = new Vue({
    el: '#app',
    data: {
      message: ''
    },
    components: {
      cpn: {
        template: '#cpn',
        data(){
          return {
            pLanguages: ['JavaScript', 'Java', 'Python', 'C++', 'C#', 'Go']
          }
        }
      }
    }
  })
</script>
</body>
</html>
考试

问题:什么是作用域插槽,怎么用?

答案:作用域插槽的应用场景是,父组件对子组件的数据展示方式不满意,父组件要自己展示。

第一步,子组件当中通过动态绑定属性x,绑定子组件当中的数据。

第二步,在父组件当中,在子组件标签content位置中,写一个template标签,属性写成slot-scope=“slot”。

第三步,在template标签内,进行数据展示,通过slot.属性名获取数据,可以操作了。


【锚点】组件化全部总结

总结


第72个视频 - 前端代码复杂带来的问题

第一部分,我们讲了邂逅vuejs。

第二部分,我们讲了vue的基础语法。

第三部分,我们讲了组件化开发。

第四部分,我们讲一下模块化开发。

image-20210830224304224

image-20210830230239555

考试

问题:为什么会出现前端模块化?

答案:团队开发,一个项目,小明命名了flag,小红也命名了flag,小明操作flag为true,小红操作flag为false,乱套了。


下午 - 14:30 - 18:00

第73个视频 - 前端模块化雏形和CommonJS

解决全局变量重名问题

我们可以使用闭包:

image-20210830230607549

匿名闭包带来的问题

降低了代码复用性,不能够用之前其他js文件中定义的函数或其他。

小明写了两个js文件:aaa.js和mmm.js。在aaa.js当中定义了flag和sum函数,想要在mmm.js当中使用,咋整?

现在为了解决全局变量重名的问题,每个js文件当中的代码,都使用了匿名闭包来包裹这,上面的需求根本实现不了的。

es5模块化雏形

通过下面的代码,通过对象,可以解决上面的问题,这种解决问题的方式,就属于模块化的雏形。

image-20210830231420087

这样在项目当中,我们只需要人为规定,模块的命名不要重复,就可以在es5的条件下,实现模块化开发了。

但是。

现在我们不采用这种模块化的方案。

我们使用别人已经规定好的模块化方案,去写自己的代码。

回顾PPT

image-20210830231751262

image-20210830231940169

CommonJS只是一个规范而已。

CommonJS非常著名的就是node实现。

node里面使用的模块化,就是按照CommonJS的。

大家在学习node当中,会更加具体学习CommonJS。

我们在项目当中主要用的是es6的模块化。

但是后面我们讲解webpack的时候,就必须使用CommonJS的导出。

AMD和CMD这两种东西,用的是比较少的。

commonjs

image-20210830232854626

模块化当中一个js文件就可以看成一个模块。

而且这个模块,有自己的作用域,不会和别人出现命名冲突的问题。

image-20210830232717492

webpack要想正常运行,是依赖node环境的,node环境当中是具有commonjs的支撑的。

commonjs的导出呢?

image-20210830233101003

考试

问题:模块化方案一般有哪几种?

答案:commonjs,amd,cmd,还有es6的modules。


第74个视频 - es6模块化的导入和导出

我们的重点是es6的模块化。

es6当中新增了两个关键字。

一个叫做import,这个是导入。

一个叫做export,这个是导出。

我们先来讲一下es6当中怎么导出,然后讲讲怎么导入。

image-20210830234903056

es6的导出是不支持像是上面的这种写法的。注意。

image-20210831000453082

对比es6模块化和commonjs的写法

image-20210831000813138

  • commonjs
    • 导出:module.exports = {}
    • 导入: let x = require('')
  • es6
    • 导出: export {}
    • 导入:import {} from " "
es6的基本使用

image-20210831001004716

多种导出方式

第一种导出方式,导出对象:

image-20210831001102054

第二种导出方式,直接导出:

image-20210831001141182

第三种导出方式,导出函数:

image-20210831001508047

第四种导出方式,导出类:

image-20210831001757608

image-20210831001909494

第五种导出方式:export default。

某些情况下,我们的模块当中包含某个功能,我们并不希望给这个功能起一个名字,我们希望导入者自己来给这个功能命名。

这个时候,我们就使用export default。

image-20210831002526457

需要注意的点:

  1. 一个模块当中默认导出的,export default导出的元素,只能够有一个。
  2. 在导入的时候,就不需要加上大括号了,而且导入的名字是可以随便起的。

image-20210831003106129

image-20210831003205732

image-20210831003927160

es6导入导出的总结
  • 导出
    1. 导出一个对象
    2. 定义的时候直接导出
    3. 导出一个函数
    4. 导出一个类
    5. export default,一个模块当中只能够有一个。
  • 导入
    • 导入一个对象
    • 导入export default定义的东西
    • 统一导入:import * as xxx from './aaa.js'

image-20210831004227220


考试

问题:commonjs和es6的导入导出有什么区别。

答案:commonjs的导出是modules.export = {},导入是let x = require(‘xxx.js’)。es6的导出是export {},导入是import x from 'xxx.js'

【锚点】开小差

到了这里的时候,我就想起来了,之前看的impress.js的代码了。

image-20210831005021730

这个时候,我就能够理解impress.js当中为什么是这样写的呢?

image-20210831005103855

这种形式,应该就是匿名函数闭包,就是为了避免整个项目当中,全局变量重名的问题。但是降低了代码的复用性。

这个匿名函数就是:

(function(document,window){}){document,window}

根据我的理解,就是从外面传入了document和window两个参数给这个函数。

  1. 为什么impress.js不使用es6的语法写呢?难道是因为es5有更好的浏览器兼容性的问题吗?
  2. 难道impress.js当中各个js文件之间,是没有什么复用的代码的吗?

这是我的一点疑问。后面我要好好看看impress.js当中的代码的。


第75个视频 - webpack的介绍和安装

webpack第1页ppt

image-20210831121651189

webpack第2页ppt

image-20210831121712165

什么是webpack。

js的静态模块打包工具

打包目前市场上有很多的打包工具:grunt、gulp、webpack、rollup。

vue的源码是使用rollup进行构建的。

webpack第3页ppt

image-20210831125055541

现阶段,我们在浏览器当中,只能够使用es6的模块化规范,这是因为浏览器底层做了一些对es6的底层支撑。

我们是在代码中不能够直接使用AMD和CMD和commonjs的规范的,因为浏览器底层没有支撑。

但是在webpack当中,我们是可以随便使用模块化规范的。

因为webpack给我们提供了支撑。

在webpack给我们的代码进行打包的时候,会对代码进行一定的转换的。

转换成为es6相关的规范,这样运行的时候,浏览器就能够支撑了。

我们在开发的过程当中是可以使用commonjs代码的,但是打包的时候,是没有commonjs代码的。

这就是webpack的强大的地方。

之前学习的gulp是不支持模块化的。


webpack第4页ppt

image-20210831130622363

webpack第5页ppt

image-20210831131041281

webpack第6页ppt

image-20210831133405785

webpack想要使用它的话,是依赖node环境的。

开发这些东西的时候,是通过模块化的方式进行开发的。

不能够直接将这些东西放到服务器上进行部署,如果直接把这些东西放到服务器上的话,意味着用户通过浏览器从服务器上请求到的ts,less,js肯定是不能够正常运行。

我们通过webpack做一层中间的模块化打包,等你把项目开发完了,你使用webpack执行一条指令进行模块化打包,生成一个文件夹,只需要把文件夹放到服务器进行部署就可以了。

webpack要想要正常运行,依赖一个环境就是node.js环境。

我们还没有学过node,但是没有关系,我们只需要安装一下就可以了。

webpack依赖node。

node环境为了可以正常执行很多代码,它必须有各种包。这些包如果你手动管理的话,是非常费劲的。

所以一般在安装node的时候,会自动帮你安装一个工具,叫做npm工具。

npm工具只是为了帮你管理,node下面的各种包而已。

npm的意思就是node package manager,就是node包管理器。

image-20210831132147016

王红元安装的node版本是:

image-20210831132240729

这就算是比较新的版本了?之前的教室装的是6.x的版本,这6.x的版本对我们来说是不能够用的。因为6.x不利于我们使用脚手架。要求你的node版本必须大于8.9。

一旦你有了node之后,你可以通过node当中的npm来安装webpack。

我们安装webpack的哪个版本呢?

我们安装webpack的3.6.0。这是因为这个版本是vue cli 2.x依赖的webpack版本。

vue cli 2.x里面才能够看到各种webpack的配置。

如果你用的是vue cli 3.x的话,webpack的各种配置都被隐藏起来了。

我们的方式是:我们按照脚手架2的方式自己去配置webpack,我们配置完了之后,可以跟脚手架2.x自动生成的webpack配置来进行一个对比。这样的话,我们去读脚手架的配置,就比较容易一点。

局部安装webpack和全局安装webpack有啥区别?

全局安装的意思是不管你是在cmd终端当中,还是在webstorm的cmd终端当中,执行webpack,用的都是全局的。

image-20210831133233347

我们之后会有一个文件,叫做package.json,这个文件当中能够定义很多的scripts,如果你定义了很多的脚本,并且,在脚本当中用了webpack的话,用的就是局部的。

image-20210831133216123

第76个视频 - webpack的基本使用过程

webpack第7页PPT

image-20210831203553506

distribution:发布的意思。

source:源码的意思。

webpack ./src/main.js ./dist/bundle.js

image-20210831205702135

我们看看bundle.js当中的代码:

image-20210831205836521

总结一下:

image-20210831210204045

我们可以在src下面,使用commonjs的规范来进行开发。

然后我们使用webpack将js代码打包到dist下面。

然后我们在index.html当中引入dist中打包好的bundle.js,这样,我们就可以通过跑页面来执行js代码了。


image-20210831210657580

考试

问题:我们可以在一个js代码当中,既使用commonjs的模块化规范,又使用es6的模块化规范,然后通过webpack来进行打包吗?

答案:可以。

问题:webpack的基础打包命令是什么?

答案:webpack ./src/main.js ./dist/bundle.js


第77个视频 - webpack.config.js配置和package.json配置

webpack第8页PPT

image-20210831210850944

webpack第9页PPT

image-20210831210920366

我之前打包的时候,是通过webpack ./src/main.js ./dist/bundle.js这个命令来进行打包的。这里的main.js是我们的入口文件,这里的bundle.js是我们打包出口的文件。

我们现在的想法是,我们执行打包命令的时候,只写一个webpack命令,就能够完成上面的操作,怎么做呢?

那么我们肯定是需要在某个位置告诉webpack,入口和出口是在什么位置的。

webpack.config.js

为什么实现上面的目标。我们需要在项目当中新建一个js文件。

这个js文件的名字叫做:webpack.config.js

这个文件是webpack的配置文件。

我们可以在这个配置文件当中配置打包入口和打包出口。

我们具体的配置就如下图所示:

image-20210831211644391

请注意,上面的图。在配置打包出口的时候,我们配置path路径的时候,这里需要是绝对路径。

我们怎么获取绝对路径呢?

我们需要利用到node的path模块。

我们在利用node之前,我们要先使用npm init来初始化我们的项目。

npm init

一旦你当前项目当中,准备用node相关的东西,就执行npm init

image-20210831212003483

这是要起一个包的名字。如果直接敲回车,就是使用小括号当中的名字。

image-20210831212154307

这是版本号,直接敲回车。

image-20210831212225404

这是描述信息,直接敲回车。

image-20210831212323923

entry point是入口,我们不需要把webpack.config.js作为入口,我们随便写一个index.js。

这里入口文件,我们无论写什么东西,我们都暂时用不上这个玩意。

在讲node的时候,会详细讲这个玩意的。

image-20210831212448614

直接敲回车。

image-20210831212511451

直接敲回车。

image-20210831212543821

直接敲回车。

image-20210831212606283

直接敲回车。

image-20210831212632107

直接敲回车。

image-20210831212722425

直接敲回车。

image-20210831212836825

node教程当中,会详细讲解这个package.json

如果在项目当中,你想要依赖node的一些东西,我们这里一般都是有一个package.json文件的。

如果你的package.json当中有依赖一些其他的包的话,我们一般会执行npm install来进行安装。

这样就会根据package.json来进行一些安装的。

image-20210831213112070

在这里,我执行了npm install,这样就生产了package-lock.json文件。

在我们的webpack第7页ppt当中,准备阶段,就已经建议了,需要提前把package.json这个文件建好。

image-20210831213312497

path

node的内建的path模块当中有一个函数叫做:path.resolve()

这个函数的作用是,可以对两个路径进行拼接。

node当中有一个全局变量叫做__dirname,这个全局变量表示的是当前文件webpack.config.js的路径。

注意是路径。

具体的如下图所示:

image-20210831213953900

如上的配置过之后,就可以实现我们文章一开始所提出来的需求。

这样,我们就将webpack的入口和出口,放到了一个配置文件当中了。

开发时候的打包命令

在开发的时候,我们一般都不会直接敲webpack命令来进行打包。

我们敲另外的一个命令。

npm run build

怎么样才能够将npm run build这个命令映射到webpack这个命令呢?

因为事实上webpack打包的时候,后面会跟一大堆的参数,会比较长比较麻烦的。

我们会使用npm run build来映射到我们的打包命令上。

webpack命令映射

如图,在package.json当中有scripts的配置项:

image-20210831214605833

上面的这个脚本配置的意思是,我们执行npm run test的时候,实际上执行的是test对应的echo \"Error: no test specified\" && exit 1命令。

image-20210831214755379

做了上面的配置之后,我们执行npm run build就是执行webpack命令了。

package.json命令映射的小优点

image-20210831215011083

当我们在package.json当中做了npm的命令映射之后,使用npm run build命令执行打包。

跟我们直接在终端当中输入webpack进行打包。

相比较而言,有一点不同。

就是,使用npm run build的话,会优先去本地找对应的命令webpack。

任何项目都有一个本地的webpack的包。

全局安装的是4.x的版本,但是你的项目可能特殊,需要的是3.x的版本。

所以开发过程当中,每个项目一般都有一个本地的webpack的包。

开发时依赖和运行时依赖
  • 开发时依赖
    • 只有在开发阶段,才用webpack这个东西,真正项目运行的时候,并不需要webpack这个东西。
    • 加上--save-dev
    • npm install webpack@3.6.0 --save-dev
  • 运行时依赖
    • 这是指项目运行的时候,还需要的依赖。
本地安装webpack

image-20210831215914680

这个时候打开package.json,就会发现新增了依赖配置:

image-20210831220000809

本地安装是安装在哪里呢?

如图,就是安装到当前目录下的位置。

image-20210831220359787

用哪个webpack打包?

这个时候,我们在webstorm的终端当中敲入webpack命令,是用全局的webpack还是用局部的webpack呢?

只要是在终端当中敲命令,无论是cmd还是webstorm终端,用的都是全局的

我们在package.json当中定义了脚本之后,执行命令,就可以使用本地的webpack了。

如果想要直接用本地的webpack,就需要像下面的做法,才可以:

image-20210831220656916

image-20210831220803844

webpack第10页PPT

image-20210831220839851

webpack第11页PPT

image-20210831220856315

webpack第12页PPT

image-20210831221009390

考试

问题:webpack.config.js这个文件是怎么产生的?

答案:这个是手动创建的webpack的配置文件,在里面可以配置打包的入口和出口等信息。

问题:package.json这个文件是怎么产生的?

答案:这个文件是在项目目录中执行npm init的时候产生的,如果项目要用到node相关的东西,就要使用npm init。在package.json当中可以配置npm命令映射。

问题:package-lock.json这个文件是怎么产生的?

答案:这个文件是执行npm install后产生的。


第78个视频 - webpack中使用css文件的配置

猛回头

讲到这里,你就可以发现一个问题。

以后我们如果只开发js相关的代码,我们就可以都使用模块化了。

第一,我们使用npm init来初始化我们的项目

第二,我们本地安装webpack。

然后,我们就可以进行模块化的开发的。

webpack第13页PPT

image-20210831221346583

我们如果学react的话,就会写.jsx文件。我们的vue当中使用的就是.vue文件。

webpack第14页PPT

image-20210831222158335

css咋办?

webpack打包的时候,只会根据我们的入口依次去寻找,去确定依赖关系,只有依赖的东西,最终去打包。

image-20210831223027551

像是上面的css文件,我们根本就没有在任何的文件当中依赖这个玩意,咋办?

我们把css当成一个模块。

我们在入口文件main.js当中依赖我们的css代码。

image-20210831223207363

然后我们使用webpack打包:

image-20210831223343306

报错信息说:你可能是需要一个合适的loader来处理css文件。

那么使用哪个loader呢?

webpack.org.js,这个才是webpack的官网。一般一些非盈利组织的官网都是用org域名的。

例如vuejs.org。

css-loader

image-20210831223630783

我们也可以直接看中文的网站:https://www.webpackjs.com/

我们可以直接查看中文文档

image-20210831223808824

image-20210831223843998

image-20210831223911877

我们安装一下:

image-20210831224004833

这样就安装成功了。

然后进行配置:

module.exports = {
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [ 'style-loader', 'css-loader' ]
      }
    ]
  }
}

我们在代码当中进行配置:

image-20210831224241613

然后运行npm run build。

css-loader版本过高的问题

得到下面的报错

image-20210831224516485

这里报错的原因是:css-loader版本过高的原因。

详细的内容,我们可以参考这篇文章

我们可以通过下面的命令卸载和重装css-loader。

npm uninstall css-loader
npm install css-loader@3.6.0 --save-dev

在视频当中,王红元安装的版本是:

image-20210831234044695

我重装了一个css-loader@3.6.0

然后我们重新运行npm run build

这个时候,并没有报错。

image-20210831234210527

但是打开我们的index.html页面,样式也没有生效。

css-loader和style-loader的分工

只负责帮你将css文件进行加载,不负责解析,也不负责将css代码放到html当中生效。

如果想要生效的话, 还需要安装style.loader

style.loader

image-20210831224726615

image-20210831224749456

如下图,安装成功:

image-20210831224850145

当然了,上面我们安装的style-loader是@3.2.1的版本的。

我为了防止还是出现上面的,loader版本过高的问题。

我直接参考王红元的版本。

我重新卸载了,安装一遍。

image-20210831234356652

然后进行style.loader的配置。

image-20210831225004415

上面的正则表达式是:/\.css$/

  • //两个是包围着正则表达式。
  • /.中,这是因为.在正则表达式当中有特殊的含义,/.表达的是转义,意思表示的代表真正的.
  • $表示结尾。
  • ^表示开始。
  • 这个正则表达式的目的是匹配所有.css结尾的文件。

上面的配置的意思是:匹配到css文件的时候,就use下面的loader。

styler-loader的作用是负责将样式添加到DOM当中。

styler-loader和css-loader在webpack.config.js当中的顺序

webpack.config.js当中,使用多个loader的时候,是从右向左读的。

所以,我们要写成下面的顺序:

use: [ 'style-loader', 'css-loader' ]
测试效果

image-20210831234737515

样式生效了。成功了。

webpack第15页PPT

image-20210831234959431

webpack第16页PPT

image-20210831235029957

webpack第17页PPT

image-20210831235053892

考试

问题:webpack.config.js当中配置loader的顺序是什么?

答案:从右向左的先后顺序。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值