假设我在一行中有一些随机的文本块。像这样
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
但无论出于何种原因(包含元素的宽度设置,使用文本缩放等),在查看器的屏幕上它显示为两行或更多行。
Lorem ipsum dolor sit amet,
consectetur adipiscing elit.
或
Lorem ipsum dolor sit
amet, consectetur
adipiscing elit.
有没有办法通过javascript找到那些换行的地方?
无论文本如何显示, $('p').text()
和$('p').html()
都会返回Lorem ipsum dolor sit amet, consectetur adipiscing elit.
。
答案 0 :(得分:26)
好吧,如果你想要的东西非常简单,对你来说可能太无用(如果你在段落中有任何类型的HTML,那么它需要进行重大修改),那么看看这个:
var para = $('p');
para.each(function(){
var current = $(this);
var text = current.text();
var words = text.split(' ');
current.text(words[0]);
var height = current.height();
for(var i = 1; i < words.length; i++){
current.text(current.text() + ' ' + words[i]);
if(current.height() > height){
height = current.height();
// (i-1) is the index of the word before the text wraps
console.log(words[i-1]);
}
}
});
它可能只是工作非常简单。这样做是通过空格分解文本,然后逐字追加单词,观察元素高度的任何增加,这表示换行。
答案 1 :(得分:12)
对于像pdf生成这样的用例。
如果分割出现在中间词中,则可以限制每行的字符数,并进行适当调整。
要获得每行更准确的字符,您可以使用等宽字体,然后确定允许的每种字体的每个字符的宽度。然后将字符宽度除以允许的文本行宽的大小,并为该字体提供每行允许的字符数。
你可以使用非等宽字体,但是你必须测量每个字母的宽度 - 呃。一种可以自动进行宽度猜测的方法是使用没有边距或填充的跨度,为每个字体(和大小)添加每个字符,然后测量跨度的宽度并使用它。
我已经完成了代码:
/**
* jQuery getFontSizeCharObject
* @version 1.0.0
* @date September 18, 2010
* @since 1.0.0, September 18, 2010
* @package jquery-sparkle {@link http://www.balupton/projects/jquery-sparkle}
* @author Benjamin "balupton" Lupton {@link http://www.balupton.com}
* @copyright (c) 2010 Benjamin Arthur Lupton {@link http://www.balupton.com}
* @license Attribution-ShareAlike 2.5 Generic {@link http://creativecommons.org/licenses/by-sa/2.5/
*/
$.getFontSizeCharObject = function(fonts,sizes,chars){
var fonts = fonts||['Arial','Times'],
sizes = sizes||['12px','14px'],
chars = chars||['a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','y','x','z',
'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','Y','X','Z',
'0','1','2','3','4','5','6','7','8','9','-','=',
'!','@','#','$','%','^','&','*','(',')','_','+',
'[',']','{','}','\\','|',
';',"'",':','"',
',','.','/','<','>','?',' '],
font_size_char = {},
$body = $('body'),
$span = $('<span style="padding:0;margin:0;letter-spacing:0:word-spacing:0"/>').appendTo($body);
$.each(fonts, function(i,font){
$span.css('font-family', font);
font_size_char[font] = font_size_char[font]||{};
$.each(sizes, function(i,size){
$span.css('font-size',size);
font_size_char[font][size] = font_size_char[font][size]||{};
$.each(chars,function(i,char){
if ( char === ' ' ) {
$span.html(' ');
}
else {
$span.text(char);
}
var width = $span.width()||0;
font_size_char[font][size][char] = width;
});
});
});
$span.remove();
return font_size_char;
};
/**
* jQuery adjustedText Element Function
* @version 1.0.0
* @date September 18, 2010
* @since 1.0.0, September 18, 2010
* @package jquery-sparkle {@link http://www.balupton/projects/jquery-sparkle}
* @author Benjamin "balupton" Lupton {@link http://www.balupton.com}
* @copyright (c) 2010 Benjamin Arthur Lupton {@link http://www.balupton.com}
* @license Attribution-ShareAlike 2.5 Generic {@link http://creativecommons.org/licenses/by-sa/2.5/
*/
$.fn.adjustedText = function(text,maxLineWidth){
var $this = $(this),
font_size_char = $.getFontSizeCharObject(),
char_width = font_size_char['Times']['14px'],
maxLineWidth = parseInt(maxLineWidth,10),
newlinesAt = [],
lineWidth = 0,
lastSpace = null;
text = text.replace(/\s+/g, ' ');
$.each(text,function(i,char){
var width = char_width[char]||0;
lineWidth += width;
if ( /^[\-\s]$/.test(char) ) {
lastSpace = i;
}
//console.log(i,char,lineWidth,width);
if ( lineWidth >= maxLineWidth ) {
newlinesAt.push(lastSpace||i);
lineWidth = width;
lastSpace = null;
}
});
$.each(newlinesAt,function(i,at){
text = text.substring(0,at+i)+"\n"+text.substring(at+i);
});
text = text.replace(/\ ?\n\ ?/g, "\n");
console.log(text,newlinesAt);
$this.text(text);
return $this;
};
$(function(){
var $body = $('body'),
$textarea = $('#mytext'),
$btn = $('#mybtn'),
$div = $('#mydiv');
if ( $textarea.length === 0 && $div.length === 0 ) {
$body.empty();
$textarea = $('<textarea id="mytext"/>').val('(When spoken repeatedly, often three times in succession: blah blah blah!) Imitative of idle, meaningless talk; used sometimes in a slightly derogatory manner to mock or downplay another\'s words, or to show disinterest in a diatribe, rant, instructions, unsolicited advice, parenting, etc. Also used when recalling and retelling another\'s words, as a substitute for the portions of the speech deemed irrelevant.').appendTo($body);
$div = $('<div id="mydiv"/>').appendTo($body);
$btn = $('<button id="mybtn">Update Div</button>').click(function(){
$div.adjustedText($textarea.val(),'300px');
}).appendTo($body);
$div.add($textarea).css({
'width':'300px',
'font-family': 'Times',
'font-size': '14px'
});
$div.css({
'width':'auto',
'white-space':'pre',
'text-align':'left'
});
}
});
答案 2 :(得分:11)
这是我最终使用的内容(随意批评并复制以用于您自己的邪恶目的)。
首先,当用户进行编辑时,它会被$(editableElement).lineText(userInput)
分解。
jQuery.fn.lineText = function (userInput) {
var a = userInput.replace(/\n/g, " \n<br/> ").split(" ");
$.each(a, function(i, val) {
if(!val.match(/\n/) && val!="") a[i] = '<span class="word-measure">' + val + '</span>';
});
$(this).html(a.join(" "));
};
换行更换是因为编辑文本框中填充了$(editableElement).text()
,忽略了<br/>
个标记,但它们仍然会更改显示中以下行的高度以进行排版。这不是最初目标的一部分,只是相当低调的成果。
当我需要提取格式化文本时,我会调用$(editableElement).getLines()
,其中
jQuery.fn.getLines = function (){
var count = $(this).children(".word-measure").length;
var lineAcc = [$(this).children(".word-measure:eq(0)").text()];
var textAcc = [];
for(var i=1; i<count; i++){
var prevY = $(this).children(".word-measure:eq("+(i-1)+")").offset().top;
if($(this).children(".word-measure:eq("+i+")").offset().top==prevY){
lineAcc.push($(this).children(".word-measure:eq("+i+")").text());
} else {
textAcc.push({text: lineAcc.join(" "), top: prevY});
lineAcc = [$(this).children(".word-measure:eq("+i+")").text()];
}
}
textAcc.push({text: lineAcc.join(" "), top: $(this).children(".word-measure:last").offset().top});
return textAcc;
};
最终结果是一个哈希列表,每个哈希包含一行文本的内容和垂直偏移。
[{"text":"Some dummy set to","top":363},
{"text":"demonstrate...","top":382},
{"text":"The output of this","top":420},
{"text":"wrap-detector.","top":439}]
如果我只想要无格式文字,$(editableElement).text()
仍会返回
"Some dummy set to demonstrate... The output of this wrap-detector."
答案 3 :(得分:7)
如果您有更复杂的结构(例如段落中的链接),则上述解决方案无效(例如,您可以在<b><i><a href></a>
内设置<p>
)。
所以我创建了一个javascript库来检测在这些情况下换行的位置:http://github.com/xdamman/js-line-wrap-detector
我希望这会有所帮助。
答案 4 :(得分:0)
我有一种情况需要在一个范围内包裹每一行。我这样做,以便我可以添加填充高亮效果到文本块。将背景添加到包装文本的span标记只会填充文本块的开头和结尾,每行必须单独包装。
这是我根据上述建议提出的:
$.fn.highlghtWrap = function () {
this.each( function () {
var current = $( this );
var text = current.text();
var words = text.split( ' ' );
var line = '';
var lines = [];
current.text( words[ 0 ] );
var height = current.height();
line = words[ 0 ];
for ( var i = 1; i < words.length; i++ ) {
current.text( current.text() + ' ' + words[ i ] );
if ( current.height() > height ) {
lines.push( line );
line = words[ i ];
height = current.height();
} else {
line = line + ' ' + words[ i ];
}
}
lines.push( line );
current.html( '' );
$.each( lines, function ( v, a ) {
current.html( current.html() + '<span>' + a +
' </span>' );
} );
} );
}
$( '.home-top_wrapper h2' ).highlghtWrap();
$( '.home-top_wrapper p' ).highlghtWrap();
答案 5 :(得分:0)
从概念上讲,一种简单的方法也适用于内部标记以及任意字体和样式的情况,即进行第一遍,将每个单词简单地放入自己的元素(可能是“ SPAN”,也可能是自定义名称,例如“ w”)
然后,您可以使用getBoundingClientRect()进行迭代,以查找“ top”属性的更改位置:
function findBreaks() {
var words = document.getElementsByTagName('w');
var lastTop = 0;
for (var i=0; i<words.length; i++) {
var newTop = words[i].getBoundingClientRect().top;
if (newTop == lastTop) continue;
console.log("new line " + words[i].textContent + " at: " + newTop);
lastTop = newTop;
}
}
这听起来很慢,但是除非文档很大,否则您不会注意到。