highlight.js 实现搜索关键词高亮效果 ,显示匹配数量及切换显示功能

先看效果:

更新:增加切换显示

折腾了老半天,记录一下

注意事项都写注释了

代码:

html 复制代码
<template>
  <div class="absolute-lt wh-full overflow-hidden p-10">
   
    <div style="width: 200px">
      <el-input v-model="keyword" @input="search"></el-input>
    </div>
    <code>
      <pre v-html="html"></pre>
    </code>
  </div>
</template>
<script setup>
import { onMounted, computed, reactive, ref } from "vue";
import hljs from "highlight.js";
// 这不引入样式防止干扰高亮显示
// import "highlight.js/styles/arta.css";
const str = `
Server: cloudflare
Date: Tue, 02 Jan 2024 15:40:15 GMT
Content-Type: text/html
Content-Length:  553
Connection: keep
CF-RAY: 83f419748811fa1a-SJC

<html>
<head><title>403 Forbidden</title></head>
<body>
<center><h1>403 Forbidden</h1></center>
<hr><center>cloudflare</center>
</body>
</html>
<!-- a padding to disable MSIE and Chrome friendly error page -->
<!-- a padding to disable MSIE and Chrome friendly error page -->
<!-- a padding to disable MSIE and Chrome friendly error page -->
<!-- a padding to disable MSIE and Chrome friendly error page -->
<!-- a padding to disable MSIE and Chrome friendly error page -->
<!-- a padding to disable MSIE and Chrome friendly error page -->

`;
const html = ref("");
const keyword = ref("");
let saveValue = ref("");

// 注册自定义语言,防止生成多余标签匹配
hljs.registerLanguage("custom", function () {
  return {};
});
html.value = saveValue.value = hljs.highlight(str, { language: "custom" }).value;


function search() {
  if (!keyword.value) return (html.value = saveValue.value);
  let reg = new RegExp(keyword.value, "g", "i");
  html.value = saveValue.value.replace(
    reg,
    "<span class='abc'> " + keyword.value + " </span>"
  );
}
</script>

<style lang="less">
span.abc {
  color: red;
}
</style>

更新后代码:

html 复制代码
<template>
  <div class="absolute-lt wh-full overflow-hidden p-10">
    <!-- <code>
      <pre>{{ str }}</pre>
    </code> -->
    <!-- <pre>
      <code>{{ str }}</code>
    </pre> -->
    <div class="flex">
      <div style="width: 200px">
        <el-input v-model="keyword" @input="search"></el-input>
      </div>
      <div>{{ cur }}/{{ total }}</div>
      <div>
        <el-button @click="pre">上一个</el-button>
        <el-button @click="next">下一个</el-button>
      </div>
    </div>
    <div class="box">
      <code>
        <pre v-html="html"></pre>
      </code>
    </div>
  </div>
</template>
<script setup>
import { onMounted, computed, reactive, ref } from "vue";
import hljs from "highlight.js";
// import "highlight.js/styles/arta.css";
const str = `
Server: cloudflare
Date: Tue, 02 Jan 2024 15:40:15 GMT
Content-Type: text/html
Content-Length:  553
Connection: keep
CF-RAY: 83f419748811fa1a-SJC

<html>
<head><title>403 Forbidden</title></head>
<body>
<center><h1>403 Forbidden</h1></center>
<hr><center>cloudflare</center>
</body>
</html>
<!-- a padding to disable MSIE and Chrome friendly error page -->
<!-- a padding to disable MSIE and Chrome friendly error page -->
<!-- a padding to disable MSIE and Chrome friendly error page -->
<!-- a padding to disable MSIE and Chrome friendly error page -->
<!-- a padding to disable MSIE and Chrome friendly error page -->
<!-- a padding to disable MSIE and Chrome friendly error page -->
Server: cloudflare
Date: Tue, 02 Jan 2024 15:40:15 GMT
Content-Type: text/html
Content-Length:  553
Connection: keep
CF-RAY: 83f419748811fa1a-SJC

<html>
<head><title>403 Forbidden</title></head>
<body>
<center><h1>403 Forbidden</h1></center>
<hr><center>cloudflare</center>
</body>
</html>
<!-- a padding to disable MSIE and Chrome friendly error page -->
<!-- a padding to disable MSIE and Chrome friendly error page -->
<!-- a padding to disable MSIE and Chrome friendly error page -->
<!-- a padding to disable MSIE and Chrome friendly error page -->
<!-- a padding to disable MSIE and Chrome friendly error page -->
<!-- a padding to disable MSIE and Chrome friendly error page -->Server: cloudflare
Date: Tue, 02 Jan 2024 15:40:15 GMT
Content-Type: text/html
Content-Length:  553
Connection: keep
CF-RAY: 83f419748811fa1a-SJC

<html>
<head><title>403 Forbidden</title></head>
<body>
<center><h1>403 Forbidden</h1></center>
<hr><center>cloudflare</center>
</body>
</html>
<!-- a padding to disable MSIE and Chrome friendly error page -->
<!-- a padding to disable MSIE and Chrome friendly error page -->
<!-- a padding to disable MSIE and Chrome friendly error page -->
<!-- a padding to disable MSIE and Chrome friendly error page -->
<!-- a padding to disable MSIE and Chrome friendly error page -->
<!-- a padding to disable MSIE and Chrome friendly error page -->
`;
const html = ref("");
const keyword = ref("");
let saveValue = ref("");
let total = ref(0);
let cur = ref(0);
let nodeList = ref([]);

hljs.registerLanguage("custom", function () {
  return {};
});
html.value = saveValue.value = hljs.highlight(str, { language: "custom" }).value;
// html.value = saveValue.value = hljs.highlightAuto(str).value;
window.hljs = hljs;
function search() {
  if (!keyword.value) return (html.value = saveValue.value);
  let reg = new RegExp(keyword.value, "g", "i");
  html.value = saveValue.value.replace(
    reg,
    "<span class='abc'>" + keyword.value + "</span>"
  );
  count();
}
function pre() {
  if (cur.value <= 0) {
    cur.value = 0;
  } else {
    cur.value--;
  }

  scorll();
}
function scorll() {
  for (let index = 0; index < nodeList.value.length; index++) {
    const element = nodeList.value[index];
    element.style = index == cur.value ? "color:blue" : "color:red";
  }
  let box = document.querySelector(".box");
  let top = nodeList.value[cur.value].offsetTop;
  let offset = nodeList.value[0].offsetTop;
  box.scrollTop = top - offset;
}
function next() {
  if (cur.value >= nodeList.value.length) {
    cur.value = nodeList.value.length;
  } else {
    cur.value++;
  }

  scorll();
}

function count() {
  setTimeout(() => {
    nodeList.value = document.querySelectorAll("span.abc");

    total.value = nodeList.value.length;
    nodeList.value[cur.value].style = "color:blue";
  }, 300);
}
</script>

<style lang="less">
span.abc {
  color: red;
}
.box {
  height: 300px;
  overflow-y: auto;
}
</style>
相关推荐
小月土星27 分钟前
React Router 前端路由深度解析:从传统后端路由到现代 SPA 的完整演进
前端
程序员黑豆35 分钟前
鸿蒙开发 Navigation 路由教程:从入门到实战
前端·harmonyos
weixin_440784111 小时前
【HandlerThread实现原理】
android·java·开发语言
天空'之城1 小时前
C 语言工业级通用组件手写 24:互补滤波
c语言·开发语言·互补滤波·嵌入式算法·工业级组件
XR1234567881 小时前
工厂车间无线网络方案对比:AGV漫游哪家强?
开发语言·php
傻啦嘿哟2 小时前
某短视频平台视频爬虫实战:抓取推荐流视频信息,绕过反爬的3种技巧
开发语言·爬虫·python
烬羽2 小时前
React Router v7 完全指南:一个 Demo 吃透前端路由
javascript·react.js·前端框架
現実君3 小时前
【硬件进阶】AD22上位替换JLEDA教程
开发语言·php
烬羽3 小时前
从"整个页面刷新"到"丝滑切换":手写一个 HashRouter 彻底搞懂前端路由
javascript·前端框架·全栈
mubei-1233 小时前
SpringDAO的用法
java·开发语言·数据库