如何在javascript中查找用户选择的是向前还是向后?

6
我是JavaScript的新手。我正在尝试制作一个简单的切换div,用户选择方向后,我会放置切换div。经过一些搜索,我找到了一个有效的fiddle,但效果不如预期。请参见下面的屏幕截图以查看差异。
当我在段落前面选择一些文本时,它可以正常工作,像这样:

enter image description here

但是,当我从底部段落选择一些文本时,它并没有按预期工作。 在此输入图片描述 JsFiddle 实际上,我正在使用React版本,而Fiddle是使用Jquery。
这是我的代码。
    import React from 'react'
import {render} from 'react-dom';

export default class App extends  React.Component{
    constructor(props){
        super(props);
        this.state = {
            display:'none'  ,
            top:'',
            bottom:'',
            left:'',
            right:'',
            diplayForDown:'none'

        };
        this.handleOnMouseDown = this.handleOnMouseDown.bind(this)
        this.onMounseUp = this.onMounseUp.bind(this)
        this.onMouseDwn = this.onMouseDwn.bind(this)
        this.triggerAlltime = this.triggerAlltime.bind(this)
    }

    handleOnMouseDown(){
        let sel = window.getSelection && window.getSelection();

        let r = sel.getRangeAt(0).getBoundingClientRect();
        let relative=document.body.parentNode.getBoundingClientRect();
        console.log('Relative ',relative);

    if(!sel.isCollapsed){

        console.log(sel,r);
        let display = 'block';

        let top = (r.bottom - relative.top - 80)+'px';
        let bottom = r.bottom+'px';
        let left =( r.left)+'px';
        let right = (r.right)+'px';
        console.log('This is Height',r.bottom-r.top);
        let selectionHeight = r.bottom - r.top;
        if(selectionHeight => 22.22){
            this.setState({
                display,
                top:top,
                bottom,
                left,
                right
            })
        }else{
            this.setState({
                display,
                top,
                bottom,
                left,
                right
            })
        }


    }else{
        this.setState({
            display:'none'
        })
    }






        console.log('Slected')
    }
    onMounseUp(e){
        e.preventDefault()
        let sel = window.getSelection && window.getSelection();
        if(!sel.isCollapsed){
            console.log('Moved Up')


        }
    }
    onMouseDwn(e){


        let sel = window.getSelection && window.getSelection();
        if(!sel.isCollapsed){
            console.log('Moved Down')
        }
    }
    getSelectionHtml() {
        let html = "";
        if (typeof window.getSelection != "undefined") {
            let sel = window.getSelection();
            if (sel.rangeCount) {
                let container = document.createElement("div");
                for (let i = 0, len = sel.rangeCount; i < len; ++i) {
                    container.appendChild(sel.getRangeAt(i).cloneContents());
                }
                html = container.innerHTML;
            }
        } else if (typeof document.selection != "undefined") {
            if (document.selection.type == "Text") {
                html = document.selection.createRange().htmlText;
            }
        }

        console.log('html',html)
        return html;

    }
    lastCharRTL(txt) {
        return /[\u0591-\u07FF\uFB1D-\uFDFD\uFE70-\uFEFC]$/.test(txt);
    }

    triggerAlltime(e){
        // console.log('Some Thinms')
        if(!window.getSelection().isCollapsed){
            //find the Direction Of Slelection
            let sel = window.getSelection();
            console.log(sel)
            let range = document.createRange();
            range.setStart(sel.anchorNode, sel.anchorOffset);
            range.setEnd(sel.focusNode, sel.focusOffset);
            let backwards = range.collapsed;
            range.detach();
            // get selection rects
            let rects = sel.getRangeAt(0).getClientRects();
            let n = rects.length - 1;
            let display = 'block';
            console.log(this.lastCharRTL(this.getSelectionHtml()))
            if (this.lastCharRTL(this.getSelectionHtml()))
                this.setState({
                   display:'none',
                    diplayForDown:'none',
                   top: rects[n].top + 10,
                   left: rects[n].left - 10
               })
            else if (backwards)
                this.setState({
                    display,
                    diplayForDown:'none',
                    top: rects[0].top + -68,
                    left: rects[0].left



                })
            else
                this.setState({
                    display:'none',
                    diplayForDown:'block',
                    top: rects[n].top + 40,
                    left: rects[n].right+-160

                })


        }else{
            this.setState({

                display:'none',
                diplayForDown:'none',


            })
        }
    }


    render(){
        return(
            <div  className="container">
                <div className="CenterCon">
                    <div contentEditable="true"  onMouseUp={this.triggerAlltime} onMouseDown={this.triggerAlltime} onKeyUp={this.triggerAlltime} onKeyDown={this.triggerAlltime} className="Edithis" >
                    <p>Test</p>
                    </div>
                </div>

                <div style={{top: this.state.top, bottom: this.state.bottom, left:this.state.left, right:this.state.right, display: this.state.display}} className="Toggle">
                    <ul>
                        <li>B</li>
                        <li>U</li>
                        <li>H</li>
                        <li>"</li>
                    </ul>
                    <div className="triangle">

                    </div>
                </div>

               {/*DownWard Toggle*/}

                <div style={{top: this.state.top, bottom: this.state.bottom, left: this.state.left, right: this.state.right, display: this.state.diplayForDown}} className="ToggleForDownWardSelection">
                    <div className="triangle-bottom" />
                    <ul>
                        <li>B</li>
                        <li>U</li>
                        <li>H</li>
                        <li>li</li>
                    </ul>
                </div>


            </div>

        )
    }
}

render(<App/>,document.getElementById('app'));

2
你使用的是哪个浏览器?因为这个代码片段在我使用的谷歌浏览器和火狐浏览器中都能正确添加切换div。http://jsfiddle.net/vCwwN/2/ - Zze
它会工作。但是请尝试选择内容的最后一行,看看它是否能够正常运行。如果可以,请在@Zze处发布截图。 - Nane
@Alex.S在他对你的回答中是正确的。我没有看到这个问题,因为我不需要滚动到底部段落。很高兴你找到了解决方法。 - Zze
5个回答

3
const isBackwards = () => {
  const selection = window.getSelection();
  let range = document.createRange();
  range.setStart(selection.anchorNode, selection.anchorOffset);
  range.setEnd(selection.focusNode, selection.focusOffset);

  let backwards = range.collapsed;
  range.detach();
  return backwards;
}

太棒了! - undefined

2

最后我找到了答案,我将简单的样式应用于contentEditable div,并且它像魅力一样工作。我不知道为什么它能够工作,但我怀疑是window API。

 <div contentEditable="true" style={{height:'100vh',overflow:'auto'}} onMouseUp={this.triggerAlltime} onMouseDown={this.triggerAlltime} onKeyUp={this.triggerAlltime} onKeyDown={this.triggerAlltime} className="Edithis" >
                    <p>Test</p>
 </div>

1
问题在于#pointer被设置为绝对位置,但当内容很长且可滚动时,top距离是从窗口顶部而不是内容顶部计算的。添加height: 100vh可以解决此问题,但在某些情况下可能会看到两个滚动条。另一种方法是将window.pageYOffset添加到指针div的top中。这里是demo - Alex.S

1
问题在于#pointer被设置为绝对定位,但当内容很长且可滚动时,顶部距离是从窗口顶部而不是内容顶部计算的。
添加height: 100vh可以解决此问题,但在某些情况下可能会看到两个滚动条。
另一种方法是在计算指针div的top时添加window.pageYOffset
if (backwards) {
    $('#pointer').css({top: rects[0].top + window.pageYOffset + 10, left: rects[0].left - 10}).show();
} else {
    $('#pointer').css({top: rects[n].top + window.pageYOffset + 10, left: rects[n].right}).show();
}

这里是 DEMO

0

那是不可能的。也许您可以检查鼠标按下和弹起事件位置,以确定初始/结束位置,从而确定是向前还是向后选择。


那是个好主意,您能否给我展示一个关于我的问题的例子? - Nane
我尝试过了,但有点困惑。你能否请发一下代码? - Nane

0

回答标题中的问题 - 检查选择是向前还是向后:

window.getSelection() 返回一个 Selection 对象,在文档中可以阅读到以下内容:

  • Selection.anchorNode:返回选择开始的节点。

然而,当您在此 Selection 对象上调用 Selection.getRangeAt(0) 时,您会得到 Range 作为选择。Range 没有锚点(和焦点),而是具有 startContainer 和 endContainer。

  • Range.startContainer:返回范围开始的节点。
  • Range.endContainer:返回范围结束的节点。

基本上,anchordNode 始终是用户开始选择的节点,而 startContainer 始终是选择的 DOM 树中的第一个节点。所以:

  • 如果选择的 anchorNode 和 anchorOffset 与 Range 的 startContainer 和 startOffset 相对应,则您拥有(正常的)向前选择
  • 如果选择的 anchorNode 和 anchorOffset 与 Range 的 endContainer 和 endOffset 相对应,则您拥有向后选择

(当然,在开始时检查选择是否折叠)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接