Java程序辅导

C C++ Java Python Processing编程在线培训 程序编写 软件开发 视频讲解

客服在线QQ:2653320439 微信:ittutor Email:itutor@qq.com
wx: cjtutor
QQ: 2653320439
Intro to JavaScript for Java Programmers Introduction to JavaScript for Java Programmers Peter Coxhead Contents  0 JavaScript covered in this handout  1 Introduction  2 JavaScript and Java  3 Data Types in JavaScript  4 Numbers  5 Strings  6 Booleans  7 Objects (including document, Date)  8 Arrays  9 Functions  10 Equality Tests  11 Scope and Existence  12 Events and Event Handling  13 Creating Objects  14 Manipulating CSS  15 Manipulating the HTML DOM  16 Loading and processing XML   References/Bibliography 0 JavaScript covered in this handout This handout is concerned with JavaScript as used in HTML pages for display in a web browser -- so-called 'client-side JavaScript'. Be aware that there are other uses of JavaScript for which statements written here may not be true; throughout by 'JavaScript' I mean only 'web browser JavaScript'. For programmers with a knowledge of Java, learning the core JavaScript language is reasonably straightforward. Learning to use JavaScript effectively is an entirely different matter. The language itself is evolving; browsers have their own idiosyncratic implementations; libraries and other sources of code are constantly being updated. The solution is to use the web. For example, the easiest way to check the syntax of the switch statement in JavaScript is to put "javascript syntax switch" into a search engine. To deal with browser differences, try "javascript browser compatibility". There are a number of good tutorial websites on JavaScript, among them http://www.howtocreate.co.uk/tutorials/javascript/, by Mark Wilton-Jones. The JavaScript described here is designed to work with Firefox, Version 2 onwards, and other so-called 'fifth generation browsers'. By its nature, client-side JavaScript is freely open to inspection and copying. Don't re-invent the wheel, but do acknowledge any code you re-use and observe any stated restrictions. Note however that JavaScript on the web is not always written in a style which should be emulated. 1 Introduction The JavaScript language dates back to 1996 and the release of Version 2 of the Netscape browser. It offered two key features: When included in HTML pages, it was executed by the Netscape browser, thus allowing web pages to have dynamic features. A page displayed by the Netscape browser was parsed in such a way that an internal 'document object model' (DOM) was created which was accessible to the JavaScript language since it mapped HTML elements to JavaScript objects. Netscape did not intend JavaScript to be a proprietary standard, and so passed the language to the European Computer Manufacturers Association (ECMA) for standardisation. This resulted in a language called ECMAscript, although the name never caught on. The ECMA standard defined the core syntax of JavaScript, but did not fully define the JavaScript DOM. JavaScript then got caught up in the 'browser wars', when Microsoft decided that a web browser was too important a piece of software to be left to independent companies and, whether intentionally or not, set about driving Netscape out of business. The result has been a very complex and tangled history whereby different browsers implement: different versions of JavaScript (e.g. Microsoft's JSoft version with its own extensions) different JavaScript DOMs. The variations in JavaScript are smaller and hence usually less important than the variations in DOMs. The latest browsers show some degree of convergence, but so long as users employ older versions, JavaScript authors face serious problems in creating compatible web pages. The issue will largely be avoided in this introductory module. The best way to find information on this rapidly changing subject is to use a search engine: a good starting point is "javascript browser compatibility". Returning to the two key features introduced by Netscape, it's important to be clear from the start that both are essential to the successful use of JavaScript. For example, suppose we want to display an image in a web page, and then change the image when the user clicks on it. Here's a simple XHTML page which does this. Example 1-0 (http://www.cs.bham.ac.uk/~pxc/infoweb/2007/Egs/Eg1-0.html) Example 1-1

Click on the image to change it.

a clickable image

Two things to note first about this example are: It is essential that it is served by the web server as "text/html" rather than, for example, "text/xml". Browsers will only attempt to execute JavaScript when presented with an HTML document. The web server may or may not use the meta element to determine how the document should be served. More usually the file extension is the crucial factor: files with extensions such as .html or .htm are served as "text/html", files with the extension .xml are served as "text/xml". When JavaScript is embedded into an XHTML document, as here, characters such as < or & make it not well-formed. At present, there's no satisfactory way of dealing with this problem which is also reasonably browser-safe.[1] The best solution seems to be to put as much JavaScript as possible into external files. Adopting this approach, we can re-write Example 1-0 as follows. Example 1-1 (http://www.cs.bham.ac.uk/~pxc/infoweb/2007/Egs/Eg1-1.html) Example 1-1

Example 1-1

Click on the image to change it.

a clickable image

Code loaded from a file via the src attribute of a script element is treated exactly as if it was written out in full in the same place. Notice that I deliberately didn't use the empty element form

We might hope that this would display a message saying which image is currently being shown. If so, we will be disappointed. The text 'Currently showing image 0' will be inserted into the HTML once and once only, namely the first time that the JavaScript is executed. (Re-loading the page doesn't change this, because it will cause the JavaScript in the header to be re-executed, setting i back to 0.) Section 12 below shows one way of achieving dynamic messages. JavaScript has the built-in ability to create 'date' objects, which make handling dates and times easier. When initially constructed, a new Date object will hold the current date and time: var now = new Date(); // Holds current date and time var dayInMonth = now.getDate(); // Day of the month, from 1 to 31 var dayInWeek = now.getDay(); // Day of the week, from 0 (Sun) to 6 (Sat) var month = now.getMonth(); // Month, from 0 (January) to 11 (December) var year = now.getFullYear(); // Year as a 4 digit number var hr = now.getHours(); // Hour, from 0 to 23 var min = now.getMinutes(); // Minute, from 0 to 59 var sec = now.getSeconds(); // Second, from 0 to 59 var timeStr = 'Time now is '+hr+':'+min+':'+sec+' on '+dayInMonth+'/'+ (month+1)+'/'+year; A web page which displays the above 'time string' using the document.write method will be found at http://www.cs.bham.ac.uk/~pxc/infoweb/2007/Egs/Eg7-1.html. Date objects store time internally as milliseconds since midnight, 1 January 1970. Using the getTime and setTime methods which access these values, it's possible to step backwards and forwards from a given date and time, without having to deal with the complexities of the varying number of days in a month or whether it's a leap year or not.[7] The code fragment below sets tomorrow to exactly one day from now: var now = new Date(); var tomorrow = newDate(); tomorrow.setTime(now.getTime()+24*60*60*1000); For an example of the use of date calculations, see http://www.cs.bham.ac.uk/~pxc/infoweb/2007/Egs/Eg7-2.html. It is also possible to create your own objects and 'classes' of object in JavaScript; see Section 13. 8 Arrays Arrays are a kind of object. Unlike Java arrays, they are not of fixed size and are untyped. Thus the following is legal: var a = Array(); a[0] = 6; a[2] = ' is '; a[3] = true; The value of a[1] is undefined. (The expression typeof a[1] will have the string value 'undefined'.) The length of the array, as determined by a.length, is 4. Had a been declared by var a = Array(5); with the same statements following, then a[4] would also be undefined. It is not an error to attempt to access undefined values in JavaScript; they generally behave as if they had the value null (similar to Java's null). We can show all the defined values in an array via code such as: function showArray(a) { var msg = ''; for (var i=0; iSchool of Computer Science

When the user clicks on the link, the browser first executes the JavaScript return check(). The function check is called and uses the function confirm (a method of window) to display a dialog asking the user to choose between the ok and cancel buttons. The value returned by confirm is one of the boolean values true or false, which in turn is the value returned by check. The result is that the onclick attribute returns true or false to the browser. For this event handler, false causes the default browser action to be abandoned, so the link is not followed. Five of the most useful general events and handlers are shown in the table below. Event Cause Effect of a return value onchange User finishes entering text in a text box or selects/deselects an item. onclick User clicks once. If a link, false prevents it being followed. onload Item finishes loading (document or image normally). onmouseover Mouse moves over item. If a link, true prevents URL being displayed in the status bar. onmouseout Mouse moves off item. Example 12-2 uses all of these five events to create a web page which can evaluate a simple arithmetic expression consisting of two numbers and an operator. I suggest you look at the web page in operation before studying the source code and reading the notes below it. Example 12-2 (http://www.cs.bham.ac.uk/~pxc/infoweb/2007/Egs/Eg12-2.html) JavaScript: var xBox; var yBox; var zBox; var msgBox; // Initialize the global variables to the five text boxes function init(xID, opID, yID, zID, msgID) { xBox = document.getElementById(xID); opBox = document.getElementById(opID); yBox = document.getElementById(yID); zBox = document.getElementById(zID); msgBox = document.getElementById(msgID); } // Reset the boxes function reset() { xBox.value = 0; yBox.value = 0; zBox.value = 0; opBox.value = '+'; msgBox.value = ''; } // Calculate and display the result of x op y function calculate() { var x = parseFloat(xBox.value); xBox.value = x; var y = parseFloat(yBox.value); yBox.value = y; var op = opBox.value; switch(op) { case '+': z = x + y; break; case '-': z = x - y; break; case '*': z = x * y; break; case '/': z = x / y; break; default: opBox.value = '+'; z = x + y; break; } zBox.value = Math.round(1000*z)/1000; } // Show a message in the msgBox function msg(msgText) { msgBox.value = msgText; } HTML: Example 12-2

Simple JavaScript calculator

=

Some notes on this example: In the interests of modularity it is desirable to de-couple HTML and JavaScript code as far as possible. In particular, it is much easier to make changes if the values of id attributes are not 'hard coded' into the JavaScript. One way of achieving this is to use an initialization function, like init in Example 12-2, which passes the necessary id values to the JavaScript program. The onload attribute of the body element causes the corresponding event handler to be called only after the body is fully loaded, thus ensuring that all elements have been created before the JavaScript code attempts to access them. When the mouse is over the first three input elements, their onmouseover and onmouseout attributes cause an informative message to appear in the "note" input element; it disappears when the mouse moves away. The "res" and "note" input elements are disabled to prevent user input as they are only used to display text. Browsers automatically refresh the contents of form elements when their values change, unlike 'normal' HTML elements which are static once displayed. The onchange attribute of the first three input elements ensures that when the user changes them, the result value is changed via a call to calculate. The user interface is slightly awkward because the user must move away from the element to trigger the onchange event. In general this is not as useful an event as it may seem. The value obtained from an input element is a string. Rather than use automatic type conversion (which will work only if the syntax of the string is exactly correct), the built-in parseFloat function has been used. This is more tolerant of incorrect input (e.g. '34.1a' will be converted to 34.1). Notice that the value produced after conversion is re-displayed so the user knows what number has been accepted. 13 Creating Objects There are a number of different ways of creating your own objects in JavaScript. Only one approach is discussed here. Although you will see examples of JavaScript programming in which objects and constructors are used in what appears to be Java-like fashion, in reality this approach is of considerably less value: In Java, classes and class-based inheritance are used to create a compatible and safe set of types. JavaScript's untyped variables make this irrelevant. Classes and their instances in Java allow information hiding to be enforced, e.g. by declaring fields and methods to be private. JavaScript objects are completely open. If data is stored in the fields of objects, access methods are only useful when consistency between fields must be maintained. Individual objects can be created by the new operator applied to the class Object:[9] var myObject = new Object(); The required fields and methods of the newly created object can then be set up. They can be added to at any time after the object has been created. myObject.age = 32; myObject.name = 'John'; myObject.toString = function () { return myObject.name+' '+myObject.age; }; Given this code, the statement alert(myObject) will display 'John 32', the toString method being called as a result of automatic type conversion (alert expects its argument to be a string). Typically we want to create more than one object of a kind. One solution is to create a 'factory' or 'make' method that creates and returns objects: function makeRect(width,height) { var r = new Object(); r.w = width; r.h = height; r.toString = function() { return r.w+' by '+r.h; }; return r; } rect1 = makeRect(10,45); rect2 = makeRect(100,10); alert(rect1); // Will display '10 by 45' As noted above, we could create accessors like getWidth or setWidth, but as there is no way of preventing access to the fields of the objects, this would produce no real gain at the expense of inefficiency.[10] The slight problem with this approach is that every object created by makeRect will contain identical copies of its methods, which is an inefficient use of memory. This is only likely to become a problem when creating a large number of objects with substantial method definitions. An alternative is to create a single global function and store a reference to it in the object. Because the variable r will not be available globally (it is local to makeRect), we need to use the special variable this which refers to the originating object of a method: function _rectToString() { return this.w+' by '+this.h; } function makeRect(width,height) { var r = new Object(); r.w = width; r.h = height; r.toString = _rectToString; return r; } var rect1 = makeRect(10,45); alert(rect1); // Displays '10 by 45'. (Since _rectToString is now global, it could be called directly; giving it a name starting with an underscore is a useful convention to show that it is not meant for independent use.) Re-use can be achieved by writing a new 'make' method which adds or changes fields based on an existing object type. For example, to create filled rectangle objects, we can start with a rectangle object: function makeFilledRect(width,height,colour) { r = makeRect(width,height); r.colour = colour; r.toString = function () { return this.w+' by '+this.h+'; colour '+this.colour; }; return r; } var rect2 = makeFilledRect(11,56,'green'); alert(rect2); // Displays '11 by 56; colour green'. JavaScript has 'object literals': a list of field name and value pairs separated by commas. The statement: r = { w: 10, h: 25, colour: 'green' }; creates an object r with fields w, h and colour. 14 Manipulating CSS with JavaScript One of the interesting uses of JavaScript is to manipulate the style of HTML elements dynamically. JavaScript creates a style object for each element and makes it a field of the object representing that element. The style object in turn has fields. Important ones are cssText and fields corresponding to each applicable CSS property. Capitalization is used in field names in place of the hyphens in CSS properties. Thus for example border-left-width becomes borderLeftWidth. Note that the style object only holds the styles explicitly declared for that element, not those inherited via class attributes. Example 14-1 shows a simple example of dynamic CSS. As with earlier examples, I suggest you look at the web page in operation before studying the source code and reading the notes below it. Example 14-1 (http://www.cs.bham.ac.uk/~pxc/infoweb/2007/Egs/Eg14-1.html) JavaScript: var box1; var goRed = true; function changeColour() { if(goRed) box1.style.borderColor = 'red' else box1.style.borderColor = 'black'; goRed = !goRed; } function init(boxID) { box1 = document.getElementById(boxID); setInterval('changeColour()',1000); } HTML: Example 14-1

The box below should change colour regularly from black to red and back again.

Some notes on this example: The style attached to all elements of class box causes them to have a 2 pixel wide black border all round. In the example, this style is attached to a div with id "box1". The function init sets the value of the global variable box1 to the JavaScript object representing the div. The setInterval function is then used for animation (see the discussion below); changeColour will be called once every second. The function changeColour then sets and re-sets the border-color style specifically for the div element, which by the rules of CSS, over-rides the class-wide style. This relies on the browser dynamically changing its display whenever the CSS changes. JavaScript provides three useful 'timer' functions (methods of the window). setInterval(JavaScript_string, time_in_msec) executes the JavaScript given in the first string argument after every interval of time_in_msec milliseconds. It returns a timer identifier which should be saved if it will be necessary to stop the activity. clearInterval(timerID) stops the action created by setInterval: timer1 = setInterval('run()', 2000); . . . . . . clearInterval(timer1); setTimeout(JavaScript_string, time_in_msec) executes the JavaScript given in the first string argument after one interval of time_in_msec milliseconds. (If the action has not taken place, it can be stopped via clearTimeout(timerID).) In Section 13, we discussed creating objects and in particular rectangle objects. By combining this with the technique discussed here we can 'draw' the rectangles as they are created. We first set up the CSS box class to ensure that a div of this class will not be visible: Notice that we declare position: fixed; to ensure that the element is positioned at an absolute location relative to the window.[11] Now we write the JavaScript to create rectangle and filled rectangle objects, defining their size, position and colour via CSS styles. Note how we store a reference to the corresponding DOM object within our rectangle object so that it is easy to access the style field. function makeRect(id,left,top,width,height) { var r = new Object(); r.left = left; r.top = top; r.right = left+width; r.bottom = top+height; r.domObj = document.getElementById(id); r.domObj.style.cssText += 'left:'+left+'px; top:'+top+'px; width:'+ width+'px; height:'+height+'px; border: solid 2px black;'; return r; } function makeFilledRect(id,left,top,width,height,colour) { r = makeRect(id,left,top,width,height); r.colour = colour; r.domObj.style.cssText += ' background-color: '+colour; } The function init is used to set up three rectangles when the body of the page has loaded: function init(box1ID,box2ID,box3ID) { makeFilledRect(box1ID,15,60,50,100,'green'); makeRect(box2ID,30,100,150,75); makeFilledRect(box3ID,45,85,50,50,'red'); } Finally we set up the initially invisible div elements in the body of the page:
The complete page will be found at http://www.cs.bham.ac.uk/~pxc/infoweb/2007/Egs/Eg14-2.html. If we want the user to interact with our objects, then it is useful to create links in both directions between our object and the corresponding DOM object. JavaScript's ability to add fields to existing objects makes this easy to do, although we must be careful not to over-ride an existing field. The makeRect function can have an additional line added: function makeRect(id,left,top,width,height) { var r = new Object(); . . . . . r.domObj = document.getElementById(id); . . . . . r.domObj.owner = r; // Relies on 'owner' being a new field! return r; } As a simple of example of how this link can be used, suppose we want to change the appearance of a rectangle object when the user clicks on it. We begin by adding a clicked field and a doClick method to makeRect: function makeRect(id,left,top,width,height) { var r = new Object(); . . . . . r.clicked = false; r.doClick = function () { if (!r.clicked) r.domObj.style.borderColor = 'yellow'; else r.domObj.style.borderColor = 'black'; r.clicked = !r.clicked; }; return r; } Finally we add an onclick event handler to the div elements. In the event handler code which is the value of an event attribute, the keyword this refers to the DOM object corresponding to the HTML element. Hence by using this and the owner field we have added to it, we can link to the corresponding rectangle object:
The complete page will be found at http://www.cs.bham.ac.uk/~pxc/infoweb/2007/Egs/Eg14-3.html. For a further example of what it is possible to do with JavaScript and dynamic CSS, see http://www.cs.bham.ac.uk/~pxc/infoweb/2007/Egs/Eg14-4.html. (Depending on your machine and browser, the animation speed may or may not be satisfactory.) 15 Manipulating the HTML DOM Consider the following XHMTL:

Manipulating the JavaScript DOM is a very important technique.

Varying browser support is the main problem.

Like all XML, it can be represented as a tree of nodes. In the following diagram, note that the limited width of the page has prevented me from aligning all the grandchildren of the div correctly; also spaces and newlines are shown explicitly in the values of text nodes. Usually we don't really want the tree to contain text nodes which represent only 'white space', but we must be prepared for them to be present.[12] The browser will create a JavaScript object for each node, including the text nodes, as part of the DOM. Each node has some standard fields and methods. To move through the tree, the following fields can be used: parentNode contains the parent of the node. childNodes contains an array of the child nodes. firstChild, lastChild provide immediate access to the first and last child nodes. nodeName holds the name of the node as a string (e.g. 'div', 'b' or '#text'). data holds the text of a text node, which have no children (hence the dotted lines in the figure above). Thus the code below should display the string 'very': var theDiv = document.getElementById('div01'); alert(theDiv.childNodes[1].childNodes[1].firstChild.data); In practice, it's rarely desirable to work through the tree in this way because the exact number of text nodes (and hence child nodes) depends on the way the document was laid out and on how the browser handles text and white space, so the shape of the tree is not readily predictable. Better approaches are: To give elements unique id attributes and use node.getElementById(id_value) to return the object with id = id_value in the tree starting at node.[13] To use node.getElementsByTagName(element_name) to return an array of all objects in the tree starting at node whose nodeName is the string element_name. Finding a node is usually a precursor to changing it (or more accurately one or more of its children). As with navigating the DOM, there are many methods and fields which can be used to make changes. The following are perhaps the most useful: document.createElement(element_name) creates an element object whose nodeName is given by the string element_name. document.createTextNode(text_string) creates a text node object whose content is given by the string text_string. node.appendChild(newNode) adds newNode as node's last child. node.insertBefore(newNode,oldNode) inserts newNode immediately before oldNode, both being children of node. node.replaceChild(newNode,oldNode) relaces node's child oldNode by newNode. node.removeChild(oldNode) removes node's child oldNode. innerHTML is a string field representing the HTML 'inside' the node; giving it a new value is an easy way of changing the text belonging to a node, avoiding the need to create text nodes and add/replace them as children.[14] (Like document.write, inserting text into innerHTML makes validation impossible. For this reason, some browsers do not allow it in pages served as XML or XHTML. Further, the corresponding nodes in the DOM are often created by a different thread, so may not be available immediately to JavaScript, causing subsequent manipulations of the DOM tree to fail.) node.setAttribute(attr_name, attr_value) adds an attribute to node whose nodeName is given by the string attr_name and whose nodeValue is given by the string attr_value. Given the HTML discussed above, the code in the following rather artificial example repeatedly changes the bold word 'very' in the first paragraph to 'somewhat' and also replaces the second paragraph. Example 15-1 (http://www.cs.bham.ac.uk/~pxc/infoweb/2007/Egs/Eg15-1.html) JavaScript: var words = ['very', 'somewhat']; var iWord = 0; var theDiv; var firstB; var secondP; var newP; function init() { // Now the document has loaded, set up the required objects. theDiv = document.getElementById('div01'); firstB = theDiv.getElementsByTagName('b')[0]; secondP = theDiv.getElementsByTagName('p')[1]; newP = document.createElement('p'); newP.innerHTML = 'One problem is varying browser support.'; // Alternate the text of the paragraphs. setInterval('changeText()',1000); } function changeText() { iWord++; if(iWord>1) iWord = 0; firstB.innerHTML = words[iWord]; if (iWord==1) theDiv.replaceChild(newP,secondP) else theDiv.replaceChild(secondP,newP) } HTML:

Manipulating the JavaScript DOM is a very important technique.

Varying browser support is the main problem.

The ability to create new HTML elements and attributes enables us to re-write Example 14-2. In the original version, the div elements which became boxes are explicitly coded in the HTML, with an initial style which makes them invisible. Then when each rectangle object is created, the style of the corresponding div is changed. This approach requires the number of boxes which will be created to be known in advance. The alternative is to create the divs dynamically. Compare the following version of makeRect with that given above. var theBody; // Must be initialized to the element. . . . . . . . . . . function makeRect(left,top,width,height) { var r = new Object(); r.left = left; r.top = top; r.right = left+width; r.bottom = top+height; r.domObj = document.createElement('div'); r.domObj.setAttributeNode('class','box'); theBody.appendChild(r.domObj); r.domObj.style.cssText += 'left:'+left+'px; top:'+top+'px; width:'+ width+'px; height:'+height+'px; border: solid 2px black;'; r.clicked = false; r.domObj.onclick = function () { if (!r.clicked) r.domObj.style.borderColor = 'yellow'; else r.domObj.style.borderColor = 'black'; r.clicked = !r.clicked; }; return r; } Note the following points: The global variable theBody must be initialized to the body element object, e.g. by theBody = document.getElementsByTagName('body')[0];. The set of statements in bold then create a div of the form
. We can bypass the need to create an onclick attribute for the div by directly setting the onclick method in the corresponding object. The DOM object now doesn't need to link to the rectangle object; clicking on the div will automatically call the right event handler. The complete HTML page is at http://www.cs.bham.ac.uk/~pxc/infoweb/2007/Egs/Eg15-2.html. For a larger example of what can be done with JavaScript and dynamic changes to both CSS and the HTML DOM, see http://www.cs.bham.ac.uk/~pxc/infoweb/FifteenPuzzle.html. 16 Loading and processing XML A set of techniques involving 'asynchronous JavaScript technology and XML' (AJAX) has become popular since about 2005. The following diagram shows the basic four steps involved.[15] The numbers in the diagram correspond to the steps: The action is initiated by the web page or by a user generated event. An XMLHttpRequest object is invoked. It is given a URL and a 'callback' function. Browsers provide this facility in a number of different ways, but the core functionality is the same. The URL is used to generate an HTTP request, addressed to the same web server which supplied the HTML page. The request is asynchronous: once initiated it runs independently. Thus while waiting for the XML document to load, the browser can continue to respond to other user actions, e.g. scrolling, or to execute other JavaScript. Based on the URL in the request, the web server returns an XML document. The simplest kind of URL would give the location of an XML file. A more plausible URL would initiate a server-side program which generates XML, perhaps based on data acquired from a database. When the XMLHttpRequest object has correctly received all of the XML document and it has been converted to a DOM object, it executes the callback function it was given. This function typically takes the XML document object as its argument and uses it to update the HTML page by manipulating the HTML document object, as discussed in Section 15. There are an important security restrictions imposed by browsers such as Firefox: An XMLHttpRequest object can only make requests via the http: protocol. This ensures that web pages cannot read files on the local computer via the file: protocol. The requested file must be served from the same domain as the web page, e.g. the web page reached via http://www.myname.co.uk/... can only request XML files whose URL also begins with http://www.myname.co.uk/. Some code needed to evoke an XMLHttpRequest object will be found in http://www.cs.bham.ac.uk/~pxc/infoweb/xhrlib.js. I have tried to write code which traps as many errors as possible -- it's not designed for 'real' use. It's not necessary to understand the details of the code in this module. The key to using this library code is the function requestXML(url, processor). This function: generates an XML HTTP request for the URL contained in the string supplied as its first argument, url when the XML has been loaded, passes the XML DOM object created by the browser to the function passed as its second argument, processor. The URL supplied must either be: relative to the web page (e.g. ../mydata.xml) a full URL starting with http:// and the same domain name as the web page. The function passed as the second argument must take one parameter. When the XML is loaded, this parameter will be set to the XML DOM object created by the browser. The function must then process the DOM object appropriately. A simple example can be used to show how this works. We begin with the XML document stored at http://www.cs.bham.ac.uk/~pxc/infoweb/2007/Egs/data.xml: ]> Arjun Sen Birmingham John Smith London Mary Jones Cardiff The task is to construct a simple HTML page which loads this file and displays names and birth places. The body of the page just has a heading and an empty div element.

People and their Places of Birth

The init function below sets up a JavaScript variable displayDiv to hold the DOM object corresponding to the empty div element, and then initiates the asynchronous request for an XML document, using the requestXML function from the xhrlib.js file. Note that because a relative URL has been used in the call of requestXML, it will be resolved to the same location as the web page, and in particular the same domain. It is essential that the web page is opened via the http: protocol and not the file: protocol, i.e. the web page must be on a web server. var displayDiv; function init(displayDivID) { displayDiv = document.getElementById(displayDivID); requestXML('data.xml', doDisplay); } Because the request is asynchronous, init will terminate after the call to requestXML; it will not wait for the file to be loaded. When the file has been loaded, the JavaScript engine will call the function doDisplay, with the XML document object as its argument. The idea is to walk through the XML document object, creating a new HTML p element (i.e. a paragraph) for each person in the XML file. Each paragraph is then made a new child of the empty 'display' div. The steps involved are: Use getElementsByTagName('person') to get an array of the objects corresponding to the person elements in the XML document. Iterate through the array extracting the text from the name and birthplace elements of each person element. Assume that the XML is valid, i.e. that each person element has only one name and one birthplace element and that the first child element of each is the text we want. Create a new paragraph whose inner HTML is the extracted text and add it to the end of the 'display' div. This produces the following code. function doDisplay(xmlDoc) { var persons = xmlDoc.getElementsByTagName('person'); for (var iPerson = 0; iPerson < persons.length; iPerson ++) { var person = persons[iPerson]; var txt = person.getElementsByTagName('name')[0].firstChild.data; txt += ', '; txt +=person.getElementsByTagName('birthplace')[0].firstChild.data; var newP = document.createElement('p'); newP.innerHTML = txt; displayDiv.appendChild(newP); } } The complete HTML page is at http://www.cs.bham.ac.uk/~pxc/infoweb/2007/Egs/Eg16-1.html. An improved alternative in which the data is displayed in a table, constructed without using the innerHTML field, will be found at http://www.cs.bham.ac.uk/~pxc/infoweb/2007/Egs/Eg16-2.html. A more realistic example would display only part of the data. For example, if the user enters a name the page should respond by showing the person's place of birth. Extending Example 16-1 to achieve this is straightforward. The body of the page is defined as:

People and their Places of Birth

Enter person's name:

The user enters a name into the text input box and then presses the "Show Place of Birth" button. The initially empty "display" div element is then used to show the result. The init function sets up the necessary objects and requests the XML document. The callback function extracts and stores an array of the objects corresponding to the person elements: var displayDiv; var nameInput; var persons; function init(displayDivID,nameInputID) { displayDiv = document.getElementById(displayDivID); nameInput = document.getElementById(nameInputID); requestXML('http://www.cs.bham.ac.uk/~pxc/infoweb/2007/Egs/'+ 'data.xml', setupPersons); } function setupPersons(xmlDoc) { persons = xmlDoc.getElementsByTagName('person'); } Finally when the user presses the button, the array is searched for the appropriate name and a result displayed. A minor issue is that, as noted in Section 15, text values retrieved from an XML source may contain extra white space. For this reason, xhrlib.js also contains normalize_space(str) which normalizes a string by stripping any opening and closing white space and replacing all other occurrences of white space by a single space.[16] function showBirthplace() { var name = normalize_space(nameInput.value); if (name != '') { var i = 0; var found = false; while (!found && i < persons.length) { var person = persons[i]; found = normalize_space(person.getElementsByTagName('name')[0]. firstChild.data) == name; i++; } if (!found) { displayDiv.innerHTML = 'Unknown person: '+name+'.'; } else { var birthplace = normalize_space(person. getElementsByTagName('birthplace')[0]. firstChild.data); displayDiv.innerHTML = name+' was born in '+birthplace+'.'; } } } The complete HTML page is at http://www.cs.bham.ac.uk/~pxc/infoweb/2007/Egs/Eg16-3.html. In spite of the fact that it only displays part of the data, Example 16-3 still downloads the entire XML file. This is clearly undesirable: The file may potentially be very large and so its loading will cause an unacceptable delay, especially with a slow connection. Since the XML file must be available by HTTP, there is no way of hiding data which the user should not be able to access -- by inspecting the source code of the JavaScript, the user can find the URL of the XML file, and then download it directly. The solution is server-side processing. For example, the URL used to access the required XML could be directed at a web page containing server-side script, written in a language such as PHP. The web server executes such script before sending the result to the client. For example, given a person's name, the server could send back some XML describing only that person. (The original data does not have to be stored as XML, since the program or script running on the server can obtain data from any source and then 'wrap' it in XML.) When http://www.cs.bham.ac.uk/~pxc/infoweb/2007/Egs/data.php?name=John Smith is accessed,[17] it returns XML equivalent to: John Smith London Given a name other than "John Smith", "Arjun Sen" or "Mary Jones", it returns the name it was given with birthplace as "unknown". The JavaScript below demonstrates how an HTML page might interact with this PHP page. Notice that the HTTP request now occurs only when specific data is required. var displayDiv; var nameInput; function init(displayDivID,nameInputID) { nameInput = document.getElementById(nameInputID); displayDiv = document.getElementById(displayDivID); } var name; function showBirthplace() { name = normalize_space(nameInput.value); requestXML('http://www.cs.bham.ac.uk/~pxc/infoweb/2007/Egs/'+ 'data.php?name='+name, displayBirthplace); } function displayBirthplace(xmlDoc) { var birthplace = normalize_space(xmlDoc. getElementsByTagName('birthplace')[0]. firstChild.data); if (birthplace == 'unknown') displayDiv.innerHTML = 'The birthplace of '+name+'is unknown.'; else displayDiv.innerHTML = name+' was born in '+birthplace+'.'; } The complete HTML page is at http://www.cs.bham.ac.uk/~pxc/infoweb/2007/Egs/Eg16-4.html. (Server-side processing with Java will be covered in the Software System Components modules in Year 2.) AJAX has significant advantages over other techniques for dynamically displaying data: It increases the separation between content and presentation. Content is transferred between the server and browser as XML. The web page only deals with presentation and user interaction. Changes to the page are 'smooth', at least compared to the alternative approach in which changes to content are handled by loading a different web page. It utilizes the advantages of XML as a medium for data transfer (e.g. high compatibility across platforms through its well-standardized text-based format; increased security compared to binary data; ease of processing through the XML DOM which closely parallels the HTML DOM). References/Bibliography See the other handouts for this module, which are available online. Footnotes [1] For a more detailed explanation, see the section on validity in my Summary of Core XHTML. [2] HTML and JavaScript allow matched single and double-quotes to be used interchangeably. I generally use double-quotes for attribute values and single quotes for JavaScript strings as here. Use of either this or the opposite convention avoids un-necessary escaping. [3] When talking about languages such as Java or C, it is conventional to put empty parentheses after the name of a method or function to distinguish it from the name of a variable or field. However, in JavaScript, as will be explained later, function values can be assigned to variables, so that it is important to distinguish the name of function from a use or call of the function. Hence in this document the name of a function will always be written without parentheses. [4] This approach is particularly likely to fail with older browsers. [5] Until its release, it was apparently called LiveWire or LiveScript. [6] JavaScript has untyped variables in that their type is not fixed. However JavaScript values are typed; the typeof operator can always be applied to determine the current type of a variable and types and type conversions are important in understanding how JavaScript works. It's thus slightly misleading when JavaScript is said to be an untyped language. [7] Since JavaScript uses only real arithmetic, complex calculations involving integers such as times may yield apparently incorrect results if care is not taken (e.g. by rounding result values). [8] Strictly the attribute value should begin with javascript:. [9] Parentheses after Object are optional. [10] Information hiding can be achieved in JavaScript by using local variables to store data, an approach not covered in this module. See my web page on Information Hiding in JavaScript. [11] Older versions of Internet Explorer are notorious for their poor support of the CSS position property. [12] Browsers may also split long blocks of text among adjacent text nodes, although sibling text nodes ought to be merged together according to the W3C standard. [13] This seems to be more browser compatible if node is document. [14] However, setting innerHTML does not work for XHTML served as XML on some browsers, e.g. Safari 2.0. [15] Redrawn from http://java.sun.com/developer/technicalArticles/J2EE/AJAX/IntroAjaxPageAuthors.html. [16] Using the prototype field of the String object, xhrlib.js also attaches normalize_space to all strings, so that normalize_space(str) and str.normalize_space() are then equivalent. [17] Strictly the space in the URL should be escaped as %20. Home Page for "Information and the Web" Page maintained by: Dr Peter Coxhead Content last updated: 12 Jul 2009

本站部分内容来自互联网,仅供学习和参考