原生JavaScript实现日志搜索高亮的解决方案

news2024/12/23 6:03:39

前言

最近在做一个日志管理的功能,其中有一个功能是这样的,在一个页面上会显示千上万条日志,
需要做一个搜索的功能,并能将搜索结果一一显示在视口中,通过控制滚动条。
这里使用html+原生js实现了一个简单的demo,核心步骤都是已实现。这里稍作一下记录。

技术实现

主要技术点是,获取装载所有日志的容器的innerHTML,然后使用js的replace搭配正则表达式,对内容进行搜索替换。
搜索替换的核心代码

const newHtml = logHtml.replace(reg, res => {
  searchNum++
  return `<span class="search-res">${res}</span>`
})

logHtml变量 日志容器的innerHTML
reg变量 要搜索的关键词正则表达式
searchNum变量 用来存放搜索结果的个数
css类search-res 用于高亮搜索结果和查询搜索结果

滚动到第num个搜索结果的核心代码
通过css类search-res来获取所有的搜索结果,并使用num来获取具体要显示的搜索结果。
要显示第num个搜索结果,需要将日志容器的滚动条scrollTop(元素到父元素顶部的高度),设置为搜索结果元素的offsetTop减去日志容器视口高度的一半。

const currentEl = document.querySelectorAll(".search-res")[num - 1]
document.querySelector("#log-container").scrollTop = currentEl.offsetTop - document.querySelector("#log-container").offsetHeight / 2
document.querySelector("#current-num").innerText = currentNum

注意:每次在innerHTML中搜索,都是日志容器的原始innerHTML。即在没有搜索前保存的innerHTML,日志数据不会,它就不会改变。
如果每次搜索前,取当前的日期容器innerHTML,那么就会保留上一次搜索的结果。

显示效果

点击enter键,跳到下一个搜索结果。
在这里插入图片描述

显示效果如上图,

完整代码

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8" />
  <title>日志搜索</title>
  <style type="text/css">
    * {
      padding: 0;
      margin: 0;
      outline: none;
    }

    html,
    body {
      height: 100%;
      font-family: "楷体", "楷体_GB2312";
    }

    .container {
      height: 100%;
      width: 1000px;
      border: 1px solid #ddd;
      margin: 0 auto;
      box-sizing: border-box;
      padding: 12px;
      position: relative;
    }

    .title {
      text-align: center;
      font-size: 24px;
    }

    .margin-8 {
      margin: 8px;
    }

    .log-container {
      text-align: left;
      overflow-y: auto;
      height: calc(100% - 40px);
    }

    .search-wrap {
      position: absolute;
      padding: 0 8px;
      right: 0px;
      width: 200px;
      height: 34px;
      color: #616161;
      transform: translateY(0);
      background-color: #f3f3f3;
      box-shadow: 0 0 8px 2px rgb(0 0 0 / 16%);
      line-height: 32px;
    }

    .keyword-input {
      background-color: rgb(255, 255, 255);
      color: rgb(97, 97, 97);
      height: 24px;
      outline: none;
      border: none;
      padding: 0;
      box-sizing: border-box;
      border-radius: 4px;
      display: inline-block;
      width: 120px;
      padding-left: 5px;
    }

    .log-row {
      font-size: 14px;
      line-height: 25px;
    }

    .search-res {
      background-color: #f73131;
      border-radius: 2px;
    }

    .search-res.active {
      background-color: #a8ac94;
    }
  </style>
</head>

<body>

  <div class="container">
    <p class="title margin-8">日志搜索定位</p>
    <div class="search-wrap">
      <input id="keyword" class="keyword-input" value="三两" />
      <span id="current-num">0</span>/<span id="search-num">0</span>
    </div>
    <div class="log-container" id="log-container">

    </div>

  </div>

  <script>
    let logHtml = ''
    let searchNum = 0
    let currentNum = 0
    let halfOffsetHeight
    function createLog(num = 100) {
      const logArr = []
      for (let i = 1; i < num; i++) {
        if (i % 20 === 0) {
          logArr.push(`<p class="log-row">${i}&nbsp;竹外桃花三两枝,春江水暖鸭先知。蒌蒿满地芦芽短,正是河豚欲上时。</p>`)
        } else {
          logArr.push(`<p class="log-row">${i}&nbsp;千山鸟飞绝,万径人踪灭。孤舟蓑笠翁,独钓寒江雪。</p>`)
        }
      }
      return logArr.join('')
    }

    function appendHtml() {
      const logHm = createLog(200)
      logHtml = document.querySelector('#log-container').innerHTML
      logHtml = logHtml + logHm
      document.querySelector('#log-container').innerHTML = logHtml
    }

    function searchWord(reg) {
      searchNum = 0
      const newHtml = logHtml.replace(reg, res => {
        searchNum++
        return `<span class="search-res">${res}</span>`
      })
      document.querySelector('#log-container').innerHTML = newHtml
      document.querySelector("#search-num").innerText = searchNum
      currentNum = currentNum + 1
      slide(currentNum)
    }

    function slide(num) {
      const currentEl = document.querySelectorAll(".search-res")[num - 1]
      if (!currentEl) {
        return false
      }
      const currentOffsetTop = currentEl.offsetTop
      document.querySelector("#log-container").scrollTop = currentOffsetTop - halfOffsetHeight
      document.querySelector("#current-num").innerText = currentNum
    }

    function init() {
      appendHtml()
      halfOffsetHeight = document.querySelector("#log-container").offsetHeight / 2
      document.querySelector("#keyword").addEventListener('keydown', function (e) {
        if (e.keyCode === 13) {
          const word = e.target.value
          const reg = new RegExp(`${word}`, 'g')
          // TODO 相同的搜索词,应该直接调用slide
          searchWord(reg)
        }
      })
    }

    init()

  </script>
</body>

</html>

总结

如果读者有更好的方案,欢迎在评论区留言。这是一次比较简单的尝试。
除此之外你还可以使用monaco编辑器来显示日志,搜索,以及着色。
对于使用虚拟滚动来实现日志展示的,不置与否。
只有最合适的技术,没有最优秀的技术。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/65170.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Win10常见知识点及部分命令

Win10常见知识点及部分命令 1 常见知识点&#xff08;通用&#xff09; 1.1 用户、用户组 1.2 DNS服务器 Domain Name Server&#xff0c;域名解析服务器 1.3 DHCP服务器 Dynamic Host Configuration Protocol&#xff0c;动态主机配置协议 1.4 Web服务器 Web服务器&#xf…

DJ13-1 汇编语言程序设计-2

目录 一、段定义伪指令 1. 段名 2. 定位类型 3. 组合类型 4. 类别名 二、设定段寄存器伪指令 1. 设定段寄存器伪指令 2. 段寄存器的初始化方法 三、过程定义伪指令 一、段定义伪指令 伪指令 SEGMENT 和 ENDS 用于定义一个逻辑段。 使用时必须配对&#xff0c;分别表…

木聚糖-聚乙二醇-聚乙烯亚胺|PEI-PEG-Xylan|聚乙烯亚胺-PEG-木聚糖

木聚糖-聚乙二醇-聚乙烯亚胺|PEI-PEG-Xylan|聚乙烯亚胺-PEG-木聚糖 中文名称&#xff1a;木聚糖-聚乙烯亚胺 英文名称&#xff1a;Xylan-PEI 别称&#xff1a;聚乙烯亚胺修饰木聚糖&#xff0c;PEI -木聚糖 提供PEG接枝修饰木聚糖&#xff0c;木聚糖-聚乙二醇-聚乙烯亚胺&a…

CenterFusion: Center-based Radar and Camera Fusion for 3D Object Detection 解读

paper: CenterFusion: Center-based Radar and Camera Fusion for 3D Object Detection code: https://github.com/mrnabati/CenterFusion 0 引言 自动驾驶的感知应用中&#xff0c; 通常会融合多模态传感器&#xff0c; 如lidar和camera的融合。 单纯基于radar做感知的研究工…

[附源码]Python计算机毕业设计Django网上书城网站

项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等等。 环境需要 1.运行环境&#xff1a;最好是python3.7.7&#xff0c;…

在 python 中使用 Haar-Cascade 进行人脸检测

介绍在本文中&#xff0c;我们将讨论在 OpenCV python 中使用 Haar Cascade&#xff08;级联&#xff09;实现人脸检测器。识别图像中的给定对象称为对象检测。可以使用多种技术来完成此任务&#xff0c;但在本文中&#xff0c;我们将使用带有预训练 XML 文件的 haar 级联。这是…

毕业设计 单片机多功能红外空调遥控器 - 嵌入式 物联网

文章目录0 前言1 简介2 主要器件3 实现效果4 硬件设计空调遥控器原理原理图解码IR信号5 软件说明代码与Homekit进行连接5 最后0 前言 &#x1f525; 这两年开始毕业设计和毕业答辩的要求和难度不断提升&#xff0c;传统的毕设题目缺少创新和亮点&#xff0c;往往达不到毕业答辩…

3D nunuStudio脚本开发入门

在 3D应用集成开发环境 nunuStudio 中&#xff0c;脚本是使用 javascript 语言编写的&#xff0c;javascript 是用于开发网页的语言&#xff0c;它是一种易于学习的语言&#xff0c;本教程不需要任何编程知识。 但我建议你在继续学习下一个教程之前学习 javascript 编程的基础知…

JSP | oa项目增加用户登录的功能

目录 一&#xff1a;实现用户登录的功能 &#xff08;1&#xff09;当前oa应用还存在的问题&#xff1f; &#xff08;2&#xff09;实现登录功能&#xff1f; &#xff08;3&#xff09;最终达到的结果&#xff1f; &#xff08;4&#xff09;目前存在的问题&#xff1f;…

ASEMI-GBU808整流桥如何测好坏

编辑-Z 整流桥是将交流转化为直流的集成电路设备&#xff0c;主要用于开关电源或逆变电源的整流电路。接下来&#xff0c;让我们了解GBU808整流桥&#xff0c;以及GBU808整流桥如何测好坏的方法。 整流桥GBU808的结构 整流桥GBU808有四只脚分别是AC输入两只脚&#xff0c;用符…

​win10下安装 RabbitMQ​

下载安装包&#xff1a;RabbitMQ-Windows版.7z-Java文档类资源-CSDN下载 下载RabbitMQ一定要保持 Erlang 和 RabbitMQ 的版本匹配 1、安装 Erlang 安装 RabbitMQ 之前需要先安装 Erlang 环境 Erlang 下载地址 https://www.erlang.org/downloads 2、安装 RabbitMQ RabbitMQ 下…

【网络层】RIP协议详解(应用层)、慢收敛、OSPF协议(适合大网络)

注&#xff1a;最后有面试挑战&#xff0c;看看自己掌握了吗 文章目录路由选择分类RIP--距离向量路由选择------简单-------每个路由器维护一个到其他的最佳距离向量记录---------跳数最少-----RIP距离最高16&#xff08;不可达&#xff09;最多15个网络-------只适合小的互联网…

Springboot集成activiti7

在pom文件中添加SpringBoot集成Activiti7的依赖 <!--添加activiti和SpringBoot整合的依赖内置的MyBatis版本与外面的会有冲突&#xff0c;所以需要排除--> <dependency><groupId>org.activiti</groupId><artifactId>activiti-spring-boot-start…

毕业设计-深度学习身份证号码检测识别-python-opencv

目录 前言 课题背景和意义 实现技术思路 实现效果图样例 前言 &#x1f4c5;大四是整个大学期间最忙碌的时光,一边要忙着备考或实习为毕业后面临的就业升学做准备,一边要为毕业设计耗费大量精力。近几年各个学校要求的毕设项目越来越难,有不少课题是研究生级别难度的,对本科…

Spring Security HTTP认证

本文内容来自王松老师的《深入浅出Spring Security》&#xff0c;自己在学习的时候为了加深理解顺手抄录的&#xff0c;有时候还会写一些自己的想法。 HTTP提供了用户权限控制和认证的通用方式&#xff0c;这种认证方式通过HTTP请求头来提供认证信息&#xff0c;而不是通过表单…

[附源码]计算机毕业设计基于Springboot校园运动会管理系统

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

opencv c++ 霍夫圆检测

1、原理 a&#xff09;对某点&#xff0c;以其为圆心的圆为无数&#xff08;一圈圈的圆&#xff09;&#xff0c;将其从x-y平面坐标系上转换到r-θ极坐标系上后&#xff0c;则变成了以r、θ为自变量&#xff0c;为固定值&#xff0c;x、y为因变量的式子&#xff1a; b&#xff…

一文带你走进JS语法(最全笔记)

目录 基本语法 1.引入方式 2.注释 3.输入输出语句 4.变量和常量 5.原始数据类型 6.运算符 7.流程控制语句 8.数组 9.函数 DOM 1.概述 2.元素对象的操作 3.元素内属性操作 4.元素内文本操作 事件 面向对象 1.定义类的方式 2.继承 内置对象 1.Number对象 2…

matlab贝叶斯隐马尔可夫hmm模型实现

贝叶斯隐马尔可夫模型是一种用于分割连续多变量数据的概率模型。该模型将数据解释为一系列隐藏状态生成。每个状态都是重尾分布的有限混合&#xff0c;具有特定于状态的混合比例和共享的位置/分散参数。 相关视频&#xff1a;马尔可夫链原理可视化解释与R语言区制转换Markov r…

java面试总结

文章目录JVM类的加载过程类加载器有哪些什么是双亲委派双亲委派的好处如何打破双亲委派java内存模型栈帧的结构java堆的分代设计对象内存分配对应的GC为什么需要Survivor区?只有Eden不行吗&#xff1f;为什么要有两个Survivor区对象创建过程对象内存布局对象头Mark Word对象大…