您的位置:首页 > Web前端 > JavaScript

JavaScript结合ArcGIS地图服务实现的搜索建议框

2017-09-19 09:14 537 查看
因项目功能需要,开发一个类似百度的那种搜索建议框,即通过输入的关键字进行匹配提示。不要求进行智能推荐,只要返回包含该关键字的若干条结果就行。效果大致如下:





初步的想法是利用第三方插件来做。进行过如下尝试。

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相比,其长处在于可以动态获取搜索建议,可对多个字段进行模糊匹配,及指定展示的字段,效果如下:



然而,由于ArcGIS地图服务的搜索结果(JSON)有自己的组织方式,我们要进行匹配的字段位于结果的features的attributes的指定字段中,如下:



如果不指定展示字段,使用默认的展示方式,结果可能像下面这个样子(忽略样式):



也就是说,对像下面这样的结果:

{
"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.选中一条结果后,建议列表隐藏

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐