最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - How should Selection selectfinishselectend event be implemented? - Stack Overflow

programmeradmin0浏览0评论

I'm looking to do something whenever a user finishes making a selection —essentially, on the first mouseup event after every selectstart event, I think— on the page. I want to take that selection and wrap it in an element to be styled via CSS. I presumed the Selection API offered an event for this; however, it doesn't seem to.

I don't simply listen for mouseup 'cause I'm especially looking for this to work with the selection that results from the browser's find functionality ("Find in This Page…"; +f).

let selContainer = document.createElement('span')
span.classList.add('user-selection')

const wrapSelection = () => {
  window.getSelection().getRangeAt(0).surroundContent(selContainer)
}


/*                   ┏━━━━━━━━━━━━━━━━━━━━━━━━━━┓
                     ┃                          ┃
                     ┃  The Selection API only  ┃
                     ┃  affords these events:   ┃
                     ┃                          ┃
                     ┃  - selectionchange       ┃
                     ┃  - selectstart     ┏━━━━━┫
                     ┃                    ┃issue┃
                     ┗━━━━━━━━━━━━━━━━━━━━┻━━━━━┛

*/document.addEventListener('selectfinish', wrapSelection)/*
                             ┗━━━━┳━━━━━┛
                                  ┃
                                  ┃
                               no such
                                event                                                                                                                                                                                                        */

I'm looking to do something whenever a user finishes making a selection —essentially, on the first mouseup event after every selectstart event, I think— on the page. I want to take that selection and wrap it in an element to be styled via CSS. I presumed the Selection API offered an event for this; however, it doesn't seem to.

I don't simply listen for mouseup 'cause I'm especially looking for this to work with the selection that results from the browser's find functionality ("Find in This Page…"; +f).

let selContainer = document.createElement('span')
span.classList.add('user-selection')

const wrapSelection = () => {
  window.getSelection().getRangeAt(0).surroundContent(selContainer)
}


/*                   ┏━━━━━━━━━━━━━━━━━━━━━━━━━━┓
                     ┃                          ┃
                     ┃  The Selection API only  ┃
                     ┃  affords these events:   ┃
                     ┃                          ┃
                     ┃  - selectionchange       ┃
                     ┃  - selectstart     ┏━━━━━┫
                     ┃                    ┃issue┃
                     ┗━━━━━━━━━━━━━━━━━━━━┻━━━━━┛

*/document.addEventListener('selectfinish', wrapSelection)/*
                             ┗━━━━┳━━━━━┛
                                  ┃
                                  ┃
                               no such
                                event                                                                                                                                                                                                        */

Share Improve this question edited Nov 26, 2020 at 0:30 tjfwalker asked Mar 1, 2018 at 22:41 tjfwalkertjfwalker 4944 silver badges18 bronze badges
Add a ment  | 

4 Answers 4

Reset to default 4

This is trickier than it should be. I’ve used a bination of element.onselectstart, element.onmouseup, and document.onselectionchange. Take a look at this demo.

function onSelect(element, callback) {
    // console.log(element, callback);
    let isSelecting = false;
    let selection = null;

    function handleSelectStart(event) {
        // console.log(event);
        isSelecting = true; 
    }

    function handleMouseUp(event) {
        // console.log(event, isSelecting);
        if (isSelecting && !document.getSelection().isCollapsed) {
            callback((selection = document.getSelection()));
            isSelecting = false;
        }
    }

    function handleSelectionChange(event) {
        // console.log('change', isSelecting);
        if (document.getSelection().isCollapsed && null !== selection) {
            callback((selection = null));
        }
    }

    element.addEventListener('selectstart', handleSelectStart);
    element.addEventListener('mouseup', handleMouseUp);
    document.addEventListener('selectionchange', handleSelectionChange);

    return function destroy() {
        element.removeEventListener('selectstart', handleSelectStart);
        element.removeEventListener('mouseup', handleMouseUp);
        document.removeEventListener('selectionchange', handleSelectionChange);
    };
}

This won’t handle non-mouse interactions. Acmodating pointer and keyboard events would be a nice enhancement. I think the overall pattern holds, though.

One way that I've gotten it to work is to track the selectionchange event and when the selection doesn't change for over 500ms, I consider that a select end. It's not perfect, but it works and correctly triggers for any kind of selection, be it mouse, keyboard, or CTRL+F.

    let selectionDelay = null, selection = '';

    document.addEventListener('selectionchange', () => {
        const currentSelection = document.getSelection().toString();
        if (currentSelection != selection) {
            selection = currentSelection;
            if (selectionDelay) {
                window.clearTimeout(selectionDelay);
            }
            selectionDelay = window.setTimeout(() => {
                wrapSelection();
                selection = '';
                selectionDelay = null;
            }, 500);
        }
    });

I picked through the source code of the hypothes.is web annotation client in an effort to understand how they get their toolbar to appear on user select action end. It seems to be a matter of employing an observer via zen-observable.

simpler alternative to the accepted answer.

 document.addEventListener('mouseup', e => {
     var s = document.getSelection();
     if (!s.isCollapsed) {
          // do sth with selection
     }
 });

or maybe better?

 document.addEventListener('selectstart', e => {
     document.addEventListener('mouseup', somefunction);
 });
 function somefunction(e) {
     // do sth
     document.removeEventListener('mouseup', somefunction);
 }
发布评论

评论列表(0)

  1. 暂无评论