1. Trang chủ
  2. » Công Nghệ Thông Tin

Practical prototype and scipt.aculo.us part 7 potx

6 267 0
Tài liệu đã được kiểm tra trùng lặp

Đang tải... (xem toàn văn)

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Định dạng
Số trang 6
Dung lượng 93,03 KB

Các công cụ chuyển đổi và chỉnh sửa cho tài liệu này

Nội dung

$A: Coercing Collections into Arrays Oftentimes in JavaScript, you’ll have to work with a collection that seems like an array but really isn’t.. The two major culprits are DOM NodeLists

Trang 1

if (person.country == "USA") {

Object.extend(data, {

socialSecurityNumber: "456-78-9012",

stateOfResidence: "TX",

standardTaxDeduction: true,

zipCode: 78701

});

}

Since objects are passed by reference, not value, the sourceobject is modified

in place

Object.extendalso solves our typing woes when extending built-ins:

Object.extend(String.prototype, {

strip: function() {

//

},

gsub: function() {

//

},

times: function() {

//

},

toQueryParams: function() {

//

}

});

for (var i in String.prototype)

console.log(i);

//-> "strip", "gsub", "times", "toQueryParams"

That’s one annoyance out of the way This construct cuts down on redundancy,

making code both smaller and easier to read Prototype uses Object.extendall over

the place internally: extending built-ins, “mixing in” interfaces, and merging default

options with user-defined options

Trang 2

WHY NOT USE OBJECT.PROTOTYPE.EXTEND?

If we were steadfastly abiding by JavaScript’s object orientation, we’d define Object.prototype extend, so that we could say the following:

var data = { height: "5ft 10in", hair: "brown" };

data.extend({

socialSecurityNumber: "456-78-9012",

stateOfResidence: "TX"

});

This may appear to make things easier for us, but it will make things much harder elsewhere Because properties defined on the prototypes of objects are enumerated in a for inloop, augment-ing Object.prototypewould “break” hashes:

for (var property in data)

console.log(property);

//-> "height", "hair", "socialSecurityNumber", "stateOfResidence", "extend" There are ways around this, but they all involve changing the way we enumerate over objects And we’d be breaking a convention that’s relied upon by many other scripts that could conceivably exist in the same environment as Prototype In the interest of “playing well with others,” nearly all modern JavaScript libraries abide by a gentleman’s agreement not to touch Object.prototype

$A: Coercing Collections into Arrays

Oftentimes in JavaScript, you’ll have to work with a collection that seems like an array but

really isn’t The two major culprits are DOM NodeLists (returned by getElementsByTagName and other DOM methods) and the magic argumentsvariable within functions (which con-tains a collection of all the arguments passed to the function)

Both types of collections have numeric indices and a lengthproperty, just like arrays—but because they don’t inherit from Array, they don’t have the same methods that arrays have For most developers, this discovery is sudden and confusing

$Aprovides a quick way to get a true array from any collection It iterates through the collection, pushes each item into an array, and returns that array

Trang 3

The arguments Variable

When referenced within a function, argumentsholds a collection of all the arguments

passed to the function It has numeric indices just like an array:

function printFirstArgument() {

console.log(arguments[0]);

}

printFirstArgument('pancakes');

//-> "pancakes"

It isn’t an array, though, as you’ll learn when you try to use array methods on it.

function joinArguments() {

return arguments.join(', ');

}

joinArguments('foo', 'bar', 'baz');

//-> Error: arguments.join is not a function

To use the joinmethod, we first need to convert the argumentsvariable to an array:

function joinArguments() {

return $A(arguments).join(', ');

}

joinArguments('foo', 'bar', 'baz');

//-> "foo, bar, baz"

DOM NodeLists

A DOM NodeListis the return value of any DOM method that fetches a collection of

elements (most notably getElementsByTagName) Sadly, DOM NodeLists are nearly

use-less They can’t be constructed manually by the user They can’t be made to inherit

from Array And the same cross-browser issues that make it hard to extend HTMLElement

also make it hard to extend NodeList

Any Prototype method that returns a collection of DOM nodes will use an array

But native methods (like getElementsByTagName) and properties (like childNodes) will

return aNodeList Be sure to convert it into an array before you attempt to use array

methods on it

// WRONG:

var items = document.getElementsByTagName('li');

items = paragraphs.slice(1);

//-> Error: items.slice is not a function

Trang 4

// RIGHT:

var items = $A(document.getElementsByTagName('li'));

items = items.slice(1);

//-> (returns all list items except the first)

$$: Complex Node Queries

The richness of an HTML document is far beyond the querying capabilities of the basic DOM methods What happens when we need to go beyond tag name queries and fetch elements by class name, attribute, or position in the document?

Cascading Style Sheets (CSS) got this right CSS, for those of you who don’t have design experience, is a declarative language for defining how elements look on a page The structure of a CSS file consists of selectors, each with a certain number of rules

(i.e., “The elements that match this selector should have these style rules.”) A CSS file,

if it were obsessively commented, might look like this:

body { /* the BODY tag */

margin: 0; /* no space outside the BODY */

padding: 0; /* no space inside the BODY */

}

a { /* all A tags (links) */

color: red; /* links are red instead of the default blue */

text-decoration: none; /* links won't be underlined */

}

ul li { /* all LIs inside a UL */

background-color: green;

}

ul#menu { /* the UL with the ID of "menu" */

border: 1px dotted black; /* a dotted, 1-pixel black line around the UL */ }

ul li.current {

/* all LIs with a class name of "current" inside a UL */

background-color: red;

}

Trang 5

To put this another way, one side of our problem is already solved: in CSS, there

exists a syntax for describing specific groups of nodes to retrieve Prototype solves the

other side of the problem: writing the code to parse these selectors in JavaScript and

turn them into collections of nodes

The $$function can be used when simple ID or tag name querying is not powerful

enough Given any number of CSS selectors as arguments, $$will search the document

for all nodes that match those selectors

$$('li'); // (all LI elements)

//-> [<li class="current" id="nav_home">, <li id="nav_archives">,

<li id="nav_contact">, <li id="nav_google">]

$$('li.current'); // (all LI elements with a class name of "current")

//-> [<li class="current" id="nav_home">]

$$('#menu a'); // (all A elements within something with an ID of "menu")

//-> [<a href="/">, <a href="/archives">, <a href="/contact">,

<a href="http://www.google.com" rel="external">]

There are two crucial advantages $$has over ordinary DOM methods The first is

brevity: using $$cuts down on keystrokes, even for the simplest of queries

// BEFORE:

var items = document.getElementsByTagName('li');

// AFTER:

var items = $$('li');

As the complexity of your query increases, so does the savings in lines of code $$

can be used to fetch node sets that would take many lines of code to fetch otherwise:

// find all LI children of a UL with a class of "current"

// BEFORE:

var nodes = document.getElementsByTagName('li');

var results = [];

for (var i = 0, node; node = nodes[i]; i++) {

if (node.parentNode.tagName.toUpperCase() == 'UL' &&

node.className.match(/(?:\s*|^)current(?:\s*|$)) {

results.push(node);

}

}

// AFTER:

var results = $$('ul > li.current');

Trang 6

The second advantage is something we’ve talked about already: the nodes returned

by $$are already “extended” with Prototype’s node instance methods

If you’re a web designer, you’re likely familiar with CSS, but the power of $$goes far beyond the sorts of selectors you’re likely accustomed to $$supports virtually all of CSS3 syntax, including some types of selectors that you may not have encountered:

• Querying by attribute:

• $('input[type="text"]')will select all text boxes

• $$('a[rel]')will select all anchor tags with a relattribute

• $$('a[rel~=external])will select all aelements with the word “external” in the relattribute

• Querying by adjacency:

• $$('ul#menu > li') li') selector>will select all lielements that are direct children of ul#menu

• $$('li.current + li')will select any lisibling that directly follows a li.currentin the markup

• $$('li.current ~ li')will select all the following siblings of a li.current element that are lielements themselves

• Negation:

• $$('ul#menu li:not(.current)')will select all lielements that don’t have a

class name of current

• $$('ul#menu a:not([rel])')will select all aelements that don’t have arel attribute

These are just some of the complex selectors you can use in $$ For more information

on what’s possible, consult the Prototype API reference online (http://prototypejs.org/ api/) We’ll encounter other complex selectors in some of the code we’ll write later in this book

Ngày đăng: 03/07/2014, 01:20

TỪ KHÓA LIÊN QUAN