Vue.js 介绍

Vue.js 也称为 Vue,读音类似 view。

Vue 有以下特点:

  • 是一个构建用户界面的框架
  • 是一个轻量级 MVVM(Model-View-ViewModel)框架,和 angular、react 类似
  • 数据驱动 + 组件化的前端开发(核心思想)
  • 通过简单的 API 实现响应式的数据绑定和组合的视图组件
  • 更容易上手、小巧

参考:官网文档

第一个 vue 程序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<div id="main">
{.{msg}.} //字符串模板
</div>

<script src="./js/vue.js"></script> //引入vue文件
<script>
new Vue({ //创建vue实例
el: '#main', //绑定元素
data: {
msg: 'hello Vue.js'
},
methods:{ //用于存放方法
}
})
</script>

以上就是一个非常简单的 vue 程序。绑定元素这里不但可以使用 id 选择器,我们还可以使用类选择器或者标签选择器。但是,vue2.0 中不允许将 vue 实例挂在到 html 或者 body 元素上。

常用指令

指令用来扩展 HTML 功能。vue 内置了很多指令。

v-model

实现双向数据绑定,实时监控数据变化,一般用于表单。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
 <div id="main">
<input type="text" v-model="content">

<br> {.{ content111 }.}
</div>

<script src="./js/vue.js"></script>
<script>
new Vue({
el: '#main',
data: {
content: ''
}
})
</script>

在这里,使用v-model指令将输入框的值与 vue 实例中的 content 进行绑定。此后,二者中的任一值发生变化,另一个值都会跟随变化。

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
<div id="main">
<ul>
<li v-for="item in arr"> //遍历数组
{.{item}.}
</li>
</ul>

<ul>
<li v-for="item in obj"> //遍历对象
{.{item}.}
</li>
</ul>

<ul>
<li v-for="(value,key) in obj"> //键值循环,数组也适用,注意key在后面
{.{key}.}----{.{value}.}
</li>
</ul>
</div>

<script src="./js/vue.js"></script>
<script>
new Vue({
el: '#main',
data: {
arr: [1, 2, 3, 4, 5, 6],
obj: {
name: 'hedawei',
age: 22,
gender: 'man'
}
}
})
</script>

v-on

用于绑定事件,用法:v-on: 事件 =”函数”。

示例:点击事件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<div id="main">
<button type="button" v-on:click="showHello()">点击显示</button>
<br>
{.{msg}.}
</div>

<script src="./js/vue.js"></script>
<script>
new Vue({
el: '#main',
data: {
msg:''
},
methods: {
showHello() {
this.msg = 'Hello Vue.js';
}
}
})
</script>

this指向当前 vue 实例,由此可获取实例的其他属性。除了点击事件外还有很多其他事件,具体参考官网 API。

v-show

用来显示或隐藏元素,v-show 是通过 display 实现。当v-show的值为 true 时显示,为 false 时隐藏。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<div id="main">
<button type="button" v-on:click="change()">隐藏</button>
<div style="width:100px;height:100px;background:red" v-show="flag"></div>
</div>

<script src="./js/vue.js"></script>
<script>
new Vue({
el: '#main',
data: {
flag: true
},
methods: {
change() {
this.flag = !this.flag;
}
}
})
</script>

事件

之前说了一些关于事件的指令,这里详细学习一下事件的相关知识。

事件简写

之前的事件都是这样的写法:v-on:click="showHello()"`,vue 提供了一种简写方式:
@click="showHello()"

事件对象 $event

我们可以通过事件对象取得事件相关信息,如事件源、事件类型、偏移量。

下面这个例子通过事件对象取得按钮的值:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<div id="main">
<button type="button" @click="print($event)">点击显示按钮的值</button>
<br> {.{msg}.}
</div>

<script src="./js/vue.js"></script>
<script>
new Vue({
el: '#main',
data: {
msg: ''
},
methods: {
print(e) {
this.msg = e.target.innerHTML;
}
}
})
</script>

事件冒泡与事件默认行为

这里需要讨论阻止事件冒泡与阻止默认行为,原生 js 阻止事件冒泡首先得取得事件对象,然后调用事件对象的stopPropagation方法。在 vue 里,则不需要依赖于事件对象,只需要调用相应的事件修饰符stop即可:

1
@click.stop = "print()"

阻止事件默认行为和阻止事件冒泡基本一致,在 vue 里也有十分便利的操作方法:

1
@click.prevent = "print()"

键盘事件

vue 里内置了一些键盘事件,便于开发者操作。语法如下:

1
2
@keydown.13 = "print()"
@keydown.enter = "print()"

除了回车事件外,还有很多其他键盘事件,例如下:`@keydown.38=”print()”`。还有一些其他键盘事件,具体参考官方文档。

默认没有 @keydown.a/b/c… 事件,可以全局自定义键盘事件,也称为自定义键码或自定义键位别名:

1
2
3
4
5
6
7
8
9
Vue.config.keyCodes = {
v: 86,
f1: 112,
// camelCase 不可用
mediaPlayPause: 179,
// 取而代之的是 kebab-case 且用双引号括起来
"media-play-pause": 179,
up: [38, 87]
}

除了stoppreventkeyCode这些事件修饰符以外,还有一些比较常用:

  • .native - 监听组件根元素的原生事件。
  • .once - 只触发一次回调。

属性

vue 提供了绑定属性的方法:v-bind:属性名="",这样我们即可动态的改变属性值。

属性简写

属性和事件一样,也有简写方式::属性名=""

class 属性和 style 属性

绑定 class 和 style 属性时的语法比较复杂。

变量形式

html 部分:

1
<p :class="myClass">Hello vue.js</p>

对应的 vue 的 data 部分:

1
2
3
data:{
myClass:className
}

数组形式,同时引入多个类

html 部分:

1
<p :class="[myClass1,myClass2]">Hello vue.js</p>

对应的 vue 的 data 部分:

1
2
3
4
data:{
myClass1:className1,
myClass2:className2,
}

JSON 形式(常用)

html 部分:

1
<p :class="{className1:true,className2:false}">Hello vue.js</p>

变量引用 JSON 形式

html 部分:

1
<p :class="myClass">Hello vue.js</p>

对应的 vue 的 data 部分:

1
2
3
4
5
data:{
myClass:{
className:true
}
}

style 的用法和 class 的用法基本一致,但是不常用。

模板

Vue.js 使用基于 HTML 的模板语法,可以将 DOM 绑定到 Vue 实例中的数据。模板就是{.{ }.},用来进行数据绑定,显示在页面中,也称为 Mustache 语法。

数据绑定的方式

双向数据绑定

使用v-model指令,前面已经学习过。

单向数据绑定
使用两对大括号 {.{}.}

这个在之前也经常使用,但是有一个缺点,就是 vue 实例需要长时间编译时会在页面中出现{.{}.}(闪烁现象)。vue 提供了一个解决办法:使用v-cloak配合 css。

1
2
3
4
5
6
7
8
9
//html内容
<div id="app" v-cloak>
{.{msg}.}
</div>

//css内容
[v-cloak] {
display: none;
}

使用指令 v-text、v-html

v-text也可达到与使用v-cloak相同的效果。

1
2
3
//html内容
<div id="app" v-text="msg">
</div>

v-html会将文本中的 html 解析为 html 标签,然后渲染到页面中。

1
2
3
4
5
6
7
8
//html内容
<div id="app" v-html="msg">
</div>

//vue实例中data部分内容
data: {
msg: 'hello<mark>vue.js<mark>'
},

这里的 vue.js 会有一个黄色的背景颜色。

过滤器

过滤器用来过滤模型数据,在显示之前进行数据处理和筛选。语法:{.{ data | filter1(参数) | filter2(参数)}.}

vue1.0 中内置了很多过滤器,但是在 2.0 中全部删除了。使用过滤器我们可以通过使用第三方库:lodash、date-fns 日期格式化、accounting.js 货币格式化。或者我们可以自定义过滤器。

自定义过滤器

过滤器分为全局过滤器和局部过滤器。

全局过滤器

使用全局方法 Vue.filter(过滤器ID,过滤器函数)。

示例:

1
2
3
4
5
<p>{.{8|addZero}.}</p>//数据会自动作为传过去

Vue.filter('addZero', data => {
return data > 10 ? data : '0' + data;
});

有时过滤器也要传递自己的参数:

1
2
3
4
5
<p>{.{12.3456|number(3)}.}</p>

Vue.filter('number', (data,n) => {
return data.toFixed(n);
});

局部过滤器

局部过滤器的使用方法与全局过滤器的使用方法一致。

不过过滤器写在 vue 实例中 filters 选项中。

1
2
3
4
5
6
7
8
9
new Vue({
el:'#app',
data:{},
filters:{
number:data => {
//具体操作
}
}
})

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
beforeCreate(){  //组件实例刚刚创建,还未进行数据观测和事件配置

},
created(){ //实例已经创建完成,并且已经进行数据观测和事件配置

},
beforeMount(){//模板编译之前,还没挂载

},
mounted(){ //模板编译之后,已经挂载,此时才会渲染页面,才能看到页面上数据的展示

},
beforeUpdate(){//组件更新之前

},
updated(){//组件更新之后

},
beforeDestroy(){//组件销毁之前

},
destroyed(){ //组件销毁之后

}

这几个钩子中,最常用的是created()mounted()

计算属性

计算属性也是用来存储数据,但具有以下几个特点:

  • 数据可以进行逻辑处理操作
  • 对计算属性中的数据进行监视

基本用法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<div id="app">
{.{addZero}.}
</div>

new Vue({
el: '#app',
data: {
num: 8
},
computed: {
//这是计算属性的get方法,用于取值
addZero() {
return this.num > 10 ? this.num : '0' + this.num;
}
}
})

这里的addZeronum一样,都是属性。不过addZero是依赖于num、进行计算后的值。一旦num的值发生变化,addZero的值也会随之变化。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<div id="app">
{.{num}.}----{.{addZero}.}
<br>
<button type="button" @click="change">点击改变num</button>
</div>

new Vue({
el: '#app',
data: {
num: 8
},
methods: {
change: () => {
this.num++;
}
},
computed: {
addZero:() => {
return this.num > 10 ? this.num : '0' + this.num;
}
}
})

一旦我们点击按钮改变num的值,那么因为计算属性实时监测依赖项,addZero也会跟着发生变化。

计算属性 vs 方法

将计算属性的 get 函数定义为一个方法也可以实现和计算属性类似的功能。那么二者之间有什么区别?

  • 区别一:计算属性是基于它的依赖进行实时更新的,方法则是调用才更新
  • 区别二:计算属性是有缓存的,只要相关依赖没有改变,多次访问计算属性得到的值是之前缓存的计算结果,不会多次执行。操作一个没有依赖项的值也是如此。
    官方文档给出了下面这个例子:
    1
    2
    3
    4
    5
    computed: {
    now: function () {
    return Date.now()
    }
    }

计算属性存在缓存,这里的now值不会发生变化。

get 和 set

计算属性由两部分组成:get 和 set,分别用来获取计算属性和设置计算属性。默认只有 get,如果需要 set,要自己添加。

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
     <div id="app">
{.{num}.}----{.{addZero}.}
<br>
<button type="button" @click="change(5)">点击改变num</button>
</div>

new Vue({
el: '#app',
data: {
num: 8
},
methods: {
change(newNumber) {
this.addZero = newNumber;
}
},
computed: {
addZero: {
get() {
return this.num > 10 ? this.num : '0' + this.num;
},
set(newNum) {
this.num = newNum
}
}
}
})

我们再change方法中改变addZero属性的值的时候会自动调用它的 set 方法。

实例属性和方法

vue 中给实例和属性提供了若干属性和方法。

属性

获取属性的语法:实例名.属性名
以下是常用的属性:

  • vm.$el: 获取 vue 实例关联的元素 DOM,进而可以对其进行操作
  • vm.$data: 获取数据对象 data
  • vm.$options:获取选项,自定义的选项也可以在这里获取。
  • vm.$refs:获取所有添加 ref 属性的元素 dom 对象,进而可以对其进行操作

方法

vm.$mount()

手动挂载 vue 实例

1
2
3
4
5
var vm=new Vue({
data:{
msg:'Hello vue.js'
}
}).$mount('#app');

vm.$destroy()

销毁实例

1
vm.$destroy(); //销毁实例所占的内存空间

vm.$nextTick(callback)

在 DOM 更新完成后再执行回调函数,一般在修改数据之后使用该方法,以便获取更新后的 DOM

1
2
3
4
5
6
7
8
9
10
11
12
13
var vm=new Vue({
data:{
msg:'Hello vue.js'
}
}).$mount('#app');

//修改数据
vm.msg='foo';

console.log(vm.$refs.title.textContent); //Hello vue.js
vm.$nextTick(function(){
console.log(vm.$refs.title.textContent); //foo
});

DOM 还没更新完,Vue 实现响应式并不是数据发生改变之后 DOM 立即变化,需要按一定的策略进行 DOM 更新,需要时间!使用$nextTick方法等 DOM 更新完再获取数据。

vm.$set(target,key,value)

通过 vue 实例的 $set 方法为对象添加属性,可以实时监视。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<div id="app">
{.{user.name}.}<br> {.{user.age}.}
<br>
<button type="button" @click="addAge">添加属性</button>
</div>

var vm = new Vue({
data: {
msg: 'Hello vue.js',
user: {
name: 'hedawei',
gender: 'man'
}
},
methods: {
addAge() {
/* this.user.age = 22; */
this.$set(this.user, 'age', 22);
}
}
}).$mount('#app');

方法中使用原始的添加属性方法的话不会在模板中显示。使用$set方法会实时监控数据,然后添加。

vm.$watch(监听的属性,callback)

监控 vue 实例的变化

1
2
3
vm.$watch('msg', (newValue, oldValue) => {
console.log('msg被修改啦,原值:' + oldValue + ',新值:' + newValue);
});

如果需要监控深度数据变化(例如监控一个对象中的某个属性),则需要在选项中添加{deep:true}

自定义指令

自定义指令分为自定义全局指令和自定义局部指令。

自定义全局指令

使用全局方法 Vue.directive (指令ID,定义对象)。注:使用指令时必须在指名名称前加前缀 v-,即v-指令名称`

简单示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Vue.directive('hello',{
bind(){ //常用!!
alert('指令第一次绑定到元素上时调用,只调用一次,可执行初始化操作');
},
inserted(){
alert('被绑定元素插入到DOM中时调用');
},
update(){
alert('被绑定元素所在模板更新时调用');
},
componentUpdated(){
alert('被绑定元素所在模板完成一次更新周期时调用');
},
unbind(){
alert('指令与元素解绑时调用,只调用一次');
}
});

这里定义了一个名为hello的指令,指令定义函数提供了几个钩子函数,分别在不同的时期生效。我们像下面这样使用这个指令:

1
<p v-hello>hello vue.js</p>

大多数情况下,我们只需要使用bindupdate钩子函数。vue 里提供了函数的简写形式:

1
2
3
Vue.directive('hello', function () {
alert("hello vue.js");
})

钩子函数有两个常用的参数elbindingel是绑定的 DOM 对象,binding是一个对象,包含若干属性。

拿到 DOM 对象,我们就可以对 DOM 进行一些操作。

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
<p v-hello="msg">hello vue.js</p>

Vue.directive('hello', function (el,binding) {
el.style.color = "red";

//属性name是指令的名字(不带v-)
console.log(binding.name); //hello
//属性value是传递给指令的值
console.log(binding.value); //alice
//属性expression是指令值的字符串形式(个人感觉就是类似变量名)
console.log(binding.expression); //msg
//属性arg是传递给指令的参数(和传值写在一起容易令初学者困惑,下面分开写
//合在一起写的写法是<p v-hello:123="msg">hello vue.js</p>)
//<p v-hello:123>hello vue.js</p>
console.log(binding.arg); //123
//属性modifiers是一个包含修饰符的对象。
//与传参传值合在一起的写法是 <p v-hello:123.bar="msg">hedawei</p>
//<p v-hello.bar>hello vue.js</p>
console.log(binding.modifiers); //{bar:true}
})

var vm = new Vue({
el: '#app',
data: {
msg: 'alice'
}
})

局部自定义指令

局部自定义指令写在实例的directives选项中。

1
2
3
4
5
6
7
8
9
10
11
12
13
 var vm = new Vue({
el: '#app',
data: {
msg: 'alice'
},
methods: {
},
directives: {
word: function(el, binding) {
console.log(binding.name);
}
}
})

其他用法与全局自定义指令一致。

过渡(动画)

Vue 在插入、更新或者移除 DOM 时,提供多种不同方式的应用过渡效果。本质上还是使用 CSS3 动画:transition、animation 属性。

基本用法

使用 transition 组件,将要执行动画的元素包含在该组件内:

1
2
3
<transition name="fade">
运动的元素
</transition>

我们需要为其定义一个name属性,以便后面为其添加 css 样式。

动画有 6 个 CSS 类名,下面结合的例子说明:

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
<style>
button {
display: block;
margin: 20px auto;
}

p {
width: 100px;
height: 100px;
background-color: red;
margin: 0 auto;
}

.fade-enter-active,
.fade-leave-active { //定义整个过渡期间的效果
transition: all 2s ease;
}

.fade-enter-to { //定义过渡进入的最终效果
opacity: 1;
width: 100px;
height: 100px;
}

.fade-leave-to { //定义过渡离开的最终效果
opacity: 0;
width: 50px;
height: 50px;
}

.fade-enter { //定义过渡进入的开始效果
opacity: 0;
width: 50px;
height: 50px;
}
</style>

<div id="app">
<button type="button" @click="flag = !flag">点 击</button>
<transition name="fade">
<p v-show="flag">
</p>
</transition>
</div>

<script>
new Vue({
el: '#app',
data: {
flag: false
}
});
</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
<transition name="fade" @before-enter="beforeEnter" @enter="enter" @after-enter="afterEnter" @before-leave="beforeLeave" @leave="leave" @after-leave="afterLeave">
<p v-show="flag">
</p>
</transition>

new Vue({
methods: {
beforeEnter(el) {
alert('动画进入之前');
},
enter(el) {
alert('动画进入');
},
afterEnter(el) {
alert('动画进入之后');
},
beforeLeave(el) {
alert('动画离开之前');
},
leave(el) {
alert('动画离开');
},
afterLeave(el) {
alert('动画离开之后');
}
}
});

在这不同的时期,我们可以取到过渡元素的 DOM 对象,从而对其进行操作。

多元素过渡

上面的标签只适用于单元素过渡。若要对多元素进行过渡,则需要使用标签,并且绑定key属性,设置不同的值。

1
2
3
4
5
6
7
<button type="button" @click="flag = !flag">点 击</button>
<transition-group name="fade">
<p v-show="flag" :key="1">
</p>
<p v-show="flag" :key="2">
</p>
</transition-group>

结合第三方库一起使用(animate.css)

我们可以使用 vue 的自定义过渡类名结合第三方动画库实现自定义动画效果。这六个自定义类名和 vue 内置的类名类似:

  • enter-class
  • enter-active-class
  • enter-to-class
  • leave-class
  • leave-active-class
  • leave-to-class

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
p {
width: 300px;
height: 300px;
background-color: red;
margin: 0 auto;
}

<div id="app">
<button type="button" @click="flag = !flag">点 击</button>
<transition enter-active-class="animated tada" leave-active-class="animated bounceOutRight">
<p v-show="flag">
</p>
</transition>
</div>

<script>
new Vue({
el: '#app',
data: {
flag: false
}
});
</script>

组件

什么是组件

组件(Component)是 Vue.js 最强大的功能之一。组件可以扩展 HTML 元素,封装可重用的代码组件是自定义元素(对象)。

创建组件的两种方式

官方推荐组件标签名是使用-连接的组合词,例如:<my-hello></my-hello>

使用构造器创建组件

使用这种方式创建组件首先需要使用Vue.extend()创建一个组件构造器,然后使用Vue.component(标签名,组件构造器),根据组件构造器来创建组件。

1
2
3
4
5
6
7
8
9
10
11
//1.创建构造器
var MyComponent=Vue.extend({
template:'<h3>Hello World</h3>'
});
//2.创建组件
Vue.component('my-hello',MyComponent);

//3.使用组件
<div id="app">
<my-hello></my-hello>
</div>

这种创建组件的方式比较麻烦,使用的较少。

直接创建组件

使用Vue.component(标签名,组件模板)`,根据组件构造器来创建组件。

1
2
3
4
5
6
7
8
9
//1.创建组件
Vue.component('my-world', {
template: '<h2>hello vue.js</h2>'
});

//2.使用组件
<div id="app">
<my-world></my-world>
</div>

组件的分类

组件分为全局组件和局部组件。

全局组件

使用Vue.component()创建的组件都是全局组件。这样的组件在任何组件内都能使用。上面我们创建就是全局组件。

局部组件

局部组件一般都是定义在实例的选项中,称为实例的子组件。相应的,实例也被称为父组件。

1
2
3
4
5
6
7
8
9
10
11
12
13
//1.定义组件
new Vue({
el: '#app',
components: {
dawei: {
template: '<h2>my name is dawei</h2>'
}
}
});
//2.使用组件
<div id="app">
<dawei></dawei>
</div>

引用模板

很多时候我们的template模板中需要存放很多标签内容,这样的话写起来会很麻烦。这时候我们可以使用template标签。

用法如下:

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
<template id="wbs">    //使用template标签
<div>
<h2>hello {.{msg}.}</h2>
<ul>
<li v-for="value in arr">
{.{value}.}
</li>
</ul>
</div>
</template>

new Vue({
el: '#app',
components: {
'my-dawei': {
template: '#wbs', //选择template标签
data() {
return {
msg: 'vue.js',
arr: ["a", "b", "c", "d"]
}
}
}
}
});

这里涉及到的几个知识点得着重提一下:

  • template模板中,所有的元素必须放置在一个根元素中,要不然会报错。例子中我们将元素放置在了<div>标签中。
  • 组件中的data选项必须是一个函数类型,使用return返回所有的数据。

动态组件

很多时候项目中需要在某一个地方动态的使用不同的组件,这时候就需要使用动态组件。
动态组件的使用需要绑定is属性:

1
<component :is="flag"></component>

简单示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//点击按钮显示不同的组件
<div id="app">
<button type="button" @click="flag='my-a'">显示a组件</button>
<button type="button" @click="flag='my-b'">显示b组件</button>

<component :is="flag"></component> //传入flag
</div>

new Vue({
el: '#app',
data: {
flag: 'my-a' //给flag赋值
},
components: {
'my-a': {
template: '<p>我是a组件</p>',
},
'my-b': {
template: '<p>我是b组件</p>'
}
}
});

keep-alive 组件

使用keep-alive组件缓存非活动组件,可以保留状态,避免重新渲染,默认每次都会销毁非活动组件并重新创建。

使用范例:

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
<keep-alive>
<component :is="flag"></component>
</keep-alive>

<div id="app">
<button type="button" @click="flag='my-x'">x</button>
<button type="button" @click="flag='my-y'">y</button>
<keep-alive>
<component :is="flag"></component>
</keep-alive>
</div>

new Vue({
el: '#app',
data: {
flag: 'my-x'
},
components: {
'my-x': {
template: '<p>{.{x}.}</p>',
data() {
return {
x: Math.random()
}
}
},
'my-y': {
template: '<p>{.{y}.}</p>',
data() {
return {
y: Math.random()
}
}
}
}
});

这样的话,第一次产生的随机数就会被缓存,再次切换的时候也不会发生改变。

组件间数据传递

父子组件

在一个组件内部定义另一个组件,那么这对组件称为父子组件。子组件只能在父组件内部使用。默认情况下,每个组件实例的作用域是独立的,子组件无法访问父组件中的数据,同样,父组件也无法访问子组件中的数据。

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
<div id="app">
<my-a></my-a>
<!-- 父组件 -->
</div>

<template id="a">
<div>
<p>{.{msg}.}</p>
<my-b></my-b> <!-- 在父组件中调用子组件 -->
</div>
</template>

<template id="b">
<div>
<p>{.{mydata}.}</p>
</div>
</template>

<script>
new Vue({ //根组件
el: '#app',
components: { //子组件写在components选项中
"my-a": { //b组件的父组件
template: "#a",
data() {
return {
msg: '我是父组件',
}
},
components: { //子组件写在父组件的components选项中
"my-b": {
template: "#b",
data() {
return {
mydata: "我是子组件"
}
}
}
}
}
}
});
</script>

组件间数据传递(通信)

子组件访问父组件的数据

步骤:

  • a、调用子组件时,绑定想要获取的父组件中的数据
  • b、在子组件内部,使用 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
<div id="app">
<my-a></my-a>
</div>

<template id="a">
<div>
<p>{.{msg}.}</p>
<p>这是要传递给子组件的值:{.{myname}.}</p>
<my-b :name="myname"></my-b> <!-- 绑定子组件想要获取的数据 -->
</div>
</template>

<template id="b">
<div>
<p>{.{mydata}.}</p>
<p>这是父组件传递过来的数据:{.{name}.}</p>
</div>
</template>

<script>
new Vue({
el: '#app',
data: {},
components: {
"my-a": {
template: "#a",
data() {
return {
msg: '我是a组件',
myname: '子组件b你好,我是父组件a'
}
},
components: {
"my-b": {
template: "#b",
data() {
return {
mydata: "我是b组件"
}
},
props: ["name"] //子组件使用props声明想要获取的数据
}
}
}
}
});
</script>
父组件访问子组件的数据

步骤:

  • a 在子组件中使用 vm.$emit(事件名, 数据) 触发一个自定义事件,将数据发送给父组件,事件名自定义
  • b 父组件在使用子组件的地方监听子组件触发的事件,并在父组件中定义方法,用来获取数据
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//子组件‘my-b’内部
methods:{
send(){//使用$emit()触发一个事件,发送数据,this指当前子组件实例
this.$emit('e-world', this.senddata);
}
}

//在调用子组件的地方监听子组件触发的事件,调用自己的方法获取数据
<my-b @e-world="getData"></my-b>


methods: {
getData(data) { //参数是子组件传递过来的数据
this.revicedata = data;
}
}
单向数据流

props 是单向数据绑定的,当父组件数据发生变化时,将传递给子组件,但是不会反过来。而且不允许子组件直接修改父组件中的数据,强制修改会报错。

解决方案:

  • 如果子组件想把它作为局部数据来使用,可以将数据存入另一个变量中再操作,不影响父组件中的数据
  • 如果子组件想修改数据并且同步更新到父组件,两个方法:
  • 使用.sync显式地触发一个更新事件(1.0 版本中支持,2.0 版本中不支持,2.3 版本又开始支持)
1
2
3
4
5
//使用.sync
<my-b :name.sync="myname"></my-b>

//子组件修改父组件传入的值name,触发update更新事件
this.$emit('update:name', "vuejs");
  • 可以将父组件中的数据包装成对象,然后在子组件中修改对象的属性 (因为对象是引用类型,指向同一个内存空间),推荐使用这种方式。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
 data() {
return { //将要传递的数据放入message对象中
message: {
hello: '子组件b你好,我是父组件a'
}
}
}

<my-b :message="message"></my-b> //传递这个对象给子组件

methods: { //在子组件内部修改这个值,这样就会同步传递给父组件。
edit() {
this.message.hello = "hahahahh";
}
}
非父子组件间的通信

非父子组件间的通信,可以通过一个空的 Vue 实例作为中央事件总线(事件中心),用它来触发事件和监听事件,从而实现非父子组件间的通信。

1
2
3
4
5
6
7
8
9
10
11
12
13
var Event = new Vue();    //空vue实例

methods: {
send() { //触发emit事件
Event.$emit("hello", this.asmsg);
}
}

mounted() { //在子组件的钩子函数中监听该事件
Event.$on('hello', data => { //获取值
this.bsmsg = data;
})
}

slot 内容分发

用来获取组件中的原内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
var vm = new Vue({
el: '#app',
components: {
'my-hello': {
template: '#hello'
}
}
});

<div id="app">
<my-hello>hello vue.js</my-hello>
</div>


<template id="hello">
<div>
<slot>如果没有原内容,则显示该内容</slot>
</div>
</template>

如果组件标签中没有内容就会显示 slot 中的内容,这也就是所谓的单个插槽。

还可以对显示的内容进行分组,这就是具名插槽,可以操作标签组中的内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<div id="app">
<my-hello>
<ul slot="s1">
<li>aaa</li>
<li>bbb</li>
<li>ccc</li>
</ul>
<ol slot="s2">
<li>111</li>
<li>222</li>
<li>333</li>
</ol>
</my-hello>
</div>

<template id="hello">
<div>
<slot name="s2"></slot> //为插槽指定名称 将名为s2的内容放置在这里
<p>hello vue.js</p>
<slot name="s1"></slot> //将名为s1的内容放置在这里
</div>
</template>

这样,就可以对组件中的内容实时操作。

vue-router

简介

我们经常使用 vue 开发单页面应用程序(SPA)。在开发 SPA 过程中,路由是必不可少的部分,vue 的官方推荐是 vue-router。单页面应用程序看起来好像是一个页面,其实是在一个页面中切换不同的 html 部分,从而达到所谓的单页面, 在这切换之中,就需要使用路由来实现不同的页面内容的展现。

基本用法

使用步骤

vue-router 的基本使用步骤如下:

  • 定义需要切换的组件
  • 配置路由,规定路径到组件的映射关系
  • 创建路由实例
  • 将路由挂载到 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
//1.定义组件,用于路由切换
var Home = {
template: '<div>我是主页</div>'
}
var News = {
template: '<div>我是新闻</div>'
}

//2.配置路由
const routes = [{
path: '/home',
component: Home
},{
path: '/news',
component: News
},{ //这一路由配置用于首次访问或者找不到所请求路由,自动跳转home页
path: '*',
redirect: '/home'
}];

//3.创建路由实例
var router = new VueRouter({
routes //传入配置好的路由信息
});

//4.挂载路由到根组件
new Vue({
el: '#app',
router
});

这样我们就配置好了一个完整的路由。在切换组件的时候会根据路由加载不同的组件。我们使用类似 a 标签的<router-link to="url"></router-link>触发组件的切换,to属性存放的是路径。使用<router-view></router-view>来显示所切换组件。

1
2
3
4
5
6
<div id="app">
<router-link to="/home">主页</router-link>
<router-link to="/news">新闻</router-link>

<router-view></router-view>
</div>

这样我们就可以实现主页和新闻组件间的切换。

参数传递

可能我们需要向所切换组件传递参数。vue 提供了两种向组件传递参数的方式。

  • 查询字符串的形式
  • /home?name=dawei&pwd=666
  • 在组件内部使用{.{$route.query}.}接收参数
  • rest 风格
  • /news/param1/param2
  • 在组件内部使用{.{$route.params}.}接收参数
路由嵌套

路由还可以多层嵌套使用,使用children属性。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
{
path:'/user',
component:User,
children:[
{
path:'login',
component:Login
},
{
path:'regist',
component:Regist
}
]
}

子路由项路径不要使用/开头,以/开头的嵌套路径会被当作根路径。

在组件中就可以使用该路由:

1
2
3
4
5
6
7
8
<div>
<h3>用户信息</h3>
<ul>
<router-link to="/user/login">用户登陆</router-link>
<router-link to="/user/regist">用户注册</router-link>
</ul>
<router-view></router-view>
</div>

注意路径的写法。

路由实例的方法

这里学习两个路由实例的方法:router.push()router.replace()

  • router.push():添加路由,功能上与相同
  • router.replace(): 替换路由,不产生历史记录
1
2
router.push({path:'home'})
router.replace({path:'user'})

路由结合动画

路由结合动画使用很简单,我们可以用 组件给它添加一些动画效果:

1
2
3
<transition>
<router-view></router-view>
</transition>

单文件组件

.vue 文件

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

.vue文件由三部分组成:<template><style><script>:

1
2
3
4
5
6
7
8
9
10
11
<template>
//html
</template>

<script>
//js
</script>

<style>
//css
</style>

vue-loader

浏览器本身并不认识. vue 文件,此时需要 vue-loader 对. vue 文件进行加载解析,。类似的 loader 还有许多,如:html-loader、css-loader、style-loader、babel-loader 等。需要注意的是 vue-loader 是基于 webpack 的。

webpack

webpack 是一个前端资源模板化加载器和打包工具,它能够把各种资源都作为模块来使用和处理。实际上,webpack 是通过不同的 loader 将这些资源加载后打包,然后输出打包后文件。简单来说,webpack 就是一个模块加载器,所有资源都可以作为模块来加载,最后打包输出。

vue-cli

简介

vue-cli 是一个 vue 脚手架,可以帮助我们快速构造项目结构,减少开发人员开发阻力。vue-cli 集成了多种版本:

  • simple :比较简单
  • webpack :包含 ESLint 代码规范检查和 unit 单元测试等
  • webpack-simple: 没有代码规范检查和单元测试
  • browserify: 使用的也比较多
  • browserify-simple

安装、操作步骤

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//安装vue-cli,配置vue命令环境 
cnpm install vue-cli -g
vue --version
vue list

// 初始化项目,生成项目模板
vue init 模板名 项目名

//进入生成的项目目录,安装模块包
cd vue-cli-demo
cnpm install

//运行
npm run dev //启动测试服务
npm run build //将项目打包输出dist目录,项目上线的话要将dist目录拷贝到服务器上

文件介绍

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
.
|-- build // 项目构建(webpack)相关代码
| |-- build.js // 生产环境构建代码
| |-- check-version.js // 检查node、npm等版本
| |-- dev-client.js // 热重载相关
| |-- dev-server.js // 构建本地服务器
| |-- utils.js // 构建工具相关
| |-- webpack.base.conf.js // webpack基础配置
| |-- webpack.dev.conf.js // webpack开发环境配置
| |-- webpack.prod.conf.js // webpack生产环境配置
|-- config // 项目开发环境配置
| |-- dev.env.js // 开发环境变量
| |-- index.js // 项目一些配置变量
| |-- prod.env.js // 生产环境变量
| |-- test.env.js // 测试环境变量
|-- src // 源码目录
| |-- components // vue组件
| |-- store // 状态管理
| |-- App.vue // 页面入口vue文件
| |-- main.js // 程序入口文件,加载各种公共组件
|-- static // 静态文件
| |-- data
|-- .babelrc // ES6语法编译配置
|-- .editorconfig // 定义代码格式
|-- .gitignore // git上传需要忽略的文件格式
|-- README.md // 项目说明
|-- favicon.ico //网页图标
|-- index.html // 入口页面
|-- package.json // 项目配置信息
.

此列表拷贝自: 这里

Reference


This is the end of post