一、data属性
data属性是传入一个函数,并且该函数需要返回一个对象:
- 在Vue2.x的时候,也可以传入一个对象(虽然官方推荐是一个函数);
- 在Vue3.x的时候,必须传入一个函数,否则就会直接在浏览器中报错;
data中返回的对象会被Vue的响应式系统劫持,之后对该对象的修改或者访问都会在劫持中被处理
- 所以我们在template或者app中通过{{counter}}访问counter,可以从对象中获取到数据;
- 所以我们修改counter的值时,app中的{{counter}}也会发生改变;
具体这种响应式的原理,我们后面会有专门的篇幅来讲解。
(1)案例
我们现在有个button按钮,我怎么通过点击这个button按钮去改变message的值?
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<div id="app">
<h2>{{message}}</h2>
<button @click="changeMessage">改变message</button>
</div>
<script src="./lib/vue.js"></script>
<script>
const app = Vue.createApp({
// data: option api
data: function () {
return {
message: 'Hello World',
};
},
// methods: option api
methods: {
changeMessage: function () {
this.message = '奥利给';
},
},
});
app.mount('#app');
</script>
</body>
</html>
二、methods属性
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<div id="app">
<h2>当前计数: {{counter}}</h2>
<button @click="increment">+1</button>
<button @click="decrement">-1</button>
</div>
<script src="./lib/vue.js"></script>
<script>
const app = Vue.createApp({
data: function () {
return {
counter: 0,
};
},
methods: {
increment: function () {
console.log(this);
this.counter++;
},
decrement: function () {
this.counter--;
},
},
});
app.mount('#app');
</script>
</body>
</html>
有同学很好奇,这里methods里面的调用的this是什么?
如果我们只单纯这么看,这里的this能知道指向的是什么吗?很明显不能。因为这里的this具体是什么,取决于这个函数到底是如何被调用的。
- 如果这个函数直接这么调用 increment() ,那这里的this指向的是window。
- 那如果我们把increment函数放到obj里面,我们直接obj.increment,那就等同于increment。
- 如果obj.increment(),这样子绑定的就是obj对象。(隐式绑定)
我们来重新考虑一下我们大概要实现一个什么样子的功能?因为我们需要改变counter的值,我们通过点击按钮触发increment这个函数,然后要在这个函数里面通过this去访问data里面的counter,改掉这个值之后上面的计数{{counter}}值才会发生改变。
那我们这里可以用window.counter++吗?明显不行。
- window有counter吗?明显没有。
- window可以改变上面的counter吗?明显也不可以。
其实函数有下面三种写法, 方法1和方法2其实是一样的。我们重点看方法3。
methods: {
// 方法1
increment: function () {
console.log(this);
this.counter++;
},
// 方法2,es6的写法
increment() {
},
// 方法3
increment: () => {
console.log(this);
},
},
首先我们了解一下箭头函数是什么意思。
箭头函数是一种简写的函数语法,可以更容易地创建匿名函数。它通常使用箭头 => 来代替函数关键字和return语句。例如,(x) => x * 2 可以代替 function(x) { return x * 2 }。这使得代码更简洁、更容易理解。
箭头函数会绑定this吗?不会,那他就去找谁?他就会去找他上层作用域里面的this。那他上层作用域是什么?难道是methods吗?很明显不是,methods是一个对象类型,没有自己作用域这一说。我们继续往上找,methods上面是什么?是不是vue创建app实例的时候需要传入的一个对象?那他也是一个对象肯定也没有自己作用域这一说。然后他继续往上层作用域里面找,再上面一层是不是就是全局作用域了。所以你在全局作用域里面打印this,肯定和箭头函数打印的this是同一个this。
看完箭头函数中的this指向,我们再来看下下面这个this指向什么?我们点击触发一下。
大家看一下,是不是一个代理对象。为什么又是一个代理对象呢?其实本质上前面跟大家讲到过,
当前的这种对象会被代理,代理之后我们是不是可以通过这个代理对象对里面的counter进行修改?当然可以。(后续会更深层次的继续讲原理)。
其实这个this在内部,如果你是一个普通函数的话,他是可以绑定this的,也就是说在执行increment这个函数的时候,他是会给你绑定一个this的。
this到底指向什么?