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

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


当前回答

对于任何一个在那里使用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将帮助我们防止这些警告

其他回答

我为此写了一个小工具。也许对某些人有用。它不需要jQuery也能工作。

https://github.com/schickling/calculate-size

用法:

var size = calculateSize("Hello world!", {
   font: 'Arial',
   fontSize: '12px'
});

console.log(size.width); // 65
console.log(size.height); // 14

小提琴:http://jsfiddle.net/PEvL8/

jQuery:

(function($) {

 $.textMetrics = function(el) {

  var h = 0, w = 0;

  var div = document.createElement('div');
  document.body.appendChild(div);
  $(div).css({
   position: 'absolute',
   left: -1000,
   top: -1000,
   display: 'none'
  });

  $(div).html($(el).html());
  var styles = ['font-size','font-style', 'font-weight', 'font-family','line-height', 'text-transform', 'letter-spacing'];
  $(styles).each(function() {
   var s = this.toString();
   $(div).css(s, $(el).css(s));
  });

  h = $(div).outerHeight();
  w = $(div).outerWidth();

  $(div).remove();

  var ret = {
   height: h,
   width: w
  };

  return ret;
 }

})(jQuery);

没有jQuery:

String.prototype.width = function (fontSize) {
    var el,
        f = fontSize + " px arial" || '12px arial';
    el = document.createElement('div');
    el.style.position = 'absolute';
    el.style.float = "left";
    el.style.whiteSpace = 'nowrap';
    el.style.visibility = 'hidden';
    el.style.font = f;
    el.innerHTML = this;
    el = document.body.appendChild(el);
    w = el.offsetWidth;
    el.parentNode.removeChild(el);
    return w;
}

// Usage
"MyString".width(12);

工作示例:http://jsfiddle.net/tdpLdqpo/1/

HTML:

<h1 id="test1">
    How wide is this text?
</h1>
<div id="result1"></div>
<hr/>
<p id="test2">
    How wide is this text?
</p>
<div id="result2"></div>
<hr/>
<p id="test3">
    How wide is this text?<br/><br/>
    f sdfj f sdlfj lfj lsdk jflsjd fljsd flj sflj sldfj lsdfjlsdjkf sfjoifoewj flsdjfl jofjlgjdlsfjsdofjisdojfsdmfnnfoisjfoi  ojfo dsjfo jdsofjsodnfo sjfoj ifjjfoewj fofew jfos fojo foew jofj s f j
</p>
<div id="result3"></div>

JavaScript代码:

function getTextWidth(text, font) {
    var canvas = getTextWidth.canvas ||
        (getTextWidth.canvas = document.createElement("canvas"));
    var context = canvas.getContext("2d");
    context.font = font;
    var metrics = context.measureText(text);
    return metrics.width;
};

$("#result1")
.text("answer: " +
    getTextWidth(
             $("#test1").text(),
             $("#test1").css("font")) + " px");

$("#result2")
    .text("answer: " +
        getTextWidth(
             $("#test2").text(),
             $("#test2").css("font")) + " px");

$("#result3")
    .text("answer: " +
        getTextWidth(
             $("#test3").text(),
             $("#test3").css("font")) + " px");

更好的方法是在显示元素之前检测文本是否合适。你可以使用这个函数它不需要元素在屏幕上。

function textWidth(text, fontProp) {
    var tag = document.createElement("div");
    tag.style.position = "absolute";
    tag.style.left = "-999em";
    tag.style.whiteSpace = "nowrap";
    tag.style.font = fontProp;
    tag.innerHTML = text;

    document.body.appendChild(tag);

    var result = tag.clientWidth;

    document.body.removeChild(tag);

    return result;
}

用法:

if ( textWidth("Text", "bold 13px Verdana") > elementWidth) {
    ...
}