搜索突出显示(CSS 高亮 API)

问题描述 投票:0回答:1

我尝试实现搜索突出显示功能。但问题是只有选择测试 1 时才有效。在其他页面上它不起作用,我不知道为什么。我想这是因为突出显示函数仅被调用一次,当我选择例如测试 2 时,它不会再次被调用。 我尝试了不同的选择,但失败了。由于它是竞赛的一部分,因此重要的是不要更改代码的其他部分,仅更改最终脚本。

    <!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title></title>
  </head>
  <style>
    :root {
      --bg-primary: #fbfbfb;
      --bg-secondary: #fff;
      --control-primary: #fdde55;
      --color-primary: #000;
      --depot-color-stroke: rgba(7, 28, 71, 0.12);
    }

    @media (prefers-color-scheme: dark) {
      :root {
        --bg-primary: #111112;
        --bg-secondary: #18181a;
        --color-primary: #fff;
        --depot-color-stroke: rgba(255, 255, 255, 0.12);
      }
    }

    body {
      background-color: var(--bg-primary);
      font-family: Helvetica, Arial, sans-serif;
    }

    header {
      box-shadow: 0 1px var(--depot-color-stroke);
      margin-block-end: 12px;
      padding-block-end: 8px;
    }

    .select-wrapper {
      color: var(--color-primary);
      margin-block-end: 12px;
    }

    .select-wrapper select {
      min-width: 40px;
      cursor: pointer;
      font-size: 20px;
    }

    .search {
      display: flex;
      overflow: hidden;
      flex: 1 1;
      box-sizing: border-box;
      height: 44px;
      border: 2px solid #fc0;
      border: 2px solid var(--control-primary);
      border-radius: 12px;
    }

    .search input {
      flex: 1 1;
      box-sizing: border-box;
      padding-left: 14px;
      font-family: inherit;
      font-size: 16px;
      text-overflow: clip;
      color: var(--color-primary);
      border: 0;
      outline: 0;
      background: initial;
    }

    .card-item {
      padding: 12px 16px;
      border-radius: 16px;
      color: var(--color-primary);
      background-color: var(--bg-secondary);
      box-shadow: 0 4px 12px #0d234308;
    }
  </style>
  <style>
    ::highlight(search-results) {
      background-color: orange;
      text-decoration: underline;
    }

    .search-results {
      background-color: orange;
      text-decoration: underline;
    }
  </style>

  <body>
    <header>
      <div class="select-wrapper">
        <label for="tests-select">Choose test</label>
        <select name="tests" id="tests-select"></select>
      </div>
      <form class="search" role="search" aria-label="Search">
        <input
          id="site-search"
          type="text"
          autocomplete="off"
          aria-label="Query"
        />
      </form>
    </header>

    <div id="root" class="card-item"></div>
  </body>
  <script>
    const rootElement = document.getElementById("root");
    const testsSelect = document.getElementById("tests-select");

    rootElement.addEventListener("onSolutionReady", (event) => {
      const { detail } = event;

      if (detail) {
        testsSelect.innerHTML = detail
          .map((t, index) => `<option value="${t.id}">${index + 1}</option>`)
          .join("");

        rootElement.innerHTML = detail[0].content;

        testsSelect.addEventListener("change", (e) => {
          const test = detail.find((t) => t.id === e.target.value);
          rootElement.innerHTML = test.content;
        });
      }
    });
  </script>
  <script>
    const onSolutionReady = new CustomEvent("onSolutionReady", {
      bubbles: true,
      cancelable: true,
      composed: false,
      detail: [
        {
          id: "f38d0cca-167c-46dc-9504-69ebe13c1e47",
          comment:
            "One text node. Content contains in the middle of a single tag",
          content: `<p>sit amet, Lorem ipsum. Sed non risus</p>`,
          searchFor: "Lorem ipsum",
        },
        {
          id: "20b81641-b065-492d-801a-e786d2a6894b",
          comment: "One text node. Content contains in the end of a single tag",
          content: `<p>Sed non risus. Suspendisse lectus tortor, dignissim sit amet, adipiscing nec, ultricies sed, dolor. Cras elementum ultrices diam. Maecenas ligula massa, Lorem ipsum</p>`,
          searchFor: "Lorem ipsum",
        },
        {
          id: "c8b707f7-91e9-4778-acc6-4f06849bd323",
          comment: "One text node and content contains in a single tag",
          content: `
              <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed non risus. Suspendisse lectus tortor, dignissim sit amet, adipiscing nec, ultricies sed, dolor. Cras elementum ultrices diam. Maecenas ligula massa, varius a, semper congue, euismod non, mi. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed non risus. Suspendisse lectus tortor, dignissim sit amet, adipiscing nec, ultricies sed, dolor. Cras elementum ultrices diam. Maecenas ligula massa, varius a, semper congue, euismod non, mi. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed non risus. Suspendisse lectus tortor, dignissim sit amet, adipiscing nec, ultricies sed, dolor. Cras elementum ultrices diam. Maecenas ligula massa, varius a, semper congue, euismod non, mi.</p>
              `,
          searchFor: "Lorem ipsum",
        },
        {
          id: "eb375bed-bf98-4150-b8ac-711a6c0fe33a",
          comment:
            "The two text nodes and content are contained in sibling tags",
          content: `
              <div><p>Lorem </p><p>ipsum</p></div>
              `,
          searchFor: "Lorem ipsum",
        },
      ],
    });

    document.getElementById("root").dispatchEvent(onSolutionReady);
  </script>

  <script>
    if (!CSS.highlights) {
      document.getElementById("root").innerHTML =
        "CSS Custom Highlight API is not supported. <br />Please, choose another browser. <a href='https://developer.mozilla.org/en-US/docs/Web/API/CSS_Custom_Highlight_API#browser_compatibility'>More</a>";
    }
  </script>

  <script>
    // Copy paste this script

    const root = document.getElementById("root");
    const siteSearch = document.getElementById("site-search");
    const selectTest = document.getElementById("tests-select");

    const treeWalker = document.createTreeWalker(root, NodeFilter.SHOW_TEXT);

    const allTextNodes = [];

    let currentNode = treeWalker.nextNode();
    while (currentNode) {
      allTextNodes.push(currentNode);
      currentNode = treeWalker.nextNode();
    }

    testsSelect.addEventListener("change", highlight);

    siteSearch.addEventListener("input", highlight);

    function highlight() {
      const str = siteSearch.value.trim().toLowerCase();

      if (!str) {
        CSS.highlights.clear();
        return;
      }

      const ranges = allTextNodes
        .map((el) => {
          return { el, text: el.nodeValue.toLowerCase() };
        })
        .map(({ text, el }) => {
          const indices = [];
          let startPos = 0;
          while (startPos < text.length) {
            const index = text.indexOf(str, startPos);
            if (index === -1) break;
            indices.push(index);
            startPos = index + str.length;
          }

          return indices.map((index) => {
            const range = new Range();
            range.setStart(el, index);
            range.setEnd(el, index + str.length);

            return range;
          });
        });

      const searchResultsHighlight = new Highlight(...ranges.flat());

      // Register the Highlight object in the registry.
      CSS.highlights.set("search-results", searchResultsHighlight);
    }
  </script>
</html>
css text highlight
1个回答
0
投票

确保将此代码块也包含在highlight()函数中:

let currentNode = treeWalker.nextNode();
while (currentNode) {
  allTextNodes.push(currentNode);
  currentNode = treeWalker.nextNode();
}

testsSelect.addEventListener("change", highlight);
siteSearch.addEventListener("input", highlight);

我在 Yandex 暑期学校测试期间面临着同样的任务。尽管我设法解决了这个问题并且对我来说效果很好,但测试人员表示这是不正确的。招聘人员和高年级学生似乎期待不同的算法。

© www.soinside.com 2019 - 2024. All rights reserved.