javascript - 触发方法定义在 javascript 对象中,但在对象本身之外

标签 javascript jquery html

我怀疑我的问题可能有点迟钝,我很抱歉。这是我想要实现的目标:

我正在使用这个multi-level push menu ,而且开箱即用,效果很好。但是,我希望在提交并关闭模式后关闭多级菜单。我很难弄清楚如何触发此菜单关闭。

那么,我们来看一些代码。首先,运行菜单本身的 Javascript。

mlPushMenu.prototype = {
    defaults : {
        // overlap: there will be a gap between open levels
        // cover: the open levels will be on top of any previous open level
        type : 'overlap', // overlap || cover
        // space between each overlaped level
        levelSpacing : 40,
        // classname for the element (if any) that when clicked closes the current level
        backClass : 'mp-back'
    },
    _init : function() {
        // if menu is open or not
        this.open = false;
        // level depth
        this.level = 0;
        // the moving wrapper
        this.wrapper = document.getElementById( 'mp-pusher' );
        // the mp-level elements
        this.levels = Array.prototype.slice.call( this.el.querySelectorAll( 'div.mp-level' ) );
        // save the depth of each of these mp-level elements
        var self = this;
        this.levels.forEach( function( el, i ) { el.setAttribute( 'data-level', getLevelDepth( el, self.el.id, 'mp-level' ) ); } );
        // the menu items
        this.menuItems = Array.prototype.slice.call( this.el.querySelectorAll( 'li' ) );
        // if type == "cover" these will serve as hooks to move back to the previous level
        this.levelBack = Array.prototype.slice.call( this.el.querySelectorAll( '.' + this.options.backClass ) );
        // event type (if mobile use touch events)
        this.eventtype = mobilecheck() ? 'touchstart' : 'click';
        // add the class mp-overlap or mp-cover to the main element depending on options.type
        classie.add( this.el, 'mp-' + this.options.type );
        // initialize / bind the necessary events
        this._initEvents();
    },
    _initEvents : function() {
        var self = this;

        // the menu should close if clicking somewhere on the body
        var bodyClickFn = function( el ) {
            self._resetMenu();
            el.removeEventListener( self.eventtype, bodyClickFn );
        };

        // open (or close) the menu
        this.trigger.addEventListener( this.eventtype, function( ev ) {
            ev.stopPropagation();
            ev.preventDefault();
            if( self.open ) {
                self._resetMenu();
            }
            else {
                self._openMenu();
                // the menu should close if clicking somewhere on the body (excluding clicks on the menu)
                document.addEventListener( self.eventtype, function( ev ) {
                    if( self.open && !hasParent( ev.target, self.el.id ) ) {
                        bodyClickFn( this );
                    }
                } );
            }
        } );

        // opening a sub level menu
        this.menuItems.forEach( function( el, i ) {
            // check if it has a sub level
            var subLevel = el.querySelector( 'div.mp-level' );
            if( subLevel ) {
                el.querySelector( 'a' ).addEventListener( self.eventtype, function( ev ) {
                    ev.preventDefault();
                    var level = closest( el, 'mp-level' ).getAttribute( 'data-level' );
                    if( self.level <= level ) {
                        ev.stopPropagation();
                        classie.add( closest( el, 'mp-level' ), 'mp-level-overlay' );
                        self._openMenu( subLevel );
                    }
                } );
            }
        } );

        // closing the sub levels :
        // by clicking on the visible part of the level element
        this.levels.forEach( function( el, i ) {
            el.addEventListener( self.eventtype, function( ev ) {
                ev.stopPropagation();
                var level = el.getAttribute( 'data-level' );
                if( self.level > level ) {
                    self.level = level;
                    self._closeMenu();
                }
            } );
        } );

        // by clicking on a specific element
        this.levelBack.forEach( function( el, i ) {
            el.addEventListener( self.eventtype, function( ev ) {
                ev.preventDefault();
                var level = closest( el, 'mp-level' ).getAttribute( 'data-level' );
                if( self.level <= level ) {
                    ev.stopPropagation();
                    self.level = closest( el, 'mp-level' ).getAttribute( 'data-level' ) - 1;
                    self.level === 0 ? self._resetMenu() : self._closeMenu();
                }
            } );
        } );    
    },
    _openMenu : function( subLevel ) {
        // increment level depth
        ++this.level;

        // move the main wrapper
        var levelFactor = ( this.level - 1 ) * this.options.levelSpacing,
            translateVal = this.options.type === 'overlap' ? this.el.offsetWidth + levelFactor : this.el.offsetWidth;

        this._setTransform( 'translate3d(' + translateVal + 'px,0,0)' );

        if( subLevel ) {
            // reset transform for sublevel
            this._setTransform( '', subLevel );
            // need to reset the translate value for the level menus that have the same level depth and are not open
            for( var i = 0, len = this.levels.length; i < len; ++i ) {
                var levelEl = this.levels[i];
                if( levelEl != subLevel && !classie.has( levelEl, 'mp-level-open' ) ) {
                    this._setTransform( 'translate3d(-100%,0,0) translate3d(' + -1*levelFactor + 'px,0,0)', levelEl );
                }
            }
        }
        // add class mp-pushed to main wrapper if opening the first time
        if( this.level === 1 ) {
            classie.add( this.wrapper, 'mp-pushed' );
            this.open = true;
        }
        // add class mp-level-open to the opening level element
        classie.add( subLevel || this.levels[0], 'mp-level-open' );
    },
    // close the menu
    _resetMenu : function() {
        this._setTransform('translate3d(0,0,0)');
        this.level = 0;
        // remove class mp-pushed from main wrapper
        classie.remove( this.wrapper, 'mp-pushed' );
        this._toggleLevels();
        this.open = false;
    },
    // close sub menus
    _closeMenu : function() {
        var translateVal = this.options.type === 'overlap' ? this.el.offsetWidth + ( this.level - 1 ) * this.options.levelSpacing : this.el.offsetWidth;
        this._setTransform( 'translate3d(' + translateVal + 'px,0,0)' );
        this._toggleLevels();
    },
    // translate the el
    _setTransform : function( val, el ) {
        el = el || this.wrapper;
        el.style.WebkitTransform = val;
        el.style.MozTransform = val;
        el.style.transform = val;
    },
    // removes classes mp-level-open from closing levels
    _toggleLevels : function() {
        for( var i = 0, len = this.levels.length; i < len; ++i ) {
            var levelEl = this.levels[i];
            if( levelEl.getAttribute( 'data-level' ) >= this.level + 1 ) {
                classie.remove( levelEl, 'mp-level-open' );
                classie.remove( levelEl, 'mp-level-overlay' );
            }
            else if( Number( levelEl.getAttribute( 'data-level' ) ) == this.level ) {
                classie.remove( levelEl, 'mp-level-overlay' );
            }
        }
    }
}

我想调用的方法是_resetMenu。我已经尝试了几种方法。主要尝试触发打开菜单的按钮的单击事件:

<a href="#" id="trigger" class="show-root-menu"><i class="fa fa-reorder"></i></a>

但是:

$('#trigger').trigger('click');

未按预期工作。我希望这会被解雇:

// open (or close) the menu
        this.trigger.addEventListener( this.eventtype, function( ev ) {
            ev.stopPropagation();
            ev.preventDefault();
            if( self.open ) {
                self._resetMenu();
            }
            else {
                self._openMenu();
                // the menu should close if clicking somewhere on the body (excluding clicks on the menu)
                document.addEventListener( self.eventtype, function( ev ) {
                    if( self.open && !hasParent( ev.target, self.el.id ) ) {
                        bodyClickFn( this );
                    }
                } );
            }
        } );

在本例中,this.eventtype 为“click”。

我怀疑这可能与此功能如何使用对象进行编码有关。虽然我有不错的 Javascript 技能,但我还没有太多接触过以这种方式使用它。

我正在实例化菜单:

new mlPushMenu(document.getElementById('mp-menu'), document.getElementById('trigger'));

我意识到我可以提取这个方法,但这似乎违反了一些一般的最佳实践。

如有任何建议,我们将不胜感激!

最佳答案

您不能按原样使用此模块来执行此操作。它支持的唯一事件类型是“click”和“touchstart”及其 mobilecheck()方法确定它使用两者中的哪一个。

您要么必须假装点击触发元素,要么必须修改此模块。您可以使用 .click() 来执行此操作DOM 元素的方法。 .trigger.click()可能不会这么做;您可能最好只获取元素(通过 $('#trigger')document.getElementById() ),然后调用它的 .click() 方法。

我刚刚在 Chrome 中使用 <a> 尝试过此操作有风格display:none它遵循链接,因此它可能适用于另一个隐藏元素集来触发。虽然有点 hacky,但可能比更改模块更好。

关于javascript - 触发方法定义在 javascript 对象中,但在对象本身之外,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29380408/

相关文章:

javascript - 单击 Facebook 上具有相同类别的每个按钮

javascript - 获取多个浮点图的十字准线值

javascript - 使用 .trigger() 模拟多个按键;

javascript - Firefox:是否有任何替代方法来替换 .css ("zoom")

html - 使用 CSS 为字体添加阴影效果

javascript - 如何读取 XML 文件并使用表中的数据进行验证

javascript - jquery循环遍历输入字段并进入父级和兄弟级

javascript - res.send() 在 Node js中功能代码执行之前执行

php - 使用ajax仅加载新数据

javascript - 在没有 'return false;' 的情况下停止表单 onSubmit