Twitter 如何实现其推文框? [英] How does Twitter implement its Tweet Box?

查看:99
本文介绍了Twitter 如何实现其推文框?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试实现类似 Twitter 的推文框之类的东西,具体来说:

  • 当总长度超过 140 个字符时,自动以红色背景突出显示文本.
  • 自动以蓝色突出显示链接、提及和主题标签.

这些应该在用户输入时自动发生.

根据我在 Twitter 上看到的语义标记,看起来他们正在使用 contentEditable div.每当检测到提及/主题标签/链接时,或者当长度超过 140 个字符时,就会修改里面的 DOM:

<div aria-labelledby="tweet-box-mini-home-profile-label" id="tweet-box-mini-home-profile" class="tweet-box rich-editor notie"contenteditable="true" spellcheck="true" role="textbox" aria-multiline="true" dir="ltr" aria-autocomplete="list" aria-expanded="false" aria-owns="typeahead-dropdown-6"><div>hello world <a class="twitter-atreply Pretty-link" href="/testMention" role="presentation"><s>@</s>testMention</a>text <a href="/search?q=%23helloWorld" class="twitter-hashtag Pretty-link" role="presentation"><s>#</s>helloWorld</a>文本 <a href="http://www.google.com" class="twitter-timeline-link" role="presentation">http://www.google.com</a>文字文字文字文字文字文字文字文字文字文字文字文字<em>溢出红色文字在这里</em>

到目前为止我所做的

目前,我使用的是 contentEditable 字段.它触发一个函数 onChange/onInput 来解析文本.通过 regexr 检查它是否有用户名/链接/主题标签并将它们替换为相应的标签(我现在只是使用一个简单的 标签来包含用户名和主题标签).我遇到的问题是,因为我正在更改/修改 contentEditable 的 DOM,插入符号光标位置会丢失.我看了这个帖子 坚持更改在 HTML 中选择后的范围对象,并且仅当 DOM 未更改时它才能正常工作(在我的情况下,用 <i> 标签、链接围绕标签/主题标签使用 标签,并使用 标签溢出.

小提琴:http://jsfiddle.net/4Lsqjkjb/

有没有人有任何替代解决方案/方法来解决这个问题?也许我不应该使用 contentEditable?或者某种不直接修改 contentEditable 字段的 DOM 以便保持插入符号位置的方法?任何帮助,将不胜感激!我尝试使用 window.getSelection() 并在 DOM 更改之前保存它,但它似乎总是在应用 DOM 更改后重置.

解决方案

我所做的是一种黑客行为,但作为一种变通解决方案非常有效.

我有一个简单的 textarea(因为接下来会发生什么,所以不满意,我将在下面解释)和一个绝对位于 textarea 后面的 div.使用 javascript,我将内容从 textarea 复制到 div,同时将其拆分为 140 个字符并将所有额外字符放入 <em/> 标记中.

嗯,这有点复杂,因为计算推文长度的 Twitter 算法不同(由于 t.co 网址缩短,链接不计为它们的实际价值).确切的方法可以在官方 twitter/twitter-txt 存储库.

分步代码.

将一个简单的 textarea 包装成一个 div 以简化 css:

<textarea class="editor-textarea js-keeper-editor">这是一些超过20个字符时会高亮显示的文本.就像推特一样.输入一些东西...</textarea><div class="js-keeper-placeholder-back"></div>

CSS 只是将 textarea 和 div 放在彼此的正上方并突出显示文本.

.tweet-composer {位置:相对;z-索引:1;}.js-keeper-编辑器,.js-keeper-placeholder-back {背景:透明;边框:1px 实心 #eee;字体系列:Helvetica、Arial、sans-serif;字体大小:14px;/* 两者的字体相同.*/保证金:自动;最小高度:200px;大纲:无;填充:10px;宽度:100%;}.js-keeper-placeholder-back {底部:0;颜色:透明;左:0;位置:绝对;顶部:0;空白:预包装;宽度:100%;自动换行:断字;z-索引:-1;}.js-keeper-placeholder-back em {背景:#fcc !重要;}

现在是有趣的部分,这是使用 jQuery 实现的,但这不是重要的事情.

if (0 >剩余长度) {//如果大于,则拆分值var allowedValuePart = currentValue.slice(0, realLength),被拒绝的价值部分 = currentValue.slice(realLength);//填充隐藏的 div.$placeholderBacker.html(allowedValuePart + '' + deniedValuePart + '');} 别的 {$placeholderBacker.html('');}

在更改时添加一些事件处理程序,并准备好通用文档,您就完成了.请参阅下面的代码笔链接.

注意后面的div也可以用js创建,加载页面时:

//创建一个将隐藏在占位符后面的伪元素.var $placeholderBacker = $('<div class="js-keeper-placeholder-back"></div>');$placeholderBacker.insertAfter($textarea);

完整示例

在此处查看工作示例:http://codepen.io/hussard/pen/EZvaBZ

I'm trying to implement something like Twitter's tweet box, specifically:

  • Automatically highlights text in a red background when the overall length exceeds 140 characters.
  • Automatically highlights links, mentions, and hashtags in blue.

These should happen automatically aka when a user types.

By the semantic markup I'm seeing on Twitter, it looks like they're using a contentEditable div. And the DOM inside is modified whenever a mention/hashtag/link is detected, or when the length is exceeded over 140 characters:

<div aria-labelledby="tweet-box-mini-home-profile-label" id="tweet-box-mini-home-profile" class="tweet-box rich-editor  notie" contenteditable="true" spellcheck="true" role="textbox" aria-multiline="true" dir="ltr" aria-autocomplete="list" aria-expanded="false" aria-owns="typeahead-dropdown-6">
    <div>hello world <a class="twitter-atreply pretty-link" href="/testMention" role="presentation"><s>@</s>testMention</a> text <a href="/search?q=%23helloWorld" class="twitter-hashtag pretty-link" role="presentation"><s>#</s>helloWorld</a> text <a href="http://www.google.com" class="twitter-timeline-link" role="presentation">http://www.google.com</a> text text text text text text text text text text text text text text <em>overflow red text here</em>
    </div>
</div>

What I have done so far

Currently, I'm using a contentEditable field. It triggers a function onChange/onInput that parses the text. Check if it has a username/link/hashtag via regexr and replace them with the respective tags (I'm just using a simple <i> tag to enclose username and hashtag for now). The problem I'm having is that because I'm changing/modifying the DOM of the contentEditable, the caret cursor position becomes lost. I looked at this thread Persisting the changes of range objects after selection in HTML and it works fine only if the DOM isn't changed (which it is in my case, surrounding tags/hashtags with <i> tags, links with <a> tags, and overflow with <b> tags.

Fiddle: http://jsfiddle.net/4Lsqjkjb/

Does anyone have any alternative solutions/approaches on how to tackle this problem? Maybe I shouldn't use contentEditable? Or some way that doesn't directly modify the DOM of the contentEditable field so the caret position is maintained? Any help would be appreciated! I tried playing around with window.getSelection() and saving it before DOM change, but it always seem to reset after DOM changes are applied.

解决方案

What I did is kind of a hack but works quite well as a workaround solution.

I've got a simple textarea (not contenteditable because of what's next, I'll explain below) and a div which is absolute positioned behind the textarea. Using javascript, I copy the content from the textarea to the div while splitting it at 140 chars and putting all extra characters inside an <em /> tag.

Well, it's a little bit more complicated because twitter algorithm to compute a tweet length is different (links doesn't count as their real value, because of t.co url shortening). The exact method can be found as part of the official twitter/twitter-txt repository.

Step-by-step code.

Wrap a simple textarea into a div to simplify the css:

<div class="tweet-composer">
  <textarea class="editor-textarea js-keeper-editor">This is some text that will be highlight when longer than 20 characters. Like twitter. Type something...</textarea>
  <div class="js-keeper-placeholder-back"></div>
</div>

CSS is just making the textarea and the div right above each other and highlight the text.

.tweet-composer {
  position: relative;
  z-index: 1;
}

.js-keeper-editor,
.js-keeper-placeholder-back {
  background: transparent;
  border: 1px solid #eee;
  font-family: Helvetica, Arial, sans-serif;
  font-size: 14px; /* Same font for both. */
  margin: auto;
  min-height: 200px;
  outline: none;
  padding: 10px;
  width: 100%;
}

.js-keeper-placeholder-back {
  bottom: 0;
  color: transparent;
  left: 0;
  position: absolute;
  top: 0;
  white-space: pre-wrap;
  width: 100%;
  word-wrap: break-word;
  z-index: -1;
}

.js-keeper-placeholder-back em {
  background: #fcc !important;
}

Now the fun part, this is implemented using jQuery but that's not the important thing.

if (0 > remainingLength) {
  // Split value if greater than 
  var allowedValuePart = currentValue.slice(0, realLength),
      refusedValuePart = currentValue.slice(realLength)
  ;

  // Fill the hidden div.
  $placeholderBacker.html(allowedValuePart + '<em>' + refusedValuePart + '</em>');
} else {
  $placeholderBacker.html('');
}

Add some event handler on change, and te common document ready and you're done. See the codepen link below.

Note that the div placed behind can be created using js too, when loading the page:

// Create a pseudo-element that will be hidden behind the placeholder.
var $placeholderBacker = $('<div class="js-keeper-placeholder-back"></div>');
$placeholderBacker.insertAfter($textarea);

Full example

See working example over here: http://codepen.io/hussard/pen/EZvaBZ

这篇关于Twitter 如何实现其推文框?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆