我们的 Vue 新手学习之旅即将结束,你也快要从 Vue 学徒级别毕业了。但是在这之前,你必须掌握 侦听器

今天我们将要处理两个非常重要的概念,一个是刚才提到的 侦听器,另一个是 输入绑定

话不多说,我们先构建一个超级简单的表单样例来展示这两个超赞的功能。

<html> <head> <title>Vue 101</title> </head> <body> <div id="app"> <label>What's your favorite game ever?</label> <input type="text" > <hr> <p>{{ response }}</p> </div> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> <script> const app = new Vue({ el: '#app', data() { return { favoriteGame: null, response: '' } } }); </script> </body> </html>

让我们看下这段代码到底做了啥。

<div id="app"> 内部,我们创建了一个 label 标签以及最基础形式的 <input> 标签。然后,我们在模板中输出了 response 属性的结果。

Vue 实例中,我们申明了包含两个属性的本地状态,分别是 favoriteGame 以及 response。另外请注意,如果我们的 data() 不使用函数的 return 语法来创建,v-model 将不起作用。

这个功能大概是,我们希望用户无论在 <input> 标签输入什么样的内容都能存到变量中,这样的话我们就可以在合适的地方使用它了。

在 vanilla JS 甚至是 JQuery 中,你可能会用 $('input') 或者 document.querySelector 捕捉 input 元素,但是在 Vue 中我们有更简单的方法来完成这项寻常的任务。

接下来介绍下 v-model

v-model

如同你之前学习到的那样,所有以 v- 开头的属性都是 Vue 指令v-model 的含义简单来说就是:


Vue ,我想让你获取标记了 v-model 指令的输入框上的所有输入,然后建立一个双向绑定关系。我将提供一个 属性,无论何时我的代码修改了这个属性 - 输入框中的值也要同时更新,同样的,无论何时这个输入框内的值变化了 - 这个变化值也要映射到我的属性中。


让我们实际操作下,首先跳到 <input> 声明处,然后给它加上 v-model 指令。

<input type="text" v-model="favoriteGame">

现在去浏览器运行一下这段代码,然后在你奇妙而美丽的输入框中写一点东西。哈哈哈哈哈哈… 嗝?

额,好像什么事情都没发生的样子。继续打开你的 Vue 开发工具然后检查 <Root> 元素的数据。耶,有进展了。

现在进入开发工具然后改变下 favoriteGame 的值(别忘了用引号包起来,这里需要一个字符串)。EZ-BINDS-R-US ?

Vue 非常聪明,它知道如何绑定每种类型的原生 HTML 输入框,因此你只需要添加好 v-model 然后坐收渔利即可,不过得在你开始构建自己的组件并使用时 v-model 的强大才会真正的展现出来。

在幕后 v-model 实际上为每次绑定建立了 v-bind:valuev-on:input 两个指令,但在这里对这个问题深入讨论就有点超纲了,所以有兴趣了解更多相关知识的话,看下这个链接: 在组件上使用 v-model

侦听器

现在我们已经了解了超强大的黏在一起的双向绑定 v-model,接下来结合实际做一些事情吧。

你已了解过如何把 data 状态属性通过 {{ favoriteGame }} 的方式放到模板中,所以这里就不啰嗦了。也已经学过了如何在 method 以及 computed 属性中使用 this.favoriteGame - 这里也不再啰嗦。但是如果你想 “监听” 或者 “响应” 这个属性变化时候,会发生什么呢?

计算属性非常适合重新计算内容并返回处理后的数据,但如果我们想要在某个值变更的时候更改程序中其他地方的状态,或者触发某些异步请求,应该怎么做呢?在这个小案例中 侦听器 来拯救世界了。

让我们给需要观察的属性创建一个样例。

const app = new Vue({ el: '#app', data() { return { favoriteGame: null, response: '' } }, // 侦听器在这里↓ watch: { favoriteGame(newValue, oldValue) { console.log('Favorite game was ' + oldValue + ' and now is ' + newValue) } } });

侦听器被定义在主实例或者组件的 watch 属性中,我们传递了一个对象,这个对象包含了我们想要监听的每个属性及其配置。

简答来说,每个你想要监听或者响应其变化的 data 属性或者 props 属性都需要将其名称放到 watch: {} 中。所以如果你的属性名是 favoriteGame 那么这个函数的名称也是 favoriteGame

每个函数触发时都会被传入两个参数,第一个参数是该属性获得的 新值,第二个参数是该属性改变前的 老值

代码里边添加一些 console.log 声明并刷新一下你的浏览器窗口。随后试着在 <input> 标签中输入一些内容然后检查下控制台输出。不论何时何地 favoriteGame 属性只要变了,监听函数就会被触发。

下面我们用这个来实操一点有意思的东西。还记得我们的 response 属性么?让我们根据用户的输入信息生成一些有意思内容并放到 response 属性中去,皮一下就很开心。

watch: { favoriteGame(newValue, oldValue) { if (!newValue) return // 如果是空字符串,直接返回 // 如果新值包含关键字 metroid if (newValue.toLowerCase().indexOf('metroid') !== -1) { this.response = 'Ceres station is under attack!' return } // 如果新值包含单词 zelda if (newValue.toLowerCase().indexOf('zelda') !== -1) { this.response = 'Its dangerous to go alone, take this ?️' return } // 如果老值包含 metroid 并且用户对其进行了修改 if ( oldValue.toLowerCase().indexOf('metroid') !== -1 && newValue.toLowerCase().indexOf('metroid') === -1 ) { this.response = 'GET TO DA CHOPPA NAO' return } // 默认响应值 this.response = 'Sure, why not?' } }

以防万一你不理解代码,indexOf 会检查传入的字符串是否存在于当前字符串中,并在不存在时返回 -1,存在时返回字符串所在的位置。

继续用这个做一些有意思的玩意吧,写一些新示例然后在浏览器中把玩把玩。

我期望你现在可以理解监视属性的强大,多思考有助于理解这个功能,比如我的属性发生了改变并且我需要用编程的方式去响应它(通过 ajax 调用,外部函数,更新一个辅助值等等),这些场景通常来讲用监听器是一个好的解决方案。除此之外,还有计算属性可供选择。

<html> <head> <title>Vue 101</title> </head> <body> <div id="app"> <label>What's your favorite game ever?</label> <input type="text" v-model="favoriteGame"> <hr> <p>{{ response }}</p> </div> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> <script> const app = new Vue({ el: '#app', data() { return { favoriteGame: null, response: '' } }, watch: { favoriteGame(newValue, oldValue) { if (!newValue) return if (newValue.toLowerCase().indexOf('metroid') !== -1) { this.response = 'Ceres station is under attack!' return } if (newValue.toLowerCase().indexOf('zelda') !== -1) { this.response = 'Its dangerous to go alone, take this ?️' return } if ( oldValue.toLowerCase().indexOf('metroid') !== -1 && newValue.toLowerCase().indexOf('metroid') === -1 ) { this.response = 'Nothing is true , everything is permitted' return } this.response = 'Sure, why not?' } } }); </script> </body> </html>

总结

恭喜你已经在学习 Vue 的道路上走这么远了!

现在,我确信你已经掌握了基础工具的使用,可以在 Vue 中实际构建一个非常溜的有实际功能的应用了。但是学海无涯,还有很多东西需要学习与探索以便你能榨干框架的全部能力。

不过不要担心,我曾提到过 Vue.js 最棒的地方就是它的 文档,并且我现在也还这样认为。

还记得我最开始试着写代码的时候,非常担心看不懂文档,因为技术文档一般都解释得很晦涩,并且还假定我已经对这个语言或者框架有着非常高的了解。

值得庆幸的是,Vue 文档团队对此做了很多出色的工作,为我们需要的所有功能撰写了完整的编程指南和示例代码,在本指南中我们已经详细介绍过了,除此之外你仍需要继续深入理解 Vue 框架。

Vue 实战入门系列到此结束!