Javascript 如何使用javascript突出显示文本

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/8644428/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-24 06:53:43  来源:igfitidea点击:

How to highlight text using javascript

javascripthighlighting

提问by Ankit

Can someone help me with a javascript function that can highlight text on a web page. And the requirement is to - highlight only once, not like highlight all occurrences of the text as we do in case of search.

有人可以帮助我使用可以突出显示网页上的文本的 javascript 函数吗?并且要求是 - 仅突出显示一次,而不是像我们在搜索中那样突出显示所有出现的文本。

回答by guy mograbi

You can use the jquery highlight effect.

您可以使用 jquery高亮效果

But if you are interested in raw javascript code, take a look at what I got Simply copy paste into an HTML, open the file and click "highlight" - this should highlight the word "fox". Performance wise I think this would do for small text and a single repetition (like you specified)

但是,如果您对原始 javascript 代码感兴趣,请查看我得到的内容 只需将粘贴复制到 HTML 中,打开文件并单击“突出显示” - 这应该突出显示“狐狸”一词。性能明智我认为这适用于小文本和单个重复(如您指定的那样)

function highlight(text) {
  var inputText = document.getElementById("inputText");
  var innerHTML = inputText.innerHTML;
  var index = innerHTML.indexOf(text);
  if (index >= 0) { 
   innerHTML = innerHTML.substring(0,index) + "<span class='highlight'>" + innerHTML.substring(index,index+text.length) + "</span>" + innerHTML.substring(index + text.length);
   inputText.innerHTML = innerHTML;
  }
}
.highlight {
  background-color: yellow;
}
<button onclick="highlight('fox')">Highlight</button>

<div id="inputText">
  The fox went over the fence
</div>

Edits:

编辑:

Using replace

使用 replace

I see this answer gained some popularity, I thought I might add on it. You can also easily use replace

我看到这个答案很受欢迎,我想我可以补充一下。您还可以轻松使用替换

"the fox jumped over the fence".replace(/fox/,"<span>fox</span>");

"the fox jumped over the fence".replace(/fox/,"<span>fox</span>");

Or for multiple occurrences (not relevant for the question, but was asked in comments) you simply add globalon the replace regular expression.

或者对于多次出现(与问题无关,但在评论中被问到),您只需添加global替换正则表达式。

"the fox jumped over the other fox".replace(/fox/g,"<span>fox</span>");

"the fox jumped over the other fox".replace(/fox/g,"<span>fox</span>");

Hope this helps to the intrigued commenters.

希望这对感兴趣的评论者有所帮助。

Replacing the HTML to the entire web-page

将 HTML 替换为整个网页

to replace the HTML for an entire web-page, you should refer to innerHTMLof the document's body.

要替换整个网页的 HTML,您应该参考innerHTML文档正文的 。

document.body.innerHTML

document.body.innerHTML

回答by Stefan Steiger

The solutions offered here are quite bad.

这里提供的解决方案非常糟糕。

  1. You can't use regex, because that way, you search/highlight in the html tags.
  2. You can't use regex, because it doesn't work properly with UTF* (anything with non-latin/English characters).
  3. You can't just do an innerHTML.replace, because this doesn't work when the characters have a special HTML notation, e.g. &amp;for &, &lt;for <, &gt;for >, &auml;for ä, &ouml;for ö &uuml;for ü &szlig;for ß, etc.
  1. 您不能使用正则表达式,因为那样,您可以在 html 标签中搜索/突出显示。
  2. 您不能使用正则表达式,因为它不能与 UTF*(任何非拉丁文/英文字符)一起正常工作。
  3. 你不能只做一个innerHTML.replace,因为当字符有特殊的HTML符号时这不起作用,例如&amp;&、&lt;<、&gt;>、&auml;ä、&ouml;ö &uuml;、ü &szlig;、ß等。

What you need to do:

你需要做什么:

Loop through the HTML document, find all text nodes, get the textContent, get the position of the highlight-text with indexOf(with an optional toLowerCaseif it should be case-insensitive), append everything before indexofas textNode, append the matched Text with a highlight span, and repeat for the rest of the textnode (the highlight string might occur multiple times in the textContentstring).

循环遍历 HTML 文档,找到所有文本节点,获取textContent,获取突出显示文本的位置indexOftoLowerCase如果不区分大小写,则为可选),将所有内容附加在indexofas之前textNode,将匹配的文本附加到突出显示范围,并对文本节点的其余部分重复(高亮字符串可能在textContent字符串中出现多次)。

Here is the code for this:

这是代码:

var InstantSearch = {

    "highlight": function (container, highlightText)
    {
        var internalHighlighter = function (options)
        {

            var id = {
                container: "container",
                tokens: "tokens",
                all: "all",
                token: "token",
                className: "className",
                sensitiveSearch: "sensitiveSearch"
            },
            tokens = options[id.tokens],
            allClassName = options[id.all][id.className],
            allSensitiveSearch = options[id.all][id.sensitiveSearch];


            function checkAndReplace(node, tokenArr, classNameAll, sensitiveSearchAll)
            {
                var nodeVal = node.nodeValue, parentNode = node.parentNode,
                    i, j, curToken, myToken, myClassName, mySensitiveSearch,
                    finalClassName, finalSensitiveSearch,
                    foundIndex, begin, matched, end,
                    textNode, span, isFirst;

                for (i = 0, j = tokenArr.length; i < j; i++)
                {
                    curToken = tokenArr[i];
                    myToken = curToken[id.token];
                    myClassName = curToken[id.className];
                    mySensitiveSearch = curToken[id.sensitiveSearch];

                    finalClassName = (classNameAll ? myClassName + " " + classNameAll : myClassName);

                    finalSensitiveSearch = (typeof sensitiveSearchAll !== "undefined" ? sensitiveSearchAll : mySensitiveSearch);

                    isFirst = true;
                    while (true)
                    {
                        if (finalSensitiveSearch)
                            foundIndex = nodeVal.indexOf(myToken);
                        else
                            foundIndex = nodeVal.toLowerCase().indexOf(myToken.toLowerCase());

                        if (foundIndex < 0)
                        {
                            if (isFirst)
                                break;

                            if (nodeVal)
                            {
                                textNode = document.createTextNode(nodeVal);
                                parentNode.insertBefore(textNode, node);
                            } // End if (nodeVal)

                            parentNode.removeChild(node);
                            break;
                        } // End if (foundIndex < 0)

                        isFirst = false;


                        begin = nodeVal.substring(0, foundIndex);
                        matched = nodeVal.substr(foundIndex, myToken.length);

                        if (begin)
                        {
                            textNode = document.createTextNode(begin);
                            parentNode.insertBefore(textNode, node);
                        } // End if (begin)

                        span = document.createElement("span");
                        span.className += finalClassName;
                        span.appendChild(document.createTextNode(matched));
                        parentNode.insertBefore(span, node);

                        nodeVal = nodeVal.substring(foundIndex + myToken.length);
                    } // Whend

                } // Next i 
            }; // End Function checkAndReplace 

            function iterator(p)
            {
                if (p === null) return;

                var children = Array.prototype.slice.call(p.childNodes), i, cur;

                if (children.length)
                {
                    for (i = 0; i < children.length; i++)
                    {
                        cur = children[i];
                        if (cur.nodeType === 3)
                        {
                            checkAndReplace(cur, tokens, allClassName, allSensitiveSearch);
                        }
                        else if (cur.nodeType === 1)
                        {
                            iterator(cur);
                        }
                    }
                }
            }; // End Function iterator

            iterator(options[id.container]);
        } // End Function highlighter
        ;


        internalHighlighter(
            {
                container: container
                , all:
                    {
                        className: "highlighter"
                    }
                , tokens: [
                    {
                        token: highlightText
                        , className: "highlight"
                        , sensitiveSearch: false
                    }
                ]
            }
        ); // End Call internalHighlighter 

    } // End Function highlight

};

Then you can use it like this:

然后你可以像这样使用它:

function TestTextHighlighting(highlightText)
{
    var container = document.getElementById("testDocument");
    InstantSearch.highlight(container, highlightText);
}

Here's an example HTML document

这是一个示例 HTML 文档

<!DOCTYPE html>
<html>
    <head>
        <title>Example of Text Highlight</title>
        <style type="text/css" media="screen">
            .highlight{ background: #D3E18A;}
            .light{ background-color: yellow;}
        </style>
    </head>
    <body>
        <div id="testDocument">
            This is a test
            <span> This is another test</span>
            ??ü??ü??ü??ü
            <span>Test123&auml;&ouml;&uuml;&Auml;&Ouml;&Uuml;</span>
        </div>
    </body>
</html>

By the way, if you search in a database with LIKE,
e.g. WHERE textField LIKE CONCAT('%', @query, '%')[which you shouldn't do, you should use fulltext-search or Lucene], then you can escape every character with \ and add an SQL-escape-statement, that whay you'll find special characters that are LIKE-expressions.

顺便说一句,如果你在数据库中搜索LIKE
例如WHERE textField LIKE CONCAT('%', @query, '%')[你不应该这样做,你应该使用全文搜索或 Lucene],那么你可以用 \ 转义每个字符并添加一个 SQL 转义语句,那whay你会发现 LIKE 表达式的特殊字符。

e.g.

例如

WHERE textField LIKE CONCAT('%', @query, '%') ESCAPE '\'

and the value of @query is not '%completed%'but '%\c\o\m\p\l\e\t\e\d%'

而@query 的值不是'%completed%'但是'%\c\o\m\p\l\e\t\e\d%'

(tested, works with SQL-Server and PostgreSQL, and every other RDBMS system that supports ESCAPE)

(经过测试,适用于 SQL-Server 和 PostgreSQL,以及所有其他支持 ESCAPE 的 RDBMS 系统)



A revised typescript-version:

修改后的打字稿版本:

namespace SearchTools 
{


    export interface IToken
    {
        token: string;
        className: string;
        sensitiveSearch: boolean;
    }


    export class InstantSearch 
    {

        protected m_container: Node;
        protected m_defaultClassName: string;
        protected m_defaultCaseSensitivity: boolean;
        protected m_highlightTokens: IToken[];


        constructor(container: Node, tokens: IToken[], defaultClassName?: string, defaultCaseSensitivity?: boolean)
        {
            this.iterator = this.iterator.bind(this);
            this.checkAndReplace = this.checkAndReplace.bind(this);
            this.highlight = this.highlight.bind(this);
            this.highlightNode = this.highlightNode.bind(this);    

            this.m_container = container;
            this.m_defaultClassName = defaultClassName || "highlight";
            this.m_defaultCaseSensitivity = defaultCaseSensitivity || false;
            this.m_highlightTokens = tokens || [{
                token: "test",
                className: this.m_defaultClassName,
                sensitiveSearch: this.m_defaultCaseSensitivity
            }];
        }


        protected checkAndReplace(node: Node)
        {
            let nodeVal: string = node.nodeValue;
            let parentNode: Node = node.parentNode;
            let textNode: Text = null;

            for (let i = 0, j = this.m_highlightTokens.length; i < j; i++)
            {
                let curToken: IToken = this.m_highlightTokens[i];
                let textToHighlight: string = curToken.token;
                let highlightClassName: string = curToken.className || this.m_defaultClassName;
                let caseSensitive: boolean = curToken.sensitiveSearch || this.m_defaultCaseSensitivity;

                let isFirst: boolean = true;
                while (true)
                {
                    let foundIndex: number = caseSensitive ?
                        nodeVal.indexOf(textToHighlight)
                        : nodeVal.toLowerCase().indexOf(textToHighlight.toLowerCase());

                    if (foundIndex < 0)
                    {
                        if (isFirst)
                            break;

                        if (nodeVal)
                        {
                            textNode = document.createTextNode(nodeVal);
                            parentNode.insertBefore(textNode, node);
                        } // End if (nodeVal)

                        parentNode.removeChild(node);
                        break;
                    } // End if (foundIndex < 0)

                    isFirst = false;


                    let begin: string = nodeVal.substring(0, foundIndex);
                    let matched: string = nodeVal.substr(foundIndex, textToHighlight.length);

                    if (begin)
                    {
                        textNode = document.createTextNode(begin);
                        parentNode.insertBefore(textNode, node);
                    } // End if (begin)

                    let span: HTMLSpanElement = document.createElement("span");

                    if (!span.classList.contains(highlightClassName))
                        span.classList.add(highlightClassName);

                    span.appendChild(document.createTextNode(matched));
                    parentNode.insertBefore(span, node);

                    nodeVal = nodeVal.substring(foundIndex + textToHighlight.length);
                } // Whend

            } // Next i 

        } // End Sub checkAndReplace 


        protected iterator(p: Node)
        {
            if (p == null)
                return;

            let children: Node[] = Array.prototype.slice.call(p.childNodes);

            if (children.length)
            {
                for (let i = 0; i < children.length; i++)
                {
                    let cur: Node = children[i];

                    // https://developer.mozilla.org/en-US/docs/Web/API/Node/nodeType
                    if (cur.nodeType === Node.TEXT_NODE) 
                    {
                        this.checkAndReplace(cur);
                    }
                    else if (cur.nodeType === Node.ELEMENT_NODE) 
                    {
                        this.iterator(cur);
                    }
                } // Next i 

            } // End if (children.length) 

        } // End Sub iterator


        public highlightNode(n:Node)
        {
            this.iterator(n);
        } // End Sub highlight 


        public highlight()
        {
            this.iterator(this.m_container);
        } // End Sub highlight 


    } // End Class InstantSearch 


} // End Namespace SearchTools 

Usage:

用法:

let searchText = document.getElementById("txtSearchText");
let searchContainer = document.body; // document.getElementById("someTable");
let highlighter = new SearchTools.InstantSearch(searchContainer, [
    {
        token: "this is the text to highlight" // searchText.value,
        className: "highlight", // this is the individual highlight class
        sensitiveSearch: false
    }
]);


// highlighter.highlight(); // this would highlight in the entire table
// foreach tr - for each td2 
highlighter.highlightNode(td2); // this highlights in the second column of table

回答by dude

Why using a selfmade highlighting function is a bad idea

为什么使用自制的高亮功能是个坏主意

The reason why it's probably a bad idea to start building your own highlighting function from scratch is because you will certainly run into issues that others have already solved. Challenges:

从头开始构建自己的突出显示功能可能是一个坏主意的原因是因为您肯定会遇到其他人已经解决的问题。挑战:

  • You would need to remove text nodes with HTML elements to highlight your matches without destroying DOM events and triggering DOM regeneration over and over again (which would be the case with e.g. innerHTML)
  • If you want to remove highlighted elements you would have to remove HTML elements with their content and also have to combine the splitted text-nodes for further searches. This is necessary because every highlighter plugin searches inside text nodes for matches and if your keywords will be splitted into several text nodes they will not being found.
  • You would also need to build tests to make sure your plugin works in situations which you have not thought about. And I'm talking about cross-browser tests!
  • 您需要删除带有 HTML 元素的文本节点以突出显示您的匹配项,而不会破坏 DOM 事件并一遍又一遍地触发 DOM 重新生成(例如,就是这种情况innerHTML
  • 如果要删除突出显示的元素,则必须删除 HTML 元素及其内容,并且还必须组合拆分的文本节点以进行进一步搜索。这是必要的,因为每个荧光笔插件都会在文本节点内搜索匹配项,并且如果您的关键字将被拆分为多个文本节点,它们将不会被找到。
  • 您还需要构建测试以确保您的插件在您没有考虑过的情况下工作。我说的是跨浏览器测试!

Sounds complicated? If you want some features like ignoring some elements from highlighting, diacritics mapping, synonyms mapping, search inside iframes, separated word search, etc. this becomes more and more complicated.

听起来很复杂?如果您想要一些功能,例如从突出显示、变音符号映射、同义词映射、iframe 内搜索、分隔词搜索等中忽略某些元素,这将变得越来越复杂。

Use an existing plugin

使用现有插件

When using an existing, well implemented plugin, you don't have to worry about above named things. The article 10 jQuery text highlighter pluginson Sitepoint compares popular highlighter plugins.

使用现有的、实现良好的插件时,您不必担心上述命名的事情。Sitepoint 上的文章10 jQuery 文本荧光笔插件比较了流行的荧光笔插件。

Have a look at mark.js

看看mark.js

mark.jsis such a plugin that is written in pure JavaScript, but is also available as jQuery plugin. It was developed to offer more opportunities than the other plugins with options to:

mark.js就是这样一个用纯 JavaScript 编写的插件,但也可以作为 jQuery 插件使用。它的开发目的是提供比其他插件更多的机会,可以选择:

  • search for keywords separately instead of the complete term
  • map diacritics (For example if "justo" should also match "justò")
  • ignore matches inside custom elements
  • use custom highlighting element
  • use custom highlighting class
  • map custom synonyms
  • search also inside iframes
  • receive not found terms
  • 单独搜索关键字而不是完整的术语
  • 映射变音符号(例如,如果“justo”也应该匹配“justò”)
  • 忽略自定义元素内的匹配项
  • 使用自定义高亮元素
  • 使用自定义突出显示类
  • 映射自定义同义词
  • 也在 iframe 内搜索
  • 收到未找到的条款

DEMO

演示

Alternatively you can see this fiddle.

或者你可以看到这个 fiddle

Usage example:

用法示例

// Highlight "keyword" in the specified context
$(".context").mark("keyword");

// Highlight the custom regular expression in the specified context
$(".context").markRegExp(/Lorem/gmi);

It's free and developed open-source on GitHub (project reference).

它是在 GitHub 上免费开发的开源软件(项目参考)。

回答by Mohit kumar

function stylizeHighlightedString() {

    var text = window.getSelection();

    // For diagnostics
    var start = text.anchorOffset;
    var end = text.focusOffset - text.anchorOffset;

    range = window.getSelection().getRangeAt(0);

    var selectionContents = range.extractContents();
    var span = document.createElement("span");

    span.appendChild(selectionContents);

    span.style.backgroundColor = "yellow";
    span.style.color = "black";

    range.insertNode(span);
}

回答by Klemen Tu?ar

Here's my regexp pure JavaScript solution:

这是我的正则表达式纯 JavaScript 解决方案:

function highlight(text) {
    document.body.innerHTML = document.body.innerHTML.replace(
        new RegExp(text + '(?!([^<]+)?<)', 'gi'),
        '<b style="background-color:#ff0;font-size:100%">$&</b>'
    );
}

回答by HMR

I have the same problem, a bunch of text comes in through a xmlhttp request. This text is html formatted. I need to highlight every occurrence.

我有同样的问题,一堆文本通过 xmlhttp 请求进来。此文本为 html 格式。我需要强调每一个事件。

str='<img src="brown fox.jpg" title="The brown fox" />'
    +'<p>some text containing fox.</p>'

The problem is that I don't need to highlight text in tags. For example I need to highlight fox:

问题是我不需要突出显示标签中的文本。例如,我需要突出狐狸:

Now I can replace it with:

现在我可以将其替换为:

var word="fox";
word="(\b"+ 
    word.replace(/([{}()[\]\.?*+^$|=!:~-])/g, "\")
        + "\b)";
var r = new RegExp(word,"igm");
str.replace(r,"<span class='hl'></span>")

To answer your question: you can leave out the g in regexp options and only first occurrence will be replaced but this is still the one in the img src property and destroys the image tag:

要回答您的问题:您可以在 regexp 选项中省略 g 并且只有第一次出现将被替换,但这仍然是 img src 属性中的那个并破坏图像标签:

<img src="brown <span class='hl'>fox</span>.jpg" title="The brown <span 
class='hl'>fox</span> />

This is the way I solved it but was wondering if there is a better way, something I've missed in regular expressions:

这是我解决它的方法,但想知道是否有更好的方法,我在正则表达式中遗漏了一些东西:

str='<img src="brown fox.jpg" title="The brown fox" />'
    +'<p>some text containing fox.</p>'
var word="fox";
word="(\b"+ 
    word.replace(/([{}()[\]\.?*+^$|=!:~-])/g, "\")
    + "\b)";
var r = new RegExp(word,"igm");
str.replace(/(>[^<]+<)/igm,function(a){
    return a.replace(r,"<span class='hl'></span>");
});

回答by Slavo Vojacek

Simple TypeScript example

简单的打字稿示例

NOTE: While I agree with @Stefan in many things, I only needed a simplematch highlighting:

注意:虽然我在很多方面都同意 @Stefan,但我只需要一个简单的匹配突出显示:

module myApp.Search {
    'use strict';

    export class Utils {
        private static regexFlags = 'gi';
        private static wrapper = 'mark';

        private static wrap(match: string): string {
            return '<' + Utils.wrapper + '>' + match + '</' + Utils.wrapper + '>';
        }

        static highlightSearchTerm(term: string, searchResult: string): string {
            let regex = new RegExp(term, Utils.regexFlags);

            return searchResult.replace(regex, match => Utils.wrap(match));
        }
    }
}

And then constructing the actual result:

然后构建实际结果:

module myApp.Search {
    'use strict';

    export class SearchResult {
        id: string;
        title: string;

        constructor(result, term?: string) {
            this.id = result.id;
            this.title = term ? Utils.highlightSearchTerm(term, result.title) : result.title;
        }
    }
}

回答by kasper Taeymans

Since HTML5 you can use the <mark></mark>tags to highlight text. You can use javascript to wrap some text/keyword between these tags. Here is a little example of how to mark and unmark text.

从 HTML5 开始,您可以使用<mark></mark>标签来突出显示文本。您可以使用 javascript 在这些标签之间包装一些文本/关键字。这是一个关于如何标记和取消标记文本的小例子。

JSFIDDLE DEMO

JSFIDDLE 演示

回答by elclanrs

None of the other solutions really fit my needs, and although Stefan Steiger's solution worked as I expected I found it a bit too verbose.

其他解决方案都没有真正满足我的需求,尽管 Stefan Steiger 的解决方案按我的预期工作,但我发现它有点过于冗长。

Following is my attempt:

以下是我的尝试:

/**
 * Highlight keywords inside a DOM element
 * @param {string} elem Element to search for keywords in
 * @param {string[]} keywords Keywords to highlight
 * @param {boolean} caseSensitive Differenciate between capital and lowercase letters
 * @param {string} cls Class to apply to the highlighted keyword
 */
function highlight(elem, keywords, caseSensitive = false, cls = 'highlight') {
  const flags = caseSensitive ? 'gi' : 'g';
  // Sort longer matches first to avoid
  // highlighting keywords within keywords.
  keywords.sort((a, b) => b.length - a.length);
  Array.from(elem.childNodes).forEach(child => {
    const keywordRegex = RegExp(keywords.join('|'), flags);
    if (child.nodeType !== 3) { // not a text node
      highlight(child, keywords, caseSensitive, cls);
    } else if (keywordRegex.test(child.textContent)) {
      const frag = document.createDocumentFragment();
      let lastIdx = 0;
      child.textContent.replace(keywordRegex, (match, idx) => {
        const part = document.createTextNode(child.textContent.slice(lastIdx, idx));
        const highlighted = document.createElement('span');
        highlighted.textContent = match;
        highlighted.classList.add(cls);
        frag.appendChild(part);
        frag.appendChild(highlighted);
        lastIdx = idx + match.length;
      });
      const end = document.createTextNode(child.textContent.slice(lastIdx));
      frag.appendChild(end);
      child.parentNode.replaceChild(frag, child);
    }
  });
}

// Highlight all keywords found in the page
highlight(document.body, ['lorem', 'amet', 'autem']);
.highlight {
  background: lightpink;
}
<p>Hello world lorem ipsum dolor sit amet, consectetur adipisicing elit. Est vel accusantium totam, ipsum delectus et dignissimos mollitia!</p>
<p>
  Lorem ipsum dolor sit amet, consectetur adipisicing elit. Numquam, corporis.
  <small>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Accusantium autem voluptas perferendis dolores ducimus velit error voluptatem, qui rerum modi?</small>
</p>

I would also recommend using something like escape-string-regexpif your keywords can have special characters that would need to be escaped in regexes:

如果您的关键字可以包含需要在正则表达式中转义的特殊字符,我还建议使用类似escape-string-regexp 的东西:

const keywordRegex = RegExp(keywords.map(escapeRegexp).join('|')), flags);

回答by JGuo

Fast forward to 2019, Web API now has natively support for highlighting texts:

快进到 2019 年,Web API 现在原生支持突出显示文本:

const selection = document.getSelection();
selection.setBaseAndExtent(anchorNode, anchorOffset, focusNode, focusOffset);

And you are good to go! anchorNodeis the selection starting node, focusNodeis the selection ending node. And, if they are text nodes, offsetis the index of the starting and ending character in the respective nodes. Here is the documentation

你很高兴去!anchorNode是选择开始节点,focusNode是选择结束节点。并且,如果它们是文本节点,offset则是相应节点中开始和结束字符的索引。这是文档

They even have a live demo

他们甚至有现场演示