V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
cyrbuzz
V2EX  ›  Vue.js

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

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

    背景:

    想在不修改原函数的基础上(或者无察觉的基础上)给一些函数加上调用前通知的钩子,查了 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
    Proxy 不能来代理函数吧。
    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 才能获得事件对象
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   948 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 31ms · UTC 21:01 · PVG 05:01 · LAX 14:01 · JFK 17:01
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.