Vue 2.0的学习笔记:Vue的观察者
有时你可能想要观察数据的变化和反应。通常,我们会使用计算属性(computed
),但是有些场景需要实现定制的监视程序。在我们讨论何使使用观察者之前,让我们先看一个如何使用它们的例子。我们将构建一个Live搜索,当我们在文本框输入关键词时,它将返回搜索结果。我们使用JavaScript的setTimeout
函数来模拟从API中抓取结果。
我已经准备好了模板以及一些数据属性。到目前为止,它只将文本的value
值绑定到data
中的searchQuery
属性。而搜索结果将存储在results
中,该属性将是字符串数组。为了判断我们是否在获取搜索结果,我将使用一个isSearching
布尔属性。这是我们以前见过的。
<!-- HTML -->
<div id="#app">
<input type="text" v-model="searchQuery" />
<p v-if="isSearching">Searching...</p>
<div v-else>
<ol>
<li v-for="result in results">{{ result }}</li>
</ol>
</div>
</div>
let app = new Vue({
el: '#app',
data () {
searchQuery: '',
results: [],
isSearching: false
}
})
当searchQuery
属性的值发生变化时,我想触发一个搜索,那我该怎么做呢?我们可以用一个叫做观察者的东西。观察者是当他们监视数据属性值发生变化时被调用的函数。因此,我们将一个观察者与一个数据属性关联起来。观察者被添加到一个名为watch
属性中,该属性被添加到Vue实例的顶层,类似于data
、methods
和computed
。
这个watch
具有和前面介绍的methods
具有相同的语法,但是有一个关键的区别。虽然嵌套属性的值确实是函数,但键的名称必须对应数据属性中的名称。因此,如果我们想要查看searchQuery
数据属性的更改,我们需要在watch
中输入searchQuery
作为我们观察者的键(key
)。
let app = new Vue({
el: '#app',
data () {
searchQuery: '',
results: [],
isSearching: false
},
watch: {
searchQuery: function (query) {
}
}
})
这就是我们告诉Vue的方法。观察者监视和响应数据属性。注意,我们向监视的函数添加了一个参数。这是数据属性的新值,当searchQuery
的值发生变化时,该值作为Vue的参数传递。为了向您展示,每当数据属性被更改时,这个函数确实被调用,我将新值记录到控制台。我们在searchQuery
中添加一个console.log(query)
,尝试在input
输入内容,你在控制台上就可以看到相应的值。
在键入时,我们可以看到在控制台中正在输出的搜索查询。
上面是为了向大家演示,Vue的观察者在监视searchQuery
。那么我们把实际需要的搜索逻辑放到这个函数当中。我们要做的第一件事是将isSearch
属性的值设置为true
,表明我们正在等待从服务器返回的搜索结果。与methods
一样,将使用这个关键字来访问观察者内的函数。
let app = new Vue({
el: '#app',
data () {
searchQuery: '',
results: [],
isSearching: false
},
watch: {
searchQuery: function (query) {
this.isSearch = true
console.log(query)
}
}
})
为了让体验更佳,接下来在searchQuery
中添加一个setTimeout
函数,并在500ms
后运行这个函数,以模拟从服务器检索结果。
let app = new Vue({
el: '#app',
data () {
searchQuery: '',
results: [],
isSearching: false
},
watch: {
searchQuery: function (query) {
this.isSearch = true
console.log(query)
setTimeout(() => {
console.log(this)
},500)
}
}
})
在这个函数中,我们需要更新我们的搜索结果results
属性。但是我们不能在这使用这个函数,那是因为现在的作用范围不同。同样先做个测试,观察者先监视searchQuery
,并把搜索的值打印到控制台,然后借助setTimeout
函数,延迟500ms
把this
打印到控制台。我们看到的效果是,每次在input
中输入值时,控制台会对应的打印出你的输入值,并且在500ms
后会将Vue实例打印出来。能在嵌套函数中访问到Vue的实例,那是因为我们使用了ES6的箭头函数,如果不是箭头函数,你访问到的是window
对象。
另外一种方法是比较老的技巧,将this
分配给一个变量,然后在嵌套函数中引用它。我常喜欢将其添加给一个me
或self
的变量,很多同学喜欢用that
来区分。但在Vue中,也有很多人用vm
来声明这个变量,也就是Vue model的缩写,也是一种命名Vue实例的约定,并将其分配给它。
有了这些,我们现在就可以回到实现搜索功能的案例中来。先将搜索结果results
的值设置为JavaScript
、CSS
、HTML
和MySQL
。注意results
是一个数组。为了要让搜索结果显示出来,我们还需要把isSearching
值设置为false
:
let app = new Vue({
el: '#app',
data () {
return {
searchQuery: 'Search',
results: [],
isSearching: false
}
},
watch: {
searchQuery: function (query) {
this.isSearching = true;
console.log(query)
setTimeout(() => {
this.results = ['JavaScript', 'CSS', 'HTML', 'MySQL']
this.isSearching = false
}, 500)
}
}
})
正如你看到效果一样,只要你对文本框进行操作,改变input
的值,就可以看到搜索结果的列表显示出来。
你可能会问,有什么大不了的。为什么我们不能只使用computed
或者事件监听器?实际上,你可以使用后者,但是我们没法通过computed
来完成它。原因是计算的属性是同步的,必须返回一个值。AJAX请求或者这个示例中的setTimeout
函数是异步运行的,这就是为什么我们不能使用computed
。因为Vue侦听函数的返回值。正如我提到的,你可以与一个事件侦听器完成相同的事情,但是这也有一定的缺点,你要手动处理这个事件和调用一个方法,而不是仅仅监听数据变化。而且,如果数据在某种程度上被改变,那么我们应用程序是不会做出相应的反应。
在Vue中,当你想要异步地对数据更改做出反应时,通常使用Vue的观察者。当然也可以不必在一个观察者中返回任何与计算属性相关的内容。这就是说,你通常应该尽可能地使用计算属性,除非你需要做一些无法用计算属性完成的事情。
这是为什么 Vue 通过 watch
选项提供一个更通用的方法,来响应数据的变化。当你想要在数据变化响应时,执行异步操作或开销较大的操作,这是很有用的。
前面通过一个简单地搜索实例向大家演示了Vue中的观察者如何使用?在Vue中,除了观察者watch
之外,还提供了$watch
实例方法。接下来咱们继续通过示例向大家演示如何在Vue中动态地添加观察者,即“外部”Vue实例。
在Vue中,如果你已经将一个Vue实例赋给一个变量,那么这个变量上就会有一个$watch
实例方法。这个方法让我们添加一个观察者。下面来看我们怎么用这个。
我们前面使用Vue的methods
做了一个计数器,接下来咱们继续用计数器的例子来演示Vue的$watch
实例方法的使用。
把上面的示例简化一下,变成这样:
<!-- HTML -->
<div id="app">
<button @click="count++">+</button>
<p>Counter: {{ count }}</p>
</div>
let app = new Vue({
el: '#app',
data () {
return {
count: 0
}
}
})
看到的效果如下:
现在,给它添加一个观察者,当值发生变化时,就会得到通知。当然,我们可以通过前面介绍的观察者来实现这一点,但我们想了解的是如何动态的添加这么一个观察者。
在看如何实现动态添加一个观察者之前,先看看Vue官网对$watch
的简单介绍。
$watch
的语法很简单:
vm.$watch(expOrFn, callback, [options])
其中vm
指的是Vue中的一个实例,就是我们示例中的app
。那么$watch
接受下面几个参数:
{string | Function} expOrFn
{Function | Object} callback
{Object} [options]
它将会得到一个{Function} unwatch
的返回值。简单的了解了这些,咱们来看其怎么用。在上例的基础上,咱们添加下面的代码:
app.$watch('count', function(newValue, oldValue){
alert('Count changed from ' + oldValue + ' to ' + newValue + '!')
})
这个时候,我们每点击一次button
按钮,data
中的count
就会有变化,从旧的值oldValue
变成一个新的值newValue
。如下图所示:
注意:这里我们不能使用ES6的箭头函数,因为箭头函数被绑定到父的上下文,而
this
这个关键词将不会被正确绑定到Vue的实例。
我们还可以指定一个关键路径作为表达式,这也意味着我们可以使用点表示法引用嵌套对象中的属性。为了向大家演示这一点,先在上面的示例的data
中添加person
对象:
let app = new Vue({
el: '#app',
data () {
return {
count: 0,
person: {
name: {
firstName: 'Airen',
lastName: 'Liao'
}
}
}
}
})
如果我们想观察firstName
属性的变化,我们可以使用点方法访问到这个属性,像下面这样:
app.$watch('person.name.firstName', function(newValue, oldValue){
alert('firstName 从 ' + oldValue + ' 变成 ' + newValue + '!')
})
为了看到效果,在HTML中,添加一个button
,同样绑定一个click
事件,并将firstName
指定一个新的值:
<button @click="person.name.firstName = '大漠'">改变firstName</button>
当你在渲染出来的页面中点击“改变firstName”按钮看,弹框弹出的信息如下:
但如果我们想要观察对象的变化而不是对象中特定属性呢?比如我们只希望在name
对象中发生变化时得到通知,而不是具体地侦听firstName
属性。这个时候,我们可以这样做:
app.$watch('person.name', function(newValue, oldValue){
alert('firstName从 ' + oldValue.firstName + ' 变成 ' + 'newValue.firstName' + '!')
})
注意:传递的值和新值将匹配我们指定的键路径,因此在本例中,它们都将是
name
对象。
我们运行我们的代码,并且改变firstName
。似乎没得到我们预期想要的效果,观察似乎没有工作。这是因为我们必须告诉Vue也要在对象内查找嵌套的值。我们可以通过将选项的对象作为$watch
方法的第三个参数来实现。这里选择的是deep
选项,并且将其值设置为true
:
app.$watch('person.name', function(newValue, oldValue){
alert('firstName从 ' + oldValue.firstName + ' 变成 ' + 'newValue.firstName' + '!')
}, {deep: true})
这个时候我们看到的效果是这样:
从弹出的框中,我们可以看出oldValue
和newValue
的值是一样的。这是因为当改变一个对象或数组(意味着在不创建新副本情况下修改它)时,oldValue
和newValue
的值将是相同的,因为Vue没有保留以前的值作为副本。因此,两个参数都引用同一个对象或数组。
有的时候你可能需要一个更复杂的表达式。在这种情况下,不添加表达式作为$watch
方法的第一个参数,你也可以传入一个函数。这个函数应该简单地返回你希望监视更改的表达式。上面的示例的计数器,咱们可以改成这样:
app.$watch(
function () {
return this.count
},
function (newValue, oldValue) {
alert('Count从 ' + oldValue + ' 变成 ' + newValue + '!')
}
)
当然,你可以添加比这个更复杂的表达式。每当表达式中的一个依赖项发生变化时,观察者就会被触发。这种方法支持更高级的用例,当然这种情况可能很少出现。
前面演示的都是如何动态的添加一个观察者,既然可以动态的添加,同样就可以动态删除。接下来咱们就看如何动态删除一个观察者。每当我们使用$watch
方法时,它实际上会返回一个函数,然后我们可以调用它来停止观察脚本中后面的更改。通过将方法的返回值赋给一个变量来尝试使用这个方法。
let unwatch = app.$watch(
function () {
return this.count
},
function (newValue, oldValue) {
alert('Count从 ' + oldValue + ' 变成 ' + newValue + '!')
}
)
这样我们就能看到区别,让我们在五秒种后停止观察变化。
setTimeout(function() {
unwatch();
}, 5000);
在运行代码时,我们一开始在单击按钮时看到了警报。但五秒钟后,我们不再看到警报,因为观察者已经被删除了。
修改后的完成代码可以看CodePen上的这个示例:
这就是动态增加和删除观察者的一些知识点。如果你需要应用一些逻辑,或者有条件地添加观察者,这是很有用的。最后要注意的是,除了可以观察data
属性之外,还可以观察computed
。
总结
今天我们主要学习了Vue中的观察者相关的知识。我们可以在Vue中像使用methods
和computed
一样的使用watch
。特别是当你想对data
中的某个属性进行观察的时候,侦听其变化。除了使用watch
之外,还可以使用$watch
的API,实现动态添加和删除watch
。
Vue中的watch
可以帮助我们做很多事情,比如下面这个小例子,通过watch
对data
中的date
进行观察,当时间变化时,对应的容器背景色也会改变。感兴趣的可以在CodePen上看示例的整个代码:
在Vue中除了可以使用watch
来侦听属性的变化之外,还可以使用$emit
和$on
来做一些侦听的事情,具体怎么使用,我们后续会学习这方面的东西。
由于作者是Vue的初学者,如果文章中有不对之处,还请各路大婶拍正,如果你有更好的经验或建议,欢迎在下面的评论中与我们一起分享。
如需转载,烦请注明出处:https://www.fedev.cn/vue/vue-watch.htmlNike Air Shox Deliver 809 Men Running shoes Deep Blue Black