基于javascript的自动完成/下拉菜单上的点击事件未正确关闭

时间:2016-07-08 13:07:02

标签: javascript autocomplete mootools

我创建了一个脚本,通过隐藏/显示与所述输入定位的<input type="text" />来模拟<ul>的自动完成。用户点击<input type="text" />后,<ul>将变为可见且可点击,并在满足以下三个条件之一时关闭:

  • 用户重新点击<input type="text" />
  • 用户点击显示的<ul>
  • 中的一个选项
  • 用户点击与此系统无关的任何内容

到目前为止,我已经完成了一切工作。不幸的是,如果页面上有两个这样的“自动填充”字段,我就遇到了问题。如果用户打开一个“自动完成”界面,然后单击打开另一个界面,则第一个/原始界面不会按预期关闭。

我似乎无法弄清楚我哪里出错了。

window.addEvent('domready', function() {
  new autoComplete();
});
var autoComplete = new Class({
	options: {
		version:		'1.0',
		lastUpdate:	'2016-06-27'
	},

	Implements: [Options,Events],
	initialize: function(options) {
		this.setOptions(options);
		
		$$('.autocomplete').each(function(acl) {
			acl.getChildren('ul li').each(function(li) {
				li.addEvent('click', function() {
					acl.getChildren('input[type=text]')[0].value = li.get('html');
					acl.getChildren('input[type=hidden]')[0].value = li.get('data-id');
					acl.getChildren('ul').addClass('hidden');
				});
			});
			
			acl.getChildren('input')[0].addEvents({
				click: function(e) {
					e.preventDefault();
					e.stopPropagation();
					
					var el = e.target;
					var val = el.value;
					var aul = el.getParent().getChildren('ul')[0];
					var str = '';
					
					aul.toggleClass('hidden');
					
					aul.getChildren().each(function(l) {
						str = l.get('html').toLowerCase();
						if (str.indexOf(val.toLowerCase()) != 0) {
							l.addClass('hidden');
						} else {
							l.removeClass('hidden');
						}
					});
				},
				keyup: function(e) {
					e.preventDefault();
					e.stopPropagation();
					
					var el = e.target;
					var val = el.value;
					var aul = el.getParent().getChildren('ul')[0];
					var str = '';
					
					aul.removeClass('hidden');
					
					aul.getChildren().each(function(l) {
						str = l.get('html').toLowerCase();
						if (str.indexOf(val.toLowerCase()) != 0) {
							l.addClass('hidden');
						} else {
							l.removeClass('hidden');
						}
					});
				}
			});
		});
		
		$(document.body).addEvent('click', function() {
			$$('.autocomplete ul').addClass('hidden');
		});
	}
});
html,
body {
  height: 100%;
}

.autocomplete {
  position: relative;
}

.autocomplete ul {
  list-style: none outside none;
  background-color: #FFF;
  margin: 0px;
  padding: 0px;
  position: absolute;
  top: 100;
  left: 0px;
  right: 0px;
  z-index: 500;
}

.autocomplete ul li {
  border-width: 0 1px 1px;
  border-style: solid;
  border-color: #000;
}

.autocomplete ul li:first-child {
  border-width: 1px;
}

.autocomplete ul li:hover {
  background-color: #CCC;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/mootools/1.6.0/mootools-core.min.js"></script>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet"/>
<div class="container-fluid">
  <div class="form-group">
    <label>Drk:</label>
    <div class="autocomplete">
      <input type="text" class="form-control" />
      <input type="hidden" />
      <ul class="hidden">
        <li data-id="drk1-Nito">Nito</li>
        <li data-id="drk1-Seath">Seath</li>
        <li data-id="drk1-FourKings">Four Kings</li>
        <li data-id="drk1-BedofChaos">Bed of Chaos</li>
        <li data-id="drk2-TheRotten">The Rotten</li>
        <li data-id="drk2-DukesDearFreja">Duke's Dear Freja</li>
        <li data-id="drk2-OldIronKing">Old Iron King</li>
        <li data-id="drk2-LostSinner">Lost Sinner</li>
        <li data-id="drk3-Yhorm">Yhorm</li>
        <li data-id="drk3-Aldritch">Aldritch</li>
        <li data-id="drk3-Abysswatcher">Abyss Watcher</li>
        <li data-id="drk3-Lothric">Lothric</li>
      </ul>
    </div>
  </div>
  <div class="form-group">
    <label>Bld:</label>
    <div class="autocomplete">
      <input type="text" class="form-control" />
      <input type="hidden" />
      <ul class="hidden">
        <li data-id="bld-ClericBeast">Cleric Beast</li>
        <li data-id="bld-FatherGascoigne">Father Gascoigne</li>
        <li data-id="bld-WitchesofHemwick">Witches of Hemwick</li>
        <li data-id="bld-VicarAmelia">Vicar Amelia</li>
        <li data-id="bld-ShadowsofYarhnam">Shadows of Yarhnam</li>
        <li data-id="bld-VacuousRom">Vacuous Rom</li>
        <li data-id="bld-TheOneReborn">The One Reborn</li>
        <li data-id="bld-Micolash">Micolash</li>
        <li data-id="bld-MergosWetnurse">Mergo's Wetnurse</li>
        <li data-id="bld-OldHunterGermaine">Old Hunter Germaine</li>
        <li data-id="bld-MoonPresence">Moon Presence</li>
      </ul>
    </div>
  </div>
</div>

3 个答案:

答案 0 :(得分:2)

问题是,您希望在单击正文时隐藏.autocomplete元素

inline-block

你在document.body上添加'hidden'类,但是当你点击另一个.autocomplete输入时,事件不会冒泡到body元素,因为你故意阻止它在click事件中传播线

$(document.body).addEvent('click', function() {
    $$('.autocomplete ul').addClass('hidden');
});

你可以通过添加条件来点击事件来解决它,其中隐藏所有其他.autocomplete元素,或者为模糊事件添加另一个处理程序,你隐藏元素本身。

答案 1 :(得分:1)

您可以使用blur事件。由于它会在click之前触发,如果您需要移动支持,可以将其更改为mousedowntouchstart。所以你的课程看起来像这样:

(注意我清理了一下并为每个元素创建了一个新的Class实例,我认为它更加模块化/独立于此)

window.addEvent('domready', function() {
    $$('.autocomplete').each(function(el) {
        new autoComplete(el);
    });
});
var autoComplete = new Class({
    options: {
        version: '1.0',
        lastUpdate: '2016-06-27'
    },
    Implements: [Options, Events],
    initialize: function(acl, options) {
        this.setOptions(options);
        var self = this;
        var ul = acl.getElement('ul');
        var lis = ul.getChildren('li');
        var input = acl.getElement('input');

        lis.addEvent('mousedown', function(e) {
            input.value = this.get('html');
            acl.getElement('input[type=hidden]').value = this.get('data-id');
            ul.addClass('hidden');
        });

        input.addEvents({
            mousedown: function(e) {
                ul.toggleClass('hidden');
                self.toggle(lis, this.value.toLowerCase());
            },
            keyup: function(e) {
                ul.removeClass('hidden');
                self.toggle(lis, this.value.toLowerCase());
            },
            blur: function(e) {
                ul.addClass('hidden');
            }
        });
    },
    toggle: function(els, val) {
        els.each(function(el) {
            var str = el.get('html').toLowerCase();
            var match = str.indexOf(val) != -1;
            el.toggleClass('hidden', !match);
        });
    }
});

jsFiddle:https://jsfiddle.net/1on4kpj0/

如果您需要触摸支持,可以这样做:https://jsfiddle.net/1on4kpj0/1/

答案 2 :(得分:0)

这里的问题是当你点击一个输入时,与其他输入绑定的事件不会被触发,因此该类不会被更改,你必须检查是否在文档中打开了任何其他自动完成比你应该关闭它。你可以通过点击事件中的一个小支票来做到这一点。

&#13;
&#13;
window.addEvent('domready', function() {
  new autoComplete();
});
var autoComplete = new Class({
	options: {
		version:		'1.0',
		lastUpdate:	'2016-06-27'
	},

	Implements: [Options,Events],
	initialize: function(options) {
		this.setOptions(options);
		
		$$('.autocomplete').each(function(acl) {
			acl.getChildren('ul li').each(function(li) {
				li.addEvent('click', function() {
					acl.getChildren('input[type=text]')[0].value = li.get('html');
					acl.getChildren('input[type=hidden]')[0].value = li.get('data-id');
					acl.getChildren('ul').addClass('hidden');
				});
			});
			
			acl.getChildren('input')[0].addEvents({
				click: function(e) {
					e.preventDefault();
					e.stopPropagation();
					
					var el = e.target;
					var val = el.value;
					var aul = el.getParent().getChildren('ul')[0];
					var str = '';
                    var allInput= document.getElementsByClassName(el.className);
                    for(var i =0 ;i<allInput.length; i++)
                    {
                       if(allInput[i].getParent().className=="autocomplete" && allInput[i] != el && allInput[i].getParent().getChildren('ul')[0].className != "hidden" )
                       {
                           allInput[i].getParent().getChildren('ul')  [0].className = 'hidden';
                       }
                    }
					
					aul.toggleClass('hidden');
					
					aul.getChildren().each(function(l) {
						str = l.get('html').toLowerCase();
						if (str.indexOf(val.toLowerCase()) != 0) {
							l.addClass('hidden');
						} else {
							l.removeClass('hidden');
						}
					});
				},
				keyup: function(e) {
					e.preventDefault();
					e.stopPropagation();
					
					var el = e.target;
					var val = el.value;
					var aul = el.getParent().getChildren('ul')[0];
					var str = '';
					
					aul.removeClass('hidden');
					
					aul.getChildren().each(function(l) {
						str = l.get('html').toLowerCase();
						if (str.indexOf(val.toLowerCase()) != 0) {
							l.addClass('hidden');
						} else {
							l.removeClass('hidden');
						}
					});
				}
			});
		});
		
		$(document.body).addEvent('click', function() {
			$$('.autocomplete ul').addClass('hidden');
		});
	}
});
&#13;
html,
body {
  height: 100%;
}

.autocomplete {
  position: relative;
}

.autocomplete ul {
  list-style: none outside none;
  background-color: #FFF;
  margin: 0px;
  padding: 0px;
  position: absolute;
  top: 100;
  left: 0px;
  right: 0px;
  z-index: 500;
}

.autocomplete ul li {
  border-width: 0 1px 1px;
  border-style: solid;
  border-color: #000;
}

.autocomplete ul li:first-child {
  border-width: 1px;
}

.autocomplete ul li:hover {
  background-color: #CCC;
}
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/mootools/1.6.0/mootools-core.min.js"></script>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet"/>
<div class="container-fluid">
  <div class="form-group">
    <label>Drk:</label>
    <div class="autocomplete">
      <input type="text" class="form-control" />
      <input type="hidden" />
      <ul class="hidden">
        <li data-id="drk1-Nito">Nito</li>
        <li data-id="drk1-Seath">Seath</li>
        <li data-id="drk1-FourKings">Four Kings</li>
        <li data-id="drk1-BedofChaos">Bed of Chaos</li>
        <li data-id="drk2-TheRotten">The Rotten</li>
        <li data-id="drk2-DukesDearFreja">Duke's Dear Freja</li>
        <li data-id="drk2-OldIronKing">Old Iron King</li>
        <li data-id="drk2-LostSinner">Lost Sinner</li>
        <li data-id="drk3-Yhorm">Yhorm</li>
        <li data-id="drk3-Aldritch">Aldritch</li>
        <li data-id="drk3-Abysswatcher">Abyss Watcher</li>
        <li data-id="drk3-Lothric">Lothric</li>
      </ul>
    </div>
  </div>
  <div class="form-group">
    <label>Bld:</label>
    <div class="autocomplete">
      <input type="text" class="form-control" />
      <input type="hidden" />
      <ul class="hidden">
        <li data-id="bld-ClericBeast">Cleric Beast</li>
        <li data-id="bld-FatherGascoigne">Father Gascoigne</li>
        <li data-id="bld-WitchesofHemwick">Witches of Hemwick</li>
        <li data-id="bld-VicarAmelia">Vicar Amelia</li>
        <li data-id="bld-ShadowsofYarhnam">Shadows of Yarhnam</li>
        <li data-id="bld-VacuousRom">Vacuous Rom</li>
        <li data-id="bld-TheOneReborn">The One Reborn</li>
        <li data-id="bld-Micolash">Micolash</li>
        <li data-id="bld-MergosWetnurse">Mergo's Wetnurse</li>
        <li data-id="bld-OldHunterGermaine">Old Hunter Germaine</li>
        <li data-id="bld-MoonPresence">Moon Presence</li>
      </ul>
    </div>
  </div>
</div>
&#13;
&#13;
&#13;