【问题标题】:JS replace all matching id valuesJS替换所有匹配的id值
【发布时间】:2021-06-17 10:02:48
【问题描述】:

一个网站有多个页面,其中包含从另一个页面导入的 HTML 以及需要简化的 id 标签。

目前看起来像这样。

<h2> 
    <a id="user-content-test1" href="https://www.example.com">
        Anything
    </a>
</h2>
<h2> 
    <a id="user-content-best2" href="https://www.example.com">
        Anything
    </a>
</h2>
<h2> 
    <a id="user-content-nest3" href="https://www.example.com">
        Anything
    </a>
</h2>
<h2> 
    <a id="user-content-rest4" href="https://www.example.com">
        Anything
    </a>
</h2>

有指向所有这些 id 的锚链接,但这些链接不包括“user-content-”部分。他们看起来像这个链接锚。它们看起来不像这个链接到锚点。这些 id 太多了,无法手动更改。

如何使用 jQuery 或纯 JS 将所​​有 id 标签的值从 id="user-content-test1 更改为 id="test1?期望的结果应该是:

<h2> 
    <a id="test1" href="https://www.example.com">
        Anything
    </a>
</h2>
<h2> 
    <a id="best2" href="https://www.example.com">
        Anything
    </a>
</h2>
<h2> 
    <a id="nest3" href="https://www.example.com">
        Anything
    </a>
</h2>
<h2> 
    <a id="rest4" href="https://www.example.com">
        Anything
    </a>
</h2>

我已经在 stackoverflow 和 google 上进行了搜索,但我只找到了如何替换字符串,而不是 ID。这两个脚本我都试过了,都没有结果。

<script>
$(document).ready(function(){
let result = 'user-content-'.replaceAll(/\+/g, ' ');
});
</script>
<script>
$(document).ready(function(){
var find = 'user-content-';
var re = new RegExp(find, 'g');

str = str.replace(re, '');});
</script>

【问题讨论】:

  • 如何更改所有 id 标签的值” - 为什么需要,您要解决什么问题?
  • 有指向所有这些 id 的锚链接,但这些链接不包括“user-content-”部分。它们看起来像这样 example.com/home#test1">Link 锚点。它们看起来不像 example.com/home#user-content-test1">Link 锚点。这些 id 太多了,无法手动更改。

标签: javascript jquery getelementbyid replaceall getelementsbyname


【解决方案1】:

您可以非常快速地使用jQuery 匹配&lt;h2&gt; 标签中的所有&lt;a&gt; 标签,然后替换它们的所有id。您的问题可以分解为更小的步骤:

  • 找到一种方法来匹配您想要的元素
  • 想办法获取这些元素的 ID 属性
  • 操作该 ID 属性内的字符串

前两个可以使用 jQuery 或 Pure JS 完成,第三个可以通过简单的字符串操作完成,例如 String.slice(),因为“user-content-”无论如何都是固定长度的。

【讨论】:

  • 感谢您的回答。我只能找到如何替换像这样的特定 ID document.getElementById('user-content-test1').setAttribute('id', 'test1'); 我正在寻找一种方法来查找包含 user-content- 的所有 ID,然后从 ID 值中删除该部分。
【解决方案2】:

使用选择器$("h2 a[id^=user-content]") -> 表示选择所有以user-content开始的id

$(document).ready(function() {
  $("h2 a[id^=user-content]").each((i, e) => {

    let id = $(e).attr("id");
    $(e).attr("id", id.replace("user-content-", ""));
  });
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<h2>
  <a id="user-content-test1" href="https://www.example.com">
        Anything
    </a>
</h2>
<h2>
  <a id="user-content-best2" href="https://www.example.com">
        Anything
    </a>
</h2>
<h2>
  <a id="user-content-nest3" href="https://www.example.com">
        Anything
    </a>
</h2>
<h2>
  <a id="user-content-rest4" href="https://www.example.com">
        Anything
    </a>
</h2>

【讨论】:

    【解决方案3】:

    由于问题是您在文档中的其他位置有链接到这些特定元素的锚点,因此我可以想到三种方法来解决问题:

    1. 更改这些元素的id,使它们与链接到它们的&lt;a&gt; 元素的片段标识符相匹配(正如您明确提出的问题),或者
    2. 更改链接到它们的元素的href;这意味着任何针对这些元素的样式都不需要调整它们的选择器。

    在这些潜在的解决方案中,都有一个相对简单的 JavaScript 和 jQuery 解决方案。

    所有方法都将使用以下 HTML 和 CSS:

    :root {
      --color: #000f;
      --backgroundColor: #fff;
    }
    
    *,
    ::before,
    ::after {
      box-sizing: border-box;
      margin: 0;
      padding: 0;
      font-family: sans-serif;
      line-height: 1.5;
    }
    
    nav ul {
      display: flex;
      justify-content: space-around;
      list-style-type: none;
    }
    
    nav a:is(:link, :visited) {
      color: var(--color);
      background-color: var(--backgroundColor);
    }
    
    nav a:is(:hover, :active, :focus) {
      color: var(--backgroundColor);
      background-color: var(--color);
    }
    
    h2 {
      margin-block: 3em;
    }
    
    h2 a:is(:link, :visited) {
      background: linear-gradient(90deg, lime, #ffff);
      display: block;
      color: var(--color);
      text-decoration: none;
    }
    
    h2 a:is(:hover, :active, :focus) {
      text-decoration: underline;
      text-decoration-thickness: 3px;
    }
    
    h2 a:target {
      background: linear-gradient(90deg, #f90, #ffff);
    }
    
    h2 a::after {
      content: ' (#' attr(id) ').';
    }
    <nav id="toc">
      <ul>
        <li><a href="#test1">Link to "test1"</a></li>
        <li><a href="#best2">Link to "best2"</a></li>
        <li><a href="#nest3">Link to "nest3"</a></li>
        <li><a href="#rest4">Link to "rest4"</a></li>
      </ul>
    </nav>
    <h2>
      <a id="user-content-test1" href="https://www.example.com">
        Anything
      </a>
    </h2>
    <h2>
      <a id="user-content-best2" href="https://www.example.com">
        Anything
      </a>
    </h2>
    <h2>
      <a id="user-content-nest3" href="https://www.example.com">
        Anything
      </a>
    </h2>
    <h2>
      <a id="user-content-rest4" href="https://www.example.com">
        Anything
      </a>
    </h2>

    所以,直接回答您的问题:如何更改user-content-* 元素的id 以删除user-content- 部分:

    首先,使用纯 JavaScript:

    // utility function written by: Michał Perłakowski
    // (https://stackoverflow.com/users/3853934/)
    // taken from:
    // https://stackoverflow.com/a/39977764/82548
    // used because the behaviour of Object.assign() doesn't
    // work well in merging objects with unspecifed values/keys:
    const assign = (target, ...sources) =>
      Object.assign(target, ...sources.map(x =>
        Object.entries(x)
        .filter(([key, value]) => value !== undefined)
        .reduce((obj, [key, value]) => (obj[key] = value, obj), {})
      ));
    
    // defining a named function, which accepts an Object of user-
    // defined options in order to change the default behaviour of
    // the function; if no Object is passed in the function
    // sets the opts variable to an empty Object:
    function removeTextFromAttribute(opts = {}) {
    
      // these are the default settings for the function:
      let defaults = {
          // String, accepts a CSS selector to select the
          // relevant elements:
          elements: 'a',
          // String, accepts the attribute-name from which
          // you wish to remove characters:
          attribute: 'id',
          // String, the string you wish to remove from
          // those attributes:
          remove: 'user-content-',
          // Boolean, does the attribute start with the String
          // you wish to remove:
          startsWith: false,
          // Boolean, does the attribute end with the String
          // you wish to remove:
          endsWith: false,
        },
    
        // here we use the utility function (cited above) in
        // order to compensate for the behaviour of the
        // native Object.assign() functionality (see the
        // question related to the linked answer). It
        // seems that objects later in the argument-list of
        // the function overwrite declared keys of previous
        // Objects, and we want the user to overwrite the
        // defaults; so remember to put the user-defined
        // opts Object last in order that it overwrites
        // the defaults:
        settings = assign({}, defaults, opts);
    
      // using Object destructuring assignment to assign the
      // resulting options to named variables (mainly to avoid
      // having to type settings.elements, settings.attribute...):
      const {
        elements,
        attribute,
        remove,
        startsWith,
        endsWith
      } = settings;
    
      // declaring a variable, without initialising it:
      let selector;
    
      // if the user sets both the startsWith and EndsWith value
      // to true, then the attribute-value to be changed may either
      // be equal to the provided String or it may both begin and
      // start with the provided string; to simplify selection in
      // these cases we set the selector variable to '*=' which
      // selects an element with the attribute, and an attribute-
      // value appears within the String at least once. Otherwise
      // if the startsWith and endsWith are both false this implies
      // that the remove String appears within the attribute-value
      // somewhere, so we also use the '*=' selector:
      if ((startsWith && endsWith) || (!startsWith && !endsWith)) {
        selector = '*=';
    
        // if startsWith is true and endsWith is not, we use the
        // attribute-value-starts with selector:
      } else if (startsWith && !endsWith) {
        selector = '^=';
        // finally if startsWith is falsey, and endsWith is true:
        // we use the attribute-value-ends-with selector:
      } else if (!startsWith && endsWith) {
        selector = '$=';
      }
    
      // here we use document.querySelectorAll to select all
      // elements that match the created-selector, which takes
      // the form of: 'Element[attribute<selector>"StringToRemove"]',
      // for example: 'a[id^="user-content-"]'
      const haystack = document.querySelectorAll(
        // we use a template literal string to interpolate the
        // various variables into the resulting String, this is
        // in order to avoid having to concatenate Strings and
        // variables:
        `${elements}[${attribute}${selector}"${remove}"]`
      );
    
      // we use NodeList.prototype.forEach() to iterate over the 
      // list of Nodes returned:
      haystack.forEach(
        // we use an Arrow function, since we have no need to use
        // 'this'; 'el' is a reference to the current Node of the
        // NodeList over which we're iterating:
        (el) => {
          // we use Element.getAttribute to retrieve the attribute
          // to be modified:
          let attr = el.getAttribute(attribute);
    
          -
        });
    }
    
    // calling the named function, in this case with all the default
    // settings and passing no arguments as the defaults are set to
    // your specified functionality:
    removeTextFromAttribute();
    :root {
      --color: #000f;
      --backgroundColor: #fff;
    }
    
    *,
    ::before,
    ::after {
      box-sizing: border-box;
      margin: 0;
      padding: 0;
      font-family: sans-serif;
      line-height: 1.5;
    }
    
    nav ul {
      display: flex;
      justify-content: space-around;
      list-style-type: none;
    }
    
    nav a:is(:link, :visited) {
      color: var(--color);
      background-color: var(--backgroundColor);
    }
    
    nav a:is(:hover, :active, :focus) {
      color: var(--backgroundColor);
      background-color: var(--color);
    }
    
    h2 {
      margin-block: 3em;
    }
    
    h2 a:is(:link, :visited) {
      background: linear-gradient(90deg, lime, #ffff);
      display: block;
      color: var(--color);
      text-decoration: none;
    }
    
    h2 a:is(:hover, :active, :focus) {
      text-decoration: underline;
      text-decoration-thickness: 3px;
    }
    
    h2 a:target {
      background: linear-gradient(90deg, #f90, #ffff);
    }
    
    h2 a::after {
      content: ' (#' attr(id) ').';
    }
    <nav id="toc">
      <ul>
        <li><a href="#test1">Link to "test1"</a></li>
        <li><a href="#best2">Link to "best2"</a></li>
        <li><a href="#nest3">Link to "nest3"</a></li>
        <li><a href="#rest4">Link to "rest4"</a></li>
      </ul>
    </nav>
    <h2>
      <a id="user-content-test1" href="https://www.example.com">
        Anything
      </a>
    </h2>
    <h2>
      <a id="user-content-best2" href="https://www.example.com">
        Anything
      </a>
    </h2>
    <h2>
      <a id="user-content-nest3" href="https://www.example.com">
        Anything
      </a>
    </h2>
    <h2>
      <a id="user-content-rest4" href="https://www.example.com">
        Anything
      </a>
    </h2>

    使用 jQuery:

    // here we're creating a jQuery plugin using the IIFE - Immediately-
    // Invoked Function Expression - approach:
    (function($) {
    
      // defining the name of the plugin, and passing in the opts argument:
      $.fn.removeTextFromAttribute = function(opts) {
        // defining the defaults (as above), although we're not
        // defining the element-types upon which we wish to work
        // as jQuery passes that collection to the plugin:
        let defaults = {
            attribute: 'id',
            remove: 'user-content-',
            startsWith: false,
            endsWith: false,
          },
          // a far easier means of combining the user-defined
          // properties with the default properties (bear in
          // mind this is simple because the library has taken
          // care of it elsewhere, so it's more concise for
          // yourself but obviously including the whole library
          // has its own cost/benefit analysis to be undertaken):
          settings = $.extend(defaults, opts);
    
        // again using destructuring assignment:
        const {
          attribute,
          remove,
          startsWith,
          endsWith
        } = settings;
    
        // declaring, but not initialising, the 'selector' variable:
        let selector;
    
        if ((startsWith && endsWith) || (!startsWith && !endsWith)) {
          selector = '*=';
        } else if (startsWith && !endsWith) {
          selector = '^=';
        } else if (!startsWith && endsWith) {
          selector = '$=';
        }
    
        // using a template String to create the attribute-selector:
        selectorString = `[${attribute}${selector}"${remove}"]`
    
        // here we return the results of these chained method calls,
        // first we use the filter() method:
        return this.filter(function(index, elem) {
    
          // we use a native JavaScript Element.matches method
          // to establish whether the current Node of the jQuery
          // collection matches the selector string we've
          // created above; if yes (Boolean true) that node is
          // retained in the collection, if not (Boolean false)
          // the current Node is discarded from the collection:
          return this.matches(selectorString);
          
          // next we use the attr() method as a setter, in order
          // to modify the named attribute, and use the 
          // anonymous callback function to modify each attribute
          // in turn:
        }).attr(attribute, function(i, attr) {
    
          // this is exactly the same as the above - Plain
          // JavaScript - version:
          if (attr === remove) {
            this.removeAttribute(attribute);
          } else if (attr.includes(remove)) {
            this.setAttribute(
              attribute,
              attr.replace(new RegExp(remove, 'g'), ''));
          }
        });
      }
    
      // passing jQuery into the function:
    }(jQuery));
    
    // note that here we selected all <a> elements, this forms
    // the collection passed to the jQuery plugin and is why
    // we didn't need to specify the attribute-type within the
    // plugin:
    $('a').removeTextFromAttribute();
    :root {
      --color: #000f;
      --backgroundColor: #fff;
    }
    
    *,
    ::before,
    ::after {
      box-sizing: border-box;
      margin: 0;
      padding: 0;
      font-family: sans-serif;
      line-height: 1.5;
    }
    
    nav ul {
      display: flex;
      justify-content: space-around;
      list-style-type: none;
    }
    
    nav a:is(:link, :visited) {
      color: var(--color);
      background-color: var(--backgroundColor);
    }
    
    nav a:is(:hover, :active, :focus) {
      color: var(--backgroundColor);
      background-color: var(--color);
    }
    
    h2 {
      margin-block: 3em;
    }
    
    h2 a:is(:link, :visited) {
      background: linear-gradient(90deg, lime, #ffff);
      display: block;
      color: var(--color);
      text-decoration: none;
    }
    
    h2 a:is(:hover, :active, :focus) {
      text-decoration: underline;
      text-decoration-thickness: 3px;
    }
    
    h2 a:target {
      background: linear-gradient(90deg, #f90, #ffff);
    }
    
    h2 a::after {
      content: ' (#' attr(id) ').';
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
    <nav id="toc">
      <ul>
        <li><a href="#test1">Link to "test1"</a></li>
        <li><a href="#best2">Link to "best2"</a></li>
        <li><a href="#nest3">Link to "nest3"</a></li>
        <li><a href="#rest4">Link to "rest4"</a></li>
      </ul>
    </nav>
    <h2>
      <a id="user-content-test1" href="https://www.example.com">
        Anything
      </a>
    </h2>
    <h2>
      <a id="user-content-best2" href="https://www.example.com">
        Anything
      </a>
    </h2>
    <h2>
      <a id="user-content-nest3" href="https://www.example.com">
        Anything
      </a>
    </h2>
    <h2>
      <a id="user-content-rest4" href="https://www.example.com">
        Anything
      </a>
    </h2>

    第二种方法 - 更新链接到 这些 &lt;a&gt; 元素的 &lt;a&gt; 元素的 href 属性与上面使用的方法非常相似,但显然我们正在插入/更新属性值而不是从中删除。所以这将采用一个新功能,如下所示:

    首先,使用纯 JavaScript:

    // utility function written by: Michał Perłakowski
    // (https://stackoverflow.com/users/3853934/)
    // taken from:
    // https://stackoverflow.com/a/39977764/82548
    // used because the behaviour of Object.assign() doesn't
    // work well in merging objects with unspecifed values/keys:
    const assign = (target, ...sources) =>
      Object.assign(target, ...sources.map(x =>
        Object.entries(x)
        .filter(([key, value]) => value !== undefined)
        .reduce((obj, [key, value]) => (obj[key] = value, obj), {})
      ));
    
    // new named function, set up in the same way as above,
    // albeit with new arguments:
    function insertTextIntoAttribute(opts = {}) {
      let defaults = {
          attribute: 'id',
          elements: 'a',
          // Boolean, do you wish to insert the new String
          // at the end of the current value?
          endWith: false,
          // String, the string you wish to insert:
          insert: 'user-content-',
          // Boolean, do you wish to insert the new String
          // at the start of the current value?
          startWith: true,
        },
        settings = assign({}, defaults, opts);
    
      const {
        elements,
        attribute,
        insert,
        startWith,
        endWith
      } = settings,
      // using a template literal to create a simple selector
      // to find the elements that match your requirements:
      selectorString = `${elements}`;
    
      // using document.querySelectorAll() to retrieve a 
      // NodeList of elements that match the selector
      // passed to the function:
      const haystack = document.querySelectorAll(
        selectorString
      );
    
      // NodeList.prototype.forEach() to iterate over the
      // returned NodeList:
      haystack.forEach(
        (el) => {
          // we retrieve the current attribute-value of the
          // relevant element:
          let currentValue = el.getAttribute(attribute),
            // because a hash requires some special consideration
            // (the '#' character has to be at the beginning) we
            // initialise this variable to false:
            isHash = false;
    
          // we use Element.matches to see if the current element
          // of the NodeList is an <a> element (we could have instead
          // used el.tagName === 'A') but Element.matches is
          // more concise, easier to read and doesn't require a
          // comparison), it is we then check if the current attribute-
          // value matches the <a> element's hash:
          if (el.matches('a') && currentValue === el.hash) {
            // if it does we then update the isHash variable to true:
            isHash = true;
          }
    
          // here we use Element.setAttribute() to update the named
          // attribute (first argument) to a new value:
          el.setAttribute(attribute,
    
            // this is perhaps a little confusing to read, as we're
            // taking advantage of Template strings' ability to
            // interpolate a variable into the String, and we're
            // using conditional operators to do so. In order:
            // 1. ${isHash ? '#' : ''}
            // we test isHash; if true/truthy
            // the expression returns the '#' character, if false/falsey
            // the expression returns the empty String ''.
            // 2. ${startWith ? insert : ''}
            // we test startWith; if true/truthy the expression returns
            // the 'insert' variable's value, otherwise if startWith is
            // false/falsey the expression returns the empty-string.
            // 3. ${isHash ? currentValue.replace('#','')
            // here we again test the isHash variable, and if true/truthy
            // the expression returns the result of calling
            // String.prototype.replace() on the current attribute-value
            // of the element; if isHash is false/falsey then it simply
            // returns the current attribute-value.
            // 4. ${endWith ? insert : ''}
            // this is exactly the same as the earlier assessment for
            // the startWith variable, if true/truthy we return the
            // content of the insert variable, otherwise if false/falsey
            // we return an empty String:
            `${isHash ? '#' : ''}${startWith ? insert : ''}${isHash ? currentValue.replace('#','') : currentValue}${endWith ? insert : ''}`
          );
        });
    }
    
    // here we call the function, specifying our
    // options:
    insertTextIntoAttribute({
      // we wish to modify the 'href' attribute:
      attribute: 'href',
      // and we're selecing the <a> elements inside of <li> elements
      // inside of the <nav> element:
      elements: 'nav li a',
    });
    :root {
      --color: #000f;
      --backgroundColor: #fff;
    }
    
    *,
    ::before,
    ::after {
      box-sizing: border-box;
      margin: 0;
      padding: 0;
      font-family: sans-serif;
      line-height: 1.5;
    }
    
    nav ul {
      display: flex;
      justify-content: space-around;
      list-style-type: none;
    }
    
    nav a:is(:link, :visited) {
      color: var(--color);
      background-color: var(--backgroundColor);
    }
    
    nav a:is(:hover, :active, :focus) {
      color: var(--backgroundColor);
      background-color: var(--color);
    }
    
    h2 {
      margin-block: 3em;
    }
    
    h2 a:is(:link, :visited) {
      background: linear-gradient(90deg, lime, #ffff);
      display: block;
      color: var(--color);
      text-decoration: none;
    }
    
    h2 a:is(:hover, :active, :focus) {
      text-decoration: underline;
      text-decoration-thickness: 3px;
    }
    
    h2 a:target {
      background: linear-gradient(90deg, #f90, #ffff);
    }
    
    h2 a::after {
      content: ' (#' attr(id) ').';
    }
    <nav id="toc">
      <ul>
        <li><a href="#test1">Link to "test1"</a></li>
        <li><a href="#best2">Link to "best2"</a></li>
        <li><a href="#nest3">Link to "nest3"</a></li>
        <li><a href="#rest4">Link to "rest4"</a></li>
      </ul>
    </nav>
    <h2>
      <a id="user-content-test1" href="https://www.example.com">
        Anything
      </a>
    </h2>
    <h2>
      <a id="user-content-best2" href="https://www.example.com">
        Anything
      </a>
    </h2>
    <h2>
      <a id="user-content-nest3" href="https://www.example.com">
        Anything
      </a>
    </h2>
    <h2>
      <a id="user-content-rest4" href="https://www.example.com">
        Anything
      </a>
    </h2>

    使用 jQuery:

    // here we're creating a jQuery plugin using the IIFE - Immediately-
    // Invoked Function Expression - approach:
    (function($) {
    
      // defining the name of the plugin, and passing in the opts argument:
      $.fn.insertTextToAttribute = function(opts) {
        // defining the defaults (as above), although again we're not
        // defining the element-types upon which we wish to work
        // as jQuery passes that collection to the plugin:
        let defaults = {
            attribute: 'id',
            endWith: false,
            insert: 'user-content-',
            startWith: false,
          },
    
          settings = $.extend(defaults, opts);
    
        // again using destructuring assignment:
        const {
          attribute,
          insert,
          startWith,
          endWith
        } = settings;
    
        // we're not filtering the collection here, since jQuery has
        // already taken care of finding the relevant <a> elements and
        // we don't need to select according to current attribute-values
        // since we're modifying them we may not know what they currently
        // are:
        return this.attr(attribute, function(i, attr) {
    
          // setting isHash to false:
          let isHash = false;
    
          // as above, we're using this - as jQuery makes that available
          // within its methods - and again using Element.matches, along
          // with checking that the current attribute-value - passed to
          // function automatically from jQuery - is equal to the current
          // hash of the element:
          if (this.matches('a') && attr === this.hash) {
            // if both those checks return true, we update the value to
            // true
            isHash = true;
          }
          
          // note that we could have written the above in the following way:
          // let isHash = this.matches('a') && attr === this.hash;
          // but using an if feels more readable (despite my subsequent
          // code)
    
    
          // this is almost the same as the above approach, using conditional
          // operators within template strings to interpolate various variables
          // into the string. The difference is that the 'currentValue'
          // variable was changed to the 'attr' variable-name (for no particular
          // reason):
          return `${isHash ? '#' : ''}${startWith ? insert : ''}${isHash ? attr.replace('#','') : attr}${endWith ? insert : ''}`
    
        });
      }
    
    // passing jQuery into the function:
    }(jQuery));
    
    // selecting all <a> elements on the page that are within <li> elements
    // and wrapped within a <nav> element:
    $('nav li a').insertTextToAttribute({
      attribute: 'href',
      insert: 'user-content-',
      startWith: true
    });
    :root {
      --color: #000f;
      --backgroundColor: #fff;
    }
    
    *,
    ::before,
    ::after {
      box-sizing: border-box;
      margin: 0;
      padding: 0;
      font-family: sans-serif;
      line-height: 1.5;
    }
    
    nav ul {
      display: flex;
      justify-content: space-around;
      list-style-type: none;
    }
    
    nav a:is(:link, :visited) {
      color: var(--color);
      background-color: var(--backgroundColor);
    }
    
    nav a:is(:hover, :active, :focus) {
      color: var(--backgroundColor);
      background-color: var(--color);
    }
    
    h2 {
      margin-block: 3em;
    }
    
    h2 a:is(:link, :visited) {
      background: linear-gradient(90deg, lime, #ffff);
      display: block;
      color: var(--color);
      text-decoration: none;
    }
    
    h2 a:is(:hover, :active, :focus) {
      text-decoration: underline;
      text-decoration-thickness: 3px;
    }
    
    h2 a:target {
      background: linear-gradient(90deg, #f90, #ffff);
    }
    
    h2 a::after {
      content: ' (#' attr(id) ').';
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
    <nav id="toc">
      <ul>
        <li><a href="#test1">Link to "test1"</a></li>
        <li><a href="#best2">Link to "best2"</a></li>
        <li><a href="#nest3">Link to "nest3"</a></li>
        <li><a href="#rest4">Link to "rest4"</a></li>
      </ul>
    </nav>
    <h2>
      <a id="user-content-test1" href="https://www.example.com">
        Anything
      </a>
    </h2>
    <h2>
      <a id="user-content-best2" href="https://www.example.com">
        Anything
      </a>
    </h2>
    <h2>
      <a id="user-content-nest3" href="https://www.example.com">
        Anything
      </a>
    </h2>
    <h2>
      <a id="user-content-rest4" href="https://www.example.com">
        Anything
      </a>
    </h2>

    由于 Stack Overflow 回答的字符数限制,我无法包含拦截浏览器对 &lt;a&gt; 元素的点击事件的方法,尽管我想它已经在其他地方写过。无论如何,希望您至少能够从答案中学到一些有用的东西。

    【讨论】:

      猜你喜欢
      • 2016-06-17
      • 1970-01-01
      • 1970-01-01
      • 2018-06-13
      • 1970-01-01
      • 2016-11-04
      • 1970-01-01
      • 2012-05-18
      • 1970-01-01
      相关资源
      最近更新 更多