People who often use Weibo will find that when we enter @ in the input box and then press a person's name, a tip prompt layer will pop up: Out of curiosity about this function, with a learning attitude, I read some materials and then discussed and studied this Javascript. For this function ...,. Weibo users often find that when we enter @ in the input box and then press a person's name, a tip prompt layer will pop up ,:
Out of curiosity about this function, and with a learning attitude, I read some materials and then explored and studied this Javascript.
This function is analyzed as follows:
1. Determine the cursor position
2. Determine the string @ In the textarea text box
3. tip pop-up events
4. keyboard operation events
5. ajax call
6. text insertion
......
Of course, there are other functions.
Is it complicated to look at it? It doesn't matter. Let's analyze it step by step.
First, determine the cursor position of textarea. In W3C, obtaining the cursor position is relatively simple. selectionStart and selectionEnd can be used. IE does not support these two attributes, but IE has another document. selection object, which can simulate the same function. The Code is as follows:
- // First define a basic class to set some global variables
- Function demonAt (opts ){
- This. elem = opts. elem; // text box
- This. at ={}; // temporarily Save the text box content truncation attribute
- This. opt = {};
- This. searched = ""; // used to determine whether the user's input character is the same as the previous one. If it is the same, skip ajax
- This. url = opts. url;
- This. index = 1;
- }
- // Weibo @ Function
- DemonAt. prototype = {
- GetCursor: function (elem ){
- Var _ this = this;
- Var rangeData = {
- Start: 0,
- End: 0,
- Text :""
- };
- If (typeof (this. elem. selectionStart) = "number") {// W3C
- RangeData. start = this. elem. selectionStart; // start position of the cursor
- RangeData. end = this. elem. selectionEnd; // the position at the end of the cursor.
- RangeData. text = this. elem. value. substring (0, this. elem. selectionStart); // obtain the text box value
- } Else if (document. selection) {// IE
- Var sRange = document. selection. createRange ();
- Var oRange = document. body. createTextRange ();
- ORange. moveToElementText (this. elem );
- RangeData. text = sRange. text;
- RangeData. bookmark = sRange. getBookmark ();
- For (I = 0; oRange. compareEndPoints ("StartToStart", sRange) <0 & sRange. moveStart ("character",-1 )! = 0; I ++ ){
- If (this. elem. value. charAt (I) = '\ R '){
- I ++; // special handling of IE. You need to add 1 to the enter key.
- }
- }
- RangeData. start = I;
- RangeData. end = rangeData. text. length + rangeData. start;
- RangeData. text = this. elem. value. substring (0, I );
- }
- // Alert (rangeData. text)
- Return rangeData;
- },
- SetCursor: function (elem, start, end) {// set the cursor
- If (this. elem. setSelectionRange) {// W3C
- This. elem. setSelectionRange (start, end );
- } Else if (this. elem. createRange) {// IE
- Var range = this. elem. createRange ();
- If (this. elem. value. length = rangeData. start ){
- Range. collapse (false );
- Range. select ();
- } Else {
- Range. moveToBookmark (rangeData. bookmark );
- Range. select ();
- }
- }
- },
- Add: function (elem, txtData, nStart, nLen) {// Insert the elements of the text parameter operation, data, start Coordinate Position, user input length
- // This. setCursor (this. elem, this. rangeData );
- This. elem. focus ();
- Var _ range;
- If (this. elem. setSelectionRange) {// W3C
- _ TValue = this. elem. value; // obtain the text box content.
- Var _ start = nStart-nLen, // set the cursor start point cursor position-the text length @
- _ End = _ start + txtData. length, // set the end of the cursor, start + Data Text length
- _ Value = _ tValue. substring (0, _ start) + txtData + "" + _ tValue. substring (nStart, this. elem. value. length );
- This. elem. value = _ value;
- This. setCursor (this. elem, _ end + 1, _ end + 1 );
- } Else if (this. elem. createTextRange ){
- _ Range = document. selection. createRange ();
- _ Range. moveStart ("character",-nLen); // move the cursor
- _ Range. text = txtData + "";
- }
- }
- }
Customizes A rangeData object and saves the cursor position and the string from the cursor position to the start in the textarea box. This object is used in other functions below. Based on the cursor position, you can write the text insert function add (); with the above function, we can judge the @ character in the textarea box, and then locate and pop up the tip layer, if this is determined, we can use the regular expression:
- Var _ reg =/@ [^ @ \ s] {1, 20} $/g;
So positioning is unrealistic if it is determined in textarea, because we cannot obtain the correct left and top values, so we need to simulate a p layer to insert p into the body, locate to the same position as textarea, then obtain the text in textarea, split the string, and add the tag element. In this way, the correct position can be obtained. The following code is more intuitive.
- Var _ string = "" + "@ text above" + "" +"@"+" "+" @ Text "+ "";
Many people should understand this sentence and append this paragraph to the p position of the appeal. In this way, we can
The tag obtains the offset value. So we wrote the following code:
- DemonAt. prototype = {
- Init: function () {// first we need to initialize
- Var _ body = $ ("body ");
- Var _ p = $ (""),
- _ Tip = $ ("");
- _ Body. append (_ p );
- _ Body. append (_ tip );
- Var _ left = $ (this. elem). offset (). left + "px ",
- _ Top = $ (this. elem). offset (). top + "px ",
- _ Width = $ (this. elem). outerWidth () + "px ",
- _ Height = $ (this. elem). outerHeight () + "px ",
- _Lineheight1_1_(this.elemate.css ("line-height "),
- _ Style = "position: absolute; overflow: hidden; z-index:-9999; line-height:" + _ lineHeight + "; width:" + _ width + "; height: "+ _ height +"; left: "+ _ left +"; top: "+ _ top;
- _ P. attr ("style", _ style );
- This. inset ();
- },
- GetAt: function (){
- Var _ rangeData = this. getCursor ();
- Var k = _ value = _ rangeData. text. replace (/\ r/g, ""); // remove the line break
- Var _ reg =/@ [^ @ \ s] {} $/g; // regular expression, which contains @ at the end of the value and is within 20 characters
- Var _ string = "";
- If (_ value. indexOf ("@")> =
- 0 & _ value. match (_ reg )){
- Var _ postion = _ rangeData. start;
- Var _ oValue = _ value. match (_ reg) [0]; // locate the last matched data in the value
- Var vReg = new RegExp ("^" + _ oValue + ". * $", "m"); // Regular Expressions matching data are retained temporarily.
- _ Value = _ value. slice (0, _ postion); // rewrite _ value string truncation from 0 to cursor position
- If (/^ @ [a-zA-Z0-9 \ u4e00-\ u9fa5 _] + $/. test (_ oValue )&&! /\ S/. test (_ oValue )){
- This. at ['M'] = _ oValue. slice (1); // The character entered by the user, such as @ decadent little magic, that is, "decadent little magic"
- This. at ['l'] = _ value. slice (0,-_ oValue. length-1 ); // @
- This. at ['R'] = k. slice (_ postion-_ oValue. length, k. length); // the text following @
- This. at ['pos'] = _ postion; // cursor position
- This. at ['len'] = _ oValue. length; // the length from the cursor position to @, for example, @ decadent little magic, that is, the length of "decadent little magic"
- This. showTip (this. url)
- } Else {// alert (1)
- This. hiddenTip ()
- }
- } Else {
- This. hiddenTip ()
- }
- },
- BuidTip: function () {// create a tip and set the position of the tip.
- Var _ this = this;
- $ ("# TWarp"). empty ();
- Var _ string = "" + this. format (this. at ['l']) + "" +"@"+" "+ This. format (this. at ['R']) + "";
- $ ("# TWarp" pai.html (_ string );
- Var _ left = $ ("# tWarp cite"). offset (). left + "px ",
- _ Top = $ ("# tWarp cite"). offset (). top + parseInt ($ ("# tWarp" line .css ("line-height") + "px ";
- If (parseInt (_ top)> parseInt ($ ("# tWarp"). offset (). top + $ ("# tWarp"). height ())){
- _ Top = $ ("# tWarp"). offset (). top + $ ("# tWarp"). height () + "px ";
- }
- $ ("# TipAt" ).css ({
- "Left": _ left,
- "Top": _ top,
- "Display": "block"
- });
- $ ("# TipAt li"). eq (1). addClass ("on"). siblings (). removeClass ("on ");
- _ This. hover ();
- // Cancel keyup binding, bind keydown, and select keyboard operations to avoid conflicts with text box events
- $ (_ This. elem). unbind ('keyup'). bind ('keylow', function (e ){
- Return _ this. keyMove (e );
- });
- },
- HiddenTip: function (){
- Var _ this = this;
- $ ("# TipAt" ).css ("display", "none ");
- $ ("# TipAt li"). unbind ("click, mouseover ");
- }
- }
Then we add the keyboard operation. Note that we have bound the keyup event when entering text in textarea. To avoid multiple event bindings, we use the keydown event for tip selection.
- DemonAt. prototype = {
- KeyMove: function (e) {// keyboard operation
- Var _ this = this;
- Var _ key = e. keyCode;
- Var _ len = $ ("# tipAt li"). length;
- Switch (_ key ){
- Case 40:
- // Lower
- _ This. index ++;
- If (_ this. index >_len-1 ){
- _ This. index = 1;
- }
- _ This. keyMoveTo (_ this. index );
- // Return false must be added. Otherwise, JS will continue to call keyHandler, so that the keyup event is bound, which affects the keydown event of the keyboard.
- Return false;
- Break;
- Case 38:
- // Upload
- _ This. index --;
- If (_ this. index <1 ){
- _ This. index = _ len-1;
- }
- _ This. keyMoveTo (_ this. index );
- Return false;
- Break;
- Case 13:
- // Enter
- Var txtData = $ (". on"). text ();
- _ This. add (_ this. elem, txtData, _ this. at ['pos'], _ this. at ['len'])
- _ This. keyHandler ()
- Return false;
- Break;
- Default:
- };
- _ This. keyHandler ();
- },
- KeyHandler: function (){
- Var _ this = this;
- _ This. index = 1;
- // Rebind the keyup key after the enter keyboard operation
- $ (_ This. elem). unbind ("keydown"). bind ("keyup", function (){
- _ This. getAt ();
- })
- },
- KeyMoveTo: function (index ){
- $ ("# TipAt li"). removeClass ("on"). eq (index). addClass ("on ");
- }
- }
Then, add the Click Event and hover event of the tip.
- DemonAt. prototype = {
- Inset: function () {// bind an event to li,
- Var _ this = this;
- $ ("# TipAt"). delegate ("li", "click", function () {// event delegate
- If ($ (this). index () = 0 ){
- _ This. elem. focus ();
- Return false;
- } Else {
- Var txtData = $ (this). text ();
- _ This. add (_ this. elem, txtData, _ this. at ['pos'], _ this. at ['len'])
- _ This. hiddenTip ()
- }
- })
- },
- Hover: function (){
- // Hover event
- Var _ this = this;
- $ ("# TipAt li: not (: first)"). hover (function (){
- _ This. index = $ (this). index ();
- $ (This). addClass ("hover"). siblings (). removeClass ("on hover ")
- }, Function (){
- $ (This). removeClass ("hover ");
- })
- }
- }
Here, the @ function of Weibo has been fully explained. I hope you can understand it clearly.