我想使用JavaScript来计算字符串的宽度。如果不使用单行字体,这可能吗?

如果它不是内置的,我唯一的想法是为每个字符创建一个宽度表,但这是非常不合理的,特别是支持Unicode和不同的类型大小(以及所有浏览器)。


当前回答

这是我随手拼凑的一个例子。看来我们都达成共识了。

String.prototype.width = function(font) {
  var f = font || '12px arial',
      o = $('<div></div>')
            .text(this)
            .css({'position': 'absolute', 'float': 'left', 'white-space': 'nowrap', 'visibility': 'hidden', 'font': f})
            .appendTo($('body')),
      w = o.width();

  o.remove();

  return w;
}

使用它很简单:"a string".width()

**增加了空格:nowrap,因此宽度大于窗口宽度的字符串可以被计算。

其他回答

我使用文本度量包。工作真的很好,我尝试了这个解决方案,但在某些原因,它计算错误。

textMetrics.init(document.querySelector('h1'), { fontSize: '20px' });

textMetrics.init({
  fontSize: '14px',
  lineHeight: '20px',
  fontFamily: 'Helvetica, Arial, sans-serif',
  fontWeight: 400,
  width: 100,
});

我猜这和Depak的条目很相似,但这是基于Louis Lazaris在impressiveweb页面上发表的一篇文章

(function($){

        $.fn.autofit = function() {             

            var hiddenDiv = $(document.createElement('div')),
            content = null;

            hiddenDiv.css('display','none');

            $('body').append(hiddenDiv);

            $(this).bind('fit keyup keydown blur update focus',function () {
                content = $(this).val();

                content = content.replace(/\n/g, '<br>');
                hiddenDiv.html(content);

                $(this).css('width', hiddenDiv.width());

            });

            return this;

        };
    })(jQuery);

fit事件用于在函数关联到控件之后立即执行函数调用。

例如:$(“输入”).autofit () .trigger(“适合”);

这是我随手拼凑的一个例子。看来我们都达成共识了。

String.prototype.width = function(font) {
  var f = font || '12px arial',
      o = $('<div></div>')
            .text(this)
            .css({'position': 'absolute', 'float': 'left', 'white-space': 'nowrap', 'visibility': 'hidden', 'font': f})
            .appendTo($('body')),
      w = o.width();

  o.remove();

  return w;
}

使用它很简单:"a string".width()

**增加了空格:nowrap,因此宽度大于窗口宽度的字符串可以被计算。

对于任何一个在那里使用React和/或Typescript…

试试这个Codepen!

export default function App() {
  const spanRef = useRef<HTMLSpanElement>(null);
  const [textWidth, setTextWidth] = useState(0);

  const getTextWidthInPixels = (ref: HTMLSpanElement) =>
    ref.getBoundingClientRect().width;

  useEffect(() => {
    setTextWidth(getTextWidthInPixels(spanRef.current!));
  }, [spanRef]);

  return (
    <div className="App">
      <span
        ref={spanRef}
        contentEditable
        suppressContentEditableWarning
        onInput={() => setTextWidth(getTextWidthInPixels(spanRef.current!))}
      >
        Edit Me!!!
      </span>
      {`textWidth: ${textWidth}px`}
    </div>
  );
}

将文本包装在内联定位的元素(如<span>)中是个好主意。 useRef是React访问DOM元素的方式,在我们的例子中是<span> getBoundingClientRect可以获得任何DOM元素的总宽度。 contentteditable允许用户更改元素的内容…这有点不安全(React会抛出警告!) suppresscontentteditablewarning将帮助我们防止这些警告

在文本的包含元素上使用scrollWidth来获得元素的最小宽度,包括由于溢出而隐藏的部分。更多信息请访问https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollWidth

如果元素不在DOM中,将其添加到某个隐藏区域以进行测量。例如:

function measureText(text) {
  let div = document.createElement("div");
  div.innerText = text;
  div.style.whiteSpace = 'nowrap';
  body.appendChild(div);
  let width = div.scrollWidth;
  body.removeChild(div);
  return width;
}

样式(字体大小、重量等)将被元素继承,因此计入宽度。您还可以使用scrollWidth和scrollHeight来测量更复杂内容的大小。