9

不知道标题选得好不好……

我正在尝试在 HTML/JS/CSS 中模拟文本选择,以在真正选择文本时摆脱移动设备上的动作气泡。

更具体地说,我试图避免这种情况: 在此处输入图像描述

视觉:

在此处输入图像描述

我构建它的方式可能会改变,因为这无关紧要,选择的文本包含在 aspan.selection和该标记内,还有两个插入符号用作处理程序:

Lorem ipsum dolor                            <!-- Unselected Text -->

<span class="selection">                     <!-- Start selection wrapper -->

  <span rel="previous" class="caret"></span> <!-- The left-side caret -->

  sit amet, consectetur                      <!-- The selected texts -->

  <span rel="next" class="caret"></span>     <!-- The right-side caret -->

</span>                                      <!-- End selection wrapper -->

adipiscing elit.                             <!-- Unselected Text -->

理想情况下,使用拖放来选择更多或更少的文本会很有趣,但我相信这将很难做到,在这种情况下,可能使用单击插入符号来选择上一个或下一个单词并将它包裹在里面.selection不会那么糟糕。

这是jsfiddle:http: //jsfiddle.net/m6Qx4/

周围的文本也可能包含 HTML 标记,例如:<i>、、和<b><span>并且<ul>/<li>可能存在使解析更加困难。

任何想法如何做到这一点?

状态更新:

.click();我实际上已经设法使用我的自定义 jQuery 方法使其与事件侦听器一起工作。

最终,只要它可用于移动设备,我将用可拖动的 jQuery UI 替换点击事件以选择周围的单词。

我当前的错误包括红色插入符号的重新定位。我已经尝试销毁它们并将它们添加/添加回来,但它仍然无法正常工作。更改文本节点后无法正确重新加载 DOM 可能是 Firefox 的错误?

参考: jsFiddle

要检查jsFiddle.net由于最近中断而导致的运行状况,请访问他们的Tweets

4

2 回答 2

2

一些想法:

我看不出将所有内容包装在 a<span>中是一个可行的解决方案。当你有这样的事情时会发生什么?

<p>The <b>important terms</b> will be bolded in this text</p>

当您选择 时The important,您将遇到一些标签混乱,其中<span>标签的主体想要与<b>标签的主体重叠。

我认为更好的解决方案是<span>在同一个类中使用多个选择标签。每次遇到 HTML 标记时,您都会跳过该标记并创建一个新的选择<span>。然后,当您重新定位插入符号时,您只需执行以下操作:

$(".selection:first").prepend(startCaret);
$(".selection:last").append(endCaret);

我玩弄了这个想法,它对我来说效果很好。如果您想变得非常花哨,可以<span>在遇到相应的开始标签后找到结束标签时尝试合并 selection ,但这会做很多工作。


您的插入符号没有正确移动,因为您指定了一种绝对定位样式。将其更改为 relative 并为每个插入符号提供&nbsp;. 您必须使用其他一些定位 CSS 设置才能使其看起来恰到好处,但随着这些更改,它会按照您的预期移动(例如此处)。


当我为此提出一些想法时,我尝试在插入符号上进行绝对定位,这样它们就不必在 selection 内移动<span>。那是个错误。我遇到了段落溢出到没有任何标记的新行的问题。坚持在您的选择中包含插入符号的想法<span>


最后,提出几个思考问题:

  • 你会限制范围吗?(即,如果您开始在<p>标签内选择,请不要让选择溢出该标签之外的下一个<p>或任何后续内容)
  • 某些标签将无法选择吗?(即 , <table>,<script><select>

我认为这个想法很酷,但它可能是一个非常庞大的项目。我会发布一些我尝试过的原型,当我让它们更加完善时。

于 2012-07-03T00:09:49.847 回答
0

为了解决 Rusty 的问题:

首先拆分标签:

var textBlock = textContainer.html(),
taglessArray = textBlock.split(/<[^>]*>/),
arrayOfTags = textBlock.match(/<[^>]*>/g),
tagsFirst = (textBlock[0] === '<') ? true : false, //parens for legibility only
//tagsFirst is a switch that tells us which to start splicing back in later

现在让我们将所有非空白字符包装在我们可以使用的 span 标签中

var i = taglessArray.length;
while(i--){
    taglessArray[i].replace(/([^\s]*)/g,'<span class="selectableWord">$1</span>');
}
//not 100% sure I got that right - haven't tested - but the idea is , wrap all non
//whitespace/word boundary blocks in 'selectableWord' classed span tags

现在把它们粘在一起。原始文本格式标记应保留位置。显然,“selectableWord”分类跨度应该避免布局/格式影响

var addToArray, adderArray;
if(tagsFirst){ addToArray = arrayOfTags; adderArray = taglessArray; }
else { addToArray = taglessArray; adderArray = arrayOfTags; }

var oLen, //used to retain 'original length'
i2 = oLen = (tagsFirst.length + arrayOfTags.length),
rejoinArray = [];

while(i2--){ //not 100% sure I got this right - hope you get the general idea
    var currentKey = oLen - 1 - i2;
    //if first or alternating from first 0,2,4,etc...
    if(currentKey === 0 || ( currentKey % 2 === 0) {
        rejoinArray[currentKey] = addToArray.shift(); //remove first element and return
    }
    //should be keys 1,3,5,etc...
    else {
        rejoinArray[currentKey] = adderArray.shift();
    }
}

当然,以上所有内容都未经测试,可能存在错误/错误,但我认为基本想法非常酷。撕掉标签。将未标记的单词数组包装在您可以使用的跨度中。然后将所有愚蠢的标签拼接回去。它们仍然应该包含所有相同的单词。这假定了基本的 HTML 完整性。您的文本块仅包含围绕单词或单词集的内联显示标签。除非存在不正确的嵌套跨度,否则不正确的嵌套可能不是问题。

于 2012-07-08T01:20:32.663 回答