Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống
1
/ 15 trang
THÔNG TIN TÀI LIỆU
Thông tin cơ bản
Định dạng
Số trang
15
Dung lượng
484,99 KB
Nội dung
Licensed to JamesCarlson@aol.com 172 jQuery: Novice to Ninja chapter_05/17_simple_tooltips/script.js (excerpt) // Mouse move code $('.tooltip') .css('top', (e.pageY - 10) + 'px') .css('left', (e.pageX + 20) + 'px'); Finally, we need to respond to mouse movement by updating the tooltip’s location. This way the tooltip will follow the mouse around, just like the browser’s built-in tooltips do. And presto! We’ve replaced the default tooltips with our own, and we’re fully in control of their appearance and animation. Advanced Tooltips It’s good to know how to build a simple tooltip, but we also know that we can do better. For more sophisticated tooltips, which can include other markup (such as images or links) inside the content, we’ll need to move them from the title attribute into our actual markup. We’ll hide them with CSS, then reveal and position them using jQuery as required. The final effect is illustrated in Figure 5.11. Figure 5.11. Our advanced tooltip Our tooltip markup will consist of two nested span elements, which will sit inside the element we want to use to trigger the tooltip. This may occasionally require some creativity with your markup, but helps us to position the tooltip, as we can give it an absolute position offset from the parent element. It also helps us handle triggering events, since, if the user moves the mouse over the tooltip, it will still be over the triggering element, so no additional hover event handling is required. Here’s an example of the tooltip markup: Licensed to JamesCarlson@aol.com Licensed to JamesCarlson@aol.com Menus, Tabs, Tooltips, and Panels 173 chapter_05/18_advanced_tooltips/index.html (excerpt) <p> Welcome to <strong>StarTrackr! <span class='tooltip'> <span><a href='#'>Legal Disclaimer</a></span> </span> </strong> the planet's premier celebrity tracking … </p> When we’re done, the tooltip will look great and will contain a link to the disclaimer page. But let’s not hang around; we’ve considered a few tooltip methods, so let’s drive straight in. As we’ll see when we start writing the code, our tooltip will be quite clever, posi- tioning itself on whichever side of the target element that has enough room for it to be displayed. In order to make a cool text-bubble graphic work in this context, we’ll need four different bubbles: above-left, above-right, below-left, and below- right. We’ll be using a single sprite for each of the tooltip’s four possible states, as illustrated in Figure 5.12. Figure 5.12. Our tooltip sprite These tooltips require some fairly complex jQuery code. We’ll go over it bit by bit, but don’t worry if you have trouble understanding all of it right now. There’s a bit of a leap from writing quick two- or three-line scripts which replace and highlight content on the page to writing a more complex UI widget. At the beginning of the next chapter, we’ll have a look at some of the ways we can try to minimize complex- ity and keep our code readable, even as it becomes longer and more involved. Licensed to JamesCarlson@aol.com Licensed to JamesCarlson@aol.com 174 jQuery: Novice to Ninja For the moment, try to focus on seeing the bits of jQuery you already know employed in a larger context; this should give you an idea of how you can go about combining small pieces of logic into a larger picture that performs really impressively. Our first task is to create a TT object that will contain all our code. We set a delay variable at the top of the object (this will make it easier to modify the configuration of the widget without hunting through the code to find where this variable was set): chapter_05/18_advanced_tooltips/script.js (excerpt) var TT = { delay: 600, Then we add a function called setTips, which we’ll run when the page loads or is resized. This function will find all the tooltips on the page and determine their position by looking at their parent elements. It will also set up a hover event on each of them so that they’re displayed on mouseover. Here’s the hover event: chapter_05/18_advanced_tooltips/script.js (excerpt) setTips: function() { $('.tooltip').parent().hover(function() { // store the tooltip being hovered TT.current = $(this); TT.timer = setTimeout(function() { // find the tooltip, TT.current.find(".tooltip").fadeIn('fast'); }, TT.delay); }, function() { // on mouseout, clear timer and hide tooltip clearTimeout(TT.timer); $(this).find(".tooltip").fadeOut('fast'); }).attr("title", ""); // clear the title to stop browser tooltips That’s a fairly dense block of code, so let’s see if we can make some sense of what’s happening: We’ve attached the hover event to the parent of the tooltip span. If you look back at the markup, you’ll see this is correct: we put the tooltip inside the ele- ment we want to attach it to. Licensed to JamesCarlson@aol.com Licensed to JamesCarlson@aol.com Menus, Tabs, Tooltips, and Panels 175 We store a reference to that parent element inside a variable. What’s unusual here is that we’re using a property of our TT object instead of a global variable. We’ll come back to this in the next chapter, but for now just know that it’s much the same as writing var current = $(this);. We’re using the familiar setTimeout function, except that this time we’re saving the timer to a variable. This is so we can turn it off by name if we need to. We’re accessing the delay property we set before as the second parameter for setTimeout. As we’ve seen, this is how long the browser will wait before dis- playing the tooltip. When the user mouses off the target, we want to stop the timer so that the tooltip will stay hidden after the delay expires. We do this with the JavaScript clearTimeout method, passing in the reference to our timer. Okay, so now that our hover handler is set up, we need to determine the position of each of our tooltips. We’ll use each() to loop over them, but first we’ll grab the height and width of the screen. If we were to do this inside the loop, jQuery would need to calculate those values once for each tooltip, even though they’re always the same. By storing the values outside the loop, we avoid this wasteful calculation and improve the performance of our script: Licensed to JamesCarlson@aol.com Licensed to JamesCarlson@aol.com 176 jQuery: Novice to Ninja chapter_05/18_advanced_tooltips/script.js (excerpt) var screenWidth = $(window).width(); var screenBottom = $(window).scrollTop() + $(window).height(); $(".tooltip").each(function() { // grab the containing element $container = $(this).parent(); // give it relative position if required if ($container.css("position") != 'absolute' && $container.css("position") != "fixed") { $container.css({position: 'relative'}); } var totalHeight = $container.height() + $(this).outerHeight(); var width = $(this).outerWidth(); var offset = $container.offset(); // now we get the position the tip var top = $container.height(); // default placement var left = 0; This part of the code should be a little easier to understand. We loop over each tooltip on the page, and first store a reference to the container element just to avoid having to write $(this).parent() over and over. Notice that the variable name starts with $: this is just to help us remember that the variable contains a jQuery selection. Here’s a breakdown of the contents of the loop: We check to see if the parent element has position: absolute; or position: fixed; . It has to be positioned, since we’ll be using position: absolute; to offset the tooltip from it. If it already has absolute or fixed, we’ll leave it that way. If it doesn’t, though, we’ll give it position: relative;. We need to know the total combined height of both the tooltip and the parent element, so we store that in a variable to use later. By default, we give the tooltip a top position equal to the height of the container. This means it will appear directly below the container (since it is offset from the top by exactly the container’s height). Licensed to JamesCarlson@aol.com Licensed to JamesCarlson@aol.com Menus, Tabs, Tooltips, and Panels 177 Logical Operators In JavaScript, when you’re testing for values in an if statement, you can use the && operator to mean and. So in the above example, the contents of the if block will only execute if both conditions (on either side of &&) are met. You can also write || (two pipe symbols) to mean or. If we’d used that instead of && above, the contents of the if block would execute if either condition was met. This is good work so far! We’re almost done, but we need to fix one small problem: what if the tooltip’s position takes it off the screen? If the target element is right at the bottom of the screen, and we want the tooltip to appear below it, the tooltip will remain unseen! It’s time for a little collision detection. We need to find out if the tooltip is hitting either the bottom or right edge of the screen. Let’s have a look at how we accomplish this: chapter_05/18_advanced_tooltips/script.js (excerpt) // re-position if it's off the right of the screen if (offset.left + width > screenWidth) { left = 0 - width + 42; $(this).addClass('left'); } else { $(this).removeClass('left'); } // re-position if it's off the bottom of the screen if (offset.top + totalHeight > screenBottom) { top = 0 - $(this).outerHeight(); $(this).addClass('above'); } else { $(this).removeClass('above'); } We check to see if the tip’s horizontal or vertical offset, plus its width or height, is greater than the width or height of the screen (which we calculated earlier). If it is, we modify the top or left property respectively, and assign a class that we’ll use to display the appropriate part of our background image sprite. Licensed to JamesCarlson@aol.com Licensed to JamesCarlson@aol.com 178 jQuery: Novice to Ninja The final (and easiest) step is to use the css action to assign the calculated top and left properties to the tips: chapter_05/18_advanced_tooltips/script.js (excerpt) $(this).css({ "top": top, "left": left }); We’ll call our setTips method on document-ready, and also each time the window is resized, to ensure that our tips are always adequately positioned: chapter_05/18_advanced_tooltips/script.js (excerpt) $(document).ready(function() { TT.setTips(); }); $(window).resize(function() { TT.setTips(); }); With that code in place, we just need to add some CSS to position our background sprite appropriately, based on the classes we assigned: chapter_05/18_advanced_tooltips/tooltip.css (excerpt) span.tooltip.left { background-position: 100% 0; } span.tooltip.left span { padding: 15px 0 0 17px; } span.tooltip.above { background-position: 0 100%; } span.tooltip.above span { padding: 13px 0 0 12px; } Licensed to JamesCarlson@aol.com Licensed to JamesCarlson@aol.com Menus, Tabs, Tooltips, and Panels 179 span.tooltip.above.left { background-position: 100% 100%; } span.tooltip.above.left span { padding: 13px 0 0 17px; } IE6 Support Although jQuery does a fantastic job of handling cross-browser issues in our JavaScript code, it’s not so good for our CSS. The above style rules rely on chaining several class selectors together. This will confuse Internet Explorer 6, which will only see the last class in any style rule. Moreover, our PNG image relies on alpha-channel transparency for the tooltip’s drop shadow, and this is also unsup- ported by IE6. Over the last few years, several major sites (including YouTube and Facebook) began phasing out support for IE6. This doesn’t mean that they totally ignore this browser, rather that they accept that IE6 users will receive a degraded experience (perhaps similar to what visitors without JavaScript will see). For our tooltip example, we could use conditional comments 5 to target some styles specifically to IE6 and provide it with the same tooltip functionality—except using a flat background image without a thought-bubble style or a drop shadow. This way, the background position would be inconsequential, and the PNG issue solved. And there you have it! The final tooltip not only waits to see if you really meant for it to display, but it also shifts its position to make sure it’s fully visible whenever it does display! Because we’ve avoided linking this code to anything specific on our page, it’s easy to reuse this script on any other page—you just need to include a few spans with a tooltip class, and you’re off to the races. This is an important lesson: you should always try to structure your code in such a way that you can reuse it later. This will save you work in the long run, and give you more time to experiment with cool new functionality instead of rebuilding the same old widgets every time you need them. 5 http://reference.sitepoint.com/css/conditionalcomments/ Licensed to JamesCarlson@aol.com Licensed to JamesCarlson@aol.com 180 jQuery: Novice to Ninja Order off the Menu Whew! That was a hard sprint to the finish line. Over the course of this chapter, we’ve ramped up our jQuery know-how and used it to move beyond simple hiding and revealing, and well into the territory of the true UI ninja. You’ve learned how to reduce complexity on the screen by packaging up links and widgets into collapsing menus, accordions, panels, and tooltips. In the next chapter, we’ll look at reducing complexity in our code, and then tackle what’s ostensibly the most important part of jQuery: Ajax! Licensed to JamesCarlson@aol.com Licensed to JamesCarlson@aol.com Chapter 6 Construction, Ajax, and Interactivity Throughout the preceding chapters we’ve wowed and dazzled our client with a cornucopia of visual effects and optical magic tricks, giving his site a lifelike appear- ance. Unfortunately, our client is becoming savvy: as well as wanting his pages looking Web 2.0, he wants them acting Web 2.0 as well. And having pages act Web 2.0 means one thing: Ajax! And not just a little bit—he wants the works: inline text editing, Twitter widgets, endlessly scrolling image galleries … he wants StarTrackr! to have more Ajax-enabled bells and whistles than Facebook, Flickr, and Netvibes combined. That’s fine by us. Implementing client-side Ajax functionality is easy, especially with jQuery as our framework. But these cool new features come at a cost of increased complexity. Some simple tasks (such as loading in a snippet of HTML) are no problem—but as we start to tackle the business of creating advanced Ajax compon- ents, the risk of making a mess of unmaintainable spaghetti code grows large. So before we jump into the deep end, we’ll review some ways we can manage complex- ity, and write well-behaved code that will impress our peers. Licensed to JamesCarlson@aol.com [...]... able to easily pass it around and use it however we like To access any one of an object’s values, we simply need to type the object’s name, followed by a period (.), followed by the key associated with that value we wish to access For example, given the data object defined above, if you wanted to Licensed to JamesCarlson@aol.com Licensed to JamesCarlson@aol.com Map Objects 184 jQuery: Novice to Ninja... 3.14159; TRKR.css = { "color": "#c0ffee", "top": 0 }; TRKR.exclaim = function () { alert("hooray"); }; Licensed to JamesCarlson@aol.com Licensed to JamesCarlson@aol.com function exclaim () { alert("booooo"); } exclaim();// booooo 186 jQuery: Novice to Ninja Now we can still let out a buoyant “hooray,” but there’s much less chance of other code stepping on our toes: TRKR.exclaim (); // hooray TRKR.namespaces;... helpful the name is, the more successful it will be We’re looking to avoid clashes in function names, so making namespaces that are likely to clash will only escalate the problem TRKR would be a good choice for StarTrackr! It’s short, helpful in that it alludes back to our site name, and fairly unique Licensed to JamesCarlson@aol.com Licensed to JamesCarlson@aol.com Even the nicest of libraries still lets... you write the nastiest of spaghetti code—and jQuery is no exception Sorting through 20 pages of hover and toggle commands will end up driving you crazy, so to save your sanity you’ll want to group logical chunks of code together Construction, Ajax, and Interactivity 185 Here’s what we’re looking to avoid Say you have a function named exclaim: function exclaim () { alert("hooray"); } exclaim();// hooray... code: // Assign the value '3' to the variable 'count': var count = 3; Licensed to JamesCarlson@aol.com Licensed to JamesCarlson@aol.com jQuery has greatly simplified the process of dealing with Ajax and the DOM, but it hasn’t changed the benefits of writing nice clean JavaScript code There’s no need for us to become masters of JavaScript—but there are a few steps we should take to ensure we’re writing the... contains functions, as well as static variables So when we wrote setTips: function() { … }, we were assigning that function to the setTips property of the TT object Once that’s done, we can write TT.setTips() to execute the function Now every function we write that has to do with tooltips can be contained inside TT Because the only object we’re declaring in the global scope (more on this in a second)...182 jQuery: Novice to Ninja Construction and Best Practices JavaScript is a wonderful language Don’t let anyone tell you any different Its his torically poor reputation stems from years of misunderstanding and misuse: an al most infinite collection of inline scripts, displaying... Chapter 2 We use them to pass multiple options into a single jQuery action, for example: $('p').css({color:'green', padding:'3px'}); They aren’t special jQuery constructs—once again, it’s just plain old JavaScript—but they’re great for encapsulating data to pass around in your own functions and widgets For example, if you pull data out from some form fields, you can package them up into key/value mapped... Developers have begun to respect (and con quer) the language, and the result has been some great code libraries—including our favorite, jQuery Cleaner jQuery We’ve done a fairly good job of steering clear of any involved JavaScript code—that’s a testament to how good jQuery is at doing what it does But as our jQuery compon ents and effects grow more complex, we need to start thinking about how to best structure... is just JavaScript—so it’ll serve us well to steal a few best practices from the world of JavaScript We already saw a bit of this kind of code organization when we built our advanced tooltip script at the end of Chapter 5 Now let’s reveal the whys and hows of writing cleaner jQuery code Code Comments Just like HTML and CSS, JavaScript provides you with a way to comment your code Any line that you begin . We need to know the total combined height of both the tooltip and the parent element, so we store that in a variable to use later. By default, we give the tooltip a top position equal to the. wish to access. For example, given the data object defined above, if you wanted to Licensed to JamesCarlson@aol.com Licensed to JamesCarlson@aol.com 184 jQuery: Novice to Ninja check to see. easiest) step is to use the css action to assign the calculated top and left properties to the tips: chapter_05/18_advanced_tooltips/script.js (excerpt) $(this).css({ "top": top, "left":