请教, Vue 中注册事件时带括号与不带括号的查找方式具体是怎样的?

2019-10-24 14:51:04 +08:00
 cyrbuzz

背景:

想在不修改原函数的基础上(或者无察觉的基础上)给一些函数加上调用前通知的钩子,查了 Stack Overflow 得到的也是修改原函数的。在测试时发现好像没有效果,但查看组件中的this中的 VNode 信息那个函数确实已经更改,后来想了想是不是绑定方法有问题于是试了试带括号的,结果发现真的有问题...

测试代码:

<template>
  <div>
     <a @click="test()">click</a>
  </div>
</template>

<script>
export default {
  methods: {
    test () {
      console.log(1)
    }
  },
  mounted: function () {
    this.test = function () {
      console.log(2)
    }
  }
}
</script>

如果 <a @click="test">click</a> 未带括号,调用的函数是 methods 的旧函数,打印 1,

如果 <a @click="test()">click</a> 带上括号,那调用的就是新函数,打印 2。

问题:

有能直接给函数加调用前通知的钩子的方法没.

一般写代码对于无参数的写第一种还是第二种.

这两者还有什么坑点需要注意.

想两者兼容有什么办法吗.

所做尝试:

如果是 created 时修改,两者都可以是修改后的函数。

♪(・ω・)ノ谢谢指教~。

4392 次点击
所在节点    Vue.js
15 条回复
IsaacYoung
2019-10-24 14:59:36 +08:00
test()返回值是 undefined
qping
2019-10-24 14:59:44 +08:00
官方文档是用的你的第一种
TomVista
2019-10-24 15:02:28 +08:00
TomVista
2019-10-24 15:09:10 +08:00
我了去,
这是啥?
你可以试试 data:{
test:fun(){log(1)}
},
这个东西很复杂,我讲不明白,等个大佬
cyrbuzz
2019-10-24 15:22:13 +08:00
@TomVista
谢谢~,
Vue 似乎也是将`@click="test()"`这样的包裹在了一个函数里,包裹在函数中是可以任意修改的,
有没有兼容两者的方法修改方法或者直接给函数加个钩子?最初的目的也只是想在函数调用前能有个通知。
lllllliu
2019-10-24 15:33:19 +08:00
这就可以用代理实现了呀。或者你可以搞一下 AOP。
shintendo
2019-10-24 15:44:14 +08:00
1.
不带括号的情况下,绑定的是 this.test 函数,并且在 mount 阶段就绑好了,你后面改动 this.test 的指向,不影响绑定的那个函数。
带括号的情况下,绑定的是 function(){this.test()}函数,this.test 的值是每次函数调用时计算的,所以你改变 this.test 的指向有效。
2.
我个人习惯于始终带括号,因为传参更显式。
要说有什么坑点的话,不带括号需要注意默认的 e 参数。
TomVista
2019-10-24 15:47:02 +08:00
@cyrbuzz 不是这个原因 , 你试试下面的代码

<template>
<div @click="test()">{{test}}
<p>{{d}}</p>
</div>
</template>

<script>

export default {
name: 'trainerList',
layout: 'home',
data () {
return {
d:function(){

}
}
},
async mounted () {
},
beforeCreated () {
this.test = function (params) {
console.log('1');
}
},
created () {
this.test = function (params) {
console.log('2');
}
},
beforMounted () {
this.test = function (params) {
console.log('3');
}
},
mounted () {
this.test = function (params) {
console.log('4');
}
this.test()
this.$forceUpdate()
},
methods: {
test:function () {
console.log('123');
}
}
}
</script>
cyrbuzz
2019-10-24 16:18:43 +08:00
@lllllliu
Proxy 不能来代理函数吧。
cyrbuzz
2019-10-24 16:23:53 +08:00
@TomVista
喔...用$forceUpdate 可以强制刷新,近乎完美,非常感谢~~,如果能在其他组件里也应用就更好了~。
lllllliu
2019-10-24 16:24:47 +08:00
@cyrbuzz #9 function
你现在打开控制台~ 丢一个 function,其实也只是一个在 window 下的一个属性 /对象而已。。。可以去看一下 VUE 各个部分的实现原理。。暴力实现你这个所谓的前置方法其实很容易的。多看看呀。
cyrbuzz
2019-10-24 18:45:31 +08:00
@lllllliu
谢谢,恕我愚昧,一开始在 Stack Overflow 里给出的方法也是 window 下的 hack。
```
function a () {
console.log('old')
}
let b = window.a
window.a = function () {
console.log('new')
b()
}

a()
```
结合后面 @TomVista 大佬给出的知乎中的解答和 @shintendo 大佬给出的解答,
Vue 底层应该也是用的`addEventListener`给元素添加事件监听,

```
<body>
<a id="click">click</a>
</body>
<script>
function a () {
console.log('old')
}

let c = document.getElementById('click')
c.addEventListener('click', a)

let b = window.a
window.a = function () {
console.log('new')
b()
}
</script>
```
这样的尝试后依然是无效的...
现在还是有点没解决~。
luoway
2019-10-24 19:46:02 +08:00
> 想在不修改原函数的基础上(或者无察觉的基础上)给一些函数加上调用前通知的钩子

使用 Vue.mixin 在 beforeMount、beforeUpdate 生命周期里对 this 上方法(排除 vue 保留方法)进行装饰
cyrbuzz
2019-10-24 22:10:24 +08:00
@luoway
非常感谢!!发现了新的思路~~。
zlu1123
2019-10-24 22:39:41 +08:00
加与不加括号的区别在于事件对象参数 event 的处理。不加括号时,函数第一个参数为 event,加了括号后,需要手动传入 $event 才能获得事件对象

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/612550

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX