有没有一种方法可以使文本区域部分可编辑?(仅使文本的某些部分可编辑)

25

我刚遇到一个情况,需要在文本区域中只有部分内容可编辑(已经加载的文本),而其他部分则不可编辑(变灰),这将是一个优雅的解决方案。

一般情况下,通过JavaScript实现这个功能是否可能?我想使用jQuery达到目的。


非可编辑内容会存在于文本的不同部分,还是会被固定在某个位置(例如:开头或结尾)? - Mohammed Swillam
@Mohammed 在我的特定情况下,理想的解决方案是批量可编辑文本。这些部分将通过某些标记(例如@{})来识别。 - Kenji Kina
1
嗨Kensai, 你最终实现了解决方案吗?我很想听听你的经验,因为我现在也在尝试做这件事。谢谢! - user418775
@user418775 很抱歉,我没有。在我开始这个项目之前,它就已经停止了。 - Kenji Kina
9个回答

14

你可以这样做(只是一个大致的想法,没有代码):

设计一个正则表达式,匹配整个文本。对于不可修改的部分使用固定字符串,并对可修改的部分使用 [\s\S]*? 。使用 ^$ 来锚定你的正则表达式。

/^This is fixed text\. Now something editable:[\s\S]*?Now fixed again\.$/

现在对keyup事件和可能的其他事件(比如paste)做出反应。

每次相关事件发生时,检查正则表达式是否仍然匹配。

如果不匹配,取消该事件。

这样可以有效地防止修改正则表达式中字面上的部分,从而使您的文本中某些部分只读。

记得在表单提交之后也要在服务器端测试字符串——永远不要相信客户端不能发送无效值。


编辑

您可以使用正则引用函数来动态构建该正则表达式,从而减少很多麻烦。

function regexQuote(s) { return s.replace(/[\[\]^$*+?{}.|\\]/g, "\\$&") }

使用

var re = new Regex(
  "^" + 
  [regexQuote(fixedPart1), regexQuote(fixedPart2)].join("[\\s\\S].*?")
   + "$"
);

9
以下是使用“input”事件的实现方式(不幸的是,IE9并没有完全支持它):https://jsfiddle.net/un6c950h/。使用“keyup”和“paste”事件会导致数值变化后又被还原,出现跳跃行为:https://jsfiddle.net/un6c950h/2/。 - Peter
@Peter,我们如何添加一个或多个常量值(例如:Mr. {Jack} 喜欢 {red} 颜色的水果)? - mathew

10
如果您使用普通的文本区域元素,您将无法样式化所需内容(基于该内容是否可编辑)。最好的情况是,您可以检查用户尝试更改的内容是否在黑名单或白名单上,然后相应地停止编辑或不停止。您还可以提供一些视觉反馈,如警告消息“您不能这样做”。
我的建议是利用contenteditable属性,这可能需要更多时间来进行样式设置,但从长远来看,将允许您更大的灵活性。
您将能够样式化一个div元素,使其看起来很像所需的文本区域,然后在其中使用可编辑的span来设置特定文本块是否可以编辑。然后,您可以使用JavaScript命令(参见上面的链接)或使用“保存”按钮检索此内容,将其设置为实际文本区域的值(您可以将其隐藏),并像往常一样发布您的页面。
请使用以下代码作为粗略示例。
<div id="editable-content">
    <span id="block1" class="editable" contenteditable="true">This is some editable content which will </span>
    <span id="block2" class="non-editable">quickly be followed by some non-editable content</span>
</div>
<div style="display: none;">
    <textarea id="PostedContent"></textarea>
</div>
<div>
    <input id="save-page" type="submit" value="Save Page" />
</div>

<script type="text/javascript">
    $(function () {
        $('#save-page').click(function () {
            $('#PostedContent').val($('#editable-content').text());
        });
    });
</script>

1
+1 这是一个不错的方法。然而,由于表单提交完全依赖于 JavaScript,我建议也通过 JavaScript 设置 contenteditable。此外,我不建议弹出消息框。闪烁背景颜色(或类似的东西)会更少干扰。 - Tomalak
1
这很好,但在IE9中,当写入某些内容然后删除它时,它会表现出一种奇怪的行为(有时后面的文本会回到原来的位置,有时则停留在原地,留下尴尬的空白)。 - Kenji Kina
1
哇,这太聪明了!我发现了这个网站:http://hallojs.org/demo/markdown/,结合你使用可编辑的`<span>`标签的方法,它工作得很好。我原本以为我要花上一天或五天来开发我需要的HTML文本编辑器,但看起来只需要五分钟 :) - Ruslan

6
在搜索后发现,要使文本区域部分可编辑非常困难。
这是我用于满足此要求的代码。

input
{
  width:100%;
  border:0px solid;
  outline:none
}

 
<!DOCTYPE html>
   <html>     
<div style="padding: 2px;border:1px solid #ccc;width: 82%;max-height:100px;min-height: 51px;overflow:auto;outline: none;resize: both;" contenteditable="true" unselectable="on">    
    

  <input placeholder="enter prefix..." value="editable postfix..." ></input>
  <div id='unEditable' style="background-color:yellow;width: fit-content;padding-left:10px;padding-right:10px;border-radius:10px;height: fit-content;" contenteditable="false" unselectable="off" onkeyup="" >
         fixed content non-editable
        
   </div>
  <input placeholder="enter postfix..." value="editable prefix..." style='width:97%'></input>
    
 </div>
</html>


2

好的,你可以这样做。这段代码非常低效,我只是试图勾勒出概念。

JS:

$(function () {
            var tb = $("#t").get(0);
            $("#t").keydown(function (event) {
                var start = tb.selectionStart;
                var end = tb.selectionEnd;
                var reg = new RegExp("(@{.+?})", "g");
                var amatch = null;
                while ((amatch = reg.exec(tb.value)) != null) {
                    var thisMatchStart = amatch.index;
                    var thisMatchEnd = amatch.index + amatch[0].length;
                    if (start <= thisMatchStart && end > thisMatchStart) {
                        event.preventDefault();
                        return false;
                    }
                    else if (start > thisMatchStart && start < thisMatchEnd) {
                        event.preventDefault();
                        return false;
                    }
                }
            });
        });

HTML

<textarea id="t" rows=5 cols="80">Hello this is a test @{stuff} 

        this part is editable @{other stuff}     

    </textarea>

这个使用了你提出的“标记”思路。大致思路是,判断用户尝试编辑的文本范围是否在我们的标记内。显然,每次按键都使用正则表达式来确定这一点并不是最好的方法,我没有忽略箭头键等等,但这给你一个大致的想法。


1

有趣的想法,但遗憾的是,文本区域内的文本必须被统一处理,也就是说,你不能禁用文本区域内容的子部分。

然而,你还是有选择的余地。如果你能确定需要禁用的文本,则可以将其添加为DOM元素(即div),然后以某种方式定位它,使其看起来在文本区域内。

你可以通过使文本区域变大并使用position:relative / absolute样式将div移动到文本区域上方来暗示这个div在文本区域内。或者,你可以取消文本区域的边框,并将其放置在一个包含"disabled"文本的容器中。


1
我建议,与其尝试将元素的内容分解为可编辑/不可编辑的子字符串,不如使用HTML元素的contentEditable属性,并使用JavaScript将编辑后的值传递到页面其他位置的隐藏元素中。

0
在父元素中,您可以将边框设置为1像素实心灰色,然后在其中放置以下内容:
1)文本区域(修改CSS以不显示边框) 2)标签(同样没有边框)
在这种情况下,它看起来像是1)和2)中的两个文本一起,因为它们被放置在一个框中。1)是可编辑的,而另一个则变灰。

0
我之前在一个输入标签上做过类似的事情,但是这次应用到了

-1
我建议使用两个文本区域,一个只读的和另一个可编辑的,重叠在一起看起来像是一个。

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