先看效果
<div class="search-content" id="map-search-wrapper">
<a-trigger
popup-visible
position="bl"
autoFitPopupWidth
:popup-offset="4"
:unmount-on-close="true"
trigger="click"
popup-container="#map-search-wrapper"
>
<a-input-search
v-model="keyword"
:style="{ width: '280px' }"
placeholder="输入位置搜索"
search-button
allow-clear
@input="onInputInput"
@search="onInputSearch"
>
<template #button-icon>
<icon-search size="12" />
</template>
</a-input-search>
<template #content>
<a-scrollbar style="height: 296px; overflow: auto" v-if="placeList?.length > 0">
<div class="search-result">
<div class="place-list">
<div class="place-item" v-for="(place, index) in placeList" :key="index" @click="onPlaceItemClick(place)">
<div class="place-item-content">
<span class="place-name">
<PlaceColorName :name="place.name" :keyword="keyword" />
</span>
<span class="place-district">{{ place.district }}</span>
</div>
</div>
</div>
</div>
</a-scrollbar>
</template>
</a-trigger>
</div>
难点:
问题:triggerContent 的 宽度需要和 trigger 的宽度保持一致
解决:autoFitPopupWidth属性,此属性在官方文档中并未书写,但看源码可以找到这个属性,其功能正好适合此场景
问题:如何实现在搜索大悦时,西单大悦城中大悦二字标黄
解决:利用正则实现,PlaceColorName.js 组件实现如下
import { h } from 'vue'
/**
* 分割字符串并标注关键词
* @param {string} targetStr - 目标字符串
* @param {string} keyword - 关键字
* @returns {string[]} 返回一个数组,其中目标字符串被分割,并用 "关键字" 标注
*/
function splitAndMarkKeyword(targetStr, keyword) {
// 如果 keyword 中有正则表达式的关键字,则进行转义
const escapeKeyword = keyword.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
const regex = new RegExp(`(${escapeKeyword})`, 'gi') // 创建一个全局忽略大小写的正则表达式来匹配关键字
let match
let result = []
let lastIndex = 0
while ((match = regex.exec(targetStr)) !== null) {
// 添加关键字前的部分
if (match.index > lastIndex) {
result.push(targetStr.slice(lastIndex, match.index));
}
// 添加关键字
result.push(`${match[0]}`)
lastIndex = match.index + match[0].length
}
// 添加剩余部分
if (lastIndex < targetStr.length) {
result.push(targetStr.slice(lastIndex))
}
return result
}
export default function (value) {
const name = value.name
const keyword = value.keyword
const nameStrs = splitAndMarkKeyword(name, keyword)
return h(
'span',
{},
nameStrs.map((item) => {
if (item == keyword) {
return h('span', { style: { color: '#FF874F' } }, item)
} else {
return item
}
})
)
}