我目前正在使用Javascript编写自动完成组件,根据邮政编码完成两个输入字段plz
(邮政编码)和ort
(城市)。输入3位数后,自动完成功能就会触发。
现在很遗憾德国的许多邮政编码都不能作为标识符 - 几个小城市都可以使用相同的邮政编码。
要试用我的代码,请输入
562
。
将打开一个自动提示列表,其中最多可包含10个可一次显示的项目。使用↓列表。
我需要一个问题的解决方案,当使用↓或↑活动项目不会导致列表滚动>
如果有人能指出我在这方面的正确方向,我会非常乐意自己实施。
let plz = [{"plz":"56244","ort":"Rückeroth","bundesland":"Rheinland-Pfalz","kreis":"Westerwaldkreis"},{"plz":"56244","ort":"Ötzingen","bundesland":"Rheinland-Pfalz","kreis":"Westerwaldkreis"},{"plz":"56244","ort":"Niedersayn","bundesland":"Rheinland-Pfalz","kreis":"Westerwaldkreis"},{"plz":"56244","ort":"Vielbach","bundesland":"Rheinland-Pfalz","kreis":"Westerwaldkreis"},{"plz":"56244","ort":"Hartenfels","bundesland":"Rheinland-Pfalz","kreis":"Westerwaldkreis"},{"plz":"56244","ort":"Ewighausen","bundesland":"Rheinland-Pfalz","kreis":"Westerwaldkreis"},{"plz":"56244","ort":"Leuterod","bundesland":"Rheinland-Pfalz","kreis":"Westerwaldkreis"},{"plz":"56244","ort":"Kuhnhöfen","bundesland":"Rheinland-Pfalz","kreis":"Westerwaldkreis"},{"plz":"56244","ort":"Goddert","bundesland":"Rheinland-Pfalz","kreis":"Westerwaldkreis"},{"plz":"56244","ort":"Freirachdorf","bundesland":"Rheinland-Pfalz","kreis":"Westerwaldkreis"},{"plz":"56244","ort":"Maxsain","bundesland":"Rheinland-Pfalz","kreis":"Westerwaldkreis"},{"plz":"56244","ort":"Freilingen","bundesland":"Rheinland-Pfalz","kreis":"Westerwaldkreis"},{"plz":"56244","ort":"Weidenhahn","bundesland":"Rheinland-Pfalz","kreis":"Westerwaldkreis"},{"plz":"56244","ort":"Helferskirchen","bundesland":"Rheinland-Pfalz","kreis":"Westerwaldkreis"},{"plz":"56244","ort":"Arnshöfen","bundesland":"Rheinland-Pfalz","kreis":"Westerwaldkreis"},{"plz":"56244","ort":"Hahn am See","bundesland":"Rheinland-Pfalz","kreis":"Westerwaldkreis"},{"plz":"56244","ort":"Sessenhausen","bundesland":"Rheinland-Pfalz","kreis":"Westerwaldkreis"},{"plz":"56244","ort":"Wölferlingen","bundesland":"Rheinland-Pfalz","kreis":"Westerwaldkreis"},{"plz":"56244","ort":"Steinen","bundesland":"Rheinland-Pfalz","kreis":"Westerwaldkreis"},{"plz":"56244","ort":"Schenkelberg","bundesland":"Rheinland-Pfalz","kreis":"Westerwaldkreis"},{"plz":"56244","ort":"Krümmel","bundesland":"Rheinland-Pfalz","kreis":"Westerwaldkreis"},{"plz":"56244","ort":"Ettinghausen","bundesland":"Rheinland-Pfalz","kreis":"Westerwaldkreis"}]
let plzAutoCompleteConfig = {
minCharactersToRun: 3,
maxResults: 100,
allowedKeyCodes: [8, 9, 13, 37, 38, 39, 40, 46, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105]
}
let plzOrtAutoComplete = function plzOrtAutoComplete() {
if (!document.querySelector('[data-has-plz-ort-autocomplete]')) return;
// find all plz autocompletes
let autocompletes = Array.from(document.querySelectorAll('[data-has-plz-ort-autocomplete]'))
for (let autocomplete of autocompletes) {
let plzInput = document.getElementById(autocomplete.getAttribute('data-plz'))
let ortInput = document.getElementById(autocomplete.getAttribute('data-ort'))
let suggestList = document.createElement('ul')
suggestList.flush = function() {
this.innerHTML = ''
}
suggestList.className = 'autocomplete-suggest list-unstyled'
plzInput.parentNode.appendChild(suggestList)
for (let eventName of ['input', 'focus']) {
plzInput.addEventListener(eventName, function(evt) {
const checkInput = () => {
let matches = plz.filter(x => {
return x.plz.startsWith(this.value)
})
switch (true) {
case (matches.length > plzAutoCompleteConfig.maxResults):
suggestList.flush()
break
case ((matches.length <= plzAutoCompleteConfig.maxResults && matches.length > 1) || (matches.length === 1 && this.value.length < 5)):
suggestList.flush()
for (let match of matches) {
let li = document.createElement('li')
li.textContent = `${match.plz} ${match.ort}`
li.title = `${match.plz} ${match.ort} in ${match.bundesland}, ${match.kreis} übernehmen durch Enter oder Klick`
li.addEventListener('click', () => {
plzInput.value = match.plz
ortInput.value = match.ort
ortInput.focus()
suggestList.flush()
})
li.addEventListener('mouseenter', function() {
this.classList.add('active')
})
li.addEventListener('mouseleave', function() {
this.classList.remove('active')
})
suggestList.appendChild(li)
}
this.parentNode.appendChild(suggestList)
break
case (matches.length === 1 && this.value.length === 5):
if (event.type !== 'focus' && ['deleteContentBackward', 'deleteContentForward'].indexOf(evt.inputType) === -1) {
suggestList.flush()
plzInput.value = matches[0].plz
ortInput.value = matches[0].ort
ortInput.focus()
}
break
default:
{
suggestList.flush()
break
}
}
}
if (isNaN(Number(this.value))) {
this.value = ''
return
}
if (this.value.length >= plzAutoCompleteConfig.minCharactersToRun) {
if (['deleteContentBackward', 'deleteContentForward'].indexOf(evt.inputType) > -1) {
console.log(this.value)
}
checkInput()
}
})
}
plzInput.addEventListener('keydown', function(evt) {
let keyCode = evt.keyCode || evt.which;
let activeLi = suggestList.querySelector('li.active')
if (keyCode) {
if (!plzAutoCompleteConfig.allowedKeyCodes.includes(keyCode)) {
evt.preventDefault()
} else {
switch (keyCode) {
case 8: // backspace
suggestList.flush()
break
case 13: // Enter
evt.preventDefault()
if (!suggestList.hasChildNodes()) {
return
}
if (!activeLi) {
return
} else {
plzInput.value = activeLi.textContent.substr(0, 5)
ortInput.value = activeLi.textContent.substr(6)
suggestList.flush()
ortInput.focus()
}
break
case 37:
break
case 38: // cursor up
if (!suggestList.hasChildNodes()) {
return
}
if (activeLi) {
activeLi.classList.remove('active')
let prevLi = activeLi.previousSibling
if (prevLi) {
prevLi.classList.add('active')
} else {
suggestList.querySelector('li:last-of-type').classList.add('active')
}
} else {
suggestList.querySelector('li:last-of-type').classList.add('active')
}
break
case 39:
break
case 40:
if (!suggestList.hasChildNodes()) {
return
}
if (activeLi) {
activeLi.classList.remove('active')
let nextLi = activeLi.nextSibling
if (nextLi) {
nextLi.classList.add('active')
} else {
suggestList.querySelector('li:first-of-type').classList.add('active')
}
} else {
suggestList.querySelector('li:first-of-type').classList.add('active')
}
break
case 46: // delete
suggestList.flush()
break
default:
break
}
}
}
})
plzInput.addEventListener('blur', function(evt) {
setTimeout(function() {
suggestList.flush()
}, 250)
})
ortInput.addEventListener('input', function(evt) {
console.log(this.value)
})
}
}
plzOrtAutoComplete();
.autocomplete-suggest {
background-color: #fff;
border: 1px solid #ddd;
box-shadow: 3px 3px 5px #ccc;
max-height: 6em;
left: 5px;
opacity: 1;
overflow-y: auto;
pointer-events: all;
position: absolute;
z-index: 999;
transition-duration: .2s;
}
.autocomplete-suggest:empty {
max-height: 0;
opacity: 0;
pointer-events: none;
}
.autocomplete-suggest li {
line-height: 1.5em;
margin: 0 auto;
padding: .3em 1.2em .2em .6em;
transition: all .2s ease-in-out;
white-space: nowrap;
}
.autocomplete-suggest li:nth-child(even) {
background-color: rgba(0, 0, 0, 0.05);
}
.autocomplete-suggest li:hover, .autocomplete-suggest li.active {
cursor: pointer;
background-color: #a00;
color: #fff;
}
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
<div class="form-row" data-has-plz-ort-autocomplete data-plz="eazVersicherterPLZ" data-ort="eazVersicherterOrt">
<div class="form-group col-sm-4">
<label for="eazVersicherterPLZ">PLZ</label>
<input class="form-control" type="text" id="eazVersicherterPLZ" name="eazVersicherterPLZ" data-plz="eazVersicherterOrt" maxlength=5 />
</div>
<div class="form-group col-sm-8">
<label for="eazVersicherterOrt">Ort</label>
<input class="form-control" type="text" id="eazVersicherterOrt" name="eazVersicherterOrt">
</div>
</div>
这是由Javascript生成的自动提示HTML:
<ul class="autocomplete-suggest list-unstyled">
<li>56244 Rückeroth</li>
<li>56244 Ötzingen</li>
<li>56244 Niedersayn</li>
<li>56244 Vielbach</li>
<li>56244 Hartenfels</li>
<li>56244 Ewighausen</li>
<li>56244 Leuterod</li>
<li>56244 Kuhnhöfen</li>
<li>56244 Goddert</li>
<li>56244 Freirachdorf</li>
<li>56244 Maxsain</li>
<li>56244 Freilingen</li>
<li>56244 Weidenhahn</li>
<li>56244 Helferskirchen</li>
<li>56244 Arnshöfen</li>
<li>56244 Hahn am See</li>
<li>56244 Sessenhausen</li>
<li>56244 Wölferlingen</li>
<li>56244 Steinen</li>
<li>56244 Schenkelberg</li>
<li>56244 Krümmel</li>
<li>56244 Ettinghausen</li>
</ul>
答案 0 :(得分:1)
我只需将光标向上添加,光标向下添加:
suggestList.scrollTop = suggestList.querySelector('.active').offsetTop;
它将使列表与活动元素一起滚动。
完整代码:
let plz = [{"plz":"56244","ort":"Rückeroth","bundesland":"Rheinland-Pfalz","kreis":"Westerwaldkreis"},{"plz":"56244","ort":"Ötzingen","bundesland":"Rheinland-Pfalz","kreis":"Westerwaldkreis"},{"plz":"56244","ort":"Niedersayn","bundesland":"Rheinland-Pfalz","kreis":"Westerwaldkreis"},{"plz":"56244","ort":"Vielbach","bundesland":"Rheinland-Pfalz","kreis":"Westerwaldkreis"},{"plz":"56244","ort":"Hartenfels","bundesland":"Rheinland-Pfalz","kreis":"Westerwaldkreis"},{"plz":"56244","ort":"Ewighausen","bundesland":"Rheinland-Pfalz","kreis":"Westerwaldkreis"},{"plz":"56244","ort":"Leuterod","bundesland":"Rheinland-Pfalz","kreis":"Westerwaldkreis"},{"plz":"56244","ort":"Kuhnhöfen","bundesland":"Rheinland-Pfalz","kreis":"Westerwaldkreis"},{"plz":"56244","ort":"Goddert","bundesland":"Rheinland-Pfalz","kreis":"Westerwaldkreis"},{"plz":"56244","ort":"Freirachdorf","bundesland":"Rheinland-Pfalz","kreis":"Westerwaldkreis"},{"plz":"56244","ort":"Maxsain","bundesland":"Rheinland-Pfalz","kreis":"Westerwaldkreis"},{"plz":"56244","ort":"Freilingen","bundesland":"Rheinland-Pfalz","kreis":"Westerwaldkreis"},{"plz":"56244","ort":"Weidenhahn","bundesland":"Rheinland-Pfalz","kreis":"Westerwaldkreis"},{"plz":"56244","ort":"Helferskirchen","bundesland":"Rheinland-Pfalz","kreis":"Westerwaldkreis"},{"plz":"56244","ort":"Arnshöfen","bundesland":"Rheinland-Pfalz","kreis":"Westerwaldkreis"},{"plz":"56244","ort":"Hahn am See","bundesland":"Rheinland-Pfalz","kreis":"Westerwaldkreis"},{"plz":"56244","ort":"Sessenhausen","bundesland":"Rheinland-Pfalz","kreis":"Westerwaldkreis"},{"plz":"56244","ort":"Wölferlingen","bundesland":"Rheinland-Pfalz","kreis":"Westerwaldkreis"},{"plz":"56244","ort":"Steinen","bundesland":"Rheinland-Pfalz","kreis":"Westerwaldkreis"},{"plz":"56244","ort":"Schenkelberg","bundesland":"Rheinland-Pfalz","kreis":"Westerwaldkreis"},{"plz":"56244","ort":"Krümmel","bundesland":"Rheinland-Pfalz","kreis":"Westerwaldkreis"},{"plz":"56244","ort":"Ettinghausen","bundesland":"Rheinland-Pfalz","kreis":"Westerwaldkreis"}]
let plzAutoCompleteConfig = {
minCharactersToRun: 3,
maxResults: 100,
allowedKeyCodes: [8, 9, 13, 37, 38, 39, 40, 46, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105]
}
let plzOrtAutoComplete = function plzOrtAutoComplete() {
if (!document.querySelector('[data-has-plz-ort-autocomplete]')) return;
// find all plz autocompletes
let autocompletes = Array.from(document.querySelectorAll('[data-has-plz-ort-autocomplete]'))
for (let autocomplete of autocompletes) {
let plzInput = document.getElementById(autocomplete.getAttribute('data-plz'))
let ortInput = document.getElementById(autocomplete.getAttribute('data-ort'))
let suggestList = document.createElement('ul')
suggestList.flush = function() {
this.innerHTML = ''
}
suggestList.className = 'autocomplete-suggest list-unstyled'
plzInput.parentNode.appendChild(suggestList)
for (let eventName of ['input', 'focus']) {
plzInput.addEventListener(eventName, function(evt) {
const checkInput = () => {
let matches = plz.filter(x => {
return x.plz.startsWith(this.value)
})
switch (true) {
case (matches.length > plzAutoCompleteConfig.maxResults):
suggestList.flush()
break
case ((matches.length <= plzAutoCompleteConfig.maxResults && matches.length > 1) || (matches.length === 1 && this.value.length < 5)):
suggestList.flush()
for (let match of matches) {
let li = document.createElement('li')
li.textContent = `${match.plz} ${match.ort}`
li.title = `${match.plz} ${match.ort} in ${match.bundesland}, ${match.kreis} übernehmen durch Enter oder Klick`
li.addEventListener('click', () => {
plzInput.value = match.plz
ortInput.value = match.ort
ortInput.focus()
suggestList.flush()
})
li.addEventListener('mouseenter', function() {
this.classList.add('active')
})
li.addEventListener('mouseleave', function() {
this.classList.remove('active')
})
suggestList.appendChild(li)
}
this.parentNode.appendChild(suggestList)
break
case (matches.length === 1 && this.value.length === 5):
if (event.type !== 'focus' && ['deleteContentBackward', 'deleteContentForward'].indexOf(evt.inputType) === -1) {
suggestList.flush()
plzInput.value = matches[0].plz
ortInput.value = matches[0].ort
ortInput.focus()
}
break
default:
{
suggestList.flush()
break
}
}
}
if (isNaN(Number(this.value))) {
this.value = ''
return
}
if (this.value.length >= plzAutoCompleteConfig.minCharactersToRun) {
if (['deleteContentBackward', 'deleteContentForward'].indexOf(evt.inputType) > -1) {
console.log(this.value)
}
checkInput()
}
})
}
plzInput.addEventListener('keydown', function(evt) {
let keyCode = evt.keyCode || evt.which;
let activeLi = suggestList.querySelector('li.active')
if (keyCode) {
if (!plzAutoCompleteConfig.allowedKeyCodes.includes(keyCode)) {
evt.preventDefault()
} else {
switch (keyCode) {
case 8: // backspace
suggestList.flush()
break
case 13: // Enter
evt.preventDefault()
if (!suggestList.hasChildNodes()) {
return
}
if (!activeLi) {
return
} else {
plzInput.value = activeLi.textContent.substr(0, 5)
ortInput.value = activeLi.textContent.substr(6)
suggestList.flush()
ortInput.focus()
}
break
case 37:
break
case 38: // cursor up
if (!suggestList.hasChildNodes()) {
return
}
if (activeLi) {
activeLi.classList.remove('active')
let prevLi = activeLi.previousSibling
if (prevLi) {
prevLi.classList.add('active')
} else {
suggestList.querySelector('li:last-of-type').classList.add('active')
}
} else {
suggestList.querySelector('li:last-of-type').classList.add('active')
}
/*code addedd*/
suggestList.scrollTop = suggestList.querySelector('.active').offsetTop;
break
case 39:
break
case 40: //cursor down
if (!suggestList.hasChildNodes()) {
return
}
if (activeLi) {
activeLi.classList.remove('active')
let nextLi = activeLi.nextSibling
if (nextLi) {
nextLi.classList.add('active')
} else {
suggestList.querySelector('li:first-of-type').classList.add('active')
}
} else {
suggestList.querySelector('li:first-of-type').classList.add('active')
}
/*added code*/
suggestList.scrollTop = suggestList.querySelector('.active').offsetTop;
break
case 46: // delete
suggestList.flush()
break
default:
break
}
}
}
})
plzInput.addEventListener('blur', function(evt) {
setTimeout(function() {
suggestList.flush()
}, 250)
})
ortInput.addEventListener('input', function(evt) {
console.log(this.value)
})
}
}
plzOrtAutoComplete();
&#13;
.autocomplete-suggest {
background-color: #fff;
border: 1px solid #ddd;
box-shadow: 3px 3px 5px #ccc;
max-height: 20em;
left: 5px;
opacity: 1;
overflow-y: auto;
pointer-events: all;
position: absolute;
z-index: 999;
transition-duration: .2s;
}
.autocomplete-suggest:empty {
max-height: 0;
opacity: 0;
pointer-events: none;
}
.autocomplete-suggest li {
line-height: 1.5em;
margin: 0 auto;
padding: .3em 1.2em .2em .6em;
transition: all .2s ease-in-out;
white-space: nowrap;
}
.autocomplete-suggest li:nth-child(even) {
background-color: rgba(0, 0, 0, 0.05);
}
.autocomplete-suggest li:hover, .autocomplete-suggest li.active {
cursor: pointer;
background-color: #a00;
color: #fff;
}
&#13;
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
<div class="form-row" data-has-plz-ort-autocomplete data-plz="eazVersicherterPLZ" data-ort="eazVersicherterOrt">
<div class="form-group col-md-4">
<label for="eazVersicherterPLZ">PLZ</label>
<input class="form-control" type="text" id="eazVersicherterPLZ" name="eazVersicherterPLZ" data-plz="eazVersicherterOrt" maxlength=5 />
</div>
<div class="form-group col-md-8">
<label for="eazVersicherterOrt">Ort</label>
<input class="form-control" type="text" id="eazVersicherterOrt" name="eazVersicherterOrt">
</div>
</div>
&#13;
如果您不希望活动元素始终位于顶部,您也可以使用一些偏移:
suggestList.scrollTop = suggestList.querySelector('.active').offsetTop - x;
您可以调整x
值,使活动元素位于底部,中间或保持在顶部。
let plz = [{"plz":"56244","ort":"Rückeroth","bundesland":"Rheinland-Pfalz","kreis":"Westerwaldkreis"},{"plz":"56244","ort":"Ötzingen","bundesland":"Rheinland-Pfalz","kreis":"Westerwaldkreis"},{"plz":"56244","ort":"Niedersayn","bundesland":"Rheinland-Pfalz","kreis":"Westerwaldkreis"},{"plz":"56244","ort":"Vielbach","bundesland":"Rheinland-Pfalz","kreis":"Westerwaldkreis"},{"plz":"56244","ort":"Hartenfels","bundesland":"Rheinland-Pfalz","kreis":"Westerwaldkreis"},{"plz":"56244","ort":"Ewighausen","bundesland":"Rheinland-Pfalz","kreis":"Westerwaldkreis"},{"plz":"56244","ort":"Leuterod","bundesland":"Rheinland-Pfalz","kreis":"Westerwaldkreis"},{"plz":"56244","ort":"Kuhnhöfen","bundesland":"Rheinland-Pfalz","kreis":"Westerwaldkreis"},{"plz":"56244","ort":"Goddert","bundesland":"Rheinland-Pfalz","kreis":"Westerwaldkreis"},{"plz":"56244","ort":"Freirachdorf","bundesland":"Rheinland-Pfalz","kreis":"Westerwaldkreis"},{"plz":"56244","ort":"Maxsain","bundesland":"Rheinland-Pfalz","kreis":"Westerwaldkreis"},{"plz":"56244","ort":"Freilingen","bundesland":"Rheinland-Pfalz","kreis":"Westerwaldkreis"},{"plz":"56244","ort":"Weidenhahn","bundesland":"Rheinland-Pfalz","kreis":"Westerwaldkreis"},{"plz":"56244","ort":"Helferskirchen","bundesland":"Rheinland-Pfalz","kreis":"Westerwaldkreis"},{"plz":"56244","ort":"Arnshöfen","bundesland":"Rheinland-Pfalz","kreis":"Westerwaldkreis"},{"plz":"56244","ort":"Hahn am See","bundesland":"Rheinland-Pfalz","kreis":"Westerwaldkreis"},{"plz":"56244","ort":"Sessenhausen","bundesland":"Rheinland-Pfalz","kreis":"Westerwaldkreis"},{"plz":"56244","ort":"Wölferlingen","bundesland":"Rheinland-Pfalz","kreis":"Westerwaldkreis"},{"plz":"56244","ort":"Steinen","bundesland":"Rheinland-Pfalz","kreis":"Westerwaldkreis"},{"plz":"56244","ort":"Schenkelberg","bundesland":"Rheinland-Pfalz","kreis":"Westerwaldkreis"},{"plz":"56244","ort":"Krümmel","bundesland":"Rheinland-Pfalz","kreis":"Westerwaldkreis"},{"plz":"56244","ort":"Ettinghausen","bundesland":"Rheinland-Pfalz","kreis":"Westerwaldkreis"}]
let plzAutoCompleteConfig = {
minCharactersToRun: 3,
maxResults: 100,
allowedKeyCodes: [8, 9, 13, 37, 38, 39, 40, 46, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105]
}
let plzOrtAutoComplete = function plzOrtAutoComplete() {
if (!document.querySelector('[data-has-plz-ort-autocomplete]')) return;
// find all plz autocompletes
let autocompletes = Array.from(document.querySelectorAll('[data-has-plz-ort-autocomplete]'))
for (let autocomplete of autocompletes) {
let plzInput = document.getElementById(autocomplete.getAttribute('data-plz'))
let ortInput = document.getElementById(autocomplete.getAttribute('data-ort'))
let suggestList = document.createElement('ul')
suggestList.flush = function() {
this.innerHTML = ''
}
suggestList.className = 'autocomplete-suggest list-unstyled'
plzInput.parentNode.appendChild(suggestList)
for (let eventName of ['input', 'focus']) {
plzInput.addEventListener(eventName, function(evt) {
const checkInput = () => {
let matches = plz.filter(x => {
return x.plz.startsWith(this.value)
})
switch (true) {
case (matches.length > plzAutoCompleteConfig.maxResults):
suggestList.flush()
break
case ((matches.length <= plzAutoCompleteConfig.maxResults && matches.length > 1) || (matches.length === 1 && this.value.length < 5)):
suggestList.flush()
for (let match of matches) {
let li = document.createElement('li')
li.textContent = `${match.plz} ${match.ort}`
li.title = `${match.plz} ${match.ort} in ${match.bundesland}, ${match.kreis} übernehmen durch Enter oder Klick`
li.addEventListener('click', () => {
plzInput.value = match.plz
ortInput.value = match.ort
ortInput.focus()
suggestList.flush()
})
li.addEventListener('mouseenter', function() {
this.classList.add('active')
})
li.addEventListener('mouseleave', function() {
this.classList.remove('active')
})
suggestList.appendChild(li)
}
this.parentNode.appendChild(suggestList)
break
case (matches.length === 1 && this.value.length === 5):
if (event.type !== 'focus' && ['deleteContentBackward', 'deleteContentForward'].indexOf(evt.inputType) === -1) {
suggestList.flush()
plzInput.value = matches[0].plz
ortInput.value = matches[0].ort
ortInput.focus()
}
break
default:
{
suggestList.flush()
break
}
}
}
if (isNaN(Number(this.value))) {
this.value = ''
return
}
if (this.value.length >= plzAutoCompleteConfig.minCharactersToRun) {
if (['deleteContentBackward', 'deleteContentForward'].indexOf(evt.inputType) > -1) {
console.log(this.value)
}
checkInput()
}
})
}
plzInput.addEventListener('keydown', function(evt) {
let keyCode = evt.keyCode || evt.which;
let activeLi = suggestList.querySelector('li.active')
if (keyCode) {
if (!plzAutoCompleteConfig.allowedKeyCodes.includes(keyCode)) {
evt.preventDefault()
} else {
switch (keyCode) {
case 8: // backspace
suggestList.flush()
break
case 13: // Enter
evt.preventDefault()
if (!suggestList.hasChildNodes()) {
return
}
if (!activeLi) {
return
} else {
plzInput.value = activeLi.textContent.substr(0, 5)
ortInput.value = activeLi.textContent.substr(6)
suggestList.flush()
ortInput.focus()
}
break
case 37:
break
case 38: // cursor up
if (!suggestList.hasChildNodes()) {
return
}
if (activeLi) {
activeLi.classList.remove('active')
let prevLi = activeLi.previousSibling
if (prevLi) {
prevLi.classList.add('active')
} else {
suggestList.querySelector('li:last-of-type').classList.add('active')
}
} else {
suggestList.querySelector('li:last-of-type').classList.add('active')
}
/*code addedd*/
suggestList.scrollTop = suggestList.querySelector('.active').offsetTop - 100;
break
case 39:
break
case 40: //cursor down
if (!suggestList.hasChildNodes()) {
return
}
if (activeLi) {
activeLi.classList.remove('active')
let nextLi = activeLi.nextSibling
if (nextLi) {
nextLi.classList.add('active')
} else {
suggestList.querySelector('li:first-of-type').classList.add('active')
}
} else {
suggestList.querySelector('li:first-of-type').classList.add('active')
}
/*added code*/
suggestList.scrollTop = suggestList.querySelector('.active').offsetTop - 100;
break
case 46: // delete
suggestList.flush()
break
default:
break
}
}
}
})
plzInput.addEventListener('blur', function(evt) {
setTimeout(function() {
suggestList.flush()
}, 250)
})
ortInput.addEventListener('input', function(evt) {
console.log(this.value)
})
}
}
plzOrtAutoComplete();
&#13;
.autocomplete-suggest {
background-color: #fff;
border: 1px solid #ddd;
box-shadow: 3px 3px 5px #ccc;
max-height: 20em;
left: 5px;
opacity: 1;
overflow-y: auto;
pointer-events: all;
position: absolute;
z-index: 999;
transition-duration: .2s;
}
.autocomplete-suggest:empty {
max-height: 0;
opacity: 0;
pointer-events: none;
}
.autocomplete-suggest li {
line-height: 1.5em;
margin: 0 auto;
padding: .3em 1.2em .2em .6em;
transition: all .2s ease-in-out;
white-space: nowrap;
}
.autocomplete-suggest li:nth-child(even) {
background-color: rgba(0, 0, 0, 0.05);
}
.autocomplete-suggest li:hover, .autocomplete-suggest li.active {
cursor: pointer;
background-color: #a00;
color: #fff;
}
&#13;
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
<div class="form-row" data-has-plz-ort-autocomplete data-plz="eazVersicherterPLZ" data-ort="eazVersicherterOrt">
<div class="form-group col-md-4">
<label for="eazVersicherterPLZ">PLZ</label>
<input class="form-control" type="text" id="eazVersicherterPLZ" name="eazVersicherterPLZ" data-plz="eazVersicherterOrt" maxlength=5 />
</div>
<div class="form-group col-md-8">
<label for="eazVersicherterOrt">Ort</label>
<input class="form-control" type="text" id="eazVersicherterOrt" name="eazVersicherterOrt">
</div>
</div>
&#13;
答案 1 :(得分:0)
对于那些感兴趣的人,以下是我最终实现它的方式:
let plz = [{"plz":"56244","ort":"Rückeroth","bundesland":"Rheinland-Pfalz","kreis":"Westerwaldkreis"},{"plz":"56244","ort":"Ötzingen","bundesland":"Rheinland-Pfalz","kreis":"Westerwaldkreis"},{"plz":"56244","ort":"Niedersayn","bundesland":"Rheinland-Pfalz","kreis":"Westerwaldkreis"},{"plz":"56244","ort":"Vielbach","bundesland":"Rheinland-Pfalz","kreis":"Westerwaldkreis"},{"plz":"56244","ort":"Hartenfels","bundesland":"Rheinland-Pfalz","kreis":"Westerwaldkreis"},{"plz":"56244","ort":"Ewighausen","bundesland":"Rheinland-Pfalz","kreis":"Westerwaldkreis"},{"plz":"56244","ort":"Leuterod","bundesland":"Rheinland-Pfalz","kreis":"Westerwaldkreis"},{"plz":"56244","ort":"Kuhnhöfen","bundesland":"Rheinland-Pfalz","kreis":"Westerwaldkreis"},{"plz":"56244","ort":"Goddert","bundesland":"Rheinland-Pfalz","kreis":"Westerwaldkreis"},{"plz":"56244","ort":"Freirachdorf","bundesland":"Rheinland-Pfalz","kreis":"Westerwaldkreis"},{"plz":"56244","ort":"Maxsain","bundesland":"Rheinland-Pfalz","kreis":"Westerwaldkreis"},{"plz":"56244","ort":"Freilingen","bundesland":"Rheinland-Pfalz","kreis":"Westerwaldkreis"},{"plz":"56244","ort":"Weidenhahn","bundesland":"Rheinland-Pfalz","kreis":"Westerwaldkreis"},{"plz":"56244","ort":"Helferskirchen","bundesland":"Rheinland-Pfalz","kreis":"Westerwaldkreis"},{"plz":"56244","ort":"Arnshöfen","bundesland":"Rheinland-Pfalz","kreis":"Westerwaldkreis"},{"plz":"56244","ort":"Hahn am See","bundesland":"Rheinland-Pfalz","kreis":"Westerwaldkreis"},{"plz":"56244","ort":"Sessenhausen","bundesland":"Rheinland-Pfalz","kreis":"Westerwaldkreis"},{"plz":"56244","ort":"Wölferlingen","bundesland":"Rheinland-Pfalz","kreis":"Westerwaldkreis"},{"plz":"56244","ort":"Steinen","bundesland":"Rheinland-Pfalz","kreis":"Westerwaldkreis"},{"plz":"56244","ort":"Schenkelberg","bundesland":"Rheinland-Pfalz","kreis":"Westerwaldkreis"},{"plz":"56244","ort":"Krümmel","bundesland":"Rheinland-Pfalz","kreis":"Westerwaldkreis"},{"plz":"56244","ort":"Ettinghausen","bundesland":"Rheinland-Pfalz","kreis":"Westerwaldkreis"}]
let plzAutoCompleteConfig = {
minCharactersToRun: 3,
maxResults: 100,
allowedKeyCodes: [8, 9, 13, 37, 38, 39, 40, 46, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105]
}
let plzOrtAutoComplete = function plzOrtAutoComplete() {
if (!document.querySelector('[data-has-plz-ort-autocomplete]')) return;
// find all plz autocompletes
let autocompletes = Array.from(document.querySelectorAll('[data-has-plz-ort-autocomplete]'))
for (let autocomplete of autocompletes) {
let plzInput = document.getElementById(autocomplete.getAttribute('data-plz'))
let ortInput = document.getElementById(autocomplete.getAttribute('data-ort'))
let suggestList = document.createElement('ul')
suggestList.flush = function() {
this.innerHTML = ''
}
suggestList.className = 'autocomplete-suggest list-unstyled'
plzInput.parentNode.appendChild(suggestList)
for (let eventName of ['input', 'focus']) {
plzInput.addEventListener(eventName, function(evt) {
const checkInput = () => {
let matches = plz.filter(x => {
return x.plz.startsWith(this.value)
})
switch(true) {
case(matches.length > plzAutoCompleteConfig.maxResults):
suggestList.flush()
break
case((matches.length <= plzAutoCompleteConfig.maxResults && matches.length > 1) || (matches.length === 1 && this.value.length < 5)):
suggestList.flush()
for (let match of matches) {
let li = document.createElement('li')
li.textContent = `${match.plz} ${match.ort}`
li.title = `${match.plz} ${match.ort} in ${match.bundesland}, ${match.kreis} übernehmen durch Enter oder Klick`
li.addEventListener('click', () => {
plzInput.value = match.plz
ortInput.value = match.ort
ortInput.focus()
suggestList.flush()
})
li.addEventListener('mouseenter', function() {
this.classList.add('active')
})
li.addEventListener('mouseleave', function() {
this.classList.remove('active')
})
suggestList.appendChild(li)
}
this.parentNode.appendChild(suggestList)
break
case(matches.length === 1 && this.value.length === 5):
if (event.type !== 'focus' && ['deleteContentBackward', 'deleteContentForward'].indexOf(evt.inputType) === -1) {
suggestList.flush()
plzInput.value = matches[0].plz
ortInput.value = matches[0].ort
ortInput.focus()
}
break
default: {
suggestList.flush()
break
}
}
}
if (isNaN(Number(this.value))) {
this.value = ''
return
}
if (this.value.length >= plzAutoCompleteConfig.minCharactersToRun) {
if (['deleteContentBackward', 'deleteContentForward'].indexOf(evt.inputType) > -1) {
console.log(this.value)
}
checkInput()
}
})
}
plzInput.addEventListener('keydown', function(evt) {
let keyCode = evt.keyCode || evt.which;
let activeLi = suggestList.querySelector('.active')
if (keyCode) {
if (!plzAutoCompleteConfig.allowedKeyCodes.includes(keyCode)) {
evt.preventDefault()
} else {
switch (keyCode) {
case 8: // backspace
suggestList.flush()
break
case 13: // Enter
evt.preventDefault()
if (!suggestList.hasChildNodes()) {
return
}
if (!activeLi) {
return
} else {
plzInput.value = activeLi.textContent.substr(0,5)
ortInput.value = activeLi.textContent.substr(6)
suggestList.flush()
ortInput.focus()
}
break
case 37:
break
case 38: // cursor up
if (!suggestList.hasChildNodes()) {
return
}
for (let item of Array.from(suggestList.querySelectorAll('li'))) {
if (item !== activeLi) {
item.classList.remove('active')
}
}
if (activeLi) {
activeLi.classList.remove('active')
let prevLi = activeLi.previousSibling || suggestList.querySelector('li:last-of-type')
if (prevLi) {
prevLi.classList.add('active')
if (prevLi.offsetTop < suggestList.scrollTop || prevLi.offsetTop > suggestList.scrollTop + suggestList.getBoundingClientRect().height) {
suggestList.scrollTop = prevLi.offsetTop
}
}
}
break
case 39:
break
case 40: // cursor down
if (!suggestList.hasChildNodes()) {
return
}
for (let item of Array.from(suggestList.querySelectorAll('li'))) {
if (item !== activeLi) {
item.classList.remove('active')
}
}
if (activeLi) {
activeLi.classList.remove('active')
let nextLi = activeLi.nextSibling || suggestList.querySelector('li:first-of-type')
if (nextLi) {
activeLi.classList.remove('active')
nextLi.classList.add('active')
if (nextLi.offsetTop < suggestList.scrollTop || nextLi.offsetTop > suggestList.scrollTop + suggestList.getBoundingClientRect().height - 32) {
suggestList.scrollTop = nextLi.offsetTop - suggestList.getBoundingClientRect().height + 32
}
}
} else {
suggestList.querySelector('li:first-of-type').classList.add('active')
}
break
case 46: // delete
suggestList.flush()
break
default:
break
}
}
}
})
plzInput.addEventListener('blur', function(evt) {
setTimeout(function() { suggestList.flush() }, 200500)
})
ortInput.addEventListener('input', function(evt) {
console.log(this.value)
})
}
}
plzOrtAutoComplete();
&#13;
.autocomplete-suggest {
background-color: #fff;
border: 1px solid #ddd;
box-shadow: 3px 3px 5px #ccc;
max-height: 6em;
left: 5px;
opacity: 1;
overflow-y: auto;
pointer-events: all;
position: absolute;
z-index: 999;
transition-duration: .2s;
}
.autocomplete-suggest:empty {
max-height: 0;
opacity: 0;
pointer-events: none;
}
.autocomplete-suggest li {
line-height: 1.5em;
margin: 0 auto;
padding: .3em 1.2em .2em .6em;
white-space: nowrap;
}
.autocomplete-suggest li:hover, .autocomplete-suggest li.active {
cursor: pointer;
background-color: #a00;
color: #fff;
}
&#13;
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
<div class="form-row" data-has-plz-ort-autocomplete data-plz="eazVersicherterPLZ" data-ort="eazVersicherterOrt">
<div class="form-group col-sm-4">
<label for="eazVersicherterPLZ">PLZ</label>
<input class="form-control" type="text" id="eazVersicherterPLZ" name="eazVersicherterPLZ" data-plz="eazVersicherterOrt" maxlength=5 />
</div>
<div class="form-group col-sm-8">
<label for="eazVersicherterOrt">Ort</label>
<input class="form-control" type="text" id="eazVersicherterOrt" name="eazVersicherterOrt">
</div>
</div>
&#13;