Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix an event propagate bug #1839

Closed
wants to merge 1 commit into from
Closed

fix an event propagate bug #1839

wants to merge 1 commit into from

Conversation

skyline0705
Copy link

英文实在不好,还是用中文解释一下吧,请见谅
在events里面最近我的项目遇到了一个小坑,大概是这个样一个结构:

// child1 events
events: {
    'confirm-ok' () {
        let {
            olaplink, isOperate
        } = this.needToDelete;
        if (!olaplink.value && isOperate) {
            this.$dispatch('refreshComponent', this.componentId);
            this.olaplinkSettings.operationColumn.$remove(olaplink);
        }

    }
}

// child2 events
events: {
    'refreshComponent' () {
        // something       
    }
}

// parent events
events: {
    'refreshComponent'(...args) {
        this.$broadcast('refreshComponent', ...args);
    },
    'confirm-ok'() {
        // something
    }
}

目前表现现状是当child1的confirm-ok事件触发时,parent的confirm-ok事件也被同步触发(这里的代码按照官网说明理应不被触发才对)

在这样一个需要父级中转的事件中,在child1被触发confirm-ok时,需要先触发refreshComponent事件,通过父级中转会之后,因为之前在events.js中98行得到是否继续向上触发的结果之前,本身又被父级转发的refreshComponet事件导致自身_shouldPropagate为true(events.js第91行).
事件refreshComponent触发完毕后,执行到events.js99行时,此时的_shouldPropagate结果本应该是fase,但是由于上一次事件传递的影响这里的_shouldPropagate并不是正确的值。

故我认为应该在这里增加一下对_shouldPropagate的重新赋值以得到正确的结果

谢谢

@yyx990803
Copy link
Member

感觉解释的不太清楚,能不能做成 demo...

@skyline0705
Copy link
Author

好的,我写一个简单的demo附上,请稍等

@skyline0705
Copy link
Author

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>vue event测试</title>
    <script type="text/javascript" src="http://cn.vuejs.org/js/vue.js"></script>
</head>
<body>
    <div id="main"></div>
    <script type="text/javascript">
        var confirm = {
            template: [
                '<div>',
                    '我是公共组件confirm',
                    '<input type="button" value="确认请点我" v-on:click="notify" />',
                '</div>',
            ].join(''),
            methods: {
                notify: function () {
                    this.$dispatch('alertName');
                }
            }
        }

        var child1 = {
            template:  [
                '<div>',
                    '我是子组件1',
                '</div>'
            ].join(''),
            data: function () {
                return {
                    name: '子组件1'
                };
            },
            events: {
                refreshComponent: function () {
                    alert('我是' + this.name + ',我被更新了');
                    return false;
                }
            }
        };

        var child2 = {
            template: [
                '<div>',
                    '我是子组件2,我还引用了个公共组件confirm',
                    '<confirm></confirm>',
                '</div>',
            ].join(''),
            data: function () {
                return {
                    name: '子组件2'
                };
            },
            events: {
                alertName: function () {
                    alert(this.name);
                    // 我还要通知一下其他子组件更新
                    this.$dispatch('refreshComponent');
                    return false;
                },
            },
            components: {
                confirm: confirm
            }
        };

        new Vue({
            el: '#main',
            template:  [
                '<div>',
                    '我是父组件,需要做事件中转,我有两个子组件:',
                    '<br><br>',
                    '<child1></child1>',
                    '<br><br>',
                    '<child2></child2>',
                '</div>',
            ].join(''),
            data: function () {
                return {
                    name: '父组件'
                };
            },
            events: {
                alertName: function () {
                    alert(this.name);
                },
                refreshComponent: function () {
                    this.$broadcast('refreshComponent');
                }
            },
            components: {
                child1: child1,
                child2: child2
            }
        });
    </script>
</body>
</html>

理论上点击子组件2引用的组件confirm,仅应该触发组件2的alertName以及组件1的refreshComponent,父组件的alertName并不应该被触发,但是在这个demo例子里面却并不是。

这个bug藏的有点深,总结了一下需要满足以下条件:
1父级组件有事件中转(同父的子组件之间事件通知)
2父级组件与子组件有相同的事件(上面例子中的alertName
3子组件的某个子组件向上通知2中的事件(上例中的confirm
4子组件在触发2中事件时,同时需要通过1中的方式通知其他子组件(上例中的refreshComponent

跟踪代码调试的时候发现是父组件向下通知事件时,将组件2的_shouldPropagate值改变了,但是在组件2继续执行后续代码的时候(因为return false了所以并不应该将事件继续向上通知),自身_shouldPropagate并不是正确的值,所以造成事件触发错误

因为我对我们这边团队规定对于第三方资源不能进行任何修改(外包之前乱改导致混乱到没法维护……),如有问题只能先通过hack修复,所以现在这个情况暂时通过setTimeout搞了一下(强行让上例中的refreshComponent异步触发)来避免这个bug

还望能尽快修复一下,谢谢~~
麻烦了~~~~

@yyx990803 yyx990803 closed this in 83f418e Nov 23, 2015
@yyx990803
Copy link
Member

多谢,采用了一个更稳妥的修复

@skyline0705
Copy link
Author

好的,麻烦了~

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants