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

先看效果:
在这里插入图片描述
更新:增加切换显示
在这里插入图片描述

折腾了老半天,记录一下
注意事项都写注释了
代码:

<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>

更新后代码:

<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>



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值