自定义数据列表 - 选项在选择之前消失

时间:2016-06-15 01:29:47

标签: javascript css javascript-events html-datalist

我为实时搜索准备了以下代码。在输入焦点上,将显示可用选项列表。在输入模糊时,选项消失。我的问题就在于此。单击列表中的项目时,输入将失去焦点,列表将在单击事件发生之前消失。

var artists = [{"artist":"3 Doors Down"},{"artist":"5 Seconds of Summer"},{"artist":"Adele"},{"artist":"Alicia Keys"},{"artist":"Amanda Abizaid"}];

function liveSearch(element) {
  return new liveSearch.prototype.init(element);
}
liveSearch.prototype = {
  init : function(element) {
    if (!element) {
      this.element = document.createElement("ul");
      this.element.classList.add("liveSearch");
    } else {
      this.element = element;
    }
  },
  update : function(queryElement) {
    this.clear();
    var lookUpArray = queryElement.name + "s";
    var results = this.search(artists, queryElement.value, queryElement.name);
    for (var i = 0; i < results.length; i++) {
      var li = document.createElement("li");
      var value = results[i];
      if (queryElement.value != "") {
        var re = new RegExp(queryElement.value, "gi");
        value = value.replace(re, "<span class=\"highlight\">" + "$&" + "</span>");
      }
      li.innerHTML = value;
      this.element.appendChild(li);
    }
    return results.length;
  },
  search : function(lookUpArray, string) {
    var results = [];
    for (var i = 0; i < lookUpArray.length; i++) {
      if (lookUpArray[i].artist.toLowerCase().search(string.toLowerCase()) != -1) {
        results.push(lookUpArray[i].artist);
      }
    }
    return results;
  },
  clear : function() {
    this.element.innerHTML = "";
  },
  hidden : function() {
    this.element.style.display = "none";
  },
  visible : function() {
    this.element.style.display = "";
  },
  remove : function() {
    this.element.parentElement.removeChild(this.element);
  },
};
liveSearch.prototype.init.prototype = liveSearch.prototype;

$("#lyrics-form").on("focus", "input.liveSearch-input", function() {
  this.parentElement.appendChild(liveSearch().element);
  if (liveSearch(this.nextElementSibling).update(this)) {
    liveSearch(this.nextElementSibling).visible();
  } else {
    liveSearch(this.nextElementSibling).hidden();
  }
});

$("#lyrics-form").on("blur", "input.liveSearch-input", function() {
  liveSearch(this.nextElementSibling).remove();
});

$("#lyrics-form").on("keyup", "input.liveSearch-input", function() {
  if (this.value != "") {
    if (liveSearch(this.nextElementSibling).update(this)) {
      liveSearch(this.nextElementSibling).visible();
    } else {
      liveSearch(this.nextElementSibling).hidden();
    }
  } else {
    liveSearch(this.nextElementSibling).update(this);
  }
});

$("#lyrics-form").on("click", "li", function() {
  this.parentElement.previousElementSibling.value = this.innerText;
  liveSearch(this.parentElement).hidden();
});
input, ul {
  width: 180px;
  box-sizing: border-box;
}
.liveSearch {
  margin: 0;
  border: 1px solid silver;
  box-shadow: 0 2px 5px rgba(0,0,0,.5);
  position: absolute;
  background: white;
  padding: 5px;
  max-height: 195px;
  width: 180px;
  overflow-y: scroll;
  z-index: 1000;
}
.liveSearch li {
  padding: 2px 5px;
  cursor: default;
}
.liveSearch li:hover {
  background: rgba(0,0,0,.05);
  color: black;
}
.liveSearch .highlight {
  font-weight: bold;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<form action="addlyrics.php" id="lyrics-form" method="post" autocomplete="off" enctype="multipart/form-data">
	<input type="text" name="artist" id="artist" class="liveSearch-input" placeholder="Artist" required />
</form>

我在模糊时使用了超时来解决问题,但这还不够好。它不一致,更高的延迟使设计变得丑陋。我该如何解决这个问题?

$("#lyrics-form").on("blur", "input.liveSearch-input", function() {
    /* liveSearch(this.nextElementSibling).remove(); */
    setTimeout(function() {
        liveSearch(this.nextElementSibling).remove();
    }.bind(this), 100);
});

1 个答案:

答案 0 :(得分:0)

我刚刚了解了datalist元素。它有点像我在这里尝试完成的,但我不能设计它,或修改它。所以我对代码进行了一些更改,并制作了自定义数据列表。

&#13;
&#13;
var artists = [{"artist":"3 Doors Down"},{"artist":"5 Seconds of Summer"},{"artist":"Adele"},{"artist":"Alicia Keys"},{"artist":"Amanda Abizaid"}];

function datalist(element) {
  return new datalist.prototype.init(element);
}
datalist.prototype = {
  init : function(element) {
    if (!element) {
      this.element = document.createElement("ul");
      this.element.classList.add("datalist");;
      this.hide();
    } else {
      this.element = element;
    }
  },
  update : function(queryElement) {
    this.clear();
    var lookUpArray = queryElement.name + "s";
    var results = this.search(window[lookUpArray], queryElement.value, queryElement.name);
    for (var i = 0; i < results.length; i++) {
      var li = document.createElement("li");
      var value = results[i][queryElement.name];
      if (queryElement.value != "") {
        var re = new RegExp(queryElement.value, "gi");
        value = value.replace(re, "<span class=\"highlight\">" + "$&" + "</span>");
      }
      li.innerHTML = value;
      this.element.appendChild(li);
    }
    return results.length;
  },
  search : function(lookUpArray, string, queryType) {
    var results = [];
    for (var i = 0; i < lookUpArray.length; i++) {
      if (lookUpArray[i][queryType].toLowerCase().search(string.toLowerCase()) != -1) {
        results.push(lookUpArray[i]);
      }
    }
    return results;
  },
  clear : function() {
    this.element.innerHTML = "";
  },
  hide : function() {
    this.element.style.display = "none";
  },
  show : function() {
    this.element.style.display = "";
  },
  remove : function() {
    this.element.parentElement.removeChild(this.element);
  },
};
datalist.prototype.init.prototype = datalist.prototype;

var lastVisitedInput = null;

$("#lyrics-form").on("focus", "input.datalist-input", function() {
  if (this.parentElement.children.length == 1) {
    this.parentElement.appendChild(datalist().element);
  }
  if (lastVisitedInput) {
    datalist(lastVisitedInput.nextElementSibling).hide();
  }
  lastVisitedInput = this;
  if (datalist(this.nextElementSibling).update(this)) {
    datalist(this.nextElementSibling).show();
  }
});

$("#lyrics-form").on("input", "input.datalist-input", function() {
  datalist(this.nextElementSibling).update(this);
});

$(document).on("click", function(e) {
  if (lastVisitedInput) {
    var exceptions = getExceptions(lastVisitedInput);
    if (!contains(exceptions, e.target)) {
      datalist(lastVisitedInput.nextElementSibling).remove();
      lastVisitedInput = null;
    }
  }
});

$("#lyrics-form").on("click", "li", function() {
  this.parentElement.previousElementSibling.value = this.innerText;
  $(this.parentElement.previousElementSibling).trigger("input");
});

function getExceptions(input) {
  var exceptions = [
    input,
    input.nextElementSibling,
  ];
    for (var i = 0; i < input.nextElementSibling.children.length; i++) {
    exceptions.push(input.nextElementSibling.children[i]);
}
return exceptions;
}

function contains(array, item) {
  for (var i = 0; i < array.length; i++) {
    if (array[i] === item) {
      return true;
    }
  }
  return false;
}
&#13;
input {
  padding: 5px;
}
input, ul {
  width: 200px;
  box-sizing: border-box;
}
.datalist {
  margin: 0;
  border: 1px solid silver;
  box-shadow: 0 2px 5px rgba(0,0,0,.5);
  position: absolute;
  background: white;
  padding: 5px;
  max-height: 200px;
  overflow-y: scroll;
  z-index: 1000;
}
.datalist li {
  padding: 2px 5px;
  cursor: default;
}
.datalist li:hover {
  background: rgba(0,0,0,.05);
  color: black;
}
.datalist .highlight {
  font-weight: bold;
}
&#13;
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<form id="lyrics-form" autocomplete="off" enctype="multipart/form-data">
	<input type="search" name="artist" id="artist" class="datalist-input" placeholder="Artist" required />
</form>
&#13;
&#13;
&#13;