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>
相关推荐
万少16 分钟前
第五款 HarmonyOS 上架作品 奇趣故事匣 来了
前端·harmonyos·客户端
OpenGL21 分钟前
Android targetSdkVersion升级至35(Android15)相关问题
前端
rzl0237 分钟前
java web5(黑马)
java·开发语言·前端
Amy.Wang38 分钟前
前端如何实现电子签名
前端·javascript·html5
海天胜景40 分钟前
vue3 el-table 行筛选 设置为单选
javascript·vue.js·elementui
今天又在摸鱼41 分钟前
Vue3-组件化-Vue核心思想之一
前端·javascript·vue.js
蓝婷儿43 分钟前
每天一个前端小知识 Day 21 - 浏览器兼容性与 Polyfill 策略
前端
百锦再1 小时前
Vue中对象赋值问题:对象引用被保留,仅部分属性被覆盖
前端·javascript·vue.js·vue·web·reactive·ref
jingling5551 小时前
面试版-前端开发核心知识
开发语言·前端·javascript·vue.js·面试·前端框架
拾光拾趣录1 小时前
CSS 深入解析:提升网页样式技巧与常见问题解决方案
前端·css