自定义下拉焦点:调用堆栈大小超出
Custom dropdown focus: call stack size exceeded
我正在用jquery (slim)构建我自己的下拉插件。下拉元素本身是一个带有tabindex="0"
的div。
我希望下拉菜单与浏览器的焦点状态一起工作:当元素聚焦时打开下拉菜单,当元素失去焦点时关闭下拉菜单。目前我得到以下错误:
jquery.slim.min.js:2 Uncaught RangeError:最大调用栈大小超过了
代码看起来像这样(为了可读性,删除了部分,标记了问题):
var plugin = 'dropdown',
defaults = {
onOpened : function() {},
onClosed : function() {}
};
// Constructor
function Dropdown(element, options) {
this.element = element;
this.settings = $.extend({}, defaults, options);
this.init();
}
// Instance
$.extend(Dropdown.prototype, {
init: function() {
var instance = this,
$element = $(instance.element);
// Bind listeners
$element.focus(function(e) {
instance.open();
e.preventDefault();
}).focusout(function() {
instance.close();
}).mousedown(function() {
instance.toggle();
});
},
/**
* Check the state of the dropdown.
*
* @param state
* @returns {*}
*/
is: function(state) {
var $element = $(this.element);
return {
open: function() {
return $element.hasClass('dropdown--open');
},
focused: function() {
return document.activeElement === $element[0];
}
}[state].apply();
},
/**
* Open the dropdown.
*/
open: function() {
var instance = this,
$element = $(instance.element);
if (instance.is('open')) {
return;
}
$element.addClass('dropdown--open');
this.callback(this.settings.onOpened, $element);
},
/**
* Close the dropdown.
*/
close: function() {
var instance = this,
$element = $(this.element);
if ( ! instance.is('open')) {
return;
}
$element.removeClass('dropdown--open');
this.callback(this.settings.onClosed, $element);
},
/**
* Make a callback.
*
* @param callback
* @param $element
*/
callback: function(callback, $element) {
if (callback && typeof callback === 'function') {
callback($element);
}
}
});
我知道我正在触发一个(无穷无尽的)递归函数,但我不确定如何解决这个问题。
感谢所有的帮助!
编辑:固定的
;(function($, window, document) {
'use strict';
var plugin = 'dropdown',
defaults = {
onOpened : function() {},
onClosed : function() {}
};
// Constructor
function Dropdown(element, options) {
this.element = element;
this.settings = $.extend({}, defaults, options);
this.init();
}
// Instance
$.extend(Dropdown.prototype, {
init: function() {
var instance = this,
$element = $(instance.element);
// Bind listeners
$element.focus(function(e) {
console.log('opening');
instance.open();
e.preventDefault();
}).focusout(function() {
console.log('closing');
instance.close();
}).mousedown(function() {
console.log('toggling');
instance.toggle();
});
},
/**
* Check the state of the dropdown.
*
* @param state
* @returns {*}
*/
is: function(state) {
var $element = $(this.element);
return {
open: function() {
return $element.hasClass('dropdown--open');
},
empty: function() {
return $element.hasClass('dropdown--empty');
},
focused: function() {
return document.activeElement === $element[0];
}
}[state].apply();
},
/**
* Toggles the dropdown.
*/
toggle: function() {
if (this.is('open')) this.close();
else this.open();
},
/**
* Open the dropdown.
*/
open: function() {
var instance = this,
$element = $(instance.element);
if (instance.is('open')) {
return;
}
$element.addClass('dropdown--open');
this.callback(this.settings.onOpened, $element);
},
/**
* Close the dropdown.
*/
close: function() {
var instance = this,
$element = $(this.element);
if ( ! instance.is('open')) {
return;
}
$element.removeClass('dropdown--open');
this.callback(this.settings.onClosed, $element);
},
/**
* Make a callback.
*
* @param callback
* @param $element
*/
callback: function(callback, $element) {
if (callback && typeof callback === 'function') {
callback($element);
}
}
});
// Plugin definition
$.fn.dropdown = function(options, args) {
return this.each(function() {
if ( ! $ .data(this, plugin)) {
$.data(this, plugin, new Dropdown(this, options));
}
});
};
})(jQuery, window, document);
$('.dropdown').dropdown();
.dropdown {
position: relative;
display: block;
padding: .625rem .8125rem;
padding-right: 2rem;
font-size: 16px;
color: #333;
line-height: 1.125;
outline: 0;
cursor: pointer;
border: 1px solid #d9d9d9;
background-color: #fff;
}
.dropdown.dropdown--open .dropdown__menu {
display: block;
}
.dropdown__menu {
display: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="dropdown" tabindex="0">
<span>Favorite animal</span>
<ul class="dropdown__menu" tabindex="-1">
<li class="dropdown__item">Cats</li>
<li class="dropdown__item">Dogs</li>
<li class="dropdown__item">Monkeys</li>
<li class="dropdown__item">Elephants</li>
</ul>
</div>
所以。问题:
1)你触发一次又一次focus()
和focusout()
,如果下拉菜单打开/关闭。(你已经这样做了)
2)使用toggle()函数关闭/打开下拉菜单
你的问题是你有点击事件检查是下拉打开,然后关闭。但是你必须在focusOut()
中这样做。
我编辑了你的小提琴
// Bind listeners
$element.on('click', function(e) {
instance.toggle();
});
3) 更新你的评论
修改值
相关文章:
- 是什么让一个“;Uncaught RangeError:超过了最大调用堆栈大小“;错误(Chrome,在其他浏览器中显示
- 超过了async.detect最大调用堆栈大小
- 如何远程检查JavaScript应用程序的函数调用堆栈
- 超过了最大调用堆栈大小,循环无限
- 超过了最大调用堆栈大小.递归标签
- 日志:未捕获的范围错误:超过了最大调用堆栈大小
- 未捕获的范围错误:setTimeout()超过了最大调用堆栈大小
- JavaFX+WebView/Javascript:setTimeOut不起作用调用堆栈来自Java
- JavaScript继承:未捕获的范围错误:超过了最大调用堆栈大小
- 使用$cookies和$stateChangeStart检查sessionID是否超过了最大调用堆栈
- jQuery捕获"RangeError:超过了最大调用堆栈大小“;
- 设置这个.RangeError:超过了最大调用堆栈大小
- 收到“范围错误: 超出最大调用堆栈大小”错误
- 递归 - 测试最大堆栈大小时,调用堆栈无法弹出
- 轮询 ajax 函数超出调用堆栈
- Chrome RangeError:使用jQuery$.map时超过了最大调用堆栈大小
- 要求JS 2.1.9引起“;最大调用堆栈"使用Grunt时出错
- Chrome/jQuery未捕获范围错误:超过了最大调用堆栈大小(函数循环)
- 超过了最大调用堆栈大小-没有明显的递归
- 在 javascript 中使用函数堆栈调用非递归方法