指令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重写一遍:
多快好省!前端后端,线上线下,名师精讲
更多了解 加: