vue3项目中使用css自定义高亮API实现Ag-grid搜索内容高亮
使用 CSS 自定义高亮 API,你可以通过编程方式创建文本范围并高亮显示它们,而不会影响页面中的 DOM 结构。可以完美解决我的需求。但要注意它的浏览器兼容性。感兴趣的小伙伴可以点此CSS 自定义高亮 API - Web API 接口参考 | MDN查看官方文档相关介绍。
·
前言:
公司之前使用的表格组件是DevExtreme,后面由于某些原因需要把表格组件替换成了Ag-grid,
替换后发现Ag-grid的表格不支持搜索时匹配到的内容高亮功能。这下苦逼了,只能自己实现了。
思考:
Ag-grid已经内置了快速搜索功能,剩下的就是在执行搜索后让匹配到的文字呈现高亮效果就OK啦。于是就想到了CSS 自定义高亮 API。话不多说,直接看解决方案!
解决方案:
1、写在前面:
项目中所使用到的依赖包版本:
"ag-grid-community": "~31.0.0", "ag-grid-enterprise": "~31.0.0", "ag-grid-vue3": "~31.0.0", "element-plus": "^2.4.4", "vue": "^3.3.10",
2、封装QuickFilter组件
<template>
<div class="quick-filter-wrapper">
<el-input v-model="searchStr" clearable placeholder="输入关键字搜索" @input="debounceSearch"></el-input>
</div>
</template>
<script setup lang="ts">
import {ref, toValue} from "vue";
import {debounce} from "@/utils";
const props = defineProps<{
gridApi: any
}>();
// 用户输入的搜索字符
const searchStr = ref();
// 添加防抖处理,注:debounce方法可自行实现或使用第三方库
const debounceSearch = debounce(onSearch, 400);
// 监听搜索
function onSearch() {
const gridApi = toValue(props.gridApi);
if (!gridApi) return;
// 调用Ag grid的快速搜索
gridApi.setGridOption('quickFilterText', searchStr.value);
setHighlight(gridApi.gridBodyCtrl.eBodyViewport, searchStr.value)
}
// 设置高亮效果
function setHighlight(el: HTMLElement, searchStr: string) {
if (!CSS.highlights) {
console.warn('CSS Custom Highlight API not supported.');
return;
}
// 清除之前的高亮
CSS.highlights.clear();
if (!searchStr) return;
let ranges: any = [];
const allTextNodes = getAllTextNodes(el);
allTextNodes.forEach((node: any) => {
const positions = findStrPositions(node.nodeValue, searchStr);
positions.forEach((index: number) => {
ranges.push(createRange(node, index, index + searchStr.length));
})
});
const highlight = new Highlight(...ranges);
CSS.highlights.set('search-results', highlight);
}
// 找出所有的文本节点
function getAllTextNodes(el: HTMLElement) {
const treeWalker = document.createTreeWalker(el, NodeFilter.SHOW_TEXT);
const allTextNodes: any = [];
let currentNode = treeWalker.nextNode();
while (currentNode) {
allTextNodes.push(currentNode);
currentNode = treeWalker.nextNode();
}
return allTextNodes;
}
// 找出字符串在文本节点中出现的所有位置
function findStrPositions(mainStr: string, searchStr: string) {
let positions: any = [];
let index: number = 0;
while (index != -1) {
index = mainStr.toLowerCase().indexOf(searchStr.toLowerCase(), index);
if (index != -1) {
positions.push(index);
index += searchStr.length;
}
}
return positions;
}
// 创建选区
function createRange(el: any, start: number, end: number) {
const range = new Range();
range.setStart(el, start);
range.setEnd(el, end);
return range;
}
</script>
<style lang="scss">
.quick-filter-wrapper {
display: inline-block;
.el-input {
width: 200px;
}
}
// 可根据实际应用场景调整highlight样式位置,保证highlight样式生效即可
.ag-theme-quartz .ag-center-cols-viewport .ag-center-cols-container {
::highlight(search-results) {
background-color: #f29b4a;
}
}
</style>
2、在main.ts中注册QuickFilter组件
app.component('QuickFilter', QuickFilter)
3、使用
<template>
<div class="home">
<div class="toolbar">
<el-button @click="getData">刷新</el-button>
<div class="quick-filter">
<QuickFilter :grid-api="gridApi"></QuickFilter>
</div>
</div>
<section class="grid-wrapper">
<ag-grid-vue
class="ag-theme-quartz"
style="height: 100%"
:grid-options="gridOptions"
:defaultColDef="defaultColDef"
:columnDefs="columnDefs"
:rowData="rowData"
animateRows="true"
@grid-ready="onGridReady">
</ag-grid-vue>
</section>
</div>
</template>
<script setup lang="ts">
import {getCurrentInstance, onBeforeMount, reactive, ref} from "vue";
const ctx: any = getCurrentInstance()?.appContext.config.globalProperties
const gridOptions = reactive({
suppressContextMenu: true,
suppressCellFocus: true,
enableCellTextSelection: true,
})
const columnDefs = reactive([
{field: "make",},
{field: "model"},
{field: "price"},
])
const defaultColDef = {
sortable: true,
filter: 'agSetColumnFilter',
menuTabs: ['filterMenuTab'],
flex: 1
};
let gridApi: any = null;
const rowData = ref();
onBeforeMount(() => {
getData();
});
function getData() {
fetch("https://www.ag-grid.com/example-assets/row-data.json").then(res => res.json()).then(data => {
rowData.value = data;
}).catch(err => {
ctx.$message.error('获取数据失败!')
rowData.value = []
})
}
function onGridReady(e: any) {
gridApi = e.api;
}
</script>
<style lang="scss" scoped>
.home {
height: 100%;
display: flex;
flex-direction: column;
.header-item {
display: flex;
align-items: center;
padding: 4px;
.quick-filter {
margin-left: auto;
}
}
.grid-wrapper {
flex: 1;
}
}
</style>
结语:
使用 CSS 自定义高亮 API,你可以通过编程方式创建文本范围并高亮显示它们,而不会影响页面中的 DOM 结构。可以完美解决我的需求。但要注意它的浏览器兼容性。感兴趣的小伙伴可以点此CSS 自定义高亮 API - Web API 接口参考 | MDN查看官方文档相关介绍。
更多推荐
已为社区贡献1条内容
所有评论(0)