指令v-on:后面直接跟事件名,比如:click/change/focus/blur/mouseover/keyup……
引号("")中指令的值可以是:
<h1 v-on:click="counter++" id="yz-hello">{{counter}}</h1>但counter只能是vue data中的值:
data: { counter: 1 },演示:声明一个全局变量n,click中n++仍然报错。
当handler的逻辑变得复杂,就需要将其封装到一个方法中:
methods: { plus: function () { this.counter++; } }
模板中调用:(一样不能是vue外部的function)
<h1 v-on:click="plus" id="yz-hello">{{counter}}</h1>注意:v-on:click的值只是方法名,没有圆括号。
<h1 v-on:click="plus()" id="yz-hello">{{counter}}</h1>
这实际上就是一个方法调用表达式,和只写方法名一样一样的!^_^
但是,@试一试@:直接在click后面这样写行不行呢?
<h1 v-on:click="alert('皮一下很开森')" id="yz-hello">{{counter}}</h1>结果会报错:
Property or method "alert" is not defined on the instance
说明什么?vue里面事件的运行时环境是vue实例!切记切记。
习惯于原生JavaScript或者JQuery事件绑定机制的同学可能还在等……
下面呢?下面没了,^_^Vue没有提供在JavaScript中找到某个DOM节点,然后对其绑定事件的机制。
在 HTML 中监听事件不是违背了关注点分离 (separation of concern)原则么?
PS:提这个问题的同学一定不是从头跟着飞哥学的……
软件工程哲学:
具体到Vue的事件机制(官方解释),飞哥的补充:
大赞!实际上,有很多问题,100%严格执行并无必要
在传统的JavaScript事件处理函数中,this指的是触发事件的HTML元素。
但在vue的methods中,this显然指代的是vue的当前实例。这虽然符合JavaScript语法,但要获取事件触发的HTML元素,怎么办呢?
从event中获得,根据内容不同:
plus: function (event) { event.preventDefault(); console.log(event.target); this.counter++; }这里的event和传统的JavaScript事件回调函数中的event一致,都是指的原生DOM事件。
<h1 v-on:click="plus($event)" id="yz-hello">{{counter}}</h1>
这样,methods中plus也中也能拿到event。
演示:v-on:click="plus()"时,methods中event为undefined
和表单绑定时类似,都是在事件名之后添加以点(.)开头的指令后缀:
<a href="http://17bang.ren" v-on:click.prevent="plus($event)" id="yz-hello">{{counter}}</a>
div { border: 1px solid; }
<div v-on:click="outer" style="padding:40px;" id="yz-hello"> <div v-on:click="inner">inner</div> </div>
outer: function (event) { console.log('outer:'); }, inner: function (event) { console.log('inner'); }
<!-- 只有在 `key` 是 `Enter` 时调用 `vm.inner()` --> <input v-on:keyup.enter="inner">
<!-- Alt + C --> <input v-on:keyup.alt.67="inner">
<button type="button" v-on:click="toggle">提交</button>关键点在于:如何显示和隐藏其HTML内容?更改其style样式,DOM树上remove,……?
都不是,还记得v-if/v-show么?
<span v-show="show" style="border: 1px dashed; padding: 5px;">源栈欢迎您</span>
显示,将其值设为true;隐藏,设为false即可。
toggle: function () { this.show = !this.show; }
模拟bootstrap实现。准备一个样式:
.tooltip { background-color: cadetblue; position: relative; right: 65px; bottom: 20px; }
当然要使用mouseover事件,但也不要忘了mouseout!所以这是在一个DOM元素上绑定了多个事件:
<span v-on:mouseover="show" v-on:mouseout="hide" v-bind:title="showTitle">源栈欢迎您</span> <span v-if="shown" class="tooltip">{{showTitle}}</span>
show: function () { this.shown = true; }, hide: function () { this.shown = false; }
<div id="bell" v-on:load="changeColor" v-bind:style="{color:color}">bell</div>
然后你可能会想到onload事件,但是,只有document、frame、image之类的才能绑定load事件啊!难道要把id加在body上面?试一下:
咋整?还记得我们学过的生命周期钩子么?那些钩子函数是不是和事件处理函数类似的?我们可以选择mounted:
mounted: function () { setInterval(function () { if (this.color == 'red') { this.color = 'blue'; } else { this.color = 'red'; } }, 1000) //每隔一秒变换一次颜色 },行不行?为什么?(F12断点调试:此时的this不再是vue实例)
setInterval(function () { //... }.bind(this), 1000)
复习:bind()
而且,Vue是不建议直接操作DOM的。但有的时候,因为各种各样的原因,我们还是不得不找到DOM元素……比如:
上述tooltip的例子中,DOM原有的title提示,如何消掉呢?
演示说明:都不行的。只有通过DOM操作将其属性title值设置为空才行(HTML中已添加id="slagon"):
document.getElementById('slagon').title = '';
修改一下上述代码,每次mouseover我们都更新一下title
this.times++; //初始值为1,每次递增 this.showTitle += ('-' + this.times);
这是因为Vue的渲染是异步的,所以当我们执行的getElementById()的时候,拿到的是渲染前的数据:这是一个大坑!
所以Vue提供了内置的$nextTick()方法,传入的回调函数会在渲染完成之后再执行:
this.$nextTick(function () { document.getElementById('slagon').title = ''; })
<span ref="slagon"
this.$refs.slagon.title = ''
这样可以从Vue的template开始查起,性能可以有些微提升。
因为有ViewData绑定,在vue里面进入输入验证也是已经非常容易的事情:只需要在相应事件(比如:submit/blur/change)中绑定验证方法即可。
<form novalidate="true" id="yz-hello"><!-- 注意novalidate --> <input v-on:change="require" v-model="sname" > <p v-if="error">{{error}}</p> </form>
require:function(){ if (!this.sname) {//this.能省略么? this.error = '* 用户名必须填写'; }//一眼看去,这代码有问题不? }
牢记:有if就一定要想到else。
@想一想@:上述代码能阻止form表单的提交么?
所以我们还需要给form添加submit事件:(@submit是vue3推出的简写方式)
<form @submit="checkAll" novalidate="true" id="yz-hello">
checkAll: function (event) { if (this.error) { event.preventDefault(); } }
@想一想@:能看出上述代码的问题么?
不能用this.error来判断用户的输入是否正确哟!因为this.error是因为change(或其他)事件而触发,form表单提交的时候,这些事件完全有可能没有触发,所以this.error仍然为空。还是要使用this.sname进行判断。
当有多个表单元素时,我们通常将error设置为一个对象
error: {}这样可以用:
而且还可以重用require方法,
<input v-on:blur="require" v-model="sname"> <input v-on:blur="require" v-model="password">这就需要把错误信息直接写在HTML template中:
<span v-if="error.sname">* 用户名必须填写</span> <span v-if="error.password">* 密码必须填写</span>
require方法非常简单:
this.error.sname = !this.sname; this.error.password = !this.password;
演示:未能显示错误信息!
注意:error一定不能是空对象,要把用到的属性都列出来:
error: { sname: false, password: false, confirmPassword: false }复习:set()方法
同学们可能想到能不能使用JQuery?可以的。Vue和JQuery以及JQuery的各种插件(如validation)并不冲突,直接引入稍加调整就可以使用。
但是,一般来说,Vue推荐的validation插件是:VeeValidate或vuelidate,我们后面再讲。
将之前的JavaScript事件,用vue重写一遍:
多快好省!前端后端,线上线下,名师精讲
更多了解 加: