Vue.js 响应式系统
响应式系统是 Vue.js 最具标志性的特点之一。在 Vue.js 中,模型是普通的 JavaScript 对象。当我们修改模型时,视图将被更新。这使得状态管理简单直观,但了解其如何工作也是避免一些普遍问题的关键。在这里,我们将通过使用响应系统来解决这些问题。
它是如何工作的?
如果将一个普通的 JavaScript 对象作为数据选项传递给 Vue.js 实例,你会发现 Vue.js 通过 Object.defineProperty
把它的所有属性转换为 getter 和 setter。
这是一个无法代理的、仅支持 ES5 特性的功能。由于这个特性,Vue 不支持 IE8 及以下版本。
getter 和 setter 对于用户而言是不可见的,但在幕后,它们使得 Vue.js 能够在你需要改变或访问属性时执行依赖跟踪和变更通知。你可以在浏览器的控制台上看到 getter/setter 的属性更改。如果想查看它们,你需要安装更友好的代码审查工具 vue-devtools。
每个组件实例都有一个相应的 watcher 实例。这个 watcher 记录了在组件渲染期间被“触及”的属性作为依赖项。此后,当依赖项的 setter 被触发时,它通知 watcher,watcher 再次重新渲染该组件。
Vue.js 响应式接口
Vue.js 为我们提供了一种将响应式添加到动态添加的属性的选项。假设我们已经创建了 Vue.js 实例,并且我们想添加 watch 属性。请看下面的示例:
示例:
Index.html 文件:
<html>
<head>
<title>Vue.js 响应式接口</title>
<link rel="stylesheet" href="index.css">
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id = "reactivity_1">
<p style = "font-size:25px;">Counter: {{ counter }}</p>
<button @click = "counter++" style = "font-size:25px;">Click Here</button>
</div>
<script src="index.js"></script>
</body>
</html>
Index.js 文件:
var vm = new Vue({
el: '#reactivity_1',
data: {
counter: 1
}
});
vm.$watch('counter', function(nval, oval) {
alert('Counter 增加了 :' + oval + ' 变成了 ' + nval + '!');
});
setTimeout(
function(){
vm.counter = 10;
},1000
);
让我们使用一个简单的 CSS 文件使输出更有吸引力。
Index.css 文件:
html, body {
margin: 5px;
padding: 0;
}
程序执行后,您将看到以下输出:
输出:
当您单击“Click Here”按钮时,计数器将递增。你将看到一个弹出输出或警报消息,显示计数器属性的更改值。
在我们单击“Click Here”按钮后,请查看以下输出。
示例说明
在上面的示例中,我们定义了一个名为计数器(counter)的属性,它在 data 对象中被设置为 1。当你点击“Click Here”按钮时,计数器会递增。
在创建 Vue.js 实例之后,我们必须添加 watch 属性。使用以下代码进行添加:
vm.$watch('counter', function(nval, oval) {
alert('Counter is incremented :' + oval + ' to ' + nval + '!');
});
我们使用 $watch 属性在 Vue 实例外添加了一个 watch。我们还添加了一个警报(alert),用于显示计数器属性的值更改。还添加了一个名为 setTimeout 的计时器函数,将计数器值设为 10。
setTimeout(
function(){
vm.counter = 10;
},1000
);
每次点击按钮时,计数器都会更改,并触发 watch 方法中的警报。
在运行时添加属性
在 Vue.js 实例中,最好始终预先声明需要动态响应的属性,因为 Vue.js 无法检测属性添加和删除。
如果你想在运行时添加属性,你必须使用 Vue 全局变量,Vue.set 方法和 Vue.delete 方法。
Vue.set
它用于在对象上设置属性。这是用于克服 Vue.js 无法检测属性添加的限制的方法。
语法
Vue.set( target, key, value )
这里,
target:它可以是对象或数组。
key:它可以是字符串或数字。
value:它可以是任何类型。
让我们通过一个简单的示例来理解 Vue.set 的概念。
示例:
Index.html 文件:
<html>
<head>
<title>Vue.js Reactive Interface</title>
<link rel="stylesheet" href="index.css">
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id = "reactivity_1">
<p style = "font-size:25px;">Counter value: {{ products.id }}</p>
<button @click = "products.id++" style = "font-size:25px;">Click Here</button>
</div>
<script src="index.js"></script>
</body>
</html>
Index.js 文件:
var myproduct = {"id":1, name:"shirt", "price":"1000.00"};
var vm = new Vue({
el: '#reactivity_1',
data: {
counter: 1,
products: myproduct
}
});
vm.products.qty = "1";
console.log(vm);
vm.$watch('counter', function(nval, oval) {
alert('Counter is incremented :' + oval + ' to ' + nval + '!');
})
程序执行后,你将会看到以下输出:
输出:
这里,你会看到每次点击“Click Here”按钮时,计数器值都会增加。请看以下输出。这里,我们点击了 5 次按钮。
示例说明
在上面的示例中,我们使用以下代码在开头创建了一个名为myproduct的变量:
var myproduct = {"id":1, name:"shirt", "price":"1000.00"};
将其作为数据对象传递给了Vue.js实例,代码如下:
var vm = new Vue({
el: '#reactivity_1',
data: {
counter: 1,
products: myproduct
}
});
假设在创建Vue.js实例后,你需要向myproduct数组添加一个新的属性,你可以使用以下代码完成:
vm.products.qty = "1";
如果在控制台上查看输出,你会发现在产品清单中,数量将被添加。id、name和price的get和set方法(基本上添加了反应性)是可用的,而对于qty则不可用。
因此,你可以看到,只是添加vue对象是无法实现反应性的。在Vue.js中,你必须在开始时创建所有属性。如果你想以后再创建,可以使用Vue.set。看另一个示例,其中稍后添加了所有属性。
示例:
Index.html文件:
<html>
<head>
<title>Vue.js反应式接口</title>
<link rel="stylesheet" href="index.css">
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id = "reactivity_1">
<p style = "font-size:25px;">计数器值:{{ products.id }}</p>
<button @click = "products.id++" style = "font-size:25px;">单击此处</button>
</div>
<script src="index.js"></script>
</body>
</html>
Index.js文件:
var myproduct = {"id":1, name:"shirt", "price":"1000.00"};
var vm = new Vue({
el: '#reactivity_1',
data: {
counter: 1,
products: myproduct
}
});
Vue.set(myproduct, 'qty', 1);
console.log(vm);
vm.$watch('counter', function(nval, oval) {
alert('计数器已增加 :' + oval + ' 到 ' + nval + '!');
})
在上面的示例中,我们使用Vue.set方法将qty添加到数组中的代码如下:
Vue.set(myproduct, 'qty', 1);
如果在控制台上运行此示例,你会看到使用Vue.set方法添加了qty的get/set。## Vue.delete
Vue.delete函数用于动态删除属性。这也用于克服Vue.js无法检测属性删除的限制。
语法:
Vue.delete( target, key )
在这里,
target: 它用于指定一个对象或一个数组。
key: 它用于指定一个字符串或一个数字。
让我们看一个例子来演示如何使用Vue.delete函数在Vue.js中动态删除任何属性。
例子
Index.html 文件:
<html>
<head>
<title>Vue.js Reactive Interface</title>
<link rel="stylesheet" href="index.css">
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id = "reactivity_1">
<p style = "font-size:25px;">Counter value: {{ products.id }}</p>
<button @click = "products.id++" style = "font-size:25px;">Click Here</button>
</div>
<script src="index.js"></script>
</body>
</html>
Index.js 文件:
var myproduct = {"id":1, name:"shirt", "price":"1000.00"};
var vm = new Vue({
el: '#reactivity_1',
data: {
counter: 1,
products: myproduct
}
});
Vue.delete(myproduct, 'price');
console.log(vm);
vm.$watch('counter', function(nval, oval) {
alert('Counter is incremented :' + oval + ' to ' + nval + '!');
})
在上面的例子中,我们使用了Vue.delete函数通过以下代码来删除数组中的price:
Vue.delete(myproduct, 'price');
当您在控制台上查看上面示例的输出时,您将看到只有id和name在控制台上可见,因为price已被删除。我们还会注意到get/set方法已被删除。