请教, Vue 中注册事件时带括号与不带括号的查找方式具体是怎样的? - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
cyrbuzz
V2EX    Vue.js

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

  •  
  •   cyrbuzz
    HuberTRoy 2019-10-24 14:51:04 +08:00 4681 次点击
    这是一个创建于 2179 天前的主题,其中的信息可能已经有所发展或是发生改变。

    背景:

    想在不修改原函数的基础上(或者无察觉的基础上)给一些函数加上调用前通知的钩子,查了 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 时修改,两者都可以是修改后的函数。

    (ω)谢谢指教~。

    15 条回复    2019-10-24 22:39:41 +08:00
    IsaacYoung
        1
    IsaacYoung  
       2019-10-24 14:59:36 +08:00
    test()返回值是 undefined
    qping
        2
    qping  
       2019-10-24 14:59:44 +08:00   1
    官方文档是用的你的第一种
    TomVista
        3
    TomVista  
       2019-10-24 15:02:28 +08:00   1
    TomVista
        4
    TomVista  
       2019-10-24 15:09:10 +08:00
    我了去,
    这是啥?
    你可以试试 data:{
    test:fun(){log(1)}
    },
    这个东西很复杂,我讲不明白,等个大佬
    cyrbuzz
        5
    cyrbuzz  
    OP
       2019-10-24 15:22:13 +08:00
    @TomVista
    谢谢~,
    Vue 似乎也是将`@click="test()"`这样的包裹在了一个函数里,包裹在函数中是可以任意修改的,
    有没有兼容两者的方法修改方法或者直接给函数加个钩子?最初的目的也只是想在函数调用前能有个通知。
    lllllliu
        6
    lllllliu  
       2019-10-24 15:33:19 +08:00
    这就可以用代理实现了呀。或者你可以搞一下 AOP。
    shintendo
        7
    shintendo  
       2019-10-24 15:44:14 +08:00   4
    1.
    不带括号的情况下,绑定的是 this.test 函数,并且在 mount 阶段就绑好了,你后面改动 this.test 的指向,不影响绑定的那个函数。
    带括号的情况下,绑定的是 function(){this.test()}函数,this.test 的值是每次函数调用时计算的,所以你改变 this.test 的指向有效。
    2.
    我个人习惯于始终带括号,因为传参更显式。
    要说有什么坑点的话,不带括号需要注意默认的 e 参数。
    TomVista
        8
    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
        9
    cyrbuzz  
    OP
       2019-10-24 16:18:43 +08:00
    @lllllliu
    Poxy 不能来代理函数吧。
    cyrbuzz
        10
    cyrbuzz  
    OP
       2019-10-24 16:23:53 +08:00
    @TomVista
    喔...用$forceUpdate 可以强制刷新,近乎完美,非常感谢~~,如果能在其他组件里也应用就更好了~。
    lllllliu
        11
    lllllliu  
       2019-10-24 16:24:47 +08:00
    @cyrbuzz #9 function
    你现在打开控制台~ 丢一个 function,其实也只是一个在 window 下的一个属性 /对象而已。。。可以去看一下 VUE 各个部分的实现原理。。暴力实现你这个所谓的前置方法其实很容易的。多看看呀。
    cyrbuzz
        12
    cyrbuzz  
    OP
       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
        13
    luoway  
       2019-10-24 19:46:02 +08:00   1
    > 想在不修改原函数的基础上(或者无察觉的基础上)给一些函数加上调用前通知的钩子

    使用 Vue.mixin 在 beforeMount、beforeUpdate 生命周期里对 this 上方法(排除 vue 保留方法)进行装饰
    cyrbuzz
        14
    cyrbuzz  
    OP
       2019-10-24 22:10:24 +08:00
    @luoway
    非常感谢!!发现了新的思路~~。
    zlu1123
        15
    zlu1123  
       2019-10-24 22:39:41 +08:00
    加与不加括号的区别在于事件对象参数 event 的处理。不加括号时,函数第一个参数为 event,加了括号后,需要手动传入 $event 才能获得事件对象
    /div>
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     2194 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 25ms UTC 00:49 PVG 08:49 LAX 17:49 JFK 20:49
    Do have faith in what you're doing.
    ubao snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86