Vue.js学习第一天

初体验

学完了Ajax,再来学习一下前端的三大框架吧,第一个就是Vue.js 💪

1. 认识 Vue.js

Vue是一个渐进式的框架,什么是渐进式呢?
简单来说,就是它可以做到一点一点把原本使用的技术替换成Vue的,两种技术可以共存,例如从jQuery慢慢地过渡到Vue.js。
它意味着你可以将Vue作为你应用地一部分嵌入其中,带来更丰富地交互体验,或者如果你希望将更多的业务逻辑使用Vue实现,那么Vue的核心库以及其生态系统,比如Core+Vue-router+Vuex也可以满足你的各种需求。
Vue有很多特点和Web开发中常见的高级功能:

  • 解耦试图和数据
  • 可复用的组件
  • 前端路由技术
  • 状态管理
  • 虚拟DOM

2. 安装 Vue.js

安装这里就不赘述了,详情可以见官网

3. 一些注意事项

老师说接下来会使用ES6的语法,我之前接触的很少,所以以后每天我都会把今天用到的ES6记录下来

var => let(变量) / const(常量)

然后是最简单的一个Vue大概的样子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<div id="container">
<h1>{{name}}</h1>
<h1>{{message}}</h1>
</div>
<script src="./vue.js"></script>
<script>
const app = new Vue({
el:'#container', //用于挂在要管理的元素
data:{ //定义数据
name:'beanBag',
message:'成功!'
}
})
</script>
</body>
</html>

Vue.js学习第二天

MVVM、插值操作及绑定属性

- 什么是MVVM
Model–view–viewmodel,它是一种软件架构模式(其实我也不理解,大概就是数据和视图相分离吧)

- Vue中的MVVM
在这里插入图片描述
如上图,Model模型对视图View中的DOM进行事件监听,视图View中的DOM的数据与Model模型进行绑定。

- 插值操作
Mustache(胡子/胡须)语法,也叫双大括号语法 ,大括号中间不仅可以写变量也可以写简单表达式。
下面是一些常用的插值操作,总的script代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<script>
setTimeout(()=>{
const app = new Vue({
el: '#container',
data: {
message:'插值操作相关 v-once操作 只显示一次',
url: '<h1 style="color:red;">v-html操作 解析html</h1>',
name: '插值操作相关 v-text操作 不灵活',
age: '插值操作相关 v-pre操作 不解析',
cloak:'插值操作相关 v-cloak操作 不闪动'
}
})
},2000)
</script>
  1. v-once:元素和指令只渲染一次,不会随着数据的改变而改变。
    <h1 v-once>{{message}}</h1>

  2. v-html:可以解析HTML元素
    <h1 v-html = 'url'></h1>

  3. v-text: 和Mustache语法的功能类似,展示文本一般不用,因为不够灵活,会覆盖标签里面的内容
    <h1 v-text = 'name'>aa</h1>

  4. v-pre: 不解析,原封不动的显示
    <h1 v-pre>{{age}}</h1>

  5. v-cloak:不会闪动,在vue解析之前 div中会有此属性,解析之后,此属性消失
    <h1 v-cloak>{{cloak}}</h1>

    注:以上script标签加了延时函数,是为了让 v-cloak 的功能更好的展示

    - 绑定属性
    以上方法都是针对值而进行的改变,那么有没有一种是针对属性的呢,答案就是有的,就是 v-bind : 动态绑定 ,例如可以动态绑定 img 标签的 src 属性等等
    有两种语法:

  6. 对象语法,即类的值是一个对象,例如

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
.active{
color:cyan;
}
.actives{
font-size: 10em;
}
</style>
</head>
<body>
<div id="container">
<p v-bind:class="{active:isClass,actives:isActives}">{{message}}</p>
<button v-on:click = 'change'>变色</button>
</div>

<script src="./vue.js"></script>
<script>
const app = new Vue({
el: '#container',
data:{
message:'hello',
isClass:false,
isActives:false
},
methods: {
change:function(){
this.isClass = !this.isClass;
this.isActives = !this.isActives;
}
}
})
</script>
</body>
</html>
  1. 数组语法,即类的值是一个数组,例如
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
.active{
color:cyan;
}
.actives{
font-size: 10em;
}
</style>
</head>
<body>
<div id="container">
<p :class="getClass()">{{message}}</p>
</div>
<script src="./vue.js"></script>
<script>
const app = new Vue({
el:'#container',
data:{
message:'数组语法',
active:'active',
actives:'actives'
},
methods:{
getClass:function(){
return [this.active,this.actives];
}
}
})
</script>
</body>
</html>

v-bind的语法糖形式是省略前面的 v-bind,保留一个:
v-on的语法糖形式是把 v-on: 替换成 @


学习了以上内容,有一个案例需要实现 :点击列表中的任意一项,使得那一项所在的li标签变色,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
.change {
color: cyan;
}
</style>
</head>

<body>
<div id="container">
<ul>
<li v-for='(attr,index) in movies' v-on:click='color(index)' :class='{change:index == status}'>{{attr}}</li>
</ul>
</div>
<script src="./vue.js"></script>
<script>
const app = new Vue({
el: '#container',
data: {
movies: ['海王', '小黄人大眼萌', '海绵宝宝', '进击的巨人'],
status: 0
},
methods: {
color: function (index) {
this.status = index;
}
}
})
</script>
</body>

</html>

Vue.js学习第三天

动态绑定style及计算属性

今天是元宵节,先祝大家元宵节快乐,也祝在前线的医务人员节日快乐,希望疫情早日过去,加油💪
继昨天学习的动态绑定class属性,今天是动态绑定style属性,同样的,也分为数组语法和对象语法,一般数组语法应用的不多,了解即可。

  • 对象语法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>

<body>
<div id="container">
<h2 v-bind:style="{fontSize:fontSize}">{{message}}</h2>
</div>
<script src="./vue.js"></script>
<script>
const app = new Vue({
el: '#container',
data: {
message: 'hello',
fontSize: '100px'
}
})
</script>
</body>

</html>
  • 数组语法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>

<body>
<div id="container">
<h1 :style='[baseStyle , baseStyles]'>{{message}}</h1>
</div>
<script src="./vue.js"></script>
<script>
const app = new Vue({
el: '#container',
data: {
message: 'hello',
baseStyle: { background: 'red' },
baseStyles: { fontSize: '20px' },
}
})
</script>
</body>

</html>

今天还学了一个计算属性 computed ,作用呢看起来与methods方法差不多,实际上它们的差别还是有的,在computed中,存在着 set 和 get两个方法,但是我们一般都将他们简写了,但是还是要知道有这两样东西
computed 与 methods 的区别?
computed在使用中,系统会存在有缓存,当检测到数据没有发生改变时,computed会使用缓存中的数据,但是methods会重复调用其中的函数,所以在这方面来说,methods的性能要比低一些。
下面是一些基本的例子:
set和get函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="container">
<h1>{{message}} {{finalName}}</h1>
</div>
<script src="./vue.js"></script>
<script>
const app = new Vue({
el: '#container',
data: {
message: 'hello',
startName: 'real',
endName: 'cute'
},
computed: {
finalName: {
set: function(){
console.log('---');
},
get:function () {
return this.startName + ' ' + this.endName;
}

}
}
})
</script>
</body>
</html>

基本使用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="container">
<h1>总价格 {{totalPrice}}</h1>
</div>
<script src="./vue.js"></script>
<script>
const app = new Vue({
el: '#container',
data: {
books: [{id:'1000',name:'Linux编程原理',price:100},
{id:'1001',name:'php编程原理',price:110},
{id:'1002',name:'C编程原理',price:120},
{id:'1003',name:'Java编程原理',price:130}]
},
computed:{ //计算属性 函数名一般不加动词
totalPrice:function(){
let price = 0;
for(let attr in this.books){
price += this.books[attr].price
}
return price;
}
}
})
</script>
</body>
</html>

元宵节偷懒了,没有写多少,嘿嘿!

Vue.js学习第四天

事件监听、条件判断及循环的使用

Vue.js学习第四天——事件监听、条件判断及循环的使用

  • 事件监听
    v-on:
    • 语法糖形式:@
    • 参数:event
    • 作用:绑定事件监听器
    • 注意事项:在传入参数时,有以下几种情况需要特别注意(见代码中的注释部分)并且在传入event作为参数的时候,要加$,即$event
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>

<body>
<div id="container">
<!-- 1.本身不需要传参时 加不加() 结果都一样 -->
<button @click="btn1()">按钮一</button>
<button @click="btn1">按钮一</button>

<!-- 2.本身需要传参时 1).只写了()没传参 显示undefined 2). ()都没写 会把event打印出来-->
<button @click="btn2()">按钮二</button>
<button @click="btn2">按钮二</button>

<!-- 3.本身既需要传入event 又需要传入其它参数 1)只写了()没传参 显示两个undefined 2).()都没写 会把event打印出来
另一个显示undefined 3).只写了data那个参数,event没写 报错显示两个undefined 4).只写了$event 会显示event
undefined -->
<button @click="btn3()">按钮三</button>
<button @click="btn3">按钮三</button>
<button @click="btn3($event)">按钮三</button>

</div>
<script src="./vue.js"></script>
<script>
const app = new Vue({
el: '#container',
methods: {
btn1() {
console.log('btn1 start');
},
btn2(data) {
console.log(data);
},
btn3(data, event) {
console.log(data, event);
}
}
})
</script>
</body>

</html>
  • 修饰符:修饰符主要有以下四种

                 1. **.strop**:阻止冒泡,例如在一个div中包含一个button,并且在div和button上都绑定有点击事件,当点击button时div中的点击事件也相应的触发,如果我们不希望它触发,可以使用本修饰符,详情可以见下面例子
                            2. **.prevent**:阻止默认事件,一般是阻止表单中的submit,由自己的方法进行提交时使用,详情可以见下面例子
                                       3. **.{keyCode|keyAlias}**:阻止键盘事件,阻止键盘事件,并且以自己希望的某一个按键触发,详情可以见下面例子
                                                  4. **.once**:只触发一次回调 详情可以见下面例子
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>

<body>
<div id="container">
<div @click='div' id="box">
<!-- 1. .stop 阻止冒泡 -->
<button @click.stop='btn1' id="btn1">按钮一</button>
</div>
<br />
<form>
<!-- 2. .prevent 阻止默认事件 -->
<input type='submit' @click.prevent='btn2'>
</form>
<!-- 3. .{keyCode|keyAlias} 阻止键帽只对设置的起作用 -->
<input type="text" @keyup.enter='btn3'>
<!-- 4. .once 只触发一次回调 -->
<button @click.once='btn4'>按钮4</button>
</div>
<script src="vue.js"></script>
<script>
const app = new Vue({
el: '#container',
methods: {
btn1() {
console.log('btn1');
},
div() {
console.log('div');
},
btn2() {
console.log('submit');
},
btn3() {
console.log('阻止键帽')
},
btn4() {
console.log('btn4');
}
}
})
</script>
</body>

</html>
  • 条件判断,由于这个和以前的if语句差不多,就直接看案例吧

         1. v-if
             2. v-else
                 3. v-else-if
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="container">
<h1 v-if='score>90'>优秀</h1>
<h1 v-else-if='score>=70'>良好</h1>
<h1 v-else-if='score>=60'>及格</h1>
<h1 v-else>不及格</h1>

</div>
<script src="./vue.js"></script>
<script>
const app = new Vue({
el: '#container',
data: {
score: 50
}
})
</script>
</body>
</html>

当然我们一般不会这么写,只是为了体现v-if的使用,一般都会另写函数进行判断。
案例一:实现点击切换登录按钮,将默认的账号登陆变为邮箱登录,见代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>

<body>
<div id="container">
<span v-if='isUser'>
<label for="username">账号登陆</label>
<input type="text" placeholder="账号登陆" id="username" key='username'>
</span>
<span v-else>
<label for="username">邮箱登陆</label>
<input type="text" placeholder="邮箱登陆" id="email" key='email'>
</span>
<button @click='isUser = !isUser'>切换登录</button>
</div>

<script src="./vue.js"></script>
<script>
const app = new Vue({
el: '#container',
data: {
isUser: true
}
})
</script>
</body>

</html>

问题:当我们点击切换登录按钮时,虽然它确实切换成邮箱登录,但是如果已经在input标签中写有内容,这时候内容并不会清空,这是为什么?
:很显然,vue在处理整个页面的时候,并没有重新渲染整个页面,而是出于性能考虑,会尽可能的服用已经存在的元素,而不是重新创建新的元素,vue中通过diff算法,会比较两次的不同再进行渲染,所以我们只需在input标签中添加key,并且保证两个input标签中的key不相同即可,vue就会帮助我们重新渲染这个标签。
这里同时引出了另一个知识点,就是 v-show 的使用,大致和v-if是差不多的,都是用来控制一个元素是否进行显示的下面介绍一下两者的区别

 - v-if:当条件为false时,根本就不会存在与dom中
 - v-show:当条件为false时,v-show只是给元素增加了 display:none ,从而使其隐藏

这些我们可以通过开发者模式中看出来,那么如何选择呢?
当我们的显示与隐藏的频率特别高时,使用 v-show;
当我们的频率特别低时,使用 v-if

  • 循环,这部分内容也较简单,直接贴代码了
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="container">
<!-- 1.遍历数组 格式:(index,attr)-->
<p v-for='(attr,index) in books'>{{index}}-{{attr}}</p>
<!-- 2.遍历对象 格式: (value,key,index)-->
<p v-for='(attr,value,index) in students'>{{attr}}-{{value}}-{{index}}</p>
</div>
<script src="./vue.js"></script>
<script>
const app = new Vue({
el: '#container',
data:{
books: ['php开发教程','java开发教程','c语言开发教程','python开发教程'],
students: {
name: 'beanBag',
age: 22
}
}
})
</script>
</body>
</html>

这里有几点值得注意的就是,官方推荐我们在使用v-for的时候,最好是添加 :key,这样可以是我们更高效的更新虚拟DOM,key值和后面跟着的数据的名称相同 例如 <li v-for='attr in books' :key='attr'>{{attr}}</li>,至于为什么,我的理解是当我们进行例如插入的操作时,如果没有指定key值,那么原来的key和value之间的配对关系会被重新分配,从而增加了开销,如果指定了key值,那么key和value之间的配对关系不会重新分配,而是只增加插入元素的配对关系,节约了开销。


最后补充一个知识点,数组中有些方法即使你改变了数组中的值,页面上也不会马上渲染出来,比如通过索引值直接修改数组中的元素,这点在下面那个购物车案例中,体现尤为明显。那么哪些方法是响应式的呢?

  1. push 在数组当中的末尾增加元素

  2. pop 删除数组中的末尾元素

  3. shift 删除数组中的首位元素

  4. unshift 在数组当中的首位添加元素

  5. splice 可以对数组进行删除/替换/插入操作,较为强大

  6. sort 对数组进行排序d

  7. reverse 翻转数组

    这里对splice方法进行一下说明,因为使用的较多

  1. 删除:第一个参数表示从哪一个元素开始,第二个参数表示你要删除几个元素,第三个参数如果没传则删除后面的所有元素;
    1. 替换:第一个参数表示从哪一个元素开始,第二个参数表示你哟啊替换几个元素,第三个参数是用来替换的元素;
  2. 插入:第一个参数表示从哪一个元素开始,第二个参数为0,第三个参数为要的元素。

在vue中还有一个方法可以是响应式的修改数组中的数据
Vue.set(要修改的对象,索引值,修改后的值)

学完以上的知识后,可以实现一个案例,就是购物车案例,这里我另贴一篇博客好了,见链接( https://blog.csdn.net/qq_43709292/article/details/104240962 )。

Vue.js学习第五天

表单绑定、组件化及ES6语法的补充

- 表单绑定 v-model

  • 作用:实现表单元素和数据的双向绑定
  • 本质:v-bind 指令和 v-on指令的结合,v-bind绑定一个value属性,并且            v-on给当前元素绑定input事件;
1
<input type="text" v-bind:value='message' v-on:input='message=$event.target.value'>
  • 与其它标签的结合使用(见代码):

         1. ``radio``
             2. ``checkbox`` 单选:一般传递一个布尔值;多选:传递数组
                 3. ``select``
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>

<body>
<!-- 注:一般一个label会包一个input,这样点击文字的时候也会有反应 -->
<div id="container">
<!-- 1. 与 radio 的结合使用 -->
<input type="radio" name="sex" v-model='sex' value="男">男
<input type="radio" name="sex" v-model='sex' value="女">女
<h3>您选择的是:{{sex}}</h3>

<!-- 2. 与 checkbox 的结合使用 -->
<input type="checkbox" id="agree" v-model='isAgree'>同意协议
<button v-bind:disabled='!isAgree'>下一步</button>
<h3>您选择的是:{{isAgree}}</h3>
<input type="checkbox" value="打篮球" v-model='hobbies'>打篮球
<input type="checkbox" value="打羽毛球" v-model='hobbies'>打羽毛球
<input type="checkbox" value="打乒乓球" v-model='hobbies'>打乒乓球
<input type="checkbox" value="打排球" v-model='hobbies'>打排球
<h3>您选择的是:{{hobbies}}</h3>

<!-- 3. 与 select 的结合使用 -->
<select v-model='fruits'>
<option>苹果</option>
<option>西瓜</option>
<option>香蕉</option>
<option>草莓</option>
</select>
<h3>您选择的是:{{fruits}}</h3>
<select v-model='moreFruits' multiple>
<option>苹果</option>
<option>西瓜</option>
<option>香蕉</option>
<option>草莓</option>
</select>
<h3>您选择的是:{{moreFruits}}</h3>

<!-- 值绑定 -->
<label v-for='attr in originHobbies'>
<input type="checkbox" :value="attr" v-model='hobbies'>{{attr}}
</label>
<h3>您选择的是:{{hobbies}}</h3>
</div>
<script src="./vue.js"></script>
<script>
const app = new Vue({
el: '#container',
data: {
message: 'hello',
sex: '男',
isAgree: true,
hobbies: ['打篮球'],
originHobbies: ['打篮球', '打羽毛球', '打乒乓球', '打排球'],
fruits: '',
moreFruits: []
}
})
</script>
</body>

</html>

以上代码引出一个知识点就是关于值绑定,项目实际开发过程中,不会让以上的例如爱好等数据定死,而是从服务器端请求回来的,所以要使用值绑定的操作,其实还是v-bind的使用。

  • 修饰符

    1. ``lazy``回车或失去焦点时触发,双向绑定中,由于前台页面不需要实时的与数据像绑定,只需要用户输入结束时再更新数据,故有此修饰符来减少刷新次数;
       2. ``number``保证数据的类型是number类型,若没有此修饰符,即使在input中指定类型为number,在你改变这个值之后,浏览器都会自动变成String类型来处理;
    3. ``trim``去掉前面后面的空格,中间的空格是不会去的;

  • 组件化

    什么是组件化?
    一个页面拆分成一个个小的功能块,每个功能块完成属于自己这部分独立功能,那么之后整个页面的管理和维护就会变得非常容易了。

    Vue的组件化思想
    它提供了一种抽象,让我们可以开发出一个个独立可复用的小组件,用来构造我们的应用,任何的应用都会被抽象成一棵组件树。

    注册组件的基本步骤(代码如下)

    1. 创建组件构造器(调用Vue.extend()方法创造组件构造器);
    2. 注册组件(调用Vue.component(使用的标签名,构造器实例名)方法);
    3. 使用组件(在Vue实例的作用范围内使用组件)。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<div id="app">
<my-cpn></my-cpn>
</div>
<script src="./vue.js"></script>
<script>
//1.创建组建构造器
const cpn = Vue.extend({
template: `
<div>
<p>这是模板嗷!</p>
</div>
`
});
//2.注册组件
Vue.component('my-cpn', cpn);

const app = new Vue({
el: '#app'
})
</script>

全局组件和局部组件的创建(代码如下)

全局组件可以在多个Vue的实例下面使用,而局部组件只有在特定的实例下面才能使用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
<body>
<div id="container">
<my-tpl></my-tpl>
<my-tpl></my-tpl>
<my-tpl></my-tpl>
<tpl></tpl>
</div>
<div id="box">
<!-- <tpl></tpl> -->
<tpl></tpl>
</div>
<script src="./vue.js"></script>
<script>
//全局组件 只有在Vue的实例对象中才能用
const cpn = Vue.extend({
template: `
<div>
<p>这是全局组件</p>
</div>
`
});
const cpns = Vue.extend({
template: `
<div>
<p>这是局部组件</p>
</div>
`
});
Vue.component('my-tpl', cpn);
const app = new Vue({
el: '#container'
});
const box = new Vue({
el: '#box',
//局部组件
components: {
// mytpl使用组件时的标签名
tpl: cpns
}
})
</script>
</body>

父组件和子组件的创建(代码如下)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
<body>
<div id="container">
<cpn2></cpn2>
<cpn1></cpn1>
</div>
<script src="./vue.js"></script>
<script>
//子组件
const cpnC1 = Vue.extend({
template:`
<div>
<p>这是第一个</p>
</div>
`
});
//父组件
const cpnC2 = Vue.extend({
template:`
<div>
<p>这是第二个</p>
<cpn1></cpn1>
</div>
`,
components:{
cpn1:cpnC1
}
});
const app = new Vue({
el: '#container',
components:{
cpn2:cpnC2,
cpn1:cpnC1
}
});
</script>
</body>

这个父组件和子组件我口头表述也有点绕,还是看代码吧,具体就是在父组件被创建的时候,模板中使用到了子组件,就可以在父组件构造器中增添一个compontents属性,此属性下面跟着的对象就是原本正常注册组件的两个参数,即使用到的标签名和模板的标签名。

注册组件的语法糖形式(代码如下)
不难发现,在注册组件时传递的第二个参数就代表着创建组件构造器的的实例对象,我们只需将实例对象即template部分传递到注册组件中即可,这样一来就不用写Vue.extend()方法了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<body>
<div id="container">
<cpn1></cpn1>
<cpn2></cpn2>
</div>
<script src="./vue.js"></script>
<script>
Vue.component('cpn1', {
template: `
<div>
<p>语法糖形式全局组件</p>
</div>
`
});
const app = new Vue({
el: '#container',
components: {
'cpn2': {
template: `
<div>
<p>语法糖形式局部组件</p>
</div>
`
}
}
});
</script>
</body>

模板的分离写法(代码如下)
以上的写法中,我们又发现,如果在script代码中书写大量的HTML语法显得非常臃肿,所以我们又可以将template进行分离,主要有两种方式。

  1. 使用<script type="text/x-template" >标签
  2. 使用<template>标签

将HTML标签写在这两个其中一个标签中均可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<body>
<div id="container">
<cpn></cpn>
<cpn3></cpn3>
</div>
<script type="text/x-template" id="cpn1">
<div>
<p>全局分离这是模板哦</p>
</div>
</script>
<template id="cpn2">
<div>
<p>局部分离这也是模板哦</p>
</div>
</template>
<script src="./vue.js"></script>
<script>
Vue.component('cpn',{
template:'#cpn1'
});
const app = new Vue({
el: '#container',
components:{
cpn3:{
template:'#cpn2'
}
}
})
</script>
</body>

数据的问题
我们又想,以往的Vue实例中,可以很轻松的从data属性中获取数据,那么我现在如果在模板中也需要用到数据怎么办呢?可以直接像以往的Vue实例中拿到数据吗?答案是否定的,在组件内部是不能够访问实例数据的,此时问题就来了,怎么获取数据呢?实际上,在注册组件时的第二个传递对象的参数中,是可以添加data数据的,并且组件中的data必须是一个函数,返回值必须是一个对象
至于为什么是一个函数,其实很好理解,如果像以往的Vue实例访问数据一样,那么如果有多个组件同时在对同一个数据进行处理的话,它们之间就会相互影响,这就违背了组件化的一个开发思想,所以Vue要求我们的data必须是一个函数,因为每当调用一次函数的时候,其内部都会开辟一块内存空间,这个内存空间是相互独立的,互不影响的,所以说这个值不会被其修改,避免了牵一发而动全身这样的情况。以下案例可以很好的说明这一点,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
<body>
<div id="container">
<tpl></tpl>
<tpl></tpl>
<tpl></tpl>

</div>
<template id="tpl">
<div>
<h1>当前计数:{{counter}}</h1>
<button v-on:click = 'add'>+</button>
<button @click = 'down'>-</button>
</div>
</template>
<script src="./vue.js"></script>
<script>
// const counter={
// counter:0
// }
Vue.component('tpl',{
template:'#tpl',
data(){
return {
counter:0
}
},
methods:{
add(){
this.counter++;
},
down(){
this.counter--;
}
}
});
const app = new Vue({
el: '#container'
})
</script>
</body>

此时我们可以把我注释的那部分去掉注释,并将counter:0修改为counter,这时候可以模拟data不是函数的情况,此时我们调用了多次的组件,当你点击第一个组件的按钮时,其它组件的值全都会一起改变,这就很好的说明了以上那一点。

父子组件的通信问题

  1. 父组件向子组件传递数据
    我们通过props属性向子组件传递数据
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
<body>
<div id="container">
<!-- 如果没有v-bind会把movie直接当字符串输出 不会当成变量 -->
<cpn :cmessage="message" :cmovies="movie"></cpn>
</div>
<template id="cpn">
<div>
<ul>
<li v-for='attr in cmovies'>{{attr}}</li>
</ul>
<p>{{cmovies}}</p>
<p>{{cmessage}}</p>
</div>
</template>
<script src="./vue.js"></script>
<script>
const cpn = {
template: '#cpn',
//props:['cmovies'],
props:{ //1.类型限制
//cmovies:Array,
// cmessage:String

//2.提供一些默认值 上面没有传使用默认值
cmessage:{
type:String,
default:'aaaa',
required:false //此属性必传 不传报错
},
// 类型是对象或者数组时 默认值必须是一个函数
cmovies:{
type:Array,
// default:[] //2.5.x 版本一下这样不会错 否则报错
default(){
return []
}
}
},
data(){
return{

}
}
};
const app = new Vue({
el: '#container',
data:{
message: 'hello',
movie: ['海王','海绵宝宝','海尔兄弟']
},
components:{
cpn
}
})
</script>
</body>

另外在props中还可以对数据进行一些类型 默认值 是否必须传递此属性等进行控制,可以学习一下

  1. 子组件向父组件传递数据
    我们通过事件向父组件发送消息($emit),父组件监听子组件的事件即可
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
<body>
<div id="container">
<tpl v-on:sendclick='sendClicks'></tpl>
</div>
<template id="tpl">
<div>
<button v-for='attr in some' @click='btnClick(attr)'>{{attr.name}}</button>
</div>
</template>
<script src="./vue.js"></script>
<script>
const tpl = {
template:'#tpl',
data(){
return {
some:[
{id:'aaa',name:'热门推荐'},
{id:'bbb',name:'手机数码'},
{id:'ccc',name:'家用电器'},
{id:'ddd',name:'酒水饮料'}
]
}
},
methods: {
btnClick(attr){
//发送一个事件
this.$emit('sendclick',attr);
}
},
}
const app = new Vue({
el: '#container',
components:{
tpl
},
methods: {
sendClicks(attr){
console.log(attr);
}
},
})
</script>
</body>

注意以上所有的props中的命名好像不能遵循驼峰原则,浏览器会报错,之后在脚手架开发中是不会出现的,这点注意一下即可,改成小写或是加 - 都行;还有一个小问题即 组件的模板里如果有多个标签,要有一个根标签包裹在它们外面

有关ES6语法的补充我把它放到和之前的博客一起好了,这里不再赘述了。

Vue.js学习第六天

父子组件之间访问及插槽使用相关

继昨天学习了父子组件之间的通信后,有一个案例可以帮助我们加以巩固,需求如下图:
在这里插入图片描述
当我们在第一个文本框中输入数据时,第一个父组件中的data和子组件中的props会一起改变,并且第二个父组件中的data要是第一个的100倍。步骤大致如下:

  1. 父组件向子组件传递数据,拿到数据后props和data就会有值了;
  2. 此时修改文本框中的值,虽然界面上的data改变了,但是实际我们发现父组件中的data并未发生改变,所以我们要将子组件中的数据(即input中的值)传递到父组件中,并修改父组件中的值,这时候vue有个关于类型的警号,我们在拿到数据后将它转换以下即可;
  3. 至于最后一点100倍的需求,只要在上一步的子组件传递数据给父组件的方法当中将数据乘以100再发送一个请求让父组件监听denumber2值的改变即可。完整代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
<body>
<div id="container">
<cpn :number1="num1" :number2="num2" @change1='chang1' @change2='chang2'></cpn>
</div>
<template id="tpl">
<div>
<p>props: {{number1}}</p>
<p>data: {{dnumber1}}</p>
<!-- <input type="text" v-model="dnumber1"> -->
<input type="text" :value="dnumber1" @input="num1input">
<p>props: {{number2}}</p>
<p>data: {{dnumber2}}</p>
<!-- <input type="text" v-model="dnumber2"> -->
<input type="text" :value="dnumber2" @input="num2input">
</div>

</template>
<script src="./vue.js"></script>
<script>
const app = new Vue({
el: '#container',
data: {
num1: 0,
num2: 1
},
methods: {
chang1(dnumber1) {
final1 = parseInt(dnumber1);
this.num1 = final1;
},
chang2(dnumber2) {
final2 = parseInt(dnumber2);
this.num2 = final2;
}
},
components: {
cpn: {
template: '#tpl',
props: {
// 改变一定要来自父组件
number1: Number,
number2: Number
},
data() {
return {
dnumber1: this.number1,
dnumber2: this.number2
}
},
methods: {
num1input() {
this.dnumber1 = event.target.value;
this.$emit('change1', this.dnumber1);
this.dnumber2 = this.dnumber1 * 100;
this.$emit('change2', this.dnumber2);
},
num2input() {
this.dnumber2 = event.target.value;
this.$emit('change2', this.dnumber2);
this.dnumber1 = this.dnumber2 / 100;
this.$emit('change1', this.dnumber1);
}
}
}
}
})
</script>
</body>
  • 父子组件之间的访问
    在上面的案例中,我们了解了父子组件之间的通信,指的是父子组件之间可以互相传递数据,但是现在如果我们只是想要调用一下子组件或是父组件之间的方法或一些值,并不想改变它,我们应该怎么做呢?所以Vue提供了父子组件的访问方式。
  1. 父组件访问子组件

    1. $children 这个方式主要是通过拿到下标的方式访问的,children返回的是一个数组,所以可以通过下标的方式访问,但是一般真实案例中,用的较少,因为方法本身不是很灵活
    2. $refs reference的缩写,采用引用的方式,在父组件中调用模板时,在模板上添加属性实现 <tpl ref="aaa"></tpl>实际开发中这个方式采用的较多
  2. 子组件访问父组件

    1. $parents,实际开发中也使用的较少,因为子组件访问父组件的方式,破坏了组件之间的耦合性,所以不建议使用。一些基本的使用见代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
<body>
<div id="container">
<tpl ref="aaa"></tpl>
<button @click='showMessage'>我是父组件中的按钮</button>
</div>
<template id="tpl">
<div>
<p>我是模板</p>
<button @click='showPar'>我是子组件中的按钮</button>
<son></son>
</div>
</template>
<template id="son">
<div>
<p>我是孙子</p>
<button @click='showParents'>我是孙组件中的按钮</button>
</div>
</template>
<script src="./vue.js"></script>
<script>
const app = new Vue({
el: '#container',
data:{
name:'beanBag'
},
methods:{
showMessage(){
console.log(this.$children);
this.$children[0].show();
console.log(this.$refs);
this.$refs.aaa.show();
},
showKey(){
console.log('子组件可以访问父组件啦!');
}
},
components:{
tpl:{
template:'#tpl',
methods:{
show(){
console.log('hello 父组件可以访问到子组件中啦');
},
showPar(){
console.log(this.$parent);
console.log(this.$parent.name);
this.$parent.showKey();
console.log(this.$root);
}
},
components:{
son:{
template:'#son',
methods:{
showParents(){
console.log(this.$parent);
console.log(this.$root);
}
}
}
}
}
}
})
</script>
</body>

插槽的使用(slot)
插槽的使用是为了让我们封装的组件更加具有拓展性,让使用者可以决定组件内部的一些内容到底展示什么。
1. 插槽的基本使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
<body>
<div id="container">
<tpl></tpl>
<tpl>
<div>1</div>
<p>2</p>
<i>3</i>
</tpl>
<tpl>ss</tpl>
<tpl></tpl>
</div>
<template id="tpl">
<div>
<p>haha</p>
<!-- 1.插槽的基本使用 -->
<!-- <slot></slot> -->
<!-- 2.插槽的默认值 -->
<!-- <slot>
<button>hello</button>
</slot> -->
<!-- 3.插槽中如果有多个值,同时放入组件进行替换时,一起作为替换元素 -->
<slot>
<p>beanBag</p>
</slot>
</div>

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

2. 具名插槽的使用
以上案例我们可以看出当我们需要有多个插槽时,如果想要具体修改某一个插槽,从而不影响其它插槽是非常困难的,所以有具名插槽的提出,类似上面的$refs的一个使用,给每一个插槽起一个名字区分它们即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<body>
<div id="container">
<tpl>
<p slot="center">标题</p>
</tpl>
<tpl>
<i slot="right">hello</i>
</tpl>
<tpl></tpl>
</div>
<template id="tpl">
<div>
<slot name="left">
<p>左边</p>
</slot>
<slot name="center">
<p>中间</p>
</slot>
<slot name="right">
<p>右边</p>
</slot>
</div>
</template>
<script src="./vue.js"></script>
<script>
const app = new Vue({
el: '#container',
components:{
tpl:{
template:'#tpl'
}
}
})
</script>
</body>

3. 作用域插槽
在这之前,我们需要了解一个知识点,就是编译的作用域问题父组件模板的所有东西都会在父级作用域内编译,子组件也是同理,简单来说,就是在template的标签下的模板,都只能访问到子组件中的东西,而不能访问父组件,也就是Vue实例中的东西的,在我们引用这个模板时,编译器在编译到此 tpl(模板名称) 时,已经提前将它要使用的本身子组件中的东西拼接好了,不会再访问父组件中的任何东西,所以子组件此时也是不能访问到父组件中的内容的。
作用域插槽就是可以解决此问题,父组件替换插槽的标签,但是内容由子组件来提供,这样就解决了我们在父组件中不能访问子组件中的数据,但是又必须将子组件中的数据进行修改显示的情况,代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
<body>
<div id="container">
<tpl></tpl>
<tpl>
<template slot-scope="slot">
<!-- <span v-for="attr in slot.data">{{attr}}</span> -->
<span>{{slot.data.join(' - ')}}</span>
</template>
</tpl>
<tpl></tpl>
</div>
<template id="tpl">
<div>
<slot :data='languages'>
<ul>
<li v-for='attr in languages'>{{attr}}</li>
</ul>
</slot>
</div>
</template>
<script src="./vue.js"></script>
<script>
const app = new Vue({
el: '#container',
components:{
tpl:{
template:'#tpl',
data() {
return {
languages:['c++','c','java','javascript']
}
},
}
}
})
</script>
</body>

Vue.js学习第七天

webpack的使用及ES6相关

今天是学习Vue的第七天,但是感觉自己进度有点慢,不过没关系,还是把基础打扎实比较重要,继续努力吧!
首先我们可以回顾一下,当我们学习了这么多关于前端开发的东西之后,真正使用到项目当中的时候,会带来什么问题,在实际开发过程中,同一个页面可能会由非常多的人共同完成,这时候就会带来一个问题,当我们把每一个人编写的文件汇总到一起的时候,难免会出现这个变量在你这有使用,在我这它也有被使用,那么我们很难确保同一个变量不会被别人所改变的情况出现,这时候,前端模块化的思想逐渐流行起来。
最开始,人们采用的是原始的JavaScript,用匿名函数和闭包完成一个独立的模块化,这时候问题也随之产生,使用匿名函数和闭包确实能够防止其它开发人员将此变量的值进行改变,但是文件之间的引用就没办法进行了,比如A写的文件中想要引用B写的文件中的一些方法的时候,就会变得非常麻烦,为了解决这个问题,ES6中也有相关的方法,我们可以先学习一下,我们来看下面一个例子:

40-1.js文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// 1. 导出方式一
let name = 'beanBag';
let age = 18;
let height = 1.80;

const sum = function(num1,num2){
console.log(num1+num2);
}
sum(10,20);
export {name,age,height,sum}

// 2. 导出方式二 定义时直接导出
export let names = 'hqc';
export let ages = 20;

// 3.导出方式三 导出函数/类
export function lzx(){
console.log('开心最重要');
}
export class Person{
run(){
console.log('开始奔跑了!')
}
}

// 4.导出方式四 导出后参数不唯一 但是同一个模块中只能有一个
let fruits;
export default fruits = 'apple';


40-2.js文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
let age = 15;
let weight = 70;

// 导入方式一 基本方式
import {height,sum} from './40-1.js'
sum(1,2);
console.log(height);

// 导入方式二 在定义时就导出
import {names} from './40-1.js'
console.log(names);

// 导入方式三 导入类或函数
import {Person,lzx} from './40-1.js'
const person = new Person;
person.run();
lzx();

// 导入方式四 导入后可自定义变量名
import a from './40-1.js'
console.log(a);

// 导入方式五 使用通配符
import * as just from './40-1.js'
console.log(just.name);

html文件

1
2
3
4
5
6
7
8
9
10
11
12
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script src="./40-1.js" type="module"></script>
<script src="./40-2.js" type="module"></script>
</body>
</html>

首先在引用script文件的时候,指明类型为module类型,代表它们是一个单独的模块,互不影响,然后用export将需要使用到的方法或者变量甚至是类导出,在引用的文件中用inport进行导入即可,主要用以上几种方法。
不仅在ES6中有模块化的使用,同样的,在CommonJs中也有相关模块化的规范,相关案例见代码

info.js文件

1
2
3
4
5
6
7
8
9
10
11
12
function add(num1,num2){
console.log(num1+num2);
}

function Unadd(num1,num2){
console.log(num1-num2);
}

// 1.CommonJs方式导出
module.exports = {add,Unadd};


main.js文件

1
2
3
4
// 使用CommonJs方式导入
const {add,Unadd} = require('./js/info.js');
add(10,20);
Unadd(20,10);

有了以上的知识,我们就可以学习webpack了


webpack
其本质是现代的JS应用的静态模块化打包工具,它和grount/gulp的差别是,grount/gulp更强调的是前端流程的自动化,模块化不是它的核心,恰恰相反的是webpack更加强调模块化的开发流程,而文件压缩合并预处理等功能仅仅使它附带的功能而已

1. webpack的起步
由于webpack依赖于node的相关环境,所以在安装webpack前应该先安装node,
这里我是用的10.16.2版本,老师说版本应该大于8.9,所以问题不大,webpack我们使用的是3.6.0版本,为之后学习脚手架2做一点铺垫,同时和老师使用的同步,首先我们全局安装webpack,使用以下命令
npm install webpack@3.6.0 -g 至于全局安装和局部安装的区别我在下面会说。

安装好了之后,我们在项目中新建一个dist目录用来存放待会儿webpack打包好的文件,再新建src目录存放编写的JavaScript文件,代码如下
main.js

1
2
3
4
5
6
7
8
9
// 1.使用CommonJs方式导入
const {add,Unadd} = require('./info.js');
add(10,20);
Unadd(20,10);

// 2.使用ES6方式导入
import {chu} from './math.js';
chu(20,2);

info.js

1
2
3
4
5
6
7
8
9
10
function add(num1,num2){
console.log(num1+num2);
}

function Unadd(num1,num2){
console.log(num1-num2);
}

// 1.CommonJs方式导出
module.exports = {add,Unadd};

math.js

1
2
3
4
5
function chu(num1,num2){
console.log(num1/num2);
}
// 2.使用ES6语法导出
export {chu}

在JS文件中,采用CommonJs或者是es6的语法都行,这时候轮到webpack出场了,在以往没有webpack中我们需要将每一个文件都进行引入才行,但是有了webpack我们就可以将其打包好的一个文件引入即可,在项目的终端中,输入命令webpack ./src/main.js ./dist/bundle.js,这时候我们就会发现在dist目录下,多了一个bundle.js文件,webpack之后跟着的是你将导出的变量或者方法等等导入到的那个文件,千万不要错了嗷!这样就完成了我们对于webpack一个初步的了解。

2. webpack的配置
在以上的操作中我们发现,在终端中输入的命令太过于长了,有没有可以实现自动的找到相应目录呢,这时候我们就需要来了解webpack的一个配置了,在文件中新建webpack.config.js文件名不能输错,在文件中我们需要指明文件的入口和出口,也就是你将什么文件交给webpack和webpack将处理过后的文件放到哪里去,代码如下

1
2
3
4
5
6
7
8
const path = require('path');
module.exports = {
entry: './src/main.js',
output: {
path: path.resolve(__dirname,'dist'),
filename: 'bundle.js'
}
}

这里的出口需要我们指明的是一个对象类型,第一个path需要跟的是绝对路径,我们采用node中的path模块提供的相关方法,第一个参数就是当前文件所在的目录,第二个参数指文件名,在这之前我们要将node中的npm初始化一下,因为我们用到了这个path模块,使用命令npm init这里有一些参数需要填一下,都挺简单的,看着填就行,入口现在可以随便填一个,这里用不到,这时候会自动生成package.json文件,这个时候,我们就可以采用webpack的命令直接将我们的文件进行打包,是不是方便多了!
这里我们采用的webpack命令虽然说很简便,但是有的时候,这个命令会特别长,所以我们应该再将这个命令映射一下,找到package.json文件中的script属性,默认有一个test,它指的是当我们输入npm run test的时候,它会自动执行test后面跟着的命令,同样的,我们在它下面加一行"build": "webpack",这时候,我们只要输入npm run build就可以使其运行webpack命令了,这里在后期中是比较方便的。
这时候,我们想象另外一个场景,就是当我们在公司中所采用的webpack的版本是4.0的时候,假如你在家里clone项目到本地之后,这时候你的电脑采用的是3.0版本的webpack,那么当我们在终端中输入命令的时候,它采用的是全局安装的webpack版本,不论你项目中的webpack是多少版本的,都是先去全局中找你的webpack,这时候就会有问题出现,那么怎么避免呢,这里面,有一个地方是优先在本地中搜索是否有webpack版本,那就是刚才配置映射关系的scripts,当我们在中做好映射之后,它会优先观察项目中是否有webpack版本,没有再去搜索全局,这就是全局安装和局部安装的区别,所以这里更推荐局部安装,这里采用命令npm install webpack@3.6.0 --save-dev这里的dev指的是devDependencies开发时依赖,即只是在开发的时候用到,运行的时候就不需要了,类似于工具人吧!

3 webpack中的loader
实际项目中,肯定不止是JavaScript文件需要打包,我们的css文件也是需要打包或转化的,这里就提出了loader,当然,对于webpack本身的能力来说,这些转化是不支持的,所以我们必须为他扩充一些东西即loader,那么怎么使css文件和需要转换的JavaScript文件进行联系呢,这时候,我们只需要在你需要转换的JavaScript文件中引入此css文件即可,例如require('./css/nomal.css');,然后在中断中输入命令安装loader,这里我们需要安装两个文件,一个是用来解析css代码的css-loader,另一个是用来将导出的css代码作为样式添加到DOM中的style-loader,分别使用命令npm install --save-dev css-loadernpm install style-loader --save-dev,安装完成之后,还需要在webpack.config.json文件中进行如下module中的配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
const path = require('path');
module.exports = {
entry: './src/main.js',
output: {
path: path.resolve(__dirname,'dist'),
filename: 'bundle.js'
},
module: {
rules: [
{
test: /\.css$/,
use: [ 'style-loader', 'css-loader' ]
}
]
}
}

其中use数组中的顺序不能错了,否则也会出问题,应该是样式在前,解析在后,为什么呢?因为使用多个loader时,webpack是从右向左解析的