文本框仿真功能无法正常工作,有什么替代方案吗?

12

我有这个HTML和CSS:http://jsfiddle.net/b7rDL/6/

HTML:

<div class="text-block" contenteditable="true" spellcheck="false">Some Text</div>

CSS:

.text-block {
    resize: none;
    font-size:40px;
    border: none;
    line-height: 1;
    -moz-appearance: textfield-multiline;
    -webkit-appearance: textarea;
    min-width: 30px;
    overflow: visible;
    white-space: nowrap;
    display: inline-block;
}

这段代码允许我不限制文本框的宽度和高度,它不会显示滚动条并且会随着文本自动扩展大小。这些基本上是我需要的特性。

  1. 如何将这个div转换为一个相同功能的textarea?我想在不支持"contenteditable"的浏览器上使用。因此我想要用textarea或其他基本元素替换div。我该怎么做?(我不介意使用JavaScript)
  2. 如何禁用拼写检查?spellcheck=false 不起作用。在这个例子中,当我把焦点放在文本框上时,我会看到那条烦人的红线。我正在使用Firefox。
  3. 如何在聚焦时去除边框? - 已解决

我不介意使用JavaScript来解决这些问题。

任何关于以上问题的答案都会对我有帮助。

谢谢

更新:
@Oylex 帮我解决了第三个问题。


1
是因为你知道答案还是因为你没理解就点踩了?那些不解释为什么要点踩的人没有尊严! - Naor
1
一些观察。首先,没有本地 CSS 方法可以构建自动增长的 textarea,因此您将需要 JavaScript。其次,“spellcheck =“false””绝对是在字段上禁用拼写检查的正确方法-您在哪个浏览器上看到了这个?您能添加一个 jsFiddle 和一些具体信息吗? - Jordan Gray
1
@PankitKapadia:我更新了问题。我写道:“此代码允许我编写没有宽度限制或高度限制的文本。它不显示滚动条,并随着文本的增长而增长。这些基本上就是我需要的功能。”。 - Naor
1
@arttronics:关于你的第一个和第二个例子:当我点击编辑时,我会得到带有滚动条的文本区域。jQuery插件也会滚动。我需要宽度由文本决定。 - Naor
你是否找到了 #1 和/或 #2 的解决方案? - JSuar
显示剩余9条评论
7个回答

9

#1

这里是可用的演示链接:http://jsfiddle.net/d9H9w/11/(在IE8、Chrome和Firefox中测试通过)

您需要将文本框中输入的文字设置为宽度和高度属性。

高度

这很简单:

  1. 获取文本区域的内容
  2. 匹配换行符
  3. 以em为单位将高度设置为换行符的总数(加上第一行的1和1.5的余地)。

以em作为单位设置高度,这使得它可以适用于多种字体大小。

function getNewlines(){
    // get the value(text) of the textarea
    var content = textEl.value;

    //use regex to find all the newline characters
    var newLines = content.match(/\n/g);

    // use the count of newlines(+1 for the first line + 1 for a buffer)
    // to set the height of the textarea.
    textEl.style.height = ((newLines && newLines.length || 0)+2.5)+'em';
};

宽度

这也相当容易,但有一个陷阱。

  1. 获取文本框的内容
  2. 按换行符拆分以获取由文本框行组成的数组
  3. 排序以获取最长的一行
  4. 将宽度设置为最长字符串的长度(以em为单位),乘以约0.6(我的代码中的emRatio),再加上2个em的缓冲空间。

最后一个部分是关键。'em'测量应该是表示单个字符占用的宽度和高度的正方形。这并不考虑字距,因此字符的高度通常是准确的,但宽度取决于周围的字符。所以,通过猜测和检查,我发现0.6 em大约是经过字距调整后字符的平均宽度。0.6非常接近,因此我将2个em添加到宽度中作为一些缓冲空间。

var emRatio = .6;
function longestLine(){
    // get the value(text) of the textarea
    var content = textEl.value;

    // split on newline's. this creates an array, where each item in
    // the array is the text of one line
    var a = content.split('\n');

    // use a sorting function to order the items in the array:
    // longest string to shortest string
    a.sort(function(a,b){return b.length - a.length});

    // use the longest string * the emRatio to set the width
    // Due to kerning, the letters aren't ever really 1em x 1em
    // So I'm multiplying by an approximate ratio here (guess and check)
    textEl.style.width = (a[0].length * emRatio + 2)+ 'em';
};

这种实现存在的问题

  • 为了支持长按键盘调整大小,必须包含onkeydown处理程序(这对于不包括长按键的所有情况都不是最优的)

综上所述,我认为这符合您的需求。

编辑

将emRatio从.7更改为.6,并在宽度上添加2个ems的缓冲区。这解决了@Naor在评论中提到的两个问题。

我已更新fiddle链接和宽度部分以反映这些更改。


2
@naor 这应该是答案。它完美地运行着。来吧,楼主——给这个家伙点赞! - Michael Giovanni Pumo
@Naor - 你提到的两个问题都源于将平均字距近似为0.7。将该比率降低至0.6可使平均值更准确,并减少了由于行过长而产生的空白。在计算后添加一个2ems宽度的常数可以解决关于在空文本区域中键入前几个字符的问题。我的答案已反映了这些更改。 - freethejazz
在“回车”上也有一个小跳跃。不要将高度增加2个em,而是增加2.5个em,这样就可以解决问题了。 - freethejazz
@JonathanF:-moz-appearance: textfield-multiline; 和 -webkit-appearance: textarea; 样式是必需的吗? - Naor
@JonathanF:在这个组件中,我通过拖动右下角启用了字体缩放功能。问题在于对于不同的字体大小,emRatio是不同的。我无法找到一种根据字体大小计算emRatio的方法。如果你有更好的想法,那会很有帮助。非常感谢你的回答。 - Naor
显示剩余2条评论

4

编辑 0

请求 #1 更新

可行解决方案:http://jsfiddle.net/7aeU2/

JQuery

$(function() {
    //  changes mouse cursor when highlighting loawer right of box
    $("textarea").mousemove(function(e) {
        var myPos = $(this).offset();
        myPos.bottom = $(this).offset().top + $(this).outerHeight();
        myPos.right = $(this).offset().left + $(this).outerWidth();

        if (myPos.bottom > e.pageY && e.pageY > myPos.bottom - 16 && myPos.right > e.pageX && e.pageX > myPos.right - 16) {
            $(this).css({ cursor: "nw-resize" });
        }
        else {
            $(this).css({ cursor: "" });
        }
    })
    //  the following simple make the textbox "Auto-Expand" as it is typed in
    .keyup(function(e) {
        //  the following will help the text expand as typing takes place
        while($(this).outerHeight() < this.scrollHeight + parseFloat($(this).css("borderTopWidth")) + parseFloat($(this).css("borderBottomWidth"))) {
            $(this).height($(this).height()+1);
        };
    });
});​

请求 #2 更新

此外,以下是为什么您不能直接禁用拼写检查的好解释。

这不属于CSS领域(它是可选的呈现建议)。 这不是关于渲染数据的样式特征,而是关于交互式处理数据的问题。

在支持“拼写检查”的浏览器上(可能涉及语法和风格检查),HTML属性spellcheck或相应的IDL(DOM)属性,在JavaScript中可设置有效。

在实践中,这些浏览器倾向于默认启用文本区域的“拼写检查”功能,由于文本区域通常包含人类语言文本,因此关闭它听起来并不有用。 无论如何,用户可以控制它(用户可以将其关闭或选择语言)。

via https://dev59.com/D2ox5IYBdhLWcg3wcT3r#9209791


请求 #1

  1. Simple Solution is pretty straight forward.

    Working example: http://jsfiddle.net/b7rDL/12/

    JQuery

    $("#Solution0").keyup(function(e) {   
        while($(this).outerHeight() < this.scrollHeight) {
            $(this).width($(this).width()+50);
        };
    });
    

    HTML

    <textarea id="Solution0" rows="1" style="height: 1.2em;"></textarea>
    
  2. Fancier solution that will require some updating if you want the width, rather than the height, to expand. Still, it's pretty nice.

  3. Other solutions - I know these all expand height. Let me know if you need width implementation of one of the below solutions.

请求 #2

spellcheck="true" 应该按照 Mozilla 文档中描述的方式工作:控制HTML表单中的拼写检查。在我的第一个简单示例中,Firefox 13.0.1中可以正常工作。请问您使用的是哪个版本?


@JStar:感谢您的回答。我已经看到了您提供的大部分链接。我需要确切的宽度而不是高度。我不想使用像克隆div这样的自动增长解决方案,因为我需要在一个HTML文件中添加30个类似这样的文本框(我希望使用最简单的结构)。 - Naor
@JStar:我也尝试支持回车键换行。用户应该能够像文本编辑器一样编写文本,如果他想换行,他应该能够使用回车键。 - Naor
1
我更新了你的第一个jsFiddle,现在包括一个overflow: hidden,它可以隐藏令人讨厌的跳动... http://jsfiddle.net/7aeU2/ - Michael Giovanni Pumo
@JSuar:我需要文本区域随着用户输入而自动调整大小,包括宽度和高度。 - Naor

3
对于#3,您需要查找的CSS选项是:outline: none;

谢谢,我在寻找其他答案。 - Naor

2
我在确定

在我的测试中,我试图避免使用wrap="off"属性。你为什么需要它?我们如何避免它? - Naor
$dupe.text($tx.val() + "|"); $tx.css({ width: $dupe.width() + 7, height: $dupe.height()       }); 这样做会为文本下方提供额外的空间。 - dmi3y
白空格 pre,没错,这很聪明。 - dmi3y
@dmi3y 你建议使用可折叠空格的文本区域更好?为什么 white-space: pre 不好? - tiffon
@tiffon,我告诉你它很棒,没有讽刺,它真的很聪明,以前我从未想过,我将使用它。 - dmi3y
显示剩余6条评论

2

请求 #2

工作中的演示

<body spellcheck="false">
<div class="text-block" contenteditable="true">    
Some Text SpellCheck</div>

你好Naor,这个东西唯一的问题是它会禁用<body>标签中所有元素的拼写检查。如果这不重要,你可以使用它。

你的问题真的很有趣,也很具有挑战性,我希望这可以帮到你..!!


我可以用spellcheck="false"的另一个div来包装contenteditable div!感谢您的回答 :) - Naor

0

在我过去做类似的事情时,最有效的方法是创建一个具有与文本区域完全相同样式的隐藏流程

,然后根据来自文本区域的信息设置超时以更新其HTML源。这听起来有点可怕,但经过一些测试和玩耍,没有比已经建议的更好的方法,所以这只是我的变体。

http://jsfiddle.net/f2gAD/16/

基于jQuery的脚本:

var textarea = $('textarea'),
    textBlock = $('div.text-block'),
    interval, value, freq = 10,
    doTextAreaAdjust = function(){
       textarea.css({
          height: textBlock.outerHeight(),
          width: textBlock.outerWidth()
       });
    };
doTextAreaAdjust();
textarea
.focus(function(){
    interval = window.setInterval(
        function() {
          value = textarea.val().replace(/(\r\n|\n|\r)/gm, '[rnnr]');
          value = value.replace(/</gm, '||'); // break html tags
          value = value.replace(/\[rnnr\]/gm, '<br>');
          value = value + '|'; // or <span>|</span> for better pixel perfect
          textBlock.html(value);
          doTextAreaAdjust();
        }, freq
    );console.log(interval);
})
.blur(function(){
    window.clearInterval(interval);
});
​

为了性能考虑,将其设置为在焦点/失焦时自启动/停止超时,但这里仍需要一些解决方法。在 Chrome 中测试时,注意到如果通过单击另一个标签页使模块失去焦点,则间隔没有正确地停止。因此,可能更好地将自调用函数替换为 setTimeout

它在 IE 7-8 中表现得或多或少良好,这是主要目标,但仍会时不时出现一些文本跳动,而对于其他浏览器则没有问题,但猜测您会在现代浏览器中使用可编辑功能。建议使用 Modernizr 进行检测。


这个表现不一致。填写第一行后,行会断开。然后删除所有文本并重新开始编写。现在行不会再断开了。 - Naor

-1

在这里工作 http://jsfiddle.net/H2GSx/

代码如下: HTML:

<div style="overflow: scroll; width: 200px; height: 100px;">
    <div class="text-block" contenteditable="true" spellcheck="false">Some Text</div>
</div>​

CSS:

.text-block {
    resize: none;
    font-size:40px;
    border: none;
    line-height: 1;
    -moz-appearance: textfield-multiline;
    -webkit-appearance: textarea;
    min-width: 30px;
    overflow: visible;
    white-space: nowrap;
    display: inline-block;
}
​

2
我正在尝试用更常见的东西替换contenteditable div!你所有的例子都在使用contenteditable div。难道你没有看到问题吗? - Naor

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