创建一个在输入回调上拒绝的HTML输入文本元素



我有一个JavaScript应用程序,用户可以在其中搜索地图上的位置。输入文本提供了自动完整的建议:作为用户类型,一些建议出现在文本输入本身的底部。

我正在使用第三方JavaScript自动完成库,该库收取每个用户请求的费用。不幸的是,每次击键都将其视为一个单个请求,因为库从输入元素接收onInput回调时不会实现任何辩论。因此,这些建议看起来很活泼,但要花很多用户要求。

我想做的是重新定义输入元素内的输入回调以实现bebounconcing(例如500ms(。

由于第三方库接受JavaScript元素本身,因此我不能使用外部辩论机制:(可能库检测到输入元素发送的onInput消息本身(

(
var placesAutocomplete = places({
    appId: 'xxxxxxxxxxx',
    apiKey: 'kkkkkkkkkk',
    container: document.querySelector('#inputelement'), // <- the library accepts the element itself, not an "on input" listener (which could be easily debounced by an external function)
    language: G_lang
});
placesAutocomplete.on('change', function(res){
    // user leaves the input text, set lat lon on my map (code not shown here on SO)
    var lat = res.suggestion.latlng.lat;
    var lon = res.suggestion.latlng.lng;
    finish(lat, lon);
});

必须由JavaScript元素本身提供审问。因此,基本上,该元素应发射由辩论机构过滤的onInput回调。

只能使用Vanilla JavaScript?

可以这样做吗?

编辑

看来有人试图在GitHub项目页面上提出扣除辩论功能的请求,但被拒绝了:https://github.com/algolia/places/issues/281

和其他人分配了图书馆,并自行叉 -> https://github.com/acuityscheduling/places/tree/feature/debouncous

使用官方Codepen,我做了这个hackish bebouned版本:

var client = algoliasearch("latency", "6be0576ff61c053d5f9a3225e2a90f76")
var index = client.initIndex('movies');
var myAutocomplete = autocomplete('#search-input', {
  hint: false
}, [{
  source: autocomplete.sources.hits(index, {
    hitsPerPage: 5
  }),
  displayKey: 'title',
  templates: {
    suggestion: function(suggestion) {
      var sugTemplate = "<img src='" + suggestion.image + "'/><span>" + suggestion._highlightResult.title.value + "</span>"
      return sugTemplate;
    }
  }
}]).on('autocomplete:selected', function(event, suggestion, dataset) {
  console.log(suggestion, dataset);
});
document.querySelector(".searchbox [type='reset']").addEventListener("click", function() {
  document.querySelector(".aa-input").focus();
  this.classList.add("hide");
  myAutocomplete.autocomplete.setVal("");
});
document.querySelector("#debouncer").addEventListener("input", function() {
  var s = document.querySelector("#search-input");
  s.value = this.value;
  clearTimeout(this.tick);
  this.tick = setTimeout(() => s.dispatchEvent(new KeyboardEvent('input')), 500);
});
document.querySelector("#search-input").addEventListener("input", function() {
  var searchbox = document.querySelector(".aa-input");
  var reset = document.querySelector(".searchbox [type='reset']");
  if (searchbox.value.length === 0) {
    reset.classList.add("hide");
  } else {
    reset.classList.remove('hide');
  }
});
body {
  padding: 60px;
}
.searchbox {
  display: inline-block;
  position: relative;
  width: 200px;
  height: 37px;
  white-space: nowrap;
  box-sizing: border-box;
  font-size: 13px;
  font-family: arial, sans-serif;
}
#debouncer {
  position: absolute;
  z-index: 1;
  box-sizing:border-box;
  padding: 0 30px 0 37px;
  width: 100%;
  height: 100%;
  vertical-align: middle;
  white-space: normal;
  font-size: inherit;
  -webkit-appearance: none;
  -moz-appearance: none;
  appearance: none;
  background: none;
  border:0;
}
.algolia-autocomplete {
  display: block;
  height: 100%;
}
.searchbox__wrapper {
  width: 100%;
  height: 100%;
}
.searchbox__input {
  display: inline-block;
  -webkit-transition: box-shadow .4s ease, background .4s ease;
  transition: box-shadow .4s ease, background .4s ease;
  border: 0;
  border-radius: 19px;
  box-shadow: inset 0 0 0 1px #D9D9D9;
  color:transparent;
  background: #FFFFFF;
  padding: 0;
  padding-right: 30px;
  padding-left: 37px;
  width: 100%;
  height: 100%;
  vertical-align: middle;
  white-space: normal;
  font-size: inherit;
  -webkit-appearance: none;
  -moz-appearance: none;
  appearance: none;
}
.searchbox__input::-webkit-search-decoration,
.searchbox__input::-webkit-search-cancel-button,
.searchbox__input::-webkit-search-results-button,
.searchbox__input::-webkit-search-results-decoration {
  display: none;
}
#debouncer:hover ~ * .searchbox__input {
  box-shadow: inset 0 0 0 1px silver;
}
#debouncer:focus ~ * .searchbox__input,
#debouncer:active ~ * .searchbox__input {
  outline: 0;
  box-shadow: inset 0 0 0 1px #4098CE;
  background: #FFFFFF;
}
#debouncer::-webkit-input-placeholder {
  color: #AAAAAA;
}
#debouncer::-moz-placeholder {
  color: #AAAAAA;
}
#debouncer:-ms-input-placeholder {
  color: #AAAAAA;
}
#debouncer::placeholder {
  color: #AAAAAA;
}
.searchbox__submit {
  position: absolute; z-index:2;
  top: 0;
  right: inherit;
  left: 0;
  margin: 0;
  border: 0;
  border-radius: 18px 0 0 18px;
  background-color: rgba(255, 255, 255, 0);
  padding: 0;
  width: 37px;
  height: 100%;
  vertical-align: middle;
  text-align: center;
  font-size: inherit;
  -webkit-user-select: none;
  -moz-user-select: none;
  -ms-user-select: none;
  user-select: none;
}
.searchbox__submit::before {
  display: inline-block;
  margin-right: -4px;
  height: 100%;
  vertical-align: middle;
  content: '';
}
.searchbox__submit:hover,
.searchbox__submit:active {
  cursor: pointer;
}
.searchbox__submit:focus {
  outline: 0;
}
.searchbox__submit svg {
  width: 17px;
  height: 17px;
  vertical-align: middle;
  fill: #666666;
}
.searchbox__reset {
  position: absolute; z-index:2;
  top: 8px;
  right: 8px;
  margin: 0;
  border: 0;
  background: none;
  cursor: pointer;
  padding: 0;
  font-size: inherit;
  -webkit-user-select: none;
  -moz-user-select: none;
  -ms-user-select: none;
  user-select: none;
  fill: rgba(0, 0, 0, 0.5);
}
.searchbox__reset.hide {
  display: none;
}
.searchbox__reset:focus {
  outline: 0;
}
.searchbox__reset svg {
  display: block;
  margin: 4px;
  width: 13px;
  height: 13px;
}
.searchbox__input:valid~.searchbox__reset {
  display: block;
  -webkit-animation-name: sbx-reset-in;
  animation-name: sbx-reset-in;
  -webkit-animation-duration: .15s;
  animation-duration: .15s;
}
@-webkit-keyframes sbx-reset-in {
  0% {
    -webkit-transform: translate3d(-20%, 0, 0);
    transform: translate3d(-20%, 0, 0);
    opacity: 0;
  }
  100% {
    -webkit-transform: none;
    transform: none;
    opacity: 1;
  }
}
@keyframes sbx-reset-in {
  0% {
    -webkit-transform: translate3d(-20%, 0, 0);
    transform: translate3d(-20%, 0, 0);
    opacity: 0;
  }
  100% {
    -webkit-transform: none;
    transform: none;
    opacity: 1;
  }
}
.aa-dropdown-menu {
  position: relative;
  top: -6px;
  border-radius: 3px;
  margin: 6px 0 0;
  padding: 0;
  text-align: left;
  height: auto;
  position: relative;
  background: transparent;
  border: none;
  width: 100%;
  left: 0 !important;
  box-shadow: 0 1px 0 0 rgba(0, 0, 0, 0.2), 0 2px 3px 0 rgba(0, 0, 0, 0.1);
}
.aa-dropdown-menu:before {
  position: absolute;
  content: '';
  width: 14px;
  height: 14px;
  background: #fff;
  z-index: 0;
  top: -7px;
  border-top: 1px solid #D9D9D9;
  border-right: 1px solid #D9D9D9;
  transform: rotate(-45deg);
  border-radius: 2px;
  z-index: 999;
  display: block;
  left: 24px;
}
.aa-dropdown-menu .aa-suggestions {
  position: relative;
  z-index: 1000;
}
.aa-dropdown-menu [class^="aa-dataset-"] {
  position: relative;
  border: solid 1px #D9D9D9;
  border-radius: 3px;
  overflow: auto;
  padding: 8px 8px 8px;
}
.aa-dropdown-menu * {
  box-sizing: border-box;
}
.aa-suggestion {
  font-size: 1.1em;
  padding: 4px 4px 0;
  display: block;
  width: 100%;
  height: 38px;
  clear: both;
}
.aa-suggestion span {
  white-space: nowrap!important;
  text-overflow: ellipsis;
  overflow: hidden;
  display: block;
  float: left;
  line-height: 2em;
  width: calc(100% - 30px);
}
.aa-suggestion.aa-cursor {
  background: #eee;
}
.aa-suggestion em {
  color: #4098CE;
}
.aa-suggestion img {
  float: left;
  vertical-align: middle;
  height: 30px;
  width: 20px;
  margin-right: 6px;
}
<script src="//cdn.jsdelivr.net/algoliasearch/3/algoliasearch.min.js"></script>
<script src="//cdn.jsdelivr.net/autocomplete.js/0/autocomplete.min.js"></script>
<form novalidate="novalidate" onsubmit="return false;" class="searchbox">
  <div role="search" class="searchbox__wrapper">
    <input id="debouncer" type="text" name="search" autocomplete="off" placeholder="Search for a movie">
    <input id="search-input" type="search" name="autocomplete" autocomplete="off" required="required" class="searchbox__input">
    <button type="submit" title="Submit your search query." class="searchbox__submit">
      <svg role="img" aria-label="Search">
        <use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#sbx-icon-search-13"></use>
          </svg>
        </button>
    <button type="reset" title="Clear the search query." class="searchbox__reset hide">
      <svg role="img" aria-label="Reset">
        <use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#sbx-icon-clear-3"></use>
        </svg>
      </button>
  </div>
</form>
<div class="svg-icons" style="height: 0; width: 0; position: absolute; visibility: hidden">
  <svg xmlns="http://www.w3.org/2000/svg">
    <symbol id="sbx-icon-clear-3" viewBox="0 0 40 40"><path d="M16.228 20L1.886 5.657 0 3.772 3.772 0l1.885 1.886L20 16.228 34.343 1.886 36.228 0 40 3.772l-1.886 1.885L23.772 20l14.342 14.343L40 36.228 36.228 40l-1.885-1.886L20 23.772 5.657 38.114 3.772 40 0 36.228l1.886-1.885L16.228 20z" fill-rule="evenodd"/></symbol>
    <symbol id="sbx-icon-search-13" viewBox="0 0 40 40"><path d="M26.806 29.012a16.312 16.312 0 0 1-10.427 3.746C7.332 32.758 0 25.425 0 16.378 0 7.334 7.333 0 16.38 0c9.045 0 16.378 7.333 16.378 16.38 0 3.96-1.406 7.593-3.746 10.426L39.547 37.34c.607.608.61 1.59-.004 2.203a1.56 1.56 0 0 1-2.202.004L26.807 29.012zm-10.427.627c7.322 0 13.26-5.938 13.26-13.26 0-7.324-5.938-13.26-13.26-13.26-7.324 0-13.26 5.936-13.26 13.26 0 7.322 5.936 13.26 13.26 13.26z" fill-rule="evenodd"/></symbol>
	</svg>
</div>

这种方法几乎不比这种自动完成的实现本身好。希望它能有所帮助。

我认为我设法找到了一个很好的解决方案。我分配了库并启用了访问功能(已经存在,仅针对自动完成表单禁用(。

最终结果:使用少量自动完成滞后200ms,使用80%,完全可以接受

相关内容

最新更新