Приглашаем посетить
Perl (perl.find-info.ru)

Event Binding

Event Binding

Event binding is the association between a specific event and a script. Dynamic HTML supports a number of language-independent ways to bind scripts to events. In addition, the scripting engines themselves can expose further custom ways to support event binding.

The language-independent mechanisms bind events through attributes on the Script element, through special HTML attributes associated directly with a specific element, and through the object model itself. VBScript also offers the Visual Basic-style binding mechanism, which involves naming the handler subroutines in a specific way.

Event Attributes

In Dynamic HTML, all the elements within the document have been extended to support keyboard and mouse events. These events are exposed as attributes directly on each element, allowing a direct association between the element and the behavior. This association is similar to the one between an element and its inline style using the STYLE attribute. For example, you can bind the onclick event of a button to a function using an attribute as follows:

<!-- When the user clicks the button,
     the foo() function is called. -->
<INPUT TYPE=BUTTON VALUE="Click Here" 
   ONCLICK="foo();" LANGUAGE="JavaScript">

The ONCLICK attribute can either call a function or immediately execute one or more lines of code. In this example, when the user clicks the button, the foo routine is called. The LANGUAGE attribute specifies in which language the inline code is written. Omitting the LANGUAGE attribute defaults to the language specified in the first script on the page, or to JavaScript in the absence of any prior scripts. The following example demonstrates two inline statements being executed when the user clicks the button:

<!-- When the button is clicked, display the alert and
     then call the function foo(). -->
<INPUT TYPE=BUTTON VALUE="Click Here"
   ONCLICK="alert(`The user clicked here.'); foo();"
   LANGUAGE="JavaScript">

The button first outputs the alert box, and then it calls the foo function.

All HTML attributes are case insensitive, so case sensitivity is not an issue when you use attributes such as ONCLICK to bind handlers to events. Case sensitivity can be important when you use other event-binding mechanisms, however. Event binding with HTML attributes is convenient, but it has a number of disadvantages. The first is that the HTML language needs to be extended every time a new event is invented. For example, the preceding onclick event requires the DTD (document type definition) for the <INPUT> tag to be extended to include an ONCLICK attribute. This makes it much more difficult to add events in a standard way because HTML evolves slowly. Furthermore, objects or applications that expose arbitrary events also need to extend the language or expose their own custom event-binding techniques. Therefore, this approach is used only for a small set of built-in events. If an arbitrary object is embedded on the page, its events are exposed in a more generic way.

Generic Event Support

A second binding mechanism overcomes these disadvantages. It uses a few Script element extensions—namely, a FOR attribute and an EVENT attribute—to bind functions to events. The EVENT attribute refers to the event and any parameters that may be passed in, and the FOR attribute specifies the name or ID of the element the event is being written for. For example, an onmousemove event is exposed on the document. You can use the following <SCRIPT> tag to bind to this event:

<SCRIPT FOR="document" EVENT="onmousemove()" LANGUAGE="JavaScript">
   // This event handler is called whenever the mouse moves on the 
   // document.
</SCRIPT>


NOTE: JavaScript is case sensitive for both the EVENT and the FOR attribute values on the <SCRIPT> tag. Be careful to ensure that all event names are supplied in lowercase for built-in events and in the appropriate case for any embedded objects. Also, if you specify an ID in the FOR attribute, you must type it exactly as it appears in the ID attribute of the element itself. Whenever an event appears to not be firing, always verify that the spelling and case are correct in the <SCRIPT> tag.

There is one caveat to the preceding syntax. Netscape Navigator ignores the FOR and EVENT attributes and will attempt to execute the code immediately. Here's a potential trick for working around this restriction:

<SCRIPT LANGUAGE="JavaScript">
   // Assume that the browser supports the FOR attribute.
   var ForSupport = true;
</SCRIPT>

<SCRIPT FOR="fakeObject" EVENT="foo" LANGUAGE="JavaScript">
   // This event does not exist.
   // If FOR and EVENT are supported, this code will never execute.
   ForSupport = false;
</SCRIPT>

<SCRIPT FOR="document" EVENT="onmousemove" LANGUAGE="JavaScript">
   if (ForSupport) {
      // Write actual event handler.
   } 
   else
      alert("Your browser does not support the required event 
         syntax.");
</SCRIPT>

Another way to ensure that the script code is not executed is to specify the language as JScript. JScript is Microsoft's implementation of JavaScript. Because Microsoft Internet Explorer is the only browser that supports JScript, the script does not require an if statement in order to be ignored by Netscape.

<SCRIPT FOR="document" EVENT="onmousemove()" LANGUAGE="JScript">
   // This event handler is called whenever the mouse moves over
   // the document if the browser supports the JScript language
   // engine.
</SCRIPT>


NOTE: When you specify the event name, the parentheses are optional. For example, the above event could have been specified as EVENT="onmousemove".

Visual Basic-Style Event Binding

In addition to the techniques already discussed, VBScript also supports the Visual Basic-style mechanism for binding scripts to events. Visual Basic traditionally binds code to an event using a specially named subroutine. If the subroutine is written in the Visual Basic-style format, the Visual Basic engine knows which event to bind the script to. For example, the following code binds to an onmousemove event and an onclick event on the document:

<SCRIPT LANGUAGE="VBScript">
   Sub document_onMouseMove()
      ` Event handler for the mouse moving over the document
   End Sub

   Sub document_onClick()
      ` Event handler for the user clicking on the document
   End Sub
</SCRIPT>


NOTE: Microsoft Internet Explorer 3.0 also supported the preceding syntax in JScript, but this syntax is not supported by Netscape Navigator or by Internet Explorer 4.0. Therefore, this technique should not be used with JavaScript.

In VBScript, an advantage to using this model is that multiple event handlers can be written within a single script block. The major disadvantage is that external tools cannot easily determine what events have event handlers written for them. Using the Script element's FOR and EVENT attributes syntax or the inline HTML event attribute syntax allows a tool to easily scan a document and determine what events have code associated with them. The Visual Basic-style event-binding model won't be understood by any tool that is not specially written.

It is possible to bind to the same event in multiple languages. In this case, the event will fire in each language when it occurs, but the order is undefined. In general, avoid using this approach, as the results may be unpredictable.

Specifying Scripting Languages in Event Attributes

You can specify different languages for each inline HTML event attribute. The LANGUAGE attribute used with the inline HTML event attributes specifies the default language for interpreting the code. This default can be overridden by specifying a language identifier in the event attribute value. The format is as follows:

<Element EventName="Language:Code">

Language is a case-insensitive string that specifies the scripting language for the Code that follows. The languages supported by Internet Explorer 4.0 are JScript, JavaScript, JavaScript 1.1, and VBScript. JScript, JavaScript, and JavaScript 1.1 run the same language engine. The onclick handler and the onmousedown handler in the following <body> tag are specified in different scripting languages:

<BODY ONCLICK="JavaScript:dothis(this);"
   ONMOUSEDOWN="VBScript:dothat(me)">

Netscape Navigator does not support specifying languages within the event attribute value. Netscape Navigator and Internet Explorer both support specifying a language on the HREF attribute of anchors, which allows you to create JavaScript or VBScript code that will run when the user clicks on an anchor. However, Netscape Navigator recognizes only JavaScript and will attempt to navigate to an invalid page if any other language is specified.

Events as Properties

All events are also exposed as properties in the Dynamic HTML object model. The property names are entirely in lowercase and begin with the prefix on. The purpose of exposing both events and event properties is to enable events to be dynamically bound to functions at run time. All event properties can be assigned a function pointer.

Whether function pointers are supported depends on the scripting language. JavaScript supports function pointers, but VBScript does not. Therefore, VBScript cannot generate an event handler dynamically. (However, you can use VBScript code to assign a JavaScript function to an event.) When the event occurs, the function specified by the property is invoked.

<HTML>
   <HEAD>
      <TITLE>Function Pointer Example</TITLE>
   </HEAD>
   <BODY>
      <INPUT TYPE=BUTTON ID="myButton" VALUE="Click here">
      <SCRIPT LANGUAGE="JavaScript">
         // Attach a function pointer to myButton. 
         // When myButton is clicked, an alert box is displayed.
         document.all.myButton.onclick = 
            new Function("alert(`Hello');");
      </SCRIPT>
   </BODY>
</HTML>

To assign a function pointer, assign the name of the function directly to the property.

<HTML>
   <HEAD>
      <TITLE>Function Pointer Assignment</TITLE>
      <SCRIPT LANGUAGE="JavaScript">
         // Define a function named clicked.
         function clicked() {
            alert("Clicked");
         }
      </SCRIPT>
   </HEAD>
   <BODY>
      <INPUT TYPE=BUTTON ID="myButton" VALUE="Click here">
      <SCRIPT LANGUAGE="JavaScript">
         // Assign the clicked function to the onclick handler.
         document.all.myButton.onclick = clicked;
      </SCRIPT>
   </BODY>
</HTML>


NOTE: When assigning a function pointer, use only the name of the function. Do not supply parentheses or specify any parameters. Doing so will cause the function to be executed, resulting in the function's return value, rather than a pointer to the function itself, being assigned to the property.

Timing of Event Binding

The point at which event handlers are bound to elements depends on the scripting language. JavaScript hooks up events asynchronously while the page is being loaded. Each Script element and event attribute is hooked up as it is parsed from the document. VBScript, on the other hand, does not bind events until the entire page is parsed, all external scripts are downloaded, and embedded objects have begun loading.

For JavaScript, this means that events can start firing in response to user or other actions before the page is entirely downloaded. Therefore, you should take care that your event handlers don't try to access any elements that might not have downloaded yet.

You can write code that first checks for the presence of the element or, more generically, simply checks whether the entire page is parsed. Checking whether the page is completely parsed is the simplest method and should be compatible across scripting languages and browsers:

<HTML>
   <HEAD>
      <TITLE>Parsing Example</TITLE>
      <SCRIPT LANGUAGE="JavaScript">
         function doClick() {
            if (isLoaded) {
               // Run event handler.
            }
            else {
               alert("Please wait for the document to finish 
                  loading.");
            }
         }
      </SCRIPT>
   </HEAD>
   <BODY>
      <INPUT TYPE=BUTTON ID="myInput" VALUE="Click here"
         ONCLICK="doClick()">
      <SCRIPT LANGUAGE="JavaScript">
         // This should be the last element parsed in the document.
         isLoaded = true;
      </SCRIPT>
   </BODY>
</HTML>

You can also use an event handler to check whether the entire page has been parsed. Two events can be used for this purpose: the onload event on the window, and the onreadystatechange event on the document. The onload event fires when the entire document is parsed and all elements are loaded. The more powerful onreadystatechange event on the document, which is supported only in Internet Explorer 4.0, fires several times as the document passes through several loading states and fires for the last time when the document is fully loaded. The onload and onreadystatechange events are discussed in detail in Chapter 4, "The Browser Window," and Chapter 6, "The HTML Document."

Scoping of Scripts

All event handlers are scoped to the element to which the handler is bound. This element is exposed to the scripting language in JavaScript using the this property and in VBScript using the me property.

The event's scope is not necessarily the element that first fired the event. The element that first fired the event is exposed through the srcElement property on the event object. The event object is discussed in more detail in the section "The event Object" later in this chapter.

Controlling the this Pointer

The following code demonstrates the three different ways you can bind a handler to an event. All three handlers are effectively equivalent to each other.

<INPUT NAME="myBtn" TYPE=BUTTON VALUE="My Button"
   onClick="alert(this.name);" LANGUAGE="JavaScript">

or

<SCRIPT FOR="myBtn" EVENT="onclick()" Language="JavaScript">
   alert(this.name);
</SCRIPT>

or

<SCRIPT LANGUAGE="JavaScript">
   myBtn.onclick = new Function("alert(this.name)");
</SCRIPT>

In these three examples, this.name returns myBtn because the element is referenced directly in the inline code or script. If you want to reference the element in a subroutine called by an event handler, you need to pass the element to the subroutine using the this keyword. For example, the following code will display an empty string rather than the text myBtn because the this pointer in the foo function refers to the function itself instead of the element that generated the event:

<SCRIPT LANGUAGE="JavaScript"> 
   function foo() {

      // The this pointer does not refer to the button.
      alert(this.name);
   }
</SCRIPT>
<INPUT TYPE=BUTTON NAME="myBtn" VALUE="My Button"
   ONCLICK="foo();" LANGUAGE="JavaScript">

Instead, you should pass a reference to the myBtn element to the foo function using the this keyword:

<SCRIPT LANGUAGE="JavaScript"> 
   function foo(b) {
      // The b argument refers to the button because it was passed in
      // by the event handler.
      alert(b.name);
   }
</SCRIPT>
<INPUT TYPE=BUTTON NAME="myBtn" VALUE="My Button"
   ONCLICK="foo(this);" LANGUAGE="JavaScript">

The this pointer is also automatically set when an event handler is assigned as a function pointer:

<H1 ID="myH1">This is a header.</H1>
<SCRIPT LANGUAGE="JavaScript">
   function clickHandler() {
      // The this property points to the element
      // to which the handler is bound.
      alert(this.tagName)
   }
   // Function pointer assignments do not need to pass the
   // this pointer.
   document.all.myH1.onclick = clickHandler; 
</SCRIPT>

Names in inline code are resolved by searching members of the object model in the following order:

  1. All properties of the current element
  2. All elements exposed for the name space—for example, in a form, the controls on the form
  3. The properties of the element containing the name space—for example, the form's properties for elements within the form
  4. The properties on the document

Shared Event Handlers

JavaScript supports the creation of a shared event handler. In JavaScript, any elements that share the same name can also share the same event handlers by using the Script element's FOR and EVENT attributes syntax:

<SCRIPT FOR="gender" EVENT="onclick()" LANGUAGE="JavaScript">
   // This event handler executes whenever any element with the name
   // or ID "gender" is clicked.
</SCRIPT>
<INPUT TYPE=RADIO NAME="gender" VALUE="Male">
<INPUT TYPE=Radio NAME="gender" VALUE="Female">

This technique works only in JavaScript. VBScript can fire an event handler this way only on the basis of an element's unique ID, not its NAME. If this code were rewritten in VBScript, the radio buttons would need to be supplied with unique ID values, and separate handlers would need to be written for each one.

An alternative for VBScript that also works for any scripting language is to use event bubbling and track the event from a parent container:

<SCRIPT FOR="GenderGroup" EVENT="onclick()" LANGUAGE="VBScript">
   ` This event handler executes whenever any element within
   ` the GenderGroup block is clicked.
   If "gender" = window.event.srcElement.name Then
      ` User clicked a radio button.
   End If
</SCRIPT>
<DIV ID="GenderGroup">
   <INPUT TYPE=Radio NAME="gender" VALUE="Male">
   <INPUT TYPE=Radio NAME="gender" VALUE="Female">
</DIV>

[Содержание]