Vue2-基础1

Vue2基础1

官网地址:https://cn.vuejs.org/

相信大家学习什么都是以HelloWorld开头的,那我们就以一个HelloWorld的栗子开启我们的Vue学习吧

HelloWorld案例

安装Vue

这里大家要注意,不要使用CLI创建Vue项目

新手阶段最好使用标签静态引入CDN的方式来安装Vue

这里补充一个知识点:

script标签的src属性可以写成./???.js的形式

也可以写成一个网址,为了使用这种方式引入的加载速度更快一点,所以使用了CDN加速

这是官网提供的两种Vue.js,两者有什么区别呢?

开发版本的体积比生产版本的体积大,其中包含了完整的警告和调试模式,在学习阶段,我们使用开发版本的即可

引入Vue.js

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

安装开发者工具

它是一个谷歌插件,如果你可以访问外网,可以直接在谷歌插件商场直接搜索下载,如果没有的话,我也在这里提供插件的文件,

1
2
链接:https://pan.baidu.com/s/18AFI8MpW397L6obmKnAZCw 
提取码:iupu

点击开发者模式

如果使用的是我提供的文件的话,直接将crx文件拖入该页面即可安装开发者工具

使用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
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>我的第一个Vue页面</title>
<!-- 引入Vue -->
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
</head>
<body>
<!-- 准备好一个容器 -->
<div id="app">
<!--这里的{{}}是Vue中的插值语法,可以读取data配置项中配置的数据-->
{{msg}}
</div>

<script type="text/javascript" >
Vue.config.productionTip = false //关闭vue的生产提示。
//创建Vue实例
new Vue({
el:'#app', //el用于指定当前创建的Vue实例为哪个容器服务,值为css选择器。
data:{ //data中用于存储我们需要用到的数据,数据供el所指定的容器去使用,值是一个对象。
msg:'Hello World'
}
})
</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
35
36
1、{{xxx}}中的xxx要写js表达式,且xxx可以自动读取到data中的所有属性
js表达式 VS js语句
(1)js表达式是一个值
(2)js语句是一个语句,控制代码走向
if(){}
for(){}
switch(){}

2、容器和Vue实例的关系是一对一的

3、id为app的容器内部的代码就是模板

4、一旦data中的数据发生改变,页面中使用到该数据的地方都会自动更新

5、el的两种写法,该配置的作用叫挂载,就是将创建的Vue实例与HTML元素绑定在一起
(1) el:'#app'
(2) new Vue({
data:{
msg:'Hello World'
}
}).$mount('#app')
这个$mount是Vue原型对象上提供的

6、data的两种写法
(1) 对象式,data是一个对象
data:{
msg:'Hello World'
}
(2) 函数式,data是个函数,返回的是一个对象
data(){
return {
msg: 'Hello World'
}
}
(3) 只要是Vue管理的函数,其中的this对象都是自己创建的Vue实例对象,**前提是不能是箭头函数**
(4) 我们最常使用的是函数式的,大家要多写这种形式的,具体原因的话,这里埋个伏笔,以后在讲组件的时候解释

如果我们不使用new关键词创建Vue对象的话会怎么样呢?

控制台就会出现报错

开发版

生产版

这里可以体现生产版本和开发版本之间的区别

我们来看下Vue的构造函数

1
2
3
4
5
6
7
function Vue (options) {
//先判断当前调用函数的是否是Vue的实例,如果不是,则在控制台报错
if (!(this instanceof Vue)) {
warn('Vue is a constructor and should be called with the `new` keyword');
}
this._init(options);
}

模板语法

刚刚我们在写HelloWorld案例的时候使用的{{}}叫插值语法

模板语法一共两种,插值语法就是其中的一种,另一种模板语法叫指令语法

1
2
3
4
5
6
7
插值语法:
作用:解析标签体内的内容
写法:{{xxx}}双括号内是js表达式,可以直接读取到data中的所有属性。

指令语法:
功能:解析标签(包括:标签属性、标签体内容、绑定事件.....)。
写法:v-xxx(xxx为具体指令)

我们来看看指令语法是个什么东东

为了节省代码量,这里只写核心代码

v-text

这个最简单,其作用就是插值语法,将其指定的内容替换标签体内的所有内容,不解析HTML

与之对应的还有一个指令v-html,那这个指令就是将内容放入标签体内后,如果内容有HTML元素,它也会解析

v-bind

主要使用在给HTML元素属性动态赋值的时候使用

HTML

1
2
3
4
5
<div id="app">
<a v-bind:href="url">点我去{{name}}学习1</a>
<!--这是v-bind的简写模式-->
<a :href="url">点我去{{name}}学习2</a>
</div>

JavaScript

1
2
3
4
5
6
7
new Vue({
el:'#app',
data:{
name:'百度',
url:'http://www.baidu.com',
}
})

bind的英文意思是绑定,这里先理解一下这个名词的意思,这里的v-bind是单向绑定

什么叫单向绑定?

就是我在Vue实例中的data中的数据发生了改变,页面中的数据就会跟着更新,

但是页面中的数据发送了改变,data中的数据不会发生改变

证明:

因为我们还没学其他可以修改data中的数据的方法,我们这里就使用开发者工具开帮我们完成该任务

修改data中数据,页面更新

修改页面数据,data不更新

1
document.getElementById('app').children[0].href='https://juejin.cn/'

这就是单向绑定了

既然有单向绑定,那肯定与之对应的还有一个双向绑定啦,下面我们来看看双向绑定

v-model

只使用在一些表单类的HTML标签

这个指令十分十分十分的重要,请一定要理解这个指令双向绑定的作用

HTML

1
2
3
4
<div id="app">
<!--将input的value属性和data中的name属性双向绑定起来-->
双向数据绑定:<input type="text" v-model:value="name">
</div>

JavaScript

1
2
3
4
5
6
new Vue({
el:'#app',
data:{
name:'芝麻芝麻'
}
})

单向绑定,是页面中的数据修改后,data中的数据不会更新

那双向绑定的情况下,是不是就会更新了?是的

我们来证明一下这一点

说明:

1
2
3
4
1、简写模式
<input type="text" v-model="name">
2、作用范围
只可以作用在表单元素上

MVVM模型

1
2
3
M:	模型(Model)对应data中的数据
V: 视图/模板(View)HTML元素
VM: 视图模型(ViewModel)托管数据的Vue实例,所以以后我们叫Vue的实例对象就叫vm对象

我们来输出一下vm来看看它长啥样

我们发现,橙色框中就是我们data中配置的数据,奇怪的是,它是三个点,但是点开看确实是我们刚刚配置的数据

Vue经过一些操作(我可不会告诉你这叫数据代理),将咱们在data中配置的数据直接放到了vm实例对象上

其实插值语法中可以看到vm身上所有的属性,所以可以直接写我们在data中配置的属性

数据代理

回顾Object.defineProperty()

在说这个之前,我们先来回顾一下Object上的一个方法defineProperty

1
2
3
let person={
name: 'lisi'
}

现在我要给person对象上添加一个属性age

第一种写法

1
person.age=18

第二种写法

1
2
3
Object.defineProperty(person,'age',{
value: 18
})

那有人就要说了,谁选第二种方式啊,第一种方式那么简单,此言差矣

第二种写的方式定义的age属性有两个特性

第一个,他无法被遍历,删除,修改

无法被遍历,是什么意思?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 遍历person中的所有属性
for(p in person){
console.log(p)
}
// 拿到person中的属性数组
console.log(Object.keys(person))
// 除了age属性,其他的属性都可以被遍历到

//用Object.defineProperty定义的数据有很多限制,但是可以通过一些配置项来使其解除限制
Object.defineProperty(person,'age',{
value: 18,
enumerable: true,//可被遍历,默认值是false
writable:true, //可以被修改,默认值是false
configurable:true //可以被删除,默认值是false
}
})

第二个,它可以做数据劫持

这就需要一些其他的配置项了,即getset

1
2
3
4
5
6
7
8
9
10
11
12
13
14
let number = 18;
Object.defineProperty(person,'age',{
// 当有人读取person的age的时候,即点了那三个点的时候
// 就会将这个函数的返回值作为person.age的值展示出来
get(){
console.log('嘿嘿,旧数据被我劫持了!!')
return number
},
// 当有人修改person的age的时候
set(newValue){
console.log('嘿嘿,新数据被我劫持了!!我要做坏事了')
number = newValue;
}
})

定义

给数据代理下个定义:通过一个对象代理对另一个对象中属性的操作(R/W)

我们看一下Vue中的数据代理

vm实例对象代理了data中配置的属性

我们先来证明一个事情:我们传入的data配置项和vm身上的_data是同一个对象

1
2
3
4
5
6
7
let data = {
name:'芝麻芝麻'
}
let vm = new Vue({
el:'#app',
data
})

证明

这里我们观察到data已经不是原来的那个对象了,它已经被Vue加工过了

那么Vue中的数据代理就是vm代理了_data中的数据修改

_data中的数据发生了修改,_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
<script type="text/javascript">
// 我的Vue的构造函数
function MyVue(options){
// 拿到配置项传入的data
let data = options['data'];
// 数据代理,将data中出现的属性代理给实例对象
Object.keys(data).forEach((p)=>{
Object.defineProperty(this,p,{
get(){
return data[p];
},
set(newValue){
data[p] = newValue;
}
})
})
// 数据劫持
// 将data进行一些加工,使其可以检测属性的变化,当属性变化的时候,对页面做出更新
function Observer(data){
Object.keys(data).forEach((p)=>{
Object.defineProperty(this,p,{
get(){
console.log('有人读取配置项中的数据');
return data[p];
},
set(newValue){
console.log('有人修改配置项中的数据,我要更新页面了');
data[p]=newValue;
}
})
})
}
// 对传入的data数据进行加工,并将其赋值给_data
this._data=new Observer(data);
options.data=this._data
}
const vm = new MyVue({
data: {
name: 'zhima'
}
})
</script>

证明:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 问题一
// 对于嵌套类型的对象,是无效的,因为我没有写递归语句,源码是写了递归语句,将对象的每一层都加了getter/setter

// 问题二
// 这里的_data对象和传入的data对象是不一致的
// 这里我不知道怎么实现这一点,有会的大佬可以发一下评论区
let data = {
name: 'zhima'
}
const vm = new MyVue({
data
})
//console
vm._data===data
false

这里的代码看不懂不要紧哦,我接下来还会再提一遍的,慢慢地会懂的

加油加油💪

给作者买杯咖啡吧~~~