vue的引用

通过script标签的方式进行引用。

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

组件

vue 的核心功能之一就是组件

components

组件基本分类

  • 根组件
  • 可复用的功能组件

根组件的创建

通过 vue 提供的构造函数可以实例化出来一个跟组件实例对象

1
let app = new Vue(options);

应用最顶层的组件,一般情况下,一个独立的应用有且只有一个根组件(节点)

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">
<title>Document</title>
<script src="./js/vue.js"></script>
</head>

<body>
<!-- VUE的入口 -->
<div id="app"></div>
<script>
// 创建一个根组件
let app = new Vue({
// 定义一个模板
template: '<div>xiaokang.me</div>'
})
// 将模板添加到#app这个元素中
app.$mount('#app')
</script>
</body>

</html>

image-20200925182627376

上面发生了什么?

其实通过实例化Vue对象,传入配置字段template相当于定义了一个模板,通过Vue对象提供的$mount方法,将其添加到指定的标签元素中。类似于createElementappendChild的概念。

可复用的功能组件

通过 Vue 提供的静态方法 component 窗口可复用的功能组件

1
let component1 = Vue.component(options)

组件配置选项:https://cn.vuejs.org/v2/api/

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

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

</head>

<body>
<!-- VUE的入口 -->
<div id="app"></div>
<script src="./js/vue.js"></script>
<script>
// 定义一个可以复用的组件
Vue.component('tab', {
template: `<div>这是一个tab选项卡</div>`
})
// 创建一个根组件
let app = new Vue({
// 定义一个模板
template: `
<div>
<p>xiaokang.me</p>
<tab />
<br />
</div>
`
})

app.$mount('#app')
</script>
</body>

</html>

image-20200925191124804

el选项

如果提供了 el,且又没有提供template,那么会自动把el的innerHTML作为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
26
27
28
29
30
<!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>
<!-- VUE的入口 -->
<div id="app">
<h1>xiaokang.me</h1>
<tab>
</div>
<script src="./js/vue.js"></script>
<script>
// 定义一个可以复用的组件
Vue.component('tab', {
template: `<div>这是一个tab选项卡</div>`
})
// 创建一个根组件
let app = new Vue({
el: '#app'
})
</script>
</body>

</html>

image-20200925191629284

data与更新

使用 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
<!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>
<!-- VUE的入口 -->
<!-- vue中的花括号内可填入的内容
* 表达式:可以通过运算(执行)得到结果(数据)的公式
* - 变量
* - 函数调用
* - 数学运算
*
* 语句:if,else,while,for....
*
* 数据来源于组件内部,比如 data 中的数据
* 解析过程中,会自动绑定组件实例中的数据

-->
<div id="app">
<h1>xiaokang.me</h1>
<h2>name:{{name}}</h2>
<tab>
</div>
<script src="./js/vue.js"></script>
<script>
// 定义一个可以复用的组件
Vue.component('tab', {
template: `<div>这是一个tab选项卡</div>`
})
// 创建一个根组件
let app = new Vue({
el: '#app',
// 用来挂载组件所需要渲染的数据
data: {
name: 'Xioakang',
age: 18
}
})
</script>
</body>

</html>

将数据传入到Vue对象选项中的data字段,在模板里只需要通过{{}}`即可调用到该属性,例如`{{name}}表示调用data.name,其数据来源于data中的数据,所以不需要写data.name

Vue会把data传入的属性挂载到Vue对象中,因此属性命名时不可以与原有属性冲突。

image-20200925192227986

关于数据的更新,只需要改动属性即可。如图:

image-20200925192509124

拦截数据

简单来说,就是数据修改时拦截数据,这样就实现了只关注数据的修改,而不关心渲染。

vue3 之前,数据的监听是通过 Object.defineProperty 方法来实现的,但是该方法只能监听拦截单个数据,对于对象新增属性无法监听拦截。所以,对于数据对象中新增的属性,我们需要调用 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
<!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>
let obj1 = {
x: 1,
y: 2
}
function render() {
console.log('渲染了!');
}
let obj2 = Object.assign({}, obj1)
// 当每次修改x属性时,调用render函数进行渲染。
Object.defineProperty(obj1, 'x', {
set(newVal) {
// 如果使用obj1会导致循环递归的问题,因此使用另一个变量
obj2.x = newVal
render()
},
get() {
return obj2.x
}
})
obj1.x = 2
console.log(obj1.x);
</script>
</body>

</html>

acd5884e-83cb-40ec-a7e7-6038681601c5

通过 Object.defineProperty 监听拦截中存在一些问题

  • 属性新增属性
  • 数组方法:push、pop、shift、unshift、splice、sort、reverse
  • 数组新增值:[]
  • 数组 length 属性

以上的操作中并不会触发监听拦截

vue 对数组中的 pushpop 等方法进行重新包装,所以在 vue 中调用这些方法,可以对数组的修改进行监听拦截

https://cn.vuejs.org/v2/guide/list.html#%E5%8F%98%E5%BC%82%E6%96%B9%E6%B3%95-mutation-method

为了解决上述问题,vue2提供了set方法,其原理如下:

1
2
3
4
5
6
7
8
9
10
11
function set(key, value) {
Object.defineProperty(obj1, key, {
set(newVal) {
value = newVal;
render();
},
get() {
return value;
}
})
}

此时通过调用set方法即可对新属性进行拦截。

2f273461-26c0-46a3-8093-27d9cd0733cc

在vue中有两种方式调用set方法:

1
2
3
Vue.set(app.user, 'age', 19)
// 或下面的方法(app为Vue的实例对象)
app.$set(app.user, 'age', 19)

e0bfbd08-c4de-4e91-a1d7-fa522f4b6cd7