javascript - 将包含 contentEditable 的 html 元素移动到 dom 中的另一个分支而不失去焦点

标签 javascript jquery html dom contenteditable

我希望你能帮助解决这个问题。

我有以下 html 结构(简化),它表示文档中的两个固定高度页面,其中包含页眉、页脚、正文和该正文中的多个“DataItems”(3 个只读,1 个可编辑)。还有一个“摘要”和“添加新”数据项。

我需要能够将 DataItem 的 html block (可能包含 contentEditable 元素)移动到文档中的另一个位置。但是,如果要移动的是 contentEditable 元素,我需要在不失去焦点的情况下这样做。

当用户在 contentEditable HTML 编辑器中输入时触发此操作,并且他们输入的 DataItem 会变高。当它这样做时,当底部的 DataItem 开始与页脚重叠时,它会被向下推到下一页。有点像在不允许跨页的 MS Word 表格单元格中键入内容。

我可以获得使用 jQuery 的部分解决方案。这会将下一个同级 DataItems 从第一页移动到第二页,因为前一个同级的高度会增加,但问题是当我移动具有焦点的 DataItem 时,它会失去焦点并打断用户的输入流程.我已经尝试在移动它之后将焦点放回 contentEditable div,但是选择和范围问题以及无法找到光标位置以及滚动条跳跃的问题,尽管它们被重置回来证明解决方案太不可靠。

因此,我尝试了一种不同的方法,即将第一页的最后一个 DataItem 和下一页的第一个 DataItem(如果有)之间的所有 html 内容移动到最后一个数据项之前的位置,希望这样做这样可以防止 html 内容编辑器失去焦点,但仍然给人的印象是 DataItem 已向下移动到第二页。

我尝试(但未能)实现的功能是剪切“从这里开始”和“从这里结束”div 之间的 html,并将其移动到“粘贴到这里”div。 div 只是作为占位符显示应该移动的内容。

然而,尽管尝试了使用 jQuery dom 操作和 RegEx 字符串替换的各种方法,但我似乎无法想出一个不涉及替换共同祖先的解决方案 - 即“Pages”div - 因此必须替换当前的 contentEditable - 从而失去焦点。

有没有人知道我如何做到这一点并保持焦点以便用户可以继续不间断地输入?

问候, 杰里米:)

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title></title>
    <style>
.Document
{
    text-align:left;
    margin: 0px auto;
    display:inline-block;
    position:relative;
    /*border: 1px solid blue;*/
}

.Pages
{
    margin: 0px auto;
    position:relative;
    display:inline-block;
    /*border: 1px solid yellow;*/
}

.PortraitPage
{
    height:29.7cm;
    width:21cm;
    background: #ffffff;
    position:relative;
}
       .FirstPage
    {
        border: 1px dotted black;
    }

    .ExtraPage
    {
        margin-top:10px;
        margin-bottom:10px;
        border: 1px dotted black;
    } 

.PageHeader
{
    border: 0px dotted #e2e2e2;
    position:absolute;
    top:0px;
    width: 18cm;
    left:0cm;
}

.PageBody
{
    border: 1px dotted #c2c2c2;
    position:absolute;
    top:4.5cm; /* this needs to be whatever the height of the header is */
    width: 18cm;
    left:1.5cm;
    /*min-height:22cm;*/
}

.PageFooter
{
    border: 1px dotted #e2e2e2;
    position:absolute;
    bottom:0px;
    width: 18cm;
    left:1.5cm;
}

.PageSeparator
{
    background: #999999;
    height: 1cm;
    width: 21cm;   
}
.InvoiceItemsForm
{
    position: relative;
    /*top: 2.5cm;*/
}

/* This prevents the space added in contentcell divs in the html entry cell just for the PageEditor */
.InvoiceItemsForm div
{
    margin-bottom: 0px;
}

.LineItem_Panel_ReadOnly
{
    position:relative;
    border: 1px solid transparent;
}

.LineItem_Panel_ReadOnly_Hover
{
    position:relative;
    border: 1px solid #C2C2C2;
    background-color:#ffffff;
}

.LineItem_Panel_Edit
{
    position:relative;
    border: 1px solid #C2C2C2;
}


.LineItem_Panel_Insert
{
    position:relative;
    border: 1px solid green;
}

    </style>
</head>
<body>
    <div id="ctl00_phContent_pnlInvoicePage" class="Page FirstPage PortraitPage">
        <div class="FirstHeader PageHeader">
            First Page Header
        </div>
        <div class="ExtraHeader HiddenExtraPageSection">
            Hidden ExtraPage Header that is copied when a new page is created
        </div>
        <div id="ctl00_phContent_pnlInvoicePageBody" class="PageSection Body PageBody">
            <div id="ctl00_phContent_pnlInvoiceItemsForm" class="InvoiceItemsForm DataSection">
                <div id="ctl00_phContent_lvLineItems_ctrl0_pnlLineItemReadOnly" class="DataItem LineItem_Panel_ReadOnly InvoiceLineItem">
                    <div class="LineItem_Panel_HTMLContent">
                        <span id="ctl00_phContent_lvLineItems_ctrl0_lblHTMLContent">
                            <p>
                                aaaaaaaaaaaaaaa</p>
                            <p>
                                aaaaaaaaaaaaaa</p>
                        </span>
                    </div>
                </div>
                <div id="ctl00_phContent_lvLineItems_ctrl1_pnlLineItemReadOnly" class="DataItem LineItem_Panel_ReadOnly InvoiceLineItem">
                    <div class="LineItem_Panel_HTMLContent">
                        <span id="ctl00_phContent_lvLineItems_ctrl1_lblHTMLContent">
                            <p>
                                bbbbbbbbbbbbbbb</p>
                            <p>
                                bbbbbbbbbb</p>
                        </span>
                    </div>
                </div>
                <div id="ctl00_phContent_lvLineItems_ctrl2_pnlLineItemReadOnly" class="DataItem LineItem_Panel_ReadOnly InvoiceLineItem">
                    <div class="LineItem_Panel_HTMLContent">
                        <span id="ctl00_phContent_lvLineItems_ctrl2_lblHTMLContent">cccccccccccccc</span>
                    </div>
                </div>
                <div id="ctl00_phContent_lvLineItems_ctrl3_pnlLineItemEdit" class="DataItem LineItem_Panel_Edit InvoiceLineItem">
                    <div id="ctl00_phContent_lvLineItems_ctrl3_pnlHTMLEditor" class="HTMLEditorPanel">
                        <div style="width: 126px; height: 20px;" id="ctl00_phContent_lvLineItems_ctrl3_txtHTMLContent$HtmlEditorExtenderBehavior_ExtenderContainer"
                            class="unselectable ajax__html_editor_extender_container">
                            <input style="display: none; visibility: hidden;" id="ctl00_phContent_lvLineItems_ctrl3_txtHTMLContent"
                                name="ctl00$phContent$lvLineItems$ctrl3$txtHTMLContent" value="ddddddddddddd"
                                type="text" autocomplete="off">
                            <div style="height: 21px; overflow: auto; clear: both;" id="ctl00_phContent_lvLineItems_ctrl3_heeHTMLContent_ExtenderContentEditable"
                                class="ajax__html_editor_extender_texteditor" contenteditable="true">
                                <p>
                                    ddddddddddddd</p>
                                <p>
                                    &nbsp;</p>
                            </div>
                        </div>
                    </div>
                </div>
                <div class="DataItem">
                    <p>
                        Click <a id="ctl00_phContent_lvLineItems_lbAddLineItem" href='javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions("ctl00$phContent$lvLineItems$lbAddLineItem", "", true, "", "", false, true))'>
                            here</a> to add a new Data Item</p>
                </div>
                <div id="paste-here"></div>
                <div class="DataItem InvoiceTotals">
                    <div class="InvoiceSubTotal">
                        Sub Total: <span id="ctl00_phContent_lvLineItems_lblInvoiceSubTotal">18,110.00</span></div>
                    <div class="InvoiceVATTotal">
                        VAT Total: <span id="ctl00_phContent_lvLineItems_lblInvoiceVATTotal">3,111.00</span></div>
                    <div class="InvoiceTotal">
                        Invoice Total: <span id="ctl00_phContent_lvLineItems_lblInvoiceTotal">21,221.00</span></div>
                </div>
                <div id="start-cut"></div>
            </div>
        </div>
        <div class="FirstFooter PageFooter">
            First Page Footer
        </div>
        <div class="ExtraFooter HiddenExtraPageSection">
            Hidden ExtraPage Footer that is copied when a new page is created
        </div>
    </div>
    <div id="ctl00_phContent_pnlInvoicePage" class="Page ExtraPage PortraitPage">
        <div class="ExtraHeader PageHeader">
            Extra Page Header
        </div>
        <div id="ctl00_phContent_pnlInvoicePageBody" class="PageSection Body PageBody">
            <div id="ctl00_phContent_pnlInvoiceItemsForm" class="InvoiceItemsForm DataSection">
                <div id="end-cut"></div>
            </div>
        </div>
        <div class="ExtraFooter PageFooter">
            Extra Page Footer
        </div>
    </div>
</body>
</html>

最佳答案

我看不出有任何理由必须重新设置任何内容的父级才能达到您想要的效果。我建议使用 CSS 和 javascript 来明确定位项目,而不是试图依赖足够智能的浏览器来在你想要的地方呈现东西,这将被证明在浏览器之间以及同一浏览器的可能不同版本之间是不一致的。当用户输入的文本太长无法容纳提供的空间时,您可以使用 node.style.top=newY; node.style.left=newX; 重新定位它,和 node.style.height=newHeight; node.style.width=newWidth; 调整它的大小,无论它需要多大。这些方法不需要浏览器删除并重新插入元素,因此焦点不会丢失,文本选择或光标位置也不会丢失。

关于javascript - 将包含 contentEditable 的 html 元素移动到 dom 中的另一个分支而不失去焦点,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15649577/

相关文章:

javascript - 扩展运算符的未定义结果

javascript - AJAX/jQuery/PHP - AJAX 表单处理程序 "Illegal invocation"

html - 内容溢出网格容器

javascript - 仅在桌面上重新加载页面后 Bootstrap 4 折叠保存

javascript - 如何在 JavaScript 中每 5 秒运行一个函数

javascript - 重定向到带有href链接的页面后如何执行JS代码?

javascript - 可以使用 JQuery 让文本在加载时淡出,无法让文本在点击时淡出

javascript - 有谁知道如何让 Javascript ‘onunload’ 函数工作吗?

javascript - 使用 jQuery 或纯 Javascript 访问一组 HTML 输入文本框

javascript - 从聚合物的下拉菜单中获取值