因项目功能需要,开发一个类似百度的那种搜索建议框,即通过输入的关键字进行匹配提示。不要求进行智能推荐,只要返回包含该关键字的若干条结果就行。效果大致如下:
初步的想法是利用第三方插件来做。进行过如下尝试。
1.使用autocomplete.js(自动完成)
某第三方autocomplete插件是这样写的(省略部分代码):
(function ($) {
$.fn.autocomplete = function (params) {
//Selections
var currentSelection = -1;
var currentProposals = [];
//Default parameters
params = $.extend({
hints: [],
//placeholder: 'Search',
width: 200,
height: 16,
showButton: true,
buttonText: 'Search',
onSubmit: function (text) {
},
onBlur: function () {
}
}, params);
...
}
})
调用方式类似如下:
var xxxValues=['xxxa','xxxb','xxxc']
$('#xxxDiv').autocomplete({
hints: xxxValues
})
这种方式对于搜索的结果集较小时是适用的,可以先将所有可能的结果查询出来,预先放到数组中,然后进行一次初始化即可。如下:
但对本项目,由于结果数据量太大,这种方式不合适。应当能够根据关键字进行动态查询,从建议库服务中动态获取搜索建议并填充下拉列表。于是另外找可以动态填充的插件。
2.使用typeahead.js(可以根据搜索建议库进行自动补全的插件)
该插件与autocomplete相比,其长处在于可以动态获取搜索建议,可对多个字段进行模糊匹配,及指定展示的字段,效果如下:
如果不指定展示字段,使用默认的展示方式,结果可能像下面这个样子(忽略样式):
也就是说,对像下面这样的结果:
{
"displayFieldName": "bsm",
"fieldAliases": {
"MC": "MC"
},
"fields": [
{
"name": "MC",
"type": "esriFieldTypeString",
"alias": "MC",
"length": 254
}
],
"features": [
{
"attributes": {
"MC": "龙岩市民源汽车发展有限公司"
}
},
{
"attributes": {
"MC": "龙岩市民商法律事务所"
}
},
{
"attributes": {
"MC": "龙岩市民政局"
}
},
{
"attributes": {
"MC": "龙岩市民族与宗教事务局"
}
},
{
"attributes": {
"MC": "龙岩市民宗局"
}
},
{
"attributes": {
"MC": "龙岩市民爆协会"
}
},
{
"attributes": {
"MC": "龙岩市民爆协会培训中心"
}
}
]
}
它展示的是整个JSON转化成字符串后的结果,而不是指定字段。并且,我们不想因为这样一个简单的功能而引入过多的插件。
于是,转而决定自行实现。
思路如下:
监听搜索关键字输入框的keyup事件,如输入不合法(如为空)时清空搜索建议列表(如果已有的话),否则,调用地图服务的搜索功能,根据输入的关键字进行查询,返回前10条结果并填充列表。选中列表中的任意一条结果时,将结果填充到搜索建议框中,并清空搜索建议列表。
核心代码如下:
1.输入框事件响应部分
$('#inputFromWhereKeyword').keyup(function () {
var _this = this
var divInput = $('#inputFromWhereKeyword')[0]
if (!divInput) {
return
}
var divList = $('#listSearchedAddress')[0]
if (!divList) {
return
}
_this.divInput = divInput
var keyword = divInput.value
if (!keyword || 0 == keyword.replace(' ', '').length) {
while(divList.hasChildNodes()){
divList.removeChild(divList.firstChild)
}
return
}
Promise
.all([_this.getAddress(keyword)])
.then(function (results) {
var result = results[0]
if (!result || 0 >= String(result).replace(' ', '').length || null == result) {
while(divList.hasChildNodes()){
divList.removeChild(divList.firstChild)
}
return
}
var listInnerHtml = ''
result.forEach(function (data, index) {
var anInnerHtml = '<div style="background-color:rgba(255,255,255,0.8);"><li x=' + data.geometry.x +
' y=' + data.geometry.y + '><span>' + (index + 1) + '</span><span>' + data.value + '</span></li></div>'
if (listInnerHtml) {
listInnerHtml += anInnerHtml
}else {
listInnerHtml = anInnerHtml
}
})
if (listInnerHtml) {
divList.innerHTML = listInnerHtml
}
divList.onclick = function (event) {
var tmpNode = event.target
var targetNode = (0 == tmpNode.children.length) ? tmpNode.parentNode : tmpNode
if ('LI' != targetNode.localName && 'li' != targetNode.localName) {
return
}
var x = targetNode.attributes.x.value
var y = targetNode.attributes.y.value
_this.divInput.setAttribute('x', x)
_this.divInput.setAttribute('y', y)
_this.divInput.value = targetNode.children[1].innerText
while(divList.hasChildNodes()){
divList.removeChild(divList.firstChild)
}
}
})
}.bind(this))
2.获取搜索建议结果部分
getAddress: function (keyword) {
var p = new Promise(function (resolve, reject) {
if (!keyword || 0 == keyword.trim().length) {
console.log('resolve with no records')
resolve(' ')
}else {
var targetField = 'MC'
var query = new Query(this.addressNameServiceLayer)
query.returnGeometry = true
query.where = targetField + " like '%" + keyword + "%'"
query.outFields = ['Shape', targetField]
var queryTask = new QueryTask(this.addressNameServiceLayer)
queryTask.execute(query).then(function (result) {
var values = []
if (!result || result.features.length <= 0) {
reject('no records')
}
var features = result.features
if (!features) {
reject('bad result')
}
var len = features.length
var count = len > 10 ? 10 : len
var index = 0
for (;index < count;index++) {
var aFeature = features[index]
var aResult = aFeature.attributes[targetField]
if (aResult) {
var aValue = {
value: aResult,
geometry: aFeature.geometry
}
values.push(aValue)
}
}
if (0 == values.length) {
reject('empty result')
}
resolve(values)
})
}
}.bind(this))
return p
},
最终达到的效果如下:
1.输入关键字时,动态推荐结果
2.选中一条结果后,建议列表隐藏