vue学习笔记

虽然本人更多从事的是java后端开发,但作为一名精神小伙,本就有着架构的梦想,所以一直希望自己前后端都要有所涉猎,于是开始学习Vue框架作为拓展前端道路的试水区。

一、简介

官网https://cn.vuejs.org

1. 概念

  • Vue.js是一套构建用户界面的渐进式框架。Vue只关注视图层, 采用自底向上增量开发的设计。Vue 的目标是通过尽可能简单的 API实现响应的数据绑定和组合的视图组件。简单的理解:Vue就是和jQuery类似但更强的一个前端框架,它的中心思想就是数据驱动。而jQuery是结构驱动的,具体来说jQuery不算框架,而是js库。

  • Vue.js 是目前最火的一个前端框架,React是最流行的一个前端框架(React除了开发网站,还可以开发手机AppVue语法也是可以用于进行手机App开发的,需要借助于Weex

  • Vue.js 是前端的主流框架之一,和Angular.jsReact.js 一起,并成为前端三大主流框架!

  • Vue.js 是一套构建用户界面的框架,只关注视图层,它不仅易于上手,还便于与第三方库或既有项目整合。(Vue有配套的第三方类库,可以整合起来做大型项目的开发)

2. 框架和库的区别

  • 框架:是一套完整的解决方案;对项目的侵入性较大,项目如果需要更换框架,则需要重新架构整个项目,虽然有这个缺点,但是功能完善。

  • 库(插件):提供某一个小功能,对项目的侵入性较小,如果某个库无法完成某些需求,可以很容易切换到其它库实现需求。比如从Jquery 切换到Zepto,又比如从 EJS 切换到 art-template

3. 为什么要学习前端框架

  • 提高开发效率。提高开发效率的发展历程:原生JS -> Jquery之类的类库 -> 前端模板引擎 -> Angular.js/ Vue.js/React.js(能够帮助我们减少不必要的DOM操作;提高渲染效率;双向数据绑定的概念【通过框架提供的指令,我们前端程序员只需要关心数据的业务逻辑,不再关心DOM是如何渲染的了】)

  • 减少少DOM操作。在Vue中,一个核心的概念,就是让用户不再操作DOM元素,解放了用户的双手,让程序员可以更多的时间去关注业务逻辑。

4. 前端的MVVM

为了维护和管理前端开发,前端开发一般还要MVVM的分层开发模式。不要理解成MVCMVC 是后端的分层开发概念。而MVVM是前端视图层的概念,主要关注于视图层分离,也就是说:MVVM把前端的视图层,分为了 三部分 Model, View , VM (即ViewModel)。

mmvm

二、安装

1. <script> 标签引入vue.js文件

1
<script src="https://cdn.jsdelivr.net/npm/vue"></script>

例如:

1
2
3
4
5
6
7
8
9
10
11
12
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>VueJS Tutorials</title>
<link href="styles.css" rel="stylesheet" />
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
</head>
<body>

</body>
</html>

2. 使用NPM工具构建

1
2
# 最新稳定版
$ npm install vue

三、 hello world

app.js

1
2
3
4
5
6
7
new Vue({  //引入vue包后,浏览器的内存中就多了一个Vue的构造函数,只需要new Vue,就能实例化出Vue对象,该对象就是ViewModel,每当我们创建了一个Vue实例,就创建了一个新的ViewModel。
el: '#vue-app', //el(即elemet): 挂载点,需要绑定的vue根容器(根元素),一切的vue相关操作都在这个元素内进行。元素外不起作用。
data: { //data:数据选项,用于数据的存储,存放key/value。data就是mvvm中的model
username: 'qcmoke', //只需要在元素标签中使用表达式{{key}}或者v-text等插值表达式就能显示key对应的值,省略了麻烦的dom操作
msg: 'hello world !'
}
});

index.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>hello world</title>
<script src="https://cdn.jsdelivr.net/npm/vue"></script><!--引入vue.js-->
</head>
<body>
<div id="vue-app"> <!-- vue根容器(根元素) -->
<h1>Hey, {{ username }}</h1><!--根据data中的key使用模版语法{{}}取出值,vue将{{}}里的内容放到虚拟dom里,再通过虚拟dom将该内容放回真实dom的相关元素里-->
<h1>{{ msg }}</h1>
</div>
</body>

<script src="app.js"></script><!--引入app.js,app.js存储vue对象等相关业务代码-->
</html>

1557198901438

四、数据显示

1. 显示文本内容

1.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
<!DOCTYPE html>
<html>

<head>
<meta charset="utf-8">
<title>hello world</title>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<style>
[v-cloak] {
display: none;
}
</style>
</head>

<body>
<div id="vue-app">
<!-- 使用v-cloak结合css样式能够解决插值表达式闪烁的问题 -->
<h1 v-cloak>Hey, {{ username }}</h1>
<h1 v-cloak>{{ msg }}</h1>
</div>
</body>

<script>
new Vue({
el: '#vue-app',
data: {
username: 'qcmoke',
msg: 'hello world !'
}
});
</script>

</html>

解决使用插值表达式显示data数据出现闪烁的问题。步骤是,在有插值表达式内容的标签里添加v-cloak属性,然后添加如下css样式表即可解决。

1
2
3
4
5
<style>
[v-cloak]{
display: none;
}
</style>

1.2 v-text

与插值表达式功能是一样的。

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
<!DOCTYPE html>
<html>

<head>
<meta charset="utf-8">
<title>v-text</title>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
</head>

<body>
<div id="vue-app">
<h1 v-text="username"></h1>
<h1 v-text="msg"></h1>
<!--
<h1>Hey, {{ username }}</h1>
<h1>{{ msg }}</h1>
-->

</div>
</body>
<script>
new Vue({
el: '#vue-app',
data: {
username: 'qcmoke',
msg: 'hello world !'
}
});
</script>

</html>

与插值表达式不同的是不会出现插值表达式的闪烁的问题。原因是v-text会覆盖元素中原本的内容,但是 插值表达式 只会替换自己的这个占位符,不会把 整个元素的内容清空。

如何选择插值表达式和v-text?

如果内容含有data没有的一些字符,那么建议使用插值表达式结合v-cloak属性使用。

如果内容只有data里的数据,那么建议使用v-cloak

2. 显示html元素

2.1 v-html

作用:用于输出data中的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
<!DOCTYPE html>
<html>

<head>
<meta charset="utf-8">
<title>v-html</title>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
</head>

<body>
<div id="vue-app">
<h1 v-html="msg_el"></h1>
</div>
</body>
<script>
new Vue({
el: '#vue-app',
data: {
msg_el: '<h1 style="color: red">hello world !</h1>'
}
});
</script>

</html>

使用v-text或者插值表达式只能显示纯文本内容

1557209682585

五、属性数据绑定

1. 单向数据绑定 v-bind

  • 作用:用于给html元素的属性绑定数据
  • 缩写: :
  • 实现步骤:在原来属性的值里写vuedatakey,并在原属性前添加"v-bind:",以此来给属性绑定vue的数据。
  • 数据绑定方式:单向数据绑定,即从model自动绑定到viewview上绑定的属性数据(值)会随着model值的改变而改变,但是view中绑定的属性数据(值)的改变不会改变model中属性的数据(值)。
  • 绑定方向:model---->view
  • 作用范围:所有标签元素。
  • vue会将元素中属性绑定的key当作是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
31
32
33
34
<!DOCTYPE html>
<html>

<head>
<meta charset="utf-8">
<title>v-bind</title>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
</head>

<body>
<div id="vue-app">
<!-- 在原来属性的值里写vue中data的key,并在原属性前添加"v-bind:",以此来给属性绑定vue的数据 -->
<a v-bind:href="vue_url">vue的官网链接</a>
<br />

<!-- vue会将元素中属性绑定的key当作是js表达式返回,所以可以进行合法的运算操作 -->
<a v-bind:href="vue_url+'/v2/guide/'">vue官方文档链接</a>
<!--
v-bind
作用:用于给html元素的属性绑定数据
-->

</div>
</body>
<script>
new Vue({
el: '#vue-app',
data: {
vue_url: 'https://cn.vuejs.org'
}
});
</script>

</html>

1557210726080

2. 双向数据绑定 v-model

  • 作用:用于给html元素的属性绑定数据
  • 缩写: :model
  • 实现步骤:在需要表单元素里添加v-model="data找那个的key"即可实现双向数据绑定。
  • 数据绑定方式:双向数据绑定,即从modelview数据互相绑定,view上绑定的属性数据(值)会随着model值的改变而改变,并且view中绑定的属性数据(值)的改变也会改变model中属性的数据(值)。
  • 绑定方向:model<---->view
  • 双向数据绑定不可以进行表达式运算操作。
  • 作用范围:v-model只能使用在表单元素中,如input(radio, text, address, email....)select checkboxtextarea等。

测试单向数据绑定和双向数据绑定的区别

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>

<head>
<meta charset="utf-8">
<title>v-bind</title>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
</head>

<body>
<div id="vue-app">
单向数据绑定:<input type="text" v-bind:value="key1">
<br><br>
双向数据绑定:<input type="text" v-model="key2">
</div>
</body>
<script>
var vm = new Vue({
el: '#vue-app',
data: {
key1: 'value of key1',
key2: 'value of key2'
}
});
</script>

</html>

model—>view方向数据变化情况(通过浏览器的控制台操作内存中的vue对象即可改变model中的数据)

model数据未改变时:

1557249199997

model数据改变时:

1557249327836

view—>model方向数据变化情况

input(view)不改变值时的情况:

1557248526679

input(view)改变值时的情况:

1557248693289

从以上两个方向数据的改变即可看出单向数据绑定和双向数据绑定的差异。

六、事件绑定

1. v-on

作用:事件绑定。

缩写: @

步骤:在原来的事件属性前添加“v-on:”,并给事件属性赋vuedata key。,最后在vue对象的methods属性里添加key对应的方法。

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>

<head>
<meta charset="utf-8">
<title>v-on</title>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
</head>

<body>
<div id="vue-app">
<button v-on:click="show">点击按钮</button>
<!--
v-on
作用:事件绑定。
步骤:在原来的事件属性前添加“v-on:”,并给事件属性赋vue的data key。,最后在vue对象的methods属性里添加key对应的方法。
-->
</div>
</body>
<script>
new Vue({
el: '#vue-app', //el属性定义vue的控制区域
data: { //data属性定义所有vue数据
vue_url: 'https://cn.vuejs.org'
},
methods: { //methods定义所有vue可用的方法
show: function () {
alert("hello Vue !");
}
}
});
</script>

</html>

1557212657868

2. 事件修饰符

  • .stop 阻止冒泡

    冒泡:在多个绑定有事件的元素嵌套中。当触发一个元素时,伴随着嵌套的元素也会触发事件。

  • .prevent 阻止默认事件

  • .capture 添加事件侦听器时使用事件捕获模式

  • .self 只当事件在该元素本身触发时触发回

  • .once 事件只触发一次

2.1 阻止冒泡.stop

(冒泡的情况)

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>

<head>
<meta charset="utf-8">
<title>事件修饰符</title>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
</head>

<body>
<div id="vue-app">
<div @click="divHandle">
<!-- 使用v-on缩写的方式指定vue事件绑定 -->
<button @click="buttonHandle">点击按钮</button>
</div>
</div>
</body>
<script>
new Vue({
el: '#vue-app', //el属性定义vue的控制区域
data: { //data属性定义所有vue数据
vue_url: 'https://cn.vuejs.org'
},
methods: { //methods定义所有vue可用的方法
divHandle: function () {
console.info("hello div !");
},
buttonHandle() {
console.info("hello button !");
}
}
});
</script>

</html>

1557214731016

(阻止冒泡的情况)

在需要阻止冒泡的的元素vue事件属性后添加.stop

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>

<head>
<meta charset="utf-8">
<title>事件修饰符</title>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
</head>

<body>
<div id="vue-app">
<div @click="divHandler">
<!-- 使用v-on缩写的方式指定vue事件绑定
使用.stop阻止父元素事件(在当前元素发生事件后就停止了,没有继续冒泡下去)
-->
<button @click.stop="buttonHandler">点击按钮</button>
</div>
</div>
</body>
<script>
new Vue({
el: '#vue-app', //el属性定义vue的控制区域
data: { //data属性定义所有vue数据
vue_url: 'https://cn.vuejs.org'
},
methods: { //methods定义所有vue可用的方法
divHandler: function () {
console.info("hello div !");
},
buttonHandler() {
console.info("hello button !");
}
}
});
</script>

</html>

1557215907917

2.2 阻止默认事件.prevent

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
<!DOCTYPE html>
<html>

<head>
<meta charset="utf-8">
<title>事件修饰符</title>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
</head>

<body>
<div id="vue-app">
<!-- 使用.prevent事件修饰符阻止a标签的默认跳转事件 -->
<a :href="vue_url" @click.prevent="linkHandler">点击链接</a>

</div>
</body>
<script>
new Vue({
el: '#vue-app', //el属性定义vue的控制区域
data: { //data属性定义所有vue数据
vue_url: 'https://cn.vuejs.org'
},
methods: { //methods定义所有vue可用的方法
linkHandler() {
console.info("触发链接点击事件!");
}
}
});
</script>

</html>

1557216567887

2.3 添加事件捕获 .capture

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>

<head>
<meta charset="utf-8">
<title>事件修饰符</title>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
</head>

<body>
<div id="vue-app">
<!--
事件捕获
即是给元素添加一个监听器,当元素发生冒泡时,先触发带有该修饰符的元素。若有多个该修饰符,则由外而内触发。 就是谁有该事件修饰符,就先触发谁。
在嵌套的事件元素组中,默认事件是从里往外触发的,如果希望从外往里触发,可以在外元素的vue事件后添加.capture修饰符即可完成。

-->
<div @click.capture="divHandler" style="width: 100px; height: 100px; background: gray;">
<button @click="buttonHandler">点击按钮</button>
</div>
</div>
</body>
<script>
new Vue({
el: '#vue-app', //el属性定义vue的控制区域
data: { //data属性定义所有vue数据
vue_url: 'https://cn.vuejs.org'
},
methods: { //methods定义所有vue可用的方法
divHandler: function () {
console.info("hello div !");
},
buttonHandler() {
console.info("hello button !");
}
}
});
</script>

</html>

1557220843931

1557220912988

2.4 只触发当前元素事件 .self

不触发其他嵌套的元素

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
<!DOCTYPE html>
<html>

<head>
<meta charset="utf-8">
<title>事件修饰符</title>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<style>
</style>
</head>

<body>
<div id="vue-app">
<!--
.self
只触发当前元素事件。不触发其他嵌套的元素

-->
<div @click.self="divHandler" style="width: 100px; height: 100px; background: gray;">
<button @click="buttonHandler">点击按钮</button>
</div>
</div>
</body>
<script>
new Vue({
el: '#vue-app', //el属性定义vue的控制区域
data: { //data属性定义所有vue数据
vue_url: 'https://cn.vuejs.org'
},
methods: { //methods定义所有vue可用的方法
divHandler: function () {
console.info("hello div !");
},
buttonHandler() {
console.info("hello button !");
}
}
});
</script>

</html>

1557221088918

1557221129874

2.5 事件只触发一次.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
<!DOCTYPE html>
<html>

<head>
<meta charset="utf-8">
<title>事件修饰符</title>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
</head>

<body>
<div id="vue-app">
<!--
.once
作用:事件只触发一次

只在第一次点击的时候触发.prevent事件修饰符阻止a标签的默认跳转事件,第二次之后原本的默认跳转事件会被触发 -->
<a :href="vue_url" @click.prevent.once="linkHandler">点击链接</a>

</div>
</body>
<script>
new Vue({
el: '#vue-app', //el属性定义vue的控制区域
data: { //data属性定义所有vue数据
vue_url: 'https://cn.vuejs.org'
},
methods: { //methods定义所有vue可用的方法
linkHandler() {
console.info("触发链接点击事件!");
}
}
});
</script>

</html>

once

3. 按键修饰符

Vue 默认提供了几个常用的按键码的别名(键盘修饰符):

1
2
3
4
5
6
7
8
9
.enter
.tab
.delete (捕获“删除”和“退格”键)
.esc
.space
.up
.down
.left
.right

使用方式:

1
v-on:keyup.键盘修饰符="事件方法()"

如下:

1
2
<!-- 只有在 `key` 是 `Enter` 时调用 `vm.submit()` -->
<input v-on:keyup.enter="submit">

如果以上提供的键盘修饰符任然不够用,可以通过以下js代码进行扩展。

1
2
// 自定义全局按键修饰符
Vue.config.keyCodes.自定义修饰符名称 = 键码值;
字母和数字键的键码值(keyCode)
按键 键码 按键 键码 按键 键码 按键 键码
A 65 J 74 S 83 1 49
B 66 K 75 T 84 2 50
C 67 L 76 U 85 3 51
D 68 M 77 V 86 4 52
E 69 N 78 W 87 5 53
F 70 O 79 X 88 6 54
G 71 P 80 Y 89 7 55
H 72 Q 81 Z 90 8 56
I 73 R 82 0 48 9 57
数字键盘上的键的键码值(keyCode) 功能键键码值(keyCode)
按键 键码 按键 键码 按键 键码 按键 键码
0 96 8 104 F1 112 F7 118
1 97 9 105 F2 113 F8 119
2 98 * 106 F3 114 F9 120
3 99 + 107 F4 115 F10 121
4 100 Enter 108 F5 116 F11 122
5 101 - 109 F6 117 F12 123
6 102 . 110
7 103 / 111
控制键键码值(keyCode)
按键 键码 按键 键码 按键 键码 按键 键码
BackSpace 8 Esc 27 Right Arrow 39 -_ 189
Tab 9 Spacebar 32 Dw Arrow 40 .> 190
Clear 12 Page Up 33 Insert 45 /? 191
Enter 13 Page Down 34 Delete 46 `~ 192
Shift 16 End 35 Num Lock 144 [{ 219
Control 17 Home 36 ;: 186 | 220
Alt 18 Left Arrow 37 =+ 187 ]} 221
Cape Lock 20 Up Arrow 38 ,< 188 '" 222
多媒体键码值(keyCode)
按键 键码 按键 键码 按键 键码 按键 键码
音量加 175
音量减 174
停止 179
静音 173
浏览器 172
邮件 180
搜索 170
收藏 171
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
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<title>Document</title>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<style>
#app input {
width: 300px;
border-style: solid;
}
</style>
</head>

<body>
<div id="app">
<input type="text" v-model:value="enter_value" @keyup.enter='enterHandler' placeholder="请输入值之后,按Enter键完成操作!">
<input type="text" v-model:value="f2_value" @keyup.f2='f2Handler' placeholder="请输入值之后,按F2键完成操作!">
</div>
<script>
// 自定义全局按键修饰符
Vue.config.keyCodes.f2 = 113;
new Vue({
el: "#app",
data: {
enter_value: '',
f2_value: ''
},
methods: {
enterHandler: function () {
alert("hello " + this.enter_value);
},
f2Handler: function () {
alert("hello " + this.f2_value);
}
}
});
</script>
</body>

</html>

七、样式绑定

1. class 属性绑定

1.1 数组形式

样式名称数组(此时的样式名称是boolean类型)

1
<div v-bind:class="['active', 'danger']"></div>

或者

数组中使用三元表达式对样式名称计算

1
<div v-bind:class="[isActive?'active':'',!'danger']"></div>

或者

数组中使用对象

1
<div v-bind:class="[!'danger',{active:isActive}]"></div>
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
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<title></title>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<style>
.active {
width: 100px;
height: 100px;
background: green;
}

.danger {
background: red;
}
</style>
</head>

<body>
<div id="vue-app">

<!-- 样式名称数组(此时的样式名称是boolean类型) -->
<div v-bind:class="['active', 'danger']"></div>
<br><br>
<!-- 数组中使用三元表达式对样式名称计算 -->
<div v-bind:class="[isActive?'active':'',!'danger']"></div>
<br><br>
<!-- 数组中使用对象 -->
<div v-bind:class="[!'danger',{active:isActive}]"></div><!-- {active:isActive}是一个对象 -->
</div>

<script>

new Vue({
el: '#vue-app',
data: {
isActive: true
}
});

</script>
</body>

</html>

1557255118063

1.2 对象形式

1
<div v-bind:class="{ key: isActive,danger: false }"></div>

或者

1
<div v-bind:class="classObj"></div>

案例

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
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<title></title>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<style>
.active {
width: 100px;
height: 100px;
background: green;
}

.danger {
background: red;
}
</style>
</head>

<body>
<div id="vue-app">
<!--
v-bind:class的值是一个对象,可以是对象实例,也可以是对象的名称(model的key)
-->

<!-- { active: isActive,danger: false }是一个对象,对象的key对应的值可以是model的key,也可以是boolean值 -->
<div v-bind:class="{ active: isActive,danger: false }"></div>

<br><br>

<!-- classObj是对象的名称(model的key) -->
<div v-bind:class="classObj"></div>
</div>

<script>

new Vue({
el: '#vue-app',
data: {
isActive: true,
classObj: { active: true, danger: true }
}
});

</script>
</body>

</html>

1557254307180

2. style(内联样式)属性绑定

  • 在:style中通过key引用data中的样式对象
1
<h1 :style="styleObj1">这是一个h1</h1>
  • 在:style中通过数组,引用多个data上的样式对象
1
<h1 :style="[ styleObj1, styleObj2 ]">这是一个h1</h1>

案例:

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">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
</head>

<body>
<div id="app">
<!-- 在:style中通过key引用data中的样式对象 -->
<h1 :style="styleObj1">这是一个h1</h1>
<br><br>

<!-- 在:style中通过数组,引用多个data上的样式对象 -->
<h1 :style="[ styleObj1, styleObj2 ]">这是一个h1</h1>
</div>

<script>
// 创建 Vue 实例,得到 ViewModel
var vm = new Vue({
el: '#app',
data: {
styleObj1: { color: 'red', 'font-weight': 200 },
styleObj2: { 'font-style': 'oblique' }
},
methods: {}
});
</script>
</body>

</html>

1557256109862

八、遍历v-for

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
<!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>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
</head>

<body>
<div id="app">

<!-- 一、遍历数字 -->
<!-- in 后面我们放过 普通数组,对象数组,对象, 还可以放数字 -->
<!-- 注意:如果使用 v-for 迭代数字的话,前面的 count 值从 1 开始 -->
<!-- 每遍历一次生成一个v-for绑定的元素 -->
<p v-for="count in 10">这是第 {{ count }} 次循环</p>



<!-- 二、遍历普通数组
(1)通过下标取值
(2)v-for属性遍历
-->
<p>{{list[0]}}</p>
<p>{{list[1]}}</p>
<p v-for="(item, i) in list">索引值:{{i}} --- 每一项:{{item}}</p>


<!-- 三、遍历对象 -->
<!-- 注意:在遍历对象身上的键值对的时候, 除了 有 val key ,在第三个位置还有 一个 索引 -->
<p v-for="(val, key, i) in user">值是: {{ val }} --- 键是: {{key}} -- 索引: {{i}}</p>


<!-- 四、遍历对象数组 -->
<p v-for="(user, i) in users">Id:{{ user.id }} --- 名字:{{ user.name }} --- 索引:{{i}}</p>
</div>

<script>
// 创建 Vue 实例,得到 ViewModel
var vm = new Vue({
el: '#app',
data: {
list: [1, 2, 3, 4, 5, 6],
user: {
id: 1,
name: '托尼·屎大颗',
gender: '男'
},
users: [
{ id: 1, name: 'zs1' },
{ id: 2, name: 'zs2' },
{ id: 3, name: 'zs3' },
{ id: 4, name: 'zs4' }
]
},
methods: {}
});
</script>
</body>

</html>

九、条件判断

1. v-if

v-if 指令将根据表达式的值(true 或 false )来决定是否插入绑定的元素。

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">
<title>v-if</title>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<style>
p {
width: 100px;
height: 100px;
text-align: center;
line-height: 100px;
background: red;
}
</style>
</head>

<body>
<div id="vue-app">
<!-- v-if 指令将根据表达式的值(true 或 false )来决定是否插入绑定的元素。 -->
<p v-if="flag1">p1</p>
<p v-if="flag2">p2</p>
</div>
<script>
// 创建 Vue 实例,得到 ViewModel
var vm = new Vue({
el: '#vue-app',
data: {
flag1: false,
flag2: true
}
});
</script>
</body>

</html>

1557259657326

2. v-if、v-else和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
27
28
29
30
31
32
33
34
35
36
<!DOCTYPE html>
<html>

<head>
<meta charset="utf-8">
<title>v-if、v-else、v-else-if</title>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
</head>

<body>
<div id="app">
<div v-if="type === 'A'">
A
</div>
<div v-else-if="type === 'B'">
B
</div>
<div v-else-if="type === 'C'">
C
</div>
<div v-else>
Not A/B/C
</div>
</div>

<script>
new Vue({
el: '#app',
data: {
type: 'C'
}
})
</script>
</body>

</html>

1557260458595

3. 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
30
31
32
33
34
35
36
37
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<title>v-show</title>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<style>
p {
width: 100px;
height: 100px;
text-align: center;
line-height: 100px;
background: red;
}
</style>
</head>

<body>
<div id="vue-app">
<!--根据条件展示或者隐藏元素(而不是像v-if那样插入或者删除元素) -->
<p v-show="flag1">p1</p>
<p v-show="flag2">p2</p>
</div>
<script>
// 创建 Vue 实例,得到 ViewModel
var vm = new Vue({
el: '#vue-app',
data: {
flag1: false,
flag2: true
}
});
</script>
</body>

</html>

1557260075930

4. v-if和v-show的区别

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">
<title>v-if和v-show</title>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
</head>
<body>
<div id="app">
<!-- 需求:通过点击修改flag的值。 -->
<!--
v-if 的特点:每次都会重新删除或创建元素。有较高的切换性能消耗。
v-show 的特点: 每次不会重新进行DOM的删除和创建操作,只是切换了元素的 display:none 样式。有较高的初始渲染消耗

选择:
如果元素涉及到频繁的切换,最好不要使用 v-if, 而是推荐使用 v-show。
如果元素可能永远也不会被显示出来被用户看到,则推荐使用 v-if。
-->

<input type="button" value="toggle" @click="flag=!flag">
<h3 v-if="flag">这是用v-if控制的元素</h3>
<h3 v-show="flag">这是用v-show控制的元素</h3>
</div>
<script>
// 创建 Vue 实例,得到 ViewModel
var vm = new Vue({
el: '#app',
data: {
flag: false
}
});
</script>
</body>
</html>

vifvshow

十、基础语法要点总结

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
1. MVC 和 MVVM 的区别

2. 学习了Vue中最基本代码的结构

3. 插值表达式 v-cloak v-text v-html v-bind(缩写是:) v-on(缩写是@) v-model v-for v-if v-show

4. 事件修饰符 : .stop .prevent .capture .self .once

5. el 指定要控制的区域 data 是个对象,指定了控制的区域内要用到的数据 methods 虽然带个s后缀,但是是个对象,这里可以自定义了方法

6. 在 VM 实例中,如果要访问 data 上的数据,或者要访问 methods 中的方法, 必须带 this

7. 在 v-for 要会使用 key 属性 (只接受 string / number)

8. v-model 只能应用于表单元素 -->

9. 在vue中绑定样式两种方式 v-bind:class v-bind:style

十一、过滤器

概念:Vue.js 允许自定义过滤器,可被用作一些常见的文本格式化。过滤器可以用在两个地方:插值表达式和 v-bind 表达式。过滤器应该被添加在 JavaScript 表达式的尾部,由**“管道”**符指示。

过滤器调用的格式:

1
{{ name | 过滤器的名称(实参列表) }}

过滤器的定义语法:

  • 全局过滤器
1
2
3
Vue.filter('过滤器的名称', function(过滤器的参数列表){
//过滤器做的处理
})
  • 私有(局部)过滤器
1
2
3
4
5
filters: {
过滤器的名称: function (过滤器的参数列表) {
//过滤器做的处理
}
}

第一个参数是管道前的内容,第二个之后的参数是过滤器调用方法的实参列表。

1. 全局过滤器

对所有VM 对象所控制的 View 区域都起作用。

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">
<title>Document</title>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
</head>

<body>
<div id="app1">
<h1>app1</h1>
<p>过滤前的内容:{{ msg}}</p>
<p>经全局过滤器处理后: {{ msg | globalFormat('global', 'filter')}}</p>
</div>

<div id="app2">
<h1>app2</h1>
<p>过滤前的内容:{{ msg}}</p>
<p>经全局过滤器处理后: {{ msg | globalFormat('global', 'filter')}}</p>
</div>

<script>
//定义全局过滤器(对所有VM对象所控制的View区域都起作用。)
Vue.filter('globalFormat', function (msg, arg, arg2) {//定义一个 Vue 全局的过滤器,名字叫做 localFormat,第一个参数是管道前的内容,其余参数是localFormat()过滤器方法的实参
//过滤器做的处理
return msg.replace(/vue/g, arg + " " + arg2);//字符串的 replace 方法,第一个参数,除了可写一个 字符串之外,还可以定义一个正则

});

var vm1 = new Vue({
el: '#app1',
data: {
msg: 'hello vue1'
}
});

var vm2 = new Vue({
el: '#app2',
data: {
msg: 'hello vue2'
}
});
</script>
</body>

</html>

1557382875950

2. 私有过滤器

私有(局部)过滤器。只能在当前 VM 对象所控制的 View 区域起作用

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">
<title>Document</title>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
</head>

<body>
<div id="app1">
<h1>app1</h1>
<p>过滤前的内容:{{ msg}}</p>
<p>经全局过滤器处理后: {{ msg | localFormat('local', 'filter')}}</p>
</div>

<div id="app2">
<h1>app2</h1>
<p>过滤前的内容:{{ msg}}</p>
<p>经全局过滤器处理后: {{ msg | localFormat('local', 'filter')}}</p>
</div>

<script>
var vm1 = new Vue({
el: '#app1',
data: {
msg: 'hello vue1'
},
filters: {
//定义私有(局部)过滤器。只能在 当前 VM 对象所控制的 View 区域起作用
localFormat: function (msg,arg,arg2) {//默认将管道前的内容当作localFormat()过滤器方法的第一个实参,其余参数是localFormat()过滤器方法的实参
//过滤器做的处理
return msg.replace(/vue/g, arg + " " + arg2);//字符串的 replace 方法,第一个参数,除了可写一个 字符串之外,还可以定义一个正则
}
}
});

var vm2 = new Vue({
el: '#app2',
data: {
msg: 'hello vue2'
}
});
</script>
</body>

</html>

1557382743418

十二、自定义指令

除了核心功能默认内置的指令 (v-modelv-show),Vue 也允许注册自定义指令。

实现自定义指令可以是全局的,也可以是局部的。全局指的是所有vue对象的控制区域,局部指的是当前定义指令所在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
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<title>Document</title>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
</head>

<body>
<div id="app">
<!-- 如果需要给自定义指令传参,那么需要在双引号里使用单引号把实参包含住,否则会报错 -->
<input type="text" v-focus v-color="'green'">
</div>
<script>
/*注册全局自定义指令 v-focus*/
/*
使用 Vue.directive() 定义全局的指令 v-focus
其中:
参数1 : 指令的名称,注意,在定义的时候,指令的名称前面,不需要加 v- 前缀, 但是: 在调用的时候,必须 在指令名称前 加上 v- 前缀来进行调用
参数2: 是一个对象,这个对象身上,有一些指令相关的函数,这些函数可以在特定的阶段,执行相关的操作。常用的有三个方法:1.bind() 2.inserted() 3.updated()。一般动作指令在inserted()中调用,而样式等在bind()中调用。
*/
Vue.directive('focus', {
bind: function (el) { // 每当指令绑定到元素上的时候,会立即执行这个 bind 函数,只执行一次
// 注意: 在每个 函数中,第一个参数,永远是 el ,表示 被绑定了指令的那个元素,这个 el 参数,是一个原生的JS对象
// 在元素 刚绑定了指令的时候,还没有 插入到 DOM中去,这时候,调用 focus 方法没有作用
// 因为,一个元素,只有插入DOM之后,才能获取焦点
// el.focus()
},
// 当被绑定的元素插入到 DOM 中时……
inserted: function (el) {
// 聚焦元素
el.focus();
},
updated: function (el) { // 当VNode更新的时候,会执行 updated, 可能会触发多次

}
});

/*注册全局指令v-color*/
Vue.directive('color', {
bind: function (el, binding) {
el.style.color = binding.value;
}
});

new Vue({
el: "#app",
/*注册局部自定义指令 v-focus,如果全局和局部自定义指令的名称相同,那么vue会采取就近原则。*/
directives: {
focus: {
// 指令的定义
inserted: function (el) {
el.focus();
}
},
color: function (el, binding) {
el.style.color = binding.value;
}
}
});
</script>
</body>

</html>

十三、vue实例的生命周期

1. 概念

  • 什么是生命周期:从Vue实例创建、运行、到销毁期间,总是伴随着各种各样的事件,这些事件,统称为生命周期!
  • 生命周期钩子:就是生命周期事件的别名;
  • 生命周期钩子 = 生命周期函数 = 生命周期事件

lifecycle

2. 生命周期函数分类

  • 创建期间的生命周期函数

    1
    2
    3
    4
    (1)beforeCreate //实例刚在内存中被创建出来,此时,还没有初始化好 data 和 methods 属性
    (2)created //实例已经在内存中创建OK,此时 data 和 methods 已经创建OK,此时还没有开始 编译模板
    (3)beforeMount //此时已经完成了模板的编译,但是还没有挂载到页面中
    (4)mounted //此时,已经将编译好的模板,挂载到了页面指定的容器中显示
  • 运行期间的生命周期函数

    1
    2
    (1)beforeUpdate //状态更新之前执行此函数, 此时 data 中的状态值是最新的,但是界面上显示的 数据还是旧的,因为此时还没有开始重新渲染DOM节点
    (2)updated //实例更新完毕之后调用此函数,此时 data 中的状态值 和 界面上显示的数据,都已经完成了更新,界面已经被重新渲染好了!
  • 销毁期间的生命周期函数

    1
    2
    (1)beforeDestroy //实例销毁之前调用。在这一步,实例仍然完全可用。
    (2)destroyed //Vue 实例销毁后调用。调用后,Vue 实例指示的所有东西都会解绑定,所有的事件监听器会被移除,所有的子实例也会被销毁。

十四、http数据请求

vue实现http数据请求有很多种第三方包可以实现。主要有两种插件包可以使用。

1. vue-resource

下载地址:https://github.com/pagekit/vue-resource

以get请求举例:

1
2
3
4
5
6
7
8
{
// GET /someUrl
this.$http.get('/someUrl').then(response => {
// success callback
}, response => {
// error callback
});
}

按照作用域可分为:

1
2
3
4
5
6
7
// global Vue object
Vue.http.get('/someUrl', [config]).then(successCallback, errorCallback);
Vue.http.post('/someUrl', [body], [config]).then(successCallback, errorCallback);

// in a Vue instance
this.$http.get('/someUrl', [config]).then(successCallback, errorCallback);
this.$http.post('/someUrl', [body], [config]).then(successCallback, errorCallback);

其他请求方式:

1
2
3
4
5
6
7
get(url, [config])
head(url, [config])
delete(url, [config])
jsonp(url, [config])
post(url, [body], [config])
put(url, [body], [config])
patch(url, [body], [config])

更多教程参考官方文档https://github.com/pagekit/vue-resource/blob/develop/docs/http.md

2. axios

这是重点,在后面的脚手架工程中另作介绍…

十五、基于脚手架的vue工程

img

工程搭建步骤

1. 安装node.js

官网下载最新版本后默认next傻瓜式安装完成。

2. 安装cnpm

为了npm下载包更快更流畅,可以改用国内淘宝镜像工具cnpm

1
$ npm install -g cnpm --registry=https://registry.npm.taobao.org

3. 安装webpack

1
$ cnpm install webpack -g

4. 安装vue脚手架(命令行工具)

使用node自带的npm包管理器安装vue-cli

1
$ npm install vue-cli -g

更多npm命令详解:

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
##安装包
$ npm install #默认根据项目下的 package.json的包配置安装对应的包
$ npm install <包名> -S #即 npm install module_name –save 写入package.json dependencies,用于生产环境
$ npm install <包名> -D #即npm install module_name –save-dev 写入package.json的devDependencies,用于开发环境
$ npm install <包名> #本地安装(将安装包放在 ./node_modules 下)不写入package.json;
$ npm install <包名> -g #全局安装(命令行使用)


##树型结构列出当前项目安装的所有模块,以及它们依赖的模块。
$ npm list #列出已安装的模块。
$ npm list -global #加上global参数,会列出全局安装的模块。
$ npm list underscore #列出单个模块。


##卸载删除包
$ npm uninstall <包名> #删除xxx包;
$ npm uninstall -g <包名> #删除全局包xxx


##更新包
npm update <包名> #更新当前项目中安装的某个包
npm update #更新当前项目中安装的所有包
npm update <包名> -g #更新全局安装的包

##搜索包
$ npm search <关键字>



##初始化package.json
#根据交互问答产生一个符合标准的 package.json,如果使用了-f(代表force)、-y(代表yes),则跳过提问阶段,直接生成一个新的package.json文件。
npm init

##设置环境变量
#上面命令等于为npm init设置了默认值,以后执行npm init的时候,package.json的作者姓名、邮件、主页、许可证字段就会自动写入预设的值。这些信息会存放在用户主目录的 ~/.npmrc文件,使得用户不用每个项目都输入。如果某个项目有不同的设置,可以针对该项目运行npm config。
$ npm set init-author-name 'Your name'
$ npm set init-author-email 'Your email'
$ npm set init-author-url 'http://yourdomain.com'
$ npm set init-license 'MIT'

##列出npm的配置
$ npm config list -l

5. 建立工程

5.1 方式1 使用webpack创建工程

1
$ vue init webpack demo1  #demo1是工程名字,工程名字不能用中文

1558582828210

等待工程初始化并下载依赖包,构建完成后,执行以下命令

1
2
3
$ cd demo1 #进入工程项目
$ cnpm install #再次安装依赖,防止init的时候安装错误,如果vue ini不报错可以省略此步
$ npm run dev #启动项目

5.2 方式2 使用vue脚手架创建工程

5.2.1 根据模板创建项目

1
$ vue init webpack-simple demo2   #demo2是工程目录的名字,工程名字不能用中文,如果不加工程名,则默认以当前目录作为工程目录

1558584929855

相比于方式1步骤更简单,省略了很多提示步骤

等待工程初始化并下载依赖包,构建完成后,执行以下命令

1
2
3
4
$ cd demo2
$ cnpm install #安装项目依赖
$ cnpm install vue-router --save #为了与方式1同步,这里也安装路由模块。当然可以等到需要的时候再单独安装
$ npm run dev #启动项目

6. 工程目录和文件介绍

以上面第二种方式创建的工程做介绍

6.1 工程目录

1
2
3
4
5
6
7
8
9
10
11
.
├── README.md #项目介绍文件,可删除
├── index.html #首页入口文件。(重点)
├── node_modules #加载的项目依赖模块
├── package.json #项目配置文件,包含依赖等配置(重点)
├── src #资源文件目录(重点)
│   ├── App.vue #根组件
│   ├── assets #图片资源目录
│   │   └── logo.png
│   └── main.js #入口js文件,项目的核心文件
└── webpack.config.js #webpack配置文件

6.2 重要工程文件详解

inde.html

1
2
3
4
5
6
7
8
9
10
11
12
<!-- 首页入口文件 -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>demo2</title>
</head>
<body>
<div id="app"></div>
<script src="/dist/build.js"></script> <!-- 指定webpack编译生成的js路径,这个js文件是入口js文件main.js的编译结果 -->
</body>
</html>

main.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
/**
* 入口js文件,项目的核心文件
*/
import Vue from 'vue' //导入vue包
import App from './App.vue' //导入组件


/*
new Vue({
el: '#app',
render: function (createElements) { // createElements 是一个 方法,调用它,能够把 指定的 组件模板,渲染为 html 结构
return createElements(App) // 注意:这里 return 的结果,会 替换页面中 el 指定的那个 容器
}
})
*/

// 创建 Vue 实例,得到 ViewModel
new Vue({
el: '#app',
render: h => h(App)
/*箭头函数,用于简写函数(箭头前是函数参数,箭头后是函数的返回值,h相当于createElements),
而h(App)相当于return createElements(App),和上面的render: function (createElements) { }
渲染函数意义一样,渲染App组件到el对应的根节点中去,会将组件替代掉el对应的标签元素,这样做的好处
是不需要在html中写组件标签*/
})

App.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
<!--
根组件
.vue组件文件由三部分组成:
1. 模版<template>
2. js脚本<script>
3. 样式<style>
-->
<template>
<!-- template里有且仅有一个并行根节点,但是根节点里可以有多个并行节点 -->
<div id="app">{{msg}}</div>
</template>

<script>
export default {
name: "app",
data() {
return {
msg: "Hello Vue !"
};
}
};
</script>

<style>
#app {
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>

7. 单文件组件

.vue文件,称为单文件组件,是Vue.js自定义的一种文件格式,一个.vue文件就是一个单独的组件,在文件内封装了组件相关的代码:htmlcssjs

.vue组件文件由三部分组成:

  • 模版<template>

  • js脚本<script>

  • 样式<style>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/**
* 一、在ES6中,通过规范的形式规定了如何导入和导出模块
* 导入模块:
* 1.导入外部的变量或函数等;
* import "模块名称" from "模块标识符(路径)"; //对于export default导出时使用
* import {key1, key2, key3} from "模块标识符(路径)"; //对于export导出时使用
* 2.导入外部的模块,并立即执行
* import "路径";
*
* 导出模块(暴露成员):
* 1.export default
* 2.export
*
*二、export default和export
* 1. export default 向外暴露的成员,可以使用任意名称的变量来接收
* 2. 在一个模块(文件)中,export default只允许向外暴露1次
* 3. 在一个模块(文件)中,可以同时使用一个export default和多个export向外暴露成员
* 4. 使用export向外暴露成员时,只能使用{暴露的成员名称}的形式接收,多个则用逗号隔开,而不需要的成员则可以不再{}中定义,这种行为叫做“按需导出”
* 5. 使用export导出的成员,如果需要引入则必须严格按照导出时定义的变量名称在{}中定义接收
* 6. 使用export导出的成员,如果需要引入,如果不希望使用导出时定义的变量名称,可以使用{导出时定义的变量名称 as 别名}的形式修改
*/

App.css

1
2
3
*{
color: #8a2be2;
}

App.js

1
alert("执行app.js");

App.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
43
44
45
46
47
<template>
<!-- template里有且仅有一个并行根节点,但是根节点里可以有多个并行节点 -->
<div id="app">
<!-- 3.在模版中使用引入的组件 -->
<v-home></v-home>

<button @click="getHomeInfo">点击按钮</button>
</div>
</template>

<script>
//导入外部的变量或函数等
import Home from "./components/Home";
import { num, title as myTitle, user } from "./components/Home";

//导入外部的模块,并立即执行
import "./css/app.css";
import "./js/app.js";

export default {
name: "app",
data() {
return {
appMsg: "This is App.vue !"
};
},
methods: {
getHomeInfo: function() {
console.log("num:" + num);
console.log("myTitle:" + myTitle);
console.log("user:");
console.log(user);
}
},
components: {
/*挂载组件
1.key/value形式,key是元素标签的名称
2.value形式,value的名称就是元素标签的名称
*/
"v-home": Home //key/value形式
// Home //value形式
}
};
</script>

<style>
</style>

Home.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
<template>
<div id="home">
<h3>{{homeMsg}}</h3>
</div>
</template>

<script>

//暴露组件对象
export default {
data() {
return {
homeMsg: "this is Home.vue !"
};
}
};

//暴露title变量
export var title = "Home Title";

export var num = 100;

//暴露user对象
export var user = {
username: "wangwu",
age: 20
};
</script>
<style scoped>
</style>

vuefile

8. 组件的数据交互

8.1.组件间传值

8.1.1 父组件传子组件

(1).在父组件设置prop绑定动态属性或者静态属性。

设父组件的数据为:

1
<v-content home2content="静态传的prop数据" v-bind:user="user" v-bind:homefuc="homefuc" v-bind:home="homeobj"/>

其中home2content是静态字符串属性,user是动态对象属性,homefuc是动态方法属性,home是动态对象属性

(2) 在子组件通过props数组或者对象属性接收父组件传过来的数据。

  • props数组:
1
props: ["user", "home2content","homefuc","home"]
  • props对象:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    props: {  //在子组件通过props对象属性接收父组件可以验证传来的数据
    "user":Object,
    "home2content":{
    type:String, //验证数据类型
    required: true, //必填的字符串
    default: 'xxxxx' 带有默认值
    },
    // 自定义验证函数
    propF: {
    validator: function (value) {
    // 这个值必须匹配下列字符串中的一个
    return ['success', 'warning', 'danger'].indexOf(value) !== -1
    }
    }
    }

(3) 在子组件的<template>或者<script>直接引用

1
2
3
4
5
6
7
8
9
10
11
 <template>
<div id="content">
{{contentMsg}}
<div>
<div>动态prop: </div>
user.username:{{user.username}}、
home.user.sex:{{home.user.sex}}</div>
<div>静态prop: {{home2content}}</div>
<button v-on:click="homefuc()">点击按钮</button>
</div>
</template>
8.1.2 子组件传父组件

(1).在父组件中:

  • (1.1)在父组件中定义有参函数
1
2
3
函数名: function(value) {
//value就是子组件传送的值
}
  • (1.2)设置prop绑定动态方法属性。

    1
    <v-content v-bind:函数名="函数名"/>

(2).在子组件中:

  • (2.1)通过props数组或者对象属性接收父组件传过来的数据
1
props: ["函数名"]
  • (2.2)子组件调用父组件方法的同时传入子组件的数据到方法的实参
1
函数名(子组件的数据)
8.1.3 非父子组件传值(通过事件广播的方式实现)

(1)首先新建一个js文件,在文件中实例一个Vue对象,并暴露出来,内容为:

1
2
3
import Vue from 'vue'
var vueEvent = new Vue();
export default vueEvent;

(2) 在发送数据的组件中引用以上js文件,并发起事件广播

  • (2.1)引用js文件:
1
import vueEvent from 'js文件路径'
  • (2.2)发起事件广播
1
vueEvent.$emit('广播名称',数据); //发送广播

(3) 在接收方组件的生命周期函数(如mounted)中监听广播事件

1
2
3
vueEvent.$on('广播名称',function(data){ //监听广播事件,function(data)中的data就是监听到的数据
//获取data并可用于操作
});

8.2 主动获取数据

就是不需要在传入方通过绑定属性的方式传值

8.2.1父组件主动获取子组件数据方式:

(1)在调用子组件的时候定义ref属性

1
2
<v-content ref="任意变量名"/>
如:<v-content ref="content"/>

(2)在父组件通过以下方式获取子组件的值

1
2
this.$refs.content.子组件属性
this.$refs.content.子组件方法
8.2.2子组件主动获取父组件数据方式:

在子组件中通过以下方式获取父组件的数据(不需要定义ref属性)

1
2
this.$parent.父组件属性
this.$parent.父组件方法

8.3 vuex

如果多个组件依赖于同一状态。传参的方法对于多层嵌套的组件和兄弟组件会非常繁琐。这时有必要学习vuex,来解决这个问题。

官网:https://vuex.vuejs.org/zh/

Vuex是一个专为Vue.js 应用程序开发的状态管理模式

主要作用是:

  • 解决不同组件间同一状态(数据)共享问题。
  • 组件的数据持久化
8.3.1 安装vuex
1
$ npm install vuex --save
8.3.2 引入和注册vuex

main.js中引入 vuex

1
2
3
4
5
import Vue from 'vue'

//引入Vuex并注册到Vue中
import Vuex from 'vuex'
Vue.use(Vuex)
8.3.3 创建和使用数据仓库

该文件的主要功能就是提供给各个组件一个数据交互中心(数据仓库),数据仓库里主要包含数据项操作数据的方法。原理是注册storeVue中,各个组件通过引入数据仓库文件后,就可通过 this.$store 访问到store中的数据和方法了。

例如:

  • (1)state和mutations的使用

数据仓库文件store.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/*1.导入并注册Vuex到Vue中*/
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex);


/*2.使用 vuex 实例化 Vuex.store*/
const store = new Vuex.Store({
/*3.state在vuex中用于存储数据*/
state: {
count: 1
},
/*4.mutations里面放的是方法,方法主要用于操作state里面的数据*/
mutations: {
incCount() {
++this.state.count;
}
}
})


/**5.导出(暴露)出数据仓库 */
export default store;

组件1:About.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
<template>
<div id="about">
about组件:
<button @click="toIncCount()">增加数量</button>
<!--2.通过 this.$store 访问到store中的数据 -->
当前store的数据:{{this.$store.state.count}}
</div>
</template>

<script>
//1.引入store
import store from "../vuex/store.js";

export default {
store: store,
methods: {
toIncCount() {
/*3.通过 this.$store 访问到store中的方法,更改 Vuex 的 store 中的状态的唯一方法是提交 mutation */
this.$store.commit("incCount");
}
}
};
</script>

<style scoped>
div {
border: solid 2px red;
margin: 20px;
}
</style>

组件2: Home.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
<template>
<div id="home">
home组件:
<button @click="toIncCount()">增加数量</button>
<!--2.通过 this.$store 访问到store中的数据 -->
当前store的数据:{{this.$store.state.count}}
</div>
</template>

<script>
//1. 引入store
import store from "../vuex/store.js";

export default {
data() {
return {};
},
store: store,
methods: {
toIncCount() {
/*3.通过 this.$store 访问到store中的方法,更改 Vuex 的 store 中的状态的唯一方法是提交 mutation */
this.$store.commit("incCount");
}
}
};
</script>
<style scoped>
div {
border: solid 2px #42109e;
margin: 20px;
}
</style>

效果:

vuex

  • (2)getters和actions的使用

数据仓库文件store.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
31
32
33
34
35
36
37
38
/*1.导入并注册Vuex到Vue中*/
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex);


/*2.使用 vuex 实例化 Vuex.store*/
const store = new Vuex.Store({
/*3.state在vuex中用于存储数据*/
state: {
count: 1
},
/*4.mutations里面放的是方法,(1)方法主要用于操作state里面的数据;(2)mutation 必须是同步函数。(重点)*/
mutations: {
//自定义mutations方法
incCount() {
++this.state.count;
}
},
/*5.类似计算属性,改变state里面的count数据的时候会触发 getters里面的方法 获取新的值 (基本用不到) */
getters: {
//自定义getters方法
computedCount: (state) => {
return state.count * 2
}
},
/*6.类似于 mutation,不同在于:(1)Action 提交的是 mutation,而不直接变更数据的状态。(2)Action 可以包含任意异步操作。(基本用不到) */
actions: {
//自定义actions方法
incMutationsCount(context) {
context.commit('incCount'); /*执行 mutations 里面的incCount方法 改变state里面的数据*/
}
}
})


/*7.导出(暴露)出数据仓库 */
export default store;

组件1 Home.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
<template>
<div id="home">
home组件:
<button @click="toIncCount()">增加数量</button>
<button @click="toAction()">触发actions的方法</button>

当前store的数据:{{this.$store.state.count}}
当前store getters的计算属性:{{this.$store.getters.computedCount}} <!-- 2.触发了getters的computedCount()方法 -->
</div>
</template>

<script>
//1. 引入store
import store from "../vuex/store.js";

export default {
data() {
return {};
},
store: store,
methods: {
toIncCount() {
this.$store.commit("incCount");
},
toAction(){
this.$store.dispatch('incMutationsCount'); /*3.触发 actions里面的方法 */
}
}
};
</script>
<style scoped>
div {
border: solid 2px #42109e;
margin: 20px;
}
</style>

组件2 About.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
<template>
<div id="about">
about组件:
<button @click="toIncCount()">增加数量</button>
当前store的数据:{{this.$store.state.count}}
</div>
</template>

<script>
import store from "../vuex/store.js";

export default {
store: store,
methods: {
toIncCount() {
this.$store.commit("incCount");
}
}
};
</script>

<style scoped>
div {
border: solid 2px red;
margin: 20px;
}
</style>

效果:

vuex2

9. 路由

官网教程https://router.vuejs.org/zh/

控制组件之间的跳转,不会请求页面、不用页面刷新,直接跳转-切换组件

安装:

1
$ cnpm install vue-router --save

9.1 普通路由

Home.vue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<template>
<div id="home">
<h3>{{homeMsg}}</h3>
</div>
</template>

<script>

//暴露组件对象
export default {
data() {
return {
homeMsg: "Welcome to Home !"
};
}
};

</script>
<style scoped>
</style>

About.vue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<template>
<div id="about">
<h2>{{aboutMe}}</h2>
</div>
</template>

<script>
//暴露组件对象
export default {
data() {
return {
aboutMe:'I am Qcmoke !'
}
}
}
</script>

<style>

</style>

main.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
import Vue from 'vue'
import VueRouter from 'vue-router' // 1. 导入 vue-router 包,安装方法:cnpm install vue-router --save

// 2. 手动安装 VueRouter
Vue.use(VueRouter)


// 3.导入组件
import App from './App.vue'
import Home from './components/Home'
import About from './components/About'

// 4. 创建路由对象(全局)
var router = new VueRouter({
routes: [
//将组件映射到路由
//path 指请求路径,component指的是组件
{ path: '/home', component: Home },
{ path: '/about', component: About },
{ path: '/*', component: Home } //默认进入展示Home
]
})



new Vue({
el: '#app',
render: h => h(App),
router // 5. 将路由对象挂载到 vm 上,(缩写) 相当于 routes: routes
})

App.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
<template>
<div id="app">

<!--
6.渲染路由
-->

<!-- 路由入口 -->
<!-- 使用 router-link 组件来导航,<router-link> 默认会被渲染成一个 `<a>` 标签 -->
<!-- 通过传入 `to` 属性指定链接. -->
<router-link to="/home">Home</router-link>
<router-link to="/about">About</router-link>

<!-- 路由出口 -->
<!-- 路由匹配到的组件将渲染在这里 -->
<router-view></router-view>
</div>
</template>

<script>
export default {
name: "app",
data() {
return {
msg: "Welcome to Your Vue.js App"
};
}
};
</script>

<style>
</style>

9.2 带有嵌套关系的路由

Home.vue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<template>
<div id="home">
<h3>{{homeMsg}}</h3>
</div>
</template>

<script>

//暴露组件对象
export default {
data() {
return {
homeMsg: "Welcome to Home !"
};
}
};

</script>
<style scoped>
</style>

About.vue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<template>
<div id="about">
<h2>{{aboutMe}}</h2>
</div>
</template>

<script>
//暴露组件对象
export default {
data() {
return {
aboutMe:'I am Qcmoke !'
}
}
}
</script>

<style>

</style>

Login.vue

1
2
3
4
5
6
7
8
9
10
11
12
<template>
<div id="login">
<div>to login</div>
</div>
</template>
<script>
export default {};
</script>

<style>

</style>

Register.vue

1
2
3
4
5
6
7
8
9
10
11
<template>
<div id="register">
<div>to register</div>
</div>
</template>
<script>
export default {};
</script>

<style>
</style>

routes.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
import VueRouter from 'vue-router' // 1. 导入 vue-router 包,安装方法:cnpm install vue-router --save

// 2.导入组件
import Home from './components/Home'
import About from './components/About'
import Account from './components/Account'
import Login from './components/Login'
import Register from './components/Register'

// 3. 创建含有嵌套关系的路由对象(全局)
var router = new VueRouter({
routes: [
//将组件映射到路由
//path 指请求路径,component指的是组件
{
path: '/account',
component: Account,
children: [
{ path: 'login', component: Login },
{ path: 'register', component: Register }
]
},
{ path: '/home', component: Home },
{ path: '/about', component: About },
{ path: '/*', component: Home } //默认进入展示Home

]
})

export default router;

main.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import Vue from 'vue'


import VueRouter from 'vue-router'
// 4. 手动安装 VueRouter
Vue.use(VueRouter)


import App from './App.vue'


import router from './routes.js'


new Vue({
el: '#app',
render: h => h(App),
router // 5. 将路由对象挂载到 vm 上,(缩写) 相当于 routes: routes
})

App.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
<template>
<div id="app">
<!--
6.渲染路由
-->

<!-- 路由入口 -->
<!-- 使用 router-link 组件来导航,<router-link> 默认会被渲染成一个 `<a>` 标签 -->
<!-- 通过传入 `to` 属性指定链接. -->
<router-link to="/home">Home</router-link>
<router-link to="/about">About</router-link>
<router-link to="/account">Account</router-link>

<!-- 路由出口 -->
<!-- 路由匹配到的组件将渲染在这里 -->
<router-view></router-view>
</div>
</template>

<script>
export default {
name: "app",
data() {
return {
msg: "Welcome to Your Vue.js App"
};
}
};
</script>

<style>

</style>

Account.vue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<template>
<div id="account">
<router-link to="/account/login">Login</router-link>

<router-link to="/account/register">Register</router-link>

<router-view></router-view>
</div>
</template>
<script>
export default {};
</script>

<style scoped>
</style>

10. axios

10.1 简介

Axios 是一个基于 promise 的 HTTP 库,可以用在浏览器和 node.js 中。

  • 从浏览器中创建 XMLHttpRequests
  • 从 node.js 创建 http 请求
  • 支持 Promise API
  • 拦截请求和响应
  • 转换请求数据和响应数据
  • 取消请求
  • 自动转换 JSON 数据
  • 客户端支持防御 XSRF

10.2 安装

1
$ npm install --save axios

10.3 使用

导入包

1
import Axios from "axios";

请求:

1
2
3
4
5
6
7
Axios.get("api_url")
.then(response => { //请求成功时回调
//请求成功时做的处理
})
.catch(function(error) {//请求失败时回调
//请求失败时做的处理
});

简单案例

AxiosDemo.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
<template>
<div id="axiosdemo">
<button @click="show">点我AxiosDemo</button>
<div class="show" v-show="showText">{{content}}</div>
</div>
</template>

<script>
import Axios from "axios"; //npm install --save axios

export default {
name: "axiosDemo",
data() {
return {
content: "",
showText: false
};
},
mounted() {
Axios.get("https://api.coindesk.com/v1/bpi/currentprice.json")
.then(response => {
this.content = response.data.bpi;
console.log("ok");
})
.catch(function(error) {
console.log(error);
});
},
methods: {
show() {
this.showText = !this.showText;
}
}
};
</script>
<style scoped>
</style>

10.4 vue-axios

vue-axios是用于将axios集成到Vuejs的小包装器,作用是扩展Vue对象的功能,即让Vue对象具有axios功能,相对原生使用vue-axios会带来更多的便利。

安装:

1
$ npm install --save  vue-axios

使用:

导入vue、axios、vue-axios三个包

1
2
3
import Axios from "axios";
import VueAxios from "vue-axios";
import Vue from "vue";

安装VueAxios和Axios到Vue中

1
Vue.use(VueAxios, Axios);

请求使用

1
2
3
4
5
6
7
8
9
10
11
Vue.axios.get(api).then((response) => {
console.log(response.data)
})

this.axios.get(api).then((response) => {
console.log(response.data)
})

this.$http.get(api).then((response) => {
console.log(response.data)
})

案例:

VueAxiosDemo.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
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
<template>
<div id="vueaxios">
<button @click="getDateForVueaxios1()">点击我vueaxios1</button>
<button @click="getDateForVueaxios2()">点击我vueaxios2</button>
<button @click="getDateForVueaxios3()">点击我vueaxios3</button>
<button @click="getDateForVueaxios4()">点击我vueaxios4</button>

<div id="view">{{content}}</div>
</div>
</template>

<script>
/*
https://www.npmjs.com/package/vue-axios

npm install --save axios vue-axios
*/
import Axios from "axios";
import VueAxios from "vue-axios";//vue-axios是用于将axios集成到Vuejs的小包装器,作用是扩展Vue对象的功能,即让Vue对象具有axios功能

import Vue from "vue";
//安装VueAxios和Axios到Vue中
Vue.use(VueAxios, Axios);

export default {
data() {
return {
content: ""
};
},
methods: {
getDateForVueaxios1() {
var api = "https://api.coindesk.com/v1/bpi/currentprice.json";
Axios.get(api) //使用原生Axios
.then(response => {
this.content = response.data;
console.log("response.data");
})
.catch(function(error) {
console.log(error);
});
},
getDateForVueaxios2() {
var api = "https://api.coindesk.com/v1/bpi/currentprice.json";
Vue.axios.get(api).then(response => {
this.content = response.data;
console.log("response.data");
});
},
getDateForVueaxios3() {
var api = "https://api.coindesk.com/v1/bpi/currentprice.json";
this.axios.get(api).then(response => {
this.content = response.data;
console.log("response.data");
});
},
getDateForVueaxios4() {
var api = "https://api.coindesk.com/v1/bpi/currentprice.json";
this.$http.get(api).then(response => {
this.content = response.data;
console.log("response.data");
});
}
}
};
</script>

<style>
</style>

11. element-ui

官网:https://element.eleme.io/#/zh-CN

11.1 安装element-ui

1
$ npm i element-ui -S

11.2 引入element-ui和element的css

1
2
import ElementUI from 'element-ui' //完整引入所有的element-ui
import 'element-ui/lib/theme-chalk/index.css'

11.3 Vue安装element-ui

1
Vue.use(ElementUI)

11.4 配置webpack的loader规则

element-uicss文件中会使用到ttf文件,所以需要到webpack.config.js中配置以下loader规则

1
2
3
4
{
test: /\.(eot|svg|ttf|woff|woff2)(\?\S*)?$/,
loader: 'file-loader'
}

11.5 使用

例如使用element-ui的标签,可以在App.vue的template中加入

1
<el-tag>element-ui标签</el-tag>

以上关系到的文件大概如下:

main.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import Vue from 'vue'

//引入element-ui和element的css
import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'
//Vue安装element-ui
Vue.use(ElementUI)


import App from './App.vue'

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

webpack.config.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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
var path = require('path')
var webpack = require('webpack')

module.exports = {
entry: './src/main.js',
output: {
path: path.resolve(__dirname, './dist'),
publicPath: '/dist/',
filename: 'build.js'
},
module: {
rules: [
{
test: /\.css$/,
use: [
'vue-style-loader',
'css-loader'
],
}, {
test: /\.vue$/,
loader: 'vue-loader',
options: {
loaders: {
}
// other vue-loader options go here
}
},
{
test: /\.js$/,
loader: 'babel-loader',
exclude: /node_modules/
},
{
test: /\.(png|jpg|gif|svg)$/,
loader: 'file-loader',
options: {
name: '[name].[ext]?[hash]'
}
},
{
test: /\.(eot|svg|ttf|woff|woff2)(\?\S*)?$/, // element-ui的css文件中会使用到ttf文件,所以需要到webpack.config.js中配置以下loader规则
loader: 'file-loader'
}
]
},
resolve: {
alias: {
'vue$': 'vue/dist/vue.esm.js'
},
extensions: ['*', '.js', '.vue', '.json']
},
devServer: {
historyApiFallback: true,
noInfo: true,
overlay: true
},
performance: {
hints: false
},
devtool: '#eval-source-map'
}

if (process.env.NODE_ENV === 'production') {
module.exports.devtool = '#source-map'
// http://vue-loader.vuejs.org/en/workflow/production.html
module.exports.plugins = (module.exports.plugins || []).concat([
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: '"production"'
}
}),
new webpack.optimize.UglifyJsPlugin({
sourceMap: true,
compress: {
warnings: false
}
}),
new webpack.LoaderOptionsPlugin({
minimize: true
})
])
}

App.vue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<template>
<div id="app">
<!-- 引用element-ui标签 -->
<el-tag>element-ui标签</el-tag>
</div>
</template>

<script>
export default {
name: "app",
data() {
return {};
}
};
</script>

<style>
</style>

效果如下图:

1558806247813

11.6 按需引入

(1)安装element-ui

1
$ npm i element-ui -S

(2)除了安装element-ui还需要安装 babel-plugin-component

1
$ npm install babel-plugin-component -D

(3) 配置webpack的loader规则

element-uicss文件中会使用到ttf文件,所以需要到webpack.config.js中配置以下loader规则

1
2
3
4
{
test: /\.(eot|svg|ttf|woff|woff2)(\?\S*)?$/,
loader: 'file-loader'
}

(4)修改.babelrc配置文件
将原来的

1
2
3
4
5
6
{
"presets": [
["env", { "modules": false }],
"stage-3"
]
}

改为以下:

1
2
3
4
5
6
7
8
9
10
11
12
{
"presets": [["env", { "modules": false }]],
"plugins": [
[
"component",
{
"libraryName": "element-ui",
"styleLibraryName": "theme-chalk"
}
]
]
}

(5)简单使用

如果只需要用到按钮和标签,那么可以通过以下实现按需引入

1
2
3
4
import Vue from 'vue'
import { Button, Tag } from 'element-ui';
Vue.use(Button) // 或写为Vue.component(Button.name, Button);
Vue.use(Tag) //或写为Vue.component(Tag.name, Tag);

注:按需引入element-ui时,element-ui的样式文件可以不用引入

完整文件如下:

App.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
<template>
<div id="app">
<!-- 引用element-ui标签 -->
<el-tag>element-ui标签</el-tag>
<el-button type="primary">按钮</el-button>
</div>
</template>

<script>

import Vue from 'vue'

//import 'element-ui/lib/theme-chalk/index.css' //按需引入element-ui时,element-ui的样式文件可以不用引入
import { Button, Tag } from 'element-ui';
Vue.use(Button)
Vue.use(Tag)


/* 或写为
* Vue.component(Button.name, Button);
* Vue.component(Tag.name, Tag);
*/

export default {
name: "app",
data() {
return {};
}
};
</script>

<style>
</style>

效果如下:

1558809406214

13. 插槽slot

作用:父组件将不同的内容分发给多个同名的子组件,即填充内容到子组件的插槽中。

Vue的插槽slot,分为3种

1.匿名插槽

2.具名插槽

3.作用域插槽

一般都会开发好插槽子组件后提供给其他人使用,其他人只要在自己的父组件中引入这个带有插槽的子组件标签后,在子组件标签里自定义自己的内容,如此就能实现相应的功能。

1.默认插槽

Child1.vue

1
2
3
4
5
6
7
<template>
<div id="child1">
<span style="color: blueviolet"> 默认插槽</span>
<!-- 默认插槽;这部分会被父组件中的<child1>里的内容覆盖掉 -->
<slot></slot>
</div>
</template>

2.具名插槽

Child2.vue

1
2
3
4
5
6
7
8
<template>
<div id="child2">
<span style="color: #2557c5">具名插槽</span>
<slot name="header"></slot><!-- 具名插槽;这部分会被父组件中的<child1>里的内容覆盖掉 -->
<slot name="content"></slot>
<slot name="footer"></slot>
</div>
</template>

3.作用域插槽

Child3.vue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<template>
<div id="child3">
<span style="color: #22da62"> 作用域插槽</span>
<!-- 作用域插槽
作用域插槽要求,在slot上面绑定数据 -->
<slot :data="user"></slot>
</div>
</template>

<script>
export default {
data: function() {
return {
user: ["zhangsan", "lisi", "wanwu", "zhaoliu", "tianqi", "xiaoba"]
};
}
};
</script>

Father.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
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
<template>
<!-- 插槽
作用:父组件将不同的内容分发给多个同名的子组件,即填充内容到子组件的插槽中。
Vue的插槽slot,分为3种
1.匿名插槽
2.具名插槽
3.作用域插槽
-->

<div class="father" id="father">
<div id="slot1">
<!-- 1.默认插槽
定义:不需要给插槽命名的插槽就是默认插槽(匿名插槽)
首先在子组件中定义插槽<slot></slot>,然后在父组件中通过引用子组件元素标签,并给子组件元素标签的内容体编写内容,已实现内容分发给需要的子组件
-->
<child1>
<div>
<li>口水鸡</li>
<li>口水鸭</li>
</div>
</child1>

<child1>
<div>大神</div>
<div>码农</div>
</child1>
</div>

<hr />

<!-- 2.具名插槽
定义:需要给插槽命名的插槽就是具名插槽
(1)内容要写在父组件中,然后分给需要的子组件。当slot多个时,可以通过name来加以区分,这就是所谓的具名插槽。
(2)在子组件中定义插槽<slot name="插槽名称"></slot>,然后在父组件引用子组件时在内容体里通过(给元素标签定义属性slot="插槽名称")或者(template元素配合v-slot:插槽名称)来使用插槽,可以在父组件的插槽引用体里编写插槽内容,以此来实现不同显示样式的插槽
-->
<div id="slot2">
<child2>
<!-- 2.6.0版本之前具名插槽的使用方式: slot="插槽名称" -->
<div slot="header">
<div>father header</div>
</div>
<!-- 2.6.0版本之后具名插槽的使用方式: template配合v-slot:插槽名称 -->
<template v-slot:content>
<div>father content</div>
</template>
<template v-slot:footer>
<div>father footer</div>
</template>
</child2>
</div>

<hr />
<!-- 3.作用域插槽
定义:绑定data数据的插槽就是作用域插槽
通过在子组件中定义作用域插槽 <slot :data="数据变量名称"></slot>,然后在父组件中使用子组件的时候在内容体里通过 <template slot-scope="子组件绑定的数据变量名称"></template>使用插槽,同时可以在父组件中使用子组件插槽绑定过来的数据
-->
<div id="slot3">
<child3>
<template slot-scope="user">
<li v-for="item in user.data">{{ item }}</li>
</template>
</child3>
</div>
</div>
</template>

<script>
import child1 from "./Child1";
import child2 from "./Child2";
import child3 from "./Child3";
export default {
components: {
child1,
child2,
child3
}
};
</script>

十六、其它vue问题参考

Vue 脱坑记 - 查漏补缺(汇总下群里高频询问的 xxx 及给出不靠谱的解决方案)



----------- 本文结束 -----------




如果你觉得我的文章对你有帮助,你可以打赏我哦~
0%