На главную страницу

Раздел 11. Использование технологии AJAX в ASP.NET

Аннотация:

  • В ASP.NET 2 альтернативой технологии AJAX стала технология ATLAS и использование клиентского диспетчера обратных вызовов. Однако, многих программистов отпугивает относительная сложность в их применении. И, кроме того, наличие множества старых наработок не так-то просто выбросить в корзину. В тоже время, как Вы убедитесь из приведенного ниже материала, ASP.NET отлично приспособлен для работы с AJAX.

  • В данном разделе приведены в подавляющей части эксклюзивные примеры, которые явились находками автора в его попытках соединить AJAX и ASP.NET.

  • В основу материала положены направления освоения тематики, предложенные в [1]. И, хотя книга Стивена Хольцнера заточена под PHP (язык, которому и автор отдал немало времени, когда он был в моде), я бы рекомендовал иметь ее настольной книгой и разработчикам ASP.Net. В ней глубоко рассматриваются вопросы именно JavaScript кодирования для Ajax. В силу того, что эти вопросы уже хорошо изложены в литературе, на них, в данном материале, обращается меньше внимания.

  • Литература


    В начало

    Глава 1. Технология AJAX - первый взгляд


    В начало

    Параграф 1. Введение в AJAX

    AJAX (Asynchronous JavaScript And XML - асинхронный JavaScript+XML), обозначает подход к созданию веб-приложений, при котором после первичного вызова Web страницы она получает возможность обмена данных с сервером и отображения данных без необходимости своей перегрузки.

    Это обеспечивают ряд механизмов, основной из которых - движок AJAX. Это посредник между браузером (загруженной в него страницей) и сервером, способный передавать данные серверу и принимать их от него. Окончательно этот механизм сформировался в 1998 году, когда в Internet Explorer 5.0 были внедрены новые ActiveX объекты, и, в частности, XMLHttpRequest объект. Именно XMLHttpRequest приобрел наибольшую популярность и поддержку в других браузерах (Mozilla Firefox, начиная с версии 1.0, Opera, начиная с версии 8.0, Safari...).

    Движок AJAX (XMLHttpRequest) производит необходимые запросы асинхронно, обычно при помощи XML, не прерывая взаимодействия пользователя с приложением. Ответ сервера - это либо текстовая строка, либо XML документ.

    Отсюда и последняя буква в названии технологии, хотя, абсолютно равно было бы и "T".

    XMLHttpRequest объект создается для страницы, именно как объект, в момент ее загрузки или при необходимости обмена данных с сервером. Созданный объект имеет свои методы и свойства, доступные коду JavaScript скриптов страницы. Вот основные:

    • open('Тип запроса "GET" или "POST"', "URL страницы", 'исполнение запроса - "True" - асинхронное исполнение', 'username', 'pasword') - создает запрос к серверу.

    • send('content') - отправляет запрос на сервер. В качестве значений может быть null или данные для запроса "POST" или пустая строка.

    • onreadystatechange - событие, возникающее при смене состояния объекта.

      • 0 - (uninitialized) - запрос не отправлен;

      • 1 - (loading) - объект инициализирован;

      • 2 - (loaded) - получен ответ от сервера;

      • 3 - (interactive) - соединение с сервером активно;

      • 4 - (complete) - объект завершил работу;

    • responseText - взять данные от сервера в виде строки.

    • responseXML - взять данные от сервера в виде XML;

    • status - свойство статус HTTP-ответа (например, 404 - страница не найдена на сервере).

    Повторимся, все свойства и методы объекта, доступны из JavaScript скриптов.

    Таким образом, AJAX, как ее трактуют сами разработчики, это несколько технологий, объединенных в новое направление:

    • стандартизованное представление данных с использованием XHTML и CSS;

    • динамическое отображение и взаимодействие при помощи DOM (Document Object Model);

    • обмен и управление данными через XML и XSLT;

    • асинхронные получение данных с использованием XMLHttpRequest;

    • JavaScript, как язык, связывающий всё компоненты.


    В начало

    Параграф 2. Простейшее использование

    Создадим сайт (с любым именем) и поместим на форму серверные контролы Button и Label (расположение контролов можно оформить по собственному усмотрению). Поместим в Page_Load следующий код:

    if (!IsPostBack)
    {
     Label1.Text = "Текст при первой загрузке страницы Default.aspx";
    }
    else
    {            
     Label1.Text = "Текст при перегрузке страницы";
    }
    

    Этот код будет сигнализировать о том, что страница не перегружается при использовании AJAX вызовов. Загрузим web сайт, текст в Label1 будет "Текст при первой загрузке страницы Default.aspx", нажимаем серверную кнопку - "Текст при перегрузке страницы". По смене текста будем судить о том, перегружалась или нет страница.

    Переходим к внедрению непосредственно элементов AJAX. В качестве первого примера возьмем широко используемый в сети и учебниках пример загрузку данных из текстового файла.

    Добавим на страницу Default.aspx еще один серверный контрол Label и Html контрол Input (Buton). Для события onclick запишем вызов некоторой функции getDataFromServer('datafile.txt', 'Label2') при нажатии кнопки. Задача функции - вывести данные в Label2 из файла без перегрузки страницы.

    <body>
        <form id="form1" runat="server">
        <table width="99%" border="1">
      <tr><td>
      <asp:Button ID="Button1" runat="server" Height="36px" Text="Серверная кнопка" 
              Width="250px" Font-Bold="True"/>
      </td></tr>    
      <tr><td>
        <asp:Label ID="Label1" runat="server" Text="Label 1"></asp:Label><br/>
      </td></tr> 
      <tr><td>
        <asp:Label ID="Label2" runat="server" Text="Сюда будем выводить текст"> <br/>
      </td></tr>
      <tr><td align="center"><font size ="+1">Ajax пример 1</font></td></tr> 
      <tr><td>  
          <input type = "button"  id="Button2" value = "Загрузить текст из текстового файла" 
            onclick = "getDataFromServer('datafile.txt', 'Label2')"/>  
        </td></tr>    
      </table>
        </form>
    </body>
    

    Запишем в файл datafile.txt текст:

    Этот текст записан в файле datafile.txt
    

    Приступим к формированию скрипта, который будет содержать функцию getDataFromServer:

    <head runat="server">
    <title>AJAX и ASP.NET</title>    
    <script language = "javascript" type="text/javascript">
    function getDataFromServer(dataSource, targetControl) 
    { 
    }
    
    <script>
    <head>
    

    Первое, что добавляем в файл - создание XMLHttpRequest объекта. О том, где и как формировать XMLHttpRequest объект можно подробно посмотреть в приведенной литературе, и, в частности, в [1]. Отметим, что мы поместим создание объекта во всех примерах именно в функции, что позволяет создавать новый объект при каждом ее вызове. В примерах, которые будут приводиться далее, это предотвратит наложение вызовов, если пользователь выполнит запрос функции ранее, чем функция освободит объект.

    var myAjaxObject = false;   
    if (window.XMLHttpRequest) 
    {
     myAjaxObject = new XMLHttpRequest();
    } 
    else 
    {
     if (window.ActiveXObject) 
     {
      myAjaxObject = new ActiveXObject("Microsoft.XMLHTTP");
     }
    }
    

    Создание объектов различно для браузеров Mozilla Firefox, Opera, Safari и некоторых других (new XMLHttpRequest()) и Internet Explorer (new ActiveXObject("Microsoft.XMLHTTP")), что и отражает данный код. Далее, после проверки того, что объект создан, мы создаем запрос к серверу (метод "open"). К событию, возникающему при смене состояния объекта (onreadystatechange), добавляем безымянную функцию, задачей которой будет слежение за состоянием объекта (нас интересует завершение получения данных):

    if(myAjaxObject) 
    {
     myAjaxObject.open("GET", dataSource);
     myAjaxObject.onreadystatechange = 
     function() 
     { 
     }
    }
    

    В теле функции определяем, что загрузка данных завершена (readyState == 4) и обмен прошел без ошибок (status == 200). Осталось получить текст (myAjaxObject.responseText) и присвоить его свойству innerHTML элемента Label2:

    if (myAjaxObject.readyState == 4 && myAjaxObject.status == 200) 
    { 
     var targetObj = document.getElementById(targetControl); 
     targetObj.innerHTML = myAjaxObject.responseText;                 
     delete myAjaxObject;
     myAjaxObject=null;
    }     
    

    И последнее - отсылка запроса на сервер:

    myAjaxObject.send(null); 
    

    Приведем полностью текст скрипта:

    <script language = "javascript" type="text/javascript">
    function getDataFromServer(dataSource, targetControl) 
    { 
     var myAjaxObject = false;   
     if (window.XMLHttpRequest) 
     {
      myAjaxObject = new XMLHttpRequest();
     } 
     else 
     {
      if (window.ActiveXObject) 
      {
       myAjaxObject = new ActiveXObject("Microsoft.XMLHTTP");
      }
     }
     if(myAjaxObject) 
     {
      myAjaxObject.open("GET", dataSource);
      myAjaxObject.onreadystatechange = 
      function() 
      { 
       if (myAjaxObject.readyState == 4 && myAjaxObject.status == 200) 
       { 
        var targetObj = document.getElementById(targetControl); 
        targetObj.innerHTML = myAjaxObject.responseText;                 
        delete myAjaxObject;
        myAjaxObject=null;
       }
      } 
      myAjaxObject.send(null);   
     }   
    }
    </script>    
    

    Откомпилируем решение сайта и выполним его. Посмотрим результаты до и после нажатия кнопки "Загрузить текст из текстового файла" (Рис.1.1.).

    ajax0101.gif

    Рис.1.1. Получение текста из файла

    Из Рис.1.1. видно:

    • Загрузка данных из файла выполнена без перегрузки страницы (в Label1 "Текст при первой загрузке страницы Default.aspx").

    • Из файла вместо "Этот текст записан в файле datafile.txt" выведена строка "????????? datafile.txt". Это говорит о том, что XMLHttpRequest не очень дружит с кириллицей.

    Обойти неувязки с кирилицей можно - достаточно сохранить текст в файле в кодировке Unicode (можно воспользоваться старым и добрым Wordpad, или другим текстовым редактором, позволяющим сохранять текстовы данные в Unicode), но это явно не выход. Рассмотрим другой подход.


    В начало

    Параграф 3. Использование HttpHandler для обмена данными с XMLHttpRequest

    В Разделе 7. "Основы работа с графикой на С# в Visual Studio 2005/2008" подробно описано использование HttpHandler на Web сайтах см. "Два подхода к отображению графической информации в ASP.NET". Поэтому здесь мы приводим только шаги создания web сайта с использованием HttpHandler.

    Все примеры могут быть выполнены и с использованием второго подхода к отображению графической информации в ASP.NET - дополнительной странице. Порой это даже проще, но ведет к росту пустых страниц в больших проектах, что не очень удобно для ориентации в решении сайта.

    • Добавим к проекту класс с именем MyHandlerAjax и включим в него необходимые методы и свойства интерфейса IHttpHandler (кроме того, в класс сразу включены пространства имен, которые понадобятся в других примерах):

      using System;
      using System.Data;
      using System.Configuration;
      using System.Linq;
      using System.Web;
      using System.Web.Security;
      using System.Web.UI;
      using System.Web.UI.HtmlControls;
      using System.Web.UI.WebControls;
      using System.Web.UI.WebControls.WebParts;
      using System.Xml.Linq;
      using System.Drawing;
      using System.IO;
      using System.Drawing.Imaging;
      
      public class MyHandlerAjax : IHttpHandler
      {	
        #region IHttpHandler Members
        public bool IsReusable
        {
         get { return true; }
        }
        public void ProcessRequest(HttpContext context)
        {
         HttpRequest Request = context.Request;
         HttpResponse Response = context.Response;        
         //Здесь будет код обработки запроса
      
        }
        #endregion
      }
      
    • В web.config, в секцию <handlers> добавим строку:

      <add verb="GET" path="getajax.aspx" type="MyHandlerAjax" />
      

    Внесем всего одно изменение в страничку "Default.aspx":

    <input type = "button"  id="Button2" value = "Загрузить текст из текстового файла" 
            onclick = "getDataFromServer('getAjax.aspx', 'Label2')"/>
    

    В код класса MyHandlerAjax добавим код чтения файла:

    void IHttpHandler.ProcessRequest(HttpContext context)
    {
     HttpRequest Request = context.Request;
     HttpResponse Response = context.Response;
     string s = AppDomain.CurrentDomain.BaseDirectory + (@"datafile.txt");        
     byte[] bText;
     using (FileStream filestream = new FileStream(s, FileMode.Open, FileAccess.Read))
     {
      int bufSize = (int)filestream.Length;
      bText = new byte[bufSize];
      filestream.Read(bText, 0, (int)filestream.Length);
     }
     //Так мы вновь потеряем кирилицу
     //Response.BinaryWrite(bText); 
     //А так нет
     s = System.Text.Encoding.Default.GetString(bText);
     Response.Write(s);
    }
    

    Откомпилируем решение сайта и выполним его. Посмотрим результаты после нажатия кнопки "Загрузить текст из текстового файла" (Рис.1.2.).

    ajax0102.gif

    Рис.1.2. Получение текста из файла с использованием HttpHandler


    В начало

    Параграф 4. Возможность выбора загружаемой информации

    Создадим еще один файл с именем datafile2.txt и в нем запишем информацию, отличную от информации в datafile.txt.

    Внесем в страничку Default.aspx еще одну кнопку и назначим функции для первой кнопки выбор данных из файла datafile.txt, для второй из datafile2.txt. Это назначение укажем в командной строке обращения к HttpHandler через введение параметров:

    <input type = "button"  id="Button2" value = "Загрузить текст из файла datafile.txt" 
     onclick = "getDataFromServer('getAjax.aspx?id=1', 'Label2')"/> 
     <input type = "button"  id="Button3" value = "Загрузить текст из файла datafile2.txt" 
     onclick = "getDataFromServer('getAjax.aspx?id=2', 'Label2')"/> 
    

    Функцию IHttpHandler.ProcessRequest в коде класса MyHandlerAjax.cs изменим следующим образом:

    void IHttpHandler.ProcessRequest(HttpContext context)
    {
     HttpRequest Request = context.Request;
     HttpResponse Response = context.Response;
     string s = string.Empty;
     //Извлечение параметров
     s = Request.QueryString.Get(0);
     if (!string.IsNullOrEmpty(s))
     {
      if (s == "1")
      {
       s = AppDomain.CurrentDomain.BaseDirectory + (@"datafile.txt");
      }
      else
      {
       s = AppDomain.CurrentDomain.BaseDirectory + (@"datafile2.txt");
      }
     }
     else
     {
      return;
     }                
     byte[] bText;
     using (FileStream filestream = new FileStream(s, FileMode.Open, FileAccess.Read))
     {
      int bufSize = (int)filestream.Length;
      bText = new byte[bufSize];
      filestream.Read(bText, 0, (int)filestream.Length);
     }
     s = System.Text.Encoding.Default.GetString(bText);
     Response.Write(s);
    }
    

    ajax0103.gif

    Рис.1.3. Получение текста из различных файлов с использованием HttpHandler

    В начало

    Параграф 5. Выбор и отображение графической информации

    Для выполнения примеров данного параграфа несколько изменим код сайта.

    На странице Default.aspx уберем кнопки и вместо них поместим HTML контрол Select:

    <select id="Select1" 
       onchange="getDataFromServer('getAjax.aspx?='+this.options[this.selectedIndex].value,
                'iddivforimage')">          
        <option value="1">Рисунок 1</option>
        <option value="2">Рисунок 2</option>          
    </select>
    

    Подготовим место для рисунков

     <div id="iddivforimage"></div>
    

    Немного изменим функцию getDataFromServer. Задача функции теперь принять рисунок от HttpHandler:

    if (myAjaxObject.readyState == 4 && myAjaxObject.status == 200) 
    { 
      var targetObj = document.getElementById(targetControl); 
      targetObj.innerHTML = "<img src= "+dataSource+">";                 
      delete myAjaxObject;
      myAjaxObject=null;
    }
    

    В директорию сайта добавим рисунки myImage.jpg и myImage1.jpg.

    IHttpHandler.ProcessRequest изменим более значительно:

    void IHttpHandler.ProcessRequest(HttpContext context)
    {
     HttpRequest Request = context.Request;
     HttpResponse Response = context.Response;
     string s = string.Empty;
     s = Request.QueryString.Get(0);
     if (!string.IsNullOrEmpty(s))
     {
      if (s == "1")
      {
       s = AppDomain.CurrentDomain.BaseDirectory + (@"myImage.jpg");
      }
      else
      {
       s = AppDomain.CurrentDomain.BaseDirectory + (@"myImage1.jpg");
      }
     }
     else
     {
      s = AppDomain.CurrentDomain.BaseDirectory + (@"myImage.jpg");
     }
     using (MemoryStream memorystream = new MemoryStream())
     {
      Bitmap bitmap = null;
      try
      {
       bitmap = new Bitmap(s);
       bitmap.Save(memorystream, ImageFormat.Png);
       byte[] b = memorystream.GetBuffer();
       //Формат файла рисунка может быть отличен от исходного файла
       Response.ContentType = "image/png";
       Response.BinaryWrite(b);
       bitmap.Dispose();
      }
      catch (Exception)
      {
      }
      memorystream.Dispose();
     }
    }
    

    Результат работы кода представлен на Рис.1.4.

    ajax0104.gif

    Рис.1.4. Получение изображений из различных файлов с использованием HttpHandler

    Решение сайта на данном этапе можно скачать по этой ссылке ~ 11.8 кб.


    В начало

    Параграф 6. Оправдывая название

    Перейдем непосредственно к использованию XML данных. Как видно из рассмотренных в Параграфе 1 свойств и методов объекта XMLHttpRequest он имеет специальное свойство для трактовки данных, полученных от сервера, как XML данные. Это свойство, доступное для чтения - responseXML. Далее, JavaScript имеет методы для разбора XML файлов.

    Следующий пример демонстрирует простейшее использование совместной работы Ajax и JavaScript при получении и разборке XML данных с сервера без перегрузки страницы.

    Создадим простой XML файл data.xml и поместим его в директорию сайта. Подробно о работе с XML файлами мы говорили в Раздел 10. Работа с XML файлами в Visual Studio NET и, поэтому, здесь приводим только текст самого файла, который мы можем использовать для вывода по запросу ссылок на литературу (можно создать подобные списки телефонов, адресов друзей...).

    <?xml version = "1.0" standalone="yes" ?>
    <sites>
      <site comments="Язык преобразований XSL (XSLT)">http://www.rol.ru/news/it/helpdesk/xslt01.htm</site>
      <site comments="Работа с XML в .NET">http://www.realcoding.net/article/view/1810</site>
      <site comments="XML Spreadsheet Reference">http://msdn.microsoft.com/en-us/library/aa140066.aspx</site>
    </sites>
    

    Теперь подготовим почву для приема и отображения информации. Для этого в предыдущем примере внесем следующие изменения:

    • Вместо HTML контрола Select вновь поместим HTML контрол Input (Buton).

      <input type = "button" value = "Список литературы" onclick = 
        "getDataFromServer('getAjax.aspx',iddivforlist')" id="Button2"  /> 
      
    • Под кнопкой поместим элемент div:

       <div id="iddivforlist">  </div> 
      
    • И начнем формировать функцию получения и преобразования XML документа:

      if (myAjaxObject.readyState == 4 && myAjaxObject.status == 200) 
      { 
       //Получение XML данных
       var xmlDocument = myAjaxObject.responseXML;                  
       .......
       delete myAjaxObject;
       myAjaxObject=null;
      }
      

    Формирование разборки XML файла и преобразование тэгов XML в HTML код - область знания, относящаяся к JavaScript и HTML, поэтому здесь приводится только результирующий код:

    if (myAjaxObject.readyState == 4 && myAjaxObject.status == 200) 
    {        
     var xmlDocument = myAjaxObject.responseXML;                  
     var i;        
     var points = xmlDocument.getElementsByTagName("site");
     var html='';
     for (i = 0; i < points.length; i++)
     {
       html=html+'<a href="'+points[i].firstChild.data+'" target="blank">'+
       points[i].getAttribute ('comments')
       +'</a><br/>';      
     }  
     var targetObj = document.getElementById(targetControl); 
     targetObj.innerHTML =html+"";
     delete myAjaxObject;
     myAjaxObject=null;
    }
    

    Осталось изменить класс HttpHandler. Обратим внимание на важную строчку (помечено цветом), без которой передача XML файла, как такового, не будет выполнена:

    void IHttpHandler.ProcessRequest(HttpContext context)
    {
     HttpRequest Request = context.Request;
     HttpResponse Response = context.Response;
     string s = string.Empty;
     s = AppDomain.CurrentDomain.BaseDirectory + (@"data.xml");
     using (FileStream filestream = new FileStream(s, FileMode.Open, FileAccess.Read))
     {
      using (TextReader streamreader = new StreamReader(s, System.Text.Encoding.Default))
      {
       s = streamreader.ReadToEnd();
       Response.ContentType = "text/xml";
       Response.BinaryWrite(System.Text.Encoding.UTF8.GetBytes(s));
      }
     }
    }
    

    Результат выполнения решения сайта, показан на Рис.1.5.

    ajax0105.gif

    Рис.1.5. Получение и использование информации из XML файла

    Решение сайта на данном этапе можно скачать по этой ссылке ~ 4.2 кб.


    В начало

    Параграф 7. Традиционный пример со сменой меню

    Вначале я не хотел приводить этот пример - все уже сказано в предыдущем параграфе. Но вспомнив аксиому, что программист пишет код один раз, а использует его бесконечно, и что этот код уже есть и работает, решил, после его легкого упрощения, поделиться им с вами.

    И так, создаем два XML файла, содержащие некоторое меню на разных языках (menu1.xml и menu2.xml):

    <?xml version = "1.0" standalone="yes" ?>
    <menu>
      <menuitem>Страница 1</menuitem>
      <menuitem>Страница 2</menuitem>
      <menuitem>Страница 3</menuitem>
    </menu>
    
    
    <?xml version = "1.0" standalone="yes" ?>
    <menu>
      <menuitem>Page 1</menuitem>
      <menuitem>Page 2</menuitem>
      <menuitem>Page 3</menuitem>
    </menu>
    

    В проекте решения в файле Default.aspx определим две кнопки:

    <input type = "button" value = "Не наше меню" 
      onclick ="getDataFromServer('getAjax.aspx?id=2','iddivforlist')" id="Button2"  /> <br/>
    <input type = "button" value = "Наше меню" 
      onclick = "getDataFromServer('getAjax.aspx?id=1','iddivforlist')" id="Button3"  /> 
    

    Поместим на форму HTML контрол Select - то куда будем выводить меню, и определим функцию, которая будет вызываться при использовании меню:

    <select id="mymenu" onchange="usemenu()" >
        <option>Выбрать пункт меню</option>
    </select>
    

    Функцию IHttpHandler.ProcessRequest в коде класса MyHandlerAjax.cs изменим следующим образом:

    void IHttpHandler.ProcessRequest(HttpContext context)
    {
     HttpRequest Request = context.Request;
     HttpResponse Response = context.Response;
     string s = string.Empty;
     //Извлечение параметров
     s = Request.QueryString.Get(0);
     if (!string.IsNullOrEmpty(s))
     {
      if (s == "1")
      {
       s = AppDomain.CurrentDomain.BaseDirectory + (@"menu1.xml");
      }
      else
      {
       s = AppDomain.CurrentDomain.BaseDirectory + (@"menu2.xml");
      }
     }
     else
     {
      return;
     }                
     byte[] bText;
     using (FileStream filestream = new FileStream(s, FileMode.Open, FileAccess.Read))
     {
      int bufSize = (int)filestream.Length;
      bText = new byte[bufSize];
      filestream.Read(bText, 0, (int)filestream.Length);
     }
     s = System.Text.Encoding.Default.GetString(bText);
     Response.ContentType = "text/xml";
     Response.Write(s);
    }
    

    Внесем изменения в функцию getDataFromServer (только на этапе трактовки информации):

    if (myAjaxObject.readyState == 4 && myAjaxObject.status == 200) 
    {        
     var xmlDocument = myAjaxObject.responseXML;        
     var targetObj = document.getElementById(targetControl);     
     var points = xmlDocument.getElementsByTagName("menuitem"); 
     var i;
     for (i = 0; i < points.length; i++)
     {     
      targetObj.options[i] = new 
               Option(points[i].firstChild.data);     
     }       
     delete myAjaxObject;
     myAjaxObject=null;
    } 
    

    И наконец функция используюшая меню:

    function usemenu()
    {
      document.getElementById('iddiv').innerHTML = 
         "Выбран пункт: " + document.getElementById('mymenu').o
            ptions[document.getElementById('mymenu').selectedIndex].text;          
    }     
    

    Для вывода результатов выбора предусмотрен тэг div:

    <div id ="iddiv"></div> 
    

    Результат выполнения решения сайта, показан на Рис.1.6.

    ajax0106.gif

    Рис.1.6. Получение и использование информации из XML файла для смены меню

    Решение сайта на данном этапе можно скачать по этой ссылке ~ 4.6 кб.


    В начало

    Параграф 8. Метод "Post"

    В данном параграфе мы покажем, как использовать метод POST для обмена данными между страницей и сервером без перегрузки страницы.

    Преимущество POST запросов по сравнению с GET-запросами - их большая безопасность и возможность передачи больших объемов информации. Поэтому метод POST обычно используют для передачи "скрытой" информации (не отображается в строке запроса), а также информации большого объема. В данной главе мы будем использовать метод POST для отсылки информации небольшого объема (как и ранее, для конкретизации того, что мы хотим получить с сервера). Пересылка больших объемов информации не является принципиальной для понимания механизмов работы AJAX при использовании метода "POST"

    Начнем с построения скрипта для взаимодействия с сервером методом "Post", а именно создания функции postDataFromServer. В первую очередь увеличим число параметров, передаваемых функции. Параметр datasend необходим для передаваемых данных на сервер.

    <script language = "javascript" type="text/javascript">
    function postDataFromServer(dataSource, targetControl,datasend) 
    { 
    }
    </script>
    

    Как и в предыдущей главе создаем XMLHttpRequest объект. В познавательных целях изменим код его создания - учтем то, что Internet Explorer, практически для каждой новой версии, имеет свой новый XMLHttpRequest объект (MSXML2.XMLHTTP, MSXML2.XMLHttp.3.0, MSXML2.XMLHttp.4.0, MSXML2.XMLHttp.5.0, Microsoft.XMLHttp). В приведенном коде выполняется попытка работы с самым современным объектом XMLHttpRequest.

    var myAjaxObject = false; 
    try 
    { 
      myAjaxObject = new ActiveXObject("MSXML2.XMLHttp.5.0"); 
    } 
    catch (exception1) 
    { 
     try 
     { 
      myAjaxObject = new ActiveXObject("MSXML2.XMLHttp.4.0"); 
     } 
     catch (exception2) 
     { 
      try 
      { 
       myAjaxObject = new ActiveXObject("MSXML2.XMLHttp.3.0"); 
      } 
      catch (exception3) 
      { 
       try 
       { 
        myAjaxObject = new ActiveXObject("MSXML2.XMLHttp"); 
       } 
       catch (exception4) 
       { 
        if (window.XMLHttpRequest) 
        {
         myAjaxObject = new XMLHttpRequest();
        } 
        else 
        {
         if (window.ActiveXObject) 
         {
           myAjaxObject = new ActiveXObject("Microsoft.XMLHTTP");
         }
        } 
    
       } 
      }
     }
    } 
    

    Этот код легко использовать для выяснения того, какой именно объект в IE в вашей организации (если Вы делаете закрытые корпоративные сайты, то это может быть полезно). Достаточно в коде, после каждой попытки создание объекта присвоить значение некоторой переменной и вывести ее в innerHTML какого либо тэга. Так, было установлено, что IE 7.0.5730.11 имеет MSXML2.XMLHttp.5.0 объект.

    Далее формируем запрос, указывая тип запроса "POST", и, собственно, отсылаем данные - myAjaxObject.send("mydata=" + datasend);

    if(myAjaxObject) 
    {
     myAjaxObject.open("POST", dataSource); 
     myAjaxObject.setRequestHeader('Content-Type', 
                'application/x-www-form-urlencoded'); 
     myAjaxObject.onreadystatechange = 
     function() 
     { 
      if (myAjaxObject.readyState == 4 &&  myAjaxObject.status == 200) 
      { 
    
    
       delete myAjaxObject;
       myAjaxObject=null;
      }   
     } 
     myAjaxObject.send("mydata=" + datasend); 
    }
    

    Больше отличий использования типа запроса "POST" от использования типа запроса "GET" нет. В теле безымянной функции function() будут повторяться те же коды, что мы использовали во всех предыдущих параграфах (естественно, что в контексте выполняемых задач).

    Теперь необходимо в секции httpHandlers файла web.config добавить строку:

    <httpHandlers>
    ......
    <add verb="POST" path="getAjax.aspx" type="MyHandlerAjax" />
    </httpHandlers>
    

    Что касается извлечения данных, то будем вновь использовать наш класс HttpHandler. В нем изменится только извлечение переданной информации. Пусть мы хотим передавать по запросу данные из первого либо второго файла:

    void IHttpHandler.ProcessRequest(HttpContext context)
    {
     HttpRequest Request = context.Request;
     HttpResponse Response = context.Response;
     string s = string.Empty;
     if (Request.Form["mydata"] != null)
     {
      s = Request.Form["mydata"];
     }
     if (s == "1")
     {
      s = AppDomain.CurrentDomain.BaseDirectory + (@"data1.txt");
     }
     else
     {
      s = AppDomain.CurrentDomain.BaseDirectory + (@"data2.txt");
     }
     byte[] bText;
     using (FileStream filestream = new FileStream(s, FileMode.Open, FileAccess.Read))
     {
      int bufSize = (int)filestream.Length;
      bText = new byte[bufSize];
      filestream.Read(bText, 0, (int)filestream.Length);
     }
     s = System.Text.Encoding.Default.GetString(bText);
     Response.Write(s);
    }
    

    Соответственно файлы data1.txt и data2.txt содержат следующие строки:

    Текст из первого файла
    
    и
    
    Текст из второго файла
    

    Осталось связать все, оформив вызовы на страничке Default.aspx и место для вывода информации:

    <input type = "button" value = "Файл 1" o
     nclick ="postDataFromServer('getAjax.aspx','iddiv','1')" id="Button2"  /> 
    <input type = "button" value = "Файл 2" 
     onclick ="postDataFromServer('getAjax.aspx','iddiv','2')" id="Button3"  /> 
    
    <div id="iddiv"></div>
    

    Результат работы кода представлен на Рис.1.7.

    ajax0107.gif

    Рис.1.7. Использование метода "POST"

    Решение сайта на данном этапе можно скачать по этой ссылке ~ 4.2 кб.

    Глава 2. Более сложные примеры использования


    В начало

    Параграф 1. Выпадающие списки поиска в поисковых системах

    Следующий пример показывает то, как в современных поисковых системах облегчается выбор (или предлагается) слов и предложений для поиска. Наберите в Google "JavaScript". Уже после ввода первой буквы появляется выпадающий список с предлагаемыми вариантами, который сужается по мере ввода очередной буквы. На любом этапе, кликнув по строке в выпадающем списке, вы выбираете то, что в данной строке, а сервер выдает вам результаты поиска.

    Стивен Хольцнер, дословно, написал о данной системе поиска следующее: "Среди известных Ajax-приложений существует несколько выдающихся, в частности, Google Suggest". Правда, в его книге [1] показано только то, как внедрить в свое приложения этот сервис прямо с сайта Google. И ничего нет насчет реализации. Вряд ли кто будет переписывать поиск в Yandex или Google, а вот идею этого поиска можно использовать в сотнях примеров (адреса, телефоны, списки, ссылки... ). Построим сайт, реализующий это "выдающееся приложение".

    Пример, который здесь описан, работает, как показано на Рис.2.1.

    ajax0201.gif

    Рис.2.1. Выпадающие списки поиска в поисковых системах

    Для реализации этого примера в директории сайта поместим файл data1.txt, содержимое которого пусть будет таким, как показано ниже (здесь может быть любой список, из которого вы хотите отображать информацию):

    Абрамов В.А.
    Абросимов А.Л.
    Антонов В.С.
    Андреев Д.Е.
    Антошкин В.С.
    Артамонов В.И.
    Артемьев Д.В.
    

    Код класса HttpHandler изменим следующим образом (за основу приложения возьмем код решения сайта из предыдущего параграфа):

    void IHttpHandler.ProcessRequest(HttpContext context)
    {
      HttpRequest Request = context.Request;
      HttpResponse Response = context.Response;
      string s = string.Empty;
      string s1 = string.Empty;
      string s2 = string.Empty;        
      if (Request.Form["mydata"] != null)
      {
       s = Request.Form["mydata"];
      }       
      s1 = AppDomain.CurrentDomain.BaseDirectory + (@"data1.txt");       
      using (StreamReader streamreader = new System.IO.StreamReader(s1,System.Text.Encoding.Default))
      {
       string sString = "";
       while ((sString = streamreader.ReadLine()) != null)
       {
         byte[]  bText = System.Text.Encoding.Default.GetBytes(sString);
         s1 = System.Text.Encoding.Default.GetString(bText).ToUpper().Substring(0, s.Length).ToUpper();
         if (!string.IsNullOrEmpty(s) && !string.IsNullOrEmpty(s1) 
                                            && s1.Equals(s.ToUpper()))
          {
              s2 += sString.Trim() + "@";
          }
       }
      }
      if (!string.IsNullOrEmpty(s2))
      {
          Response.Write(s2);
      }
    }
    

    Данный код не требует значительных пояснений, все нам уже известно из рассмотренных примеров первой главы. Новое - только то, что при получении данных от странички мы читаем текстовый файл (может быть файл HTML, таблица базы данных...) и полученную информацию сравниваем с имеющейся в файле по критерию совпадения начальных букв. Если есть совпадение, то переносим строку файла в некоторую переменную и ставим собственный разделитель между строками текста. Далее, как и ранее, отсылаем созданную текстовую переменную назад, используя Response.Write. Алгоритм поиска может быть и другой, например, по наличию вхождений подстроки в строку...

    Осталось передать, принять и отобразить информацию на странице.

    Для ввода информации будем использовать HTML контрол Input (Text). Как и раньше, задача контрола вызвать функцию, которая будет использовать XMLHttpRequest объект для передачи данных. Значение данных берется из вводимого поля, а вызов функции будет происходить по событию ввода очередной буквы (keyup). Для исключения пустых вызовов полезно проверить вводимое поля на наличие информации.

    <input type="text" name="idinput" 
    onkeyup ="if(this.form.idinput.value.length != 0)
    {postDataFromServer('getAjax.aspx','iddiv',this.form.idinput.value)}">
    </input>
    

    Принимать информацию будем в тэг Div:

    <div id="iddiv"></div>
    

    Помимо уже имеющейся в нашем проекте JavaScript функции postDataFromServer, добавим еще одну функцию (setData), задачей которой будет перенос данных из выбранной ссылки вновь в контрол Input(Text) и скрытие выпадающего списка:

    function setData(sID)
    { 
     var targetObj = document.getElementById("idinput"); 
     var targetObj1 = document.getElementById(sID);   
     var targetObj2 = document.getElementById("iddiv");   
     targetObj.value=""; 
     targetObj.value =targetObj1.innerHTML;
     targetObj2.innerHTML ="";
    }
    

    И последнее, в функцию postDataFromServer внесем изменения, позволяющие преобразовывать полученную от сервера информацию в ссылки:

    myAjaxObject.onreadystatechange = 
    function() 
    {
     if (myAjaxObject.readyState == 4 &&  myAjaxObject.status == 200) 
     { 
      var targetObj = document.getElementById(targetControl);     
      var t = myAjaxObject.responseText;
      var t2="";
      var s="";
      for(i = 0;i < t.length;i++)
      {
       if(t.substr(i,1) == '@')
       {
        t2+="<a href='#' name='a"+i+"' 
    	onclick='javascript:setData(this.name); return false;'>"+s+"</a></br>";
        s="";                
       }else
       {
        s+=t.substr(i,1);
       }
      }      
      targetObj.innerHTML =  t2; 
      delete myAjaxObject;
      myAjaxObject=null;                            
     }                                                                                                     
    }    
    myAjaxObject.send("mydata=" + datasend);    
    

    Единственное, что здесь заслуживает внимания - оформление ссылки. При ее активизации переход на другую страницу не выполняется ("#"), но на событие onclick вызывается javascript код функции setData, в качестве параметра которой передается Id самой ссылки (формируется динамически name='a"+i+" ').

    <a href='#' name='a"+i+"' onclick='javascript:
    

    На данном этапе выполняем решение сайта. Все работает, как показано на Рис.2.1.(см. выше).

    Решение сайта на данном этапе можно скачать по этой ссылке ~ 4.6 кб.


    В начало

    Параграф 2. Прокрутка картинок на странице сайта

    Пример, который мы хотим реализовать, похож на механизм, который использует Яндекс. Если набрать строку поиска (например, JavaScript) и выполнить запрос, то помимо результатов поиска, в правой части экрана, появится ссылка "JavaScript в картинках ". Перейдем по этой ссылке. После перехода кликнем на любой картинке. По вертикали окно разделится на две части. В верхней части - выбранная картинка, а в нижней - полоса картинок. Перенесем указатель курсора на эту полосу и покрутим колесико мышки - картинки начинают двигаться (скроллинг с использованием колеса мышки).

    Я не оговорился - картинки начинают двигаться. Не подгружаться, как выяснилось из анализа странички (меню "Вид", пункт "Источник"), а именно двигаться. Все изображения записаны на страницу заранее, скроллинг выполняется посредством сдвига таблицы, в ячейки которой помещены два десятка картинок.

    Недостаток такого подхода очевиден - в любом случае выполняется загрузка двух десятков картинок, а после того, как Вы подошли к последней из них, подгружается очередная порция.

    Попробуем реализовать несколько другой подход к решению данной задачи. Суть его - картинки при скроллинге должны подгружаться по мере необходимости по одной штуке.

    Далее мы будем реализовывать решение, показанное на Рис.2.2. При прокрутки мышки на себя - картинки двигаются от меньшего номера к большему, и наоборот. Причем, в примере решения реализована циклическая прокрутка.

    ajax0202.gif

    Рис.2.2. Прокрутка картинок

    Прежде всего, нам понадобятся картинки. Число их должно быть больше числа, отображаемых одновременно картинок. В решении использовано 6 картинок (число не ограничивается). Принято, что одновременного будут отображаться три картинки. Остальные - последовательно подгружаться из файлов при скроллинге. Картинки поместим в отдельную директорию Images решения сайта.

    Чтобы не строить решение сайта заново, возьмем пример, который мы использовали в параграфе 5 главы 1, который можно скачать по этой ссылке ~ 11.8 кб. Уберем из решения контрол Select, а на его место поместим табличку из одной строки и тех столбцов, в ячейки которой будем помещать картинки.

     
    <body onload  = 'initvariables()'>
        <form id="form1" runat="server">
        <table width="99%" border="1">
      <tr><td>
      <asp:Button ID="Button1" runat="server" Height="36px" 
                           Text="Серверная кнопка" 
              Width="250px" Font-Bold="True"/>
      </td></tr>    
      <tr><td>
        <asp:Label ID="Label1" runat="server" 
             Text="Текст при первой загрузке страницы Default.aspx"></asp:Label><br/>   
      </td></tr> 
      <tr><td align="center"><font size ="+1">Ajax Примеры главы 2</font></td></tr> 
        <tr><td>   
        <table border="0" align="center" id ="tableformove"> 
            <tr><td id ="idtdintable3" align="center"></td>
            <td id ="idtdintable2" align="center"></td>
            <td id ="idtdintable1" align="center"></td></tr>    
       </table>; 
        <tr><td align="center" >         
             <div id="iddiv"></div>        
      </td></tr>     
      </table>
        </form>    
    </body>
    </html>
    

    Обратим внимание на то, что каждая ячейка таблицы имеет собственное ID: idtdintable1, idtdintable2, idtdintable3.

    В тэге body добавим вызов некоторой функции initvariables(), задача которой будет при загрузке страницы проинициализировать переменные и переопределить события мыши (с принятых по умолчанию - страница сайта - на только нашу табличку). В эту табличку и будем выводить картинки. Функцию определим как:

    <script language = "javascript" type="text/javascript">
    var direction;
    var currentPosition;
    function initvariables()
    {
     var moveobject = document.getElementById('tableformove');
     
     if (moveobject.addEventListener)
     {
      moveobject.addEventListener('DOMMouseScroll', wheel, false); 
     }else
     {
      moveobject.onmousewheel = wheel;  
     } 
     
     direction=1;
     getDataFromServer('getAjax.aspx?=0&dir=1', 'idtdintable1');
     getDataFromServer('getAjax.aspx?=1&dir=1', 'idtdintable1');
     getDataFromServer('getAjax.aspx?=2&dir=1', 'idtdintable1'); 
     currentPosition=2;
    }
    

    О том, как работать с мышкой, подробно можно посмотреть в статье [4] Фитискина Александра "Укрощаем колесо мыши и создаем полноценный scroll bar средствами JavaScript".

    Переменная direction определяет направление скроллинга. В конце функции выполняется три вызова getDataFromServer для загрузки трех первых картинок.

    Помимо первоначального обращения за картинками, при прокрутке, должен также выполняться вызов на подгруздку очередной картинки. Этот вызов, естественно, должен быть оформлен в функции, на которую мы переопределили события мышки для странички - в функции wheel():

    function wheel(event)
    {  
     var wheelDelta = 0; 
     if (!event) 
     {
      event = window.event;
     }
     if (event.wheelDelta) 
     {
      wheelDelta = event.wheelDelta/120;
     } 
     else if (event.detail) 
     {
      wheelDelta = -event.detail/3;
     }
     if(wheelDelta > 0) 
     {
      direction=0;
      currentPosition--;   
     }else
     {
      direction=1;
      currentPosition++;   
     }    
     getDataFromFile("getAjax.aspx?="+currentPosition+
                             "&dir="+direction, 'idtdintable1'); 
    }
    

    О том, как определять направление и величину сдвига, см. [4].

    Оформляем обращение к нашему HttpHandler. Идея вызова - перенести картинки, которые уже отображены, на свои места (с учетом направления скроллинга) и вывести на сайт очередную картинку, которую нам предоставит класс HttpHandler.

    function getDataFromServer(dataSource, targetControl) 
    { 
       var myAjaxObject = false;   
       if (window.XMLHttpRequest) 
       {
         myAjaxObject = new XMLHttpRequest();
       } 
       else 
       {
        if (window.ActiveXObject) 
        {
         myAjaxObject = new ActiveXObject("Microsoft.XMLHTTP");
        }
       }
       if(myAjaxObject) 
       {
         myAjaxObject.open("GET", dataSource);
         myAjaxObject.onreadystatechange = 
         function() 
         { 
           if (myAjaxObject.readyState == 4 && myAjaxObject.status == 200) 
           {
            var image1 = document.getElementById('idtdintable1');
            var image2 = document.getElementById('idtdintable2');
            var image3 = document.getElementById('idtdintable3');
            if(direction == 1)
            {        
             image3.innerHTML=image2.innerHTML;
             image2.innerHTML=image1.innerHTML;                            
             image1.innerHTML="<img src= "+dataSource+">";  
            }else
            {
             image1.innerHTML=image2.innerHTML;  
             image2.innerHTML=image3.innerHTML;  
             image3.innerHTML="<img src= "+dataSource+">";  
            }        
            
           }
         } 
         myAjaxObject.send(null);   
       } 
    }
    

    Не пытайтесь использовать метод "POST" в реализации данного алгоритма, этот код работать не будет.

    Итак, у нас глобально определена переменная currentPosition. Эта переменная отслеживает позицию крайней справа выведенной на страничку картинки. Номер выведенной на страничку картинки - номер, который преобразует класс нашего HttpHandler к номеру, который соответствует номеру картинки, которая должна быть отображена при очередном запросе.

    Осталось выдать по запросу нужную картинку.

    void IHttpHandler.ProcessRequest(HttpContext context)
    {
     HttpRequest Request = context.Request;
     HttpResponse Response = context.Response;
     string s = string.Empty;
     string s1 = string.Empty;
     //Получаем список картинок
     string[] files = System.IO.Directory.GetFiles(AppDomain.CurrentDomain.BaseDirectory + @"Images");
     s = Request.QueryString.Get(0);
     s1 = Request.QueryString.Get(1);
     //Текущая позиция в массиве списка картинок от 0 до files.Length
     int viCurPos = (Math.Abs(int.Parse(s)) % files.Length);
     //Куда крутится мышь
     int viDirection = int.Parse(s1);
     if (viDirection == 1)
     {
      s = files[viCurPos];
     }
     else
     {
      //При скроллинге назад необходимо учесть переход через "0"
      if (viCurPos >= 2)
      {
       s = files[viCurPos - 2];
      }
      else
      {
       if (viCurPos == 1)
       {
        s = files[files.Length - 1];
       }
       else
       {
        s = files[files.Length - 2];
       }
      }
     }
     //Это мы уже знаем
     using (MemoryStream memorystream = new MemoryStream())
     {
      Bitmap bitmap = null;
      try
      {
       bitmap = new Bitmap(s);
       bitmap.Save(memorystream, ImageFormat.Png);
       byte[] b = memorystream.GetBuffer();
       Response.ContentType = "image/png";
       Response.BinaryWrite(b);
       bitmap.Dispose();
      }
      catch (Exception)
      {
      }
      memorystream.Dispose();
     }
    }
    

    На данном этапе выполняем решение сайта. Все работает, как показано на Рис.2.2.(см. выше).

    Решение сайта на данном этапе можно скачать по этой ссылке ~ 4.6 кб.


    В начало

    Глава 3. Модель DOM и Ajax программирование


    В начало

    Параграф 1. Свойства и методы модели DOM и JavaScript

    Браузер рассматривает страницу как документ (document), который сформирован в соответствии с объектной моделью - DOM (Document Object Model). Для браузера HTML документ это древовидная структура узлов, представленных тэгами документа (html, head, body, table...). Тип узла (свойство nodeType) может иметь значения:

    • 1 - элемент;

    • 2 - атрибут;

    • 3 - текст.

    JavaScript имеет методы и свойства, позволяющие "достучаться" до узлов и содержимого узлов документа. Объект document представляет полностью загруженный документ. Его свойство и метод, которые мы уже использовали (documentElement и getElementById), позволяют получить объект узла. Далее, можно получить доступ к методам и свойствам узла. Среди них:
    Свойчтво/Метод Описание

    attributes

    Атрибуты узла

    childNodes

    Список дочерних узлов

    documentElement

    Элемент документа

    firstChild

    Первый дочерний узел

    lastChild

    Последний дочерний узел

    localName

    Локальное имя в пространстве имен

    name

    Имя узла с пространством имен

    namespaceURI

    URI пространства имен

    nextSibling

    Следующий узел дерева

    nodeName

    Имя узла

    nodeType

    Тип узла

    nodeValue

    Значение узла

    ownerDocument

    Документ - владелец узла

    parentNode

    Родительский узел

    prefix

    Префикс пространства имен

    previousSibling

    Предыдущий узел

    setAtribute("атрибут","значение")

    Устанавливает атрибуты узла

    replaceNode(a,b)

    заменить узел а узлом b

    replaceChild(a,b)

    заменить дочерний узел а узлом b

    insertBefore(a,b)

    Вставит узел а перед узлом b

    appendChild(a)

    Добавить дочерний узел а

    Кроме того, методы объекта document (createElement, createTextNude) позволяют создавать новые узлы, которые можно далее включать в документ, используя вышеперечисленные методы.

    Более подробно рассматривать модель DOM мы не будем. Информации достаточно и в сети и в литературе [1, 2, 3]. Перейдем непосредственно к примерам использования возможностей доступа к элементам и свойствам узлов.


    В начало

    Параграф 2. Практическое использование свойств и методов модели DOM

    Конечно, очень удобно использовать свойство "innerHTML" для работы с данными (в этом мы убедились в предыдущем материале). Однако, в стандарте DOM, такого свойства нет, а значит "придумку" Microsoft для IE некоторые браузеры могут не поддерживать. И, хотя, разработчики браузеров не рискуют ссориться с Microsoft, и это свойство на сегодня поддержано практически всеми, но, пока (скорее всего свойство будет включено в стандарт), более правильным является использование свойств и методов стандарта DOM.

    Для демонстрации практического использования возможностей доступа к узлам документа с использованием модели DOM, воспользуемся примером параграфа 2 предыдущей главы - "Прокрутка картинок на странице сайта" ( решение сайта для модификации можно скачать по этой ссылке ~ 4.6 кб.). В этом примере мы изменим только функцию "getDataFromFile" в блоке обработки принятых данных. Так как все, что связано с методикой создания эффекта прокручивания картинок, мы уже обсудили, то здесь приведем только измененный код, в котором вместо использования свойства "innerHTML" будем использовать свойства и методы модели DOM.

    if (myAjaxObject.readyState == 4 && myAjaxObject.status == 200) 
    {
     var NewTd=null;
     var imgOld=null;
     var imgNew=null;
     var image1 = document.getElementById('idtdintable1');
     var image2 = document.getElementById('idtdintable2');
     var image3 = document.getElementById('idtdintable3');
     var img1 = document.getElementById('img1');
     var img2 = document.getElementById('img2');
     var img3 = document.getElementById('img3');
     if(direction == 1)
     {
      //Переносим вторую на третью картинку еа
      NewTd = document.createElement('td');        
      NewTd.setAttribute('id', 'idtdintable3');    
      imgNew = document.createElement('img');
      imgNew.setAttribute('id', 'img3');
      imgNew.setAttribute('src',img2.src);  
      imgOld=document.getElementById('img3');   
      image3.replaceChild(imgNew, imgOld);                
      
      //Переносим первую на вторую картинку      
      NewTd = document.createElement('td');        
      NewTd.setAttribute('id', 'idtdintable2');    
      imgNew = document.createElement('img');
      imgNew.setAttribute('id', 'img2');
      imgNew.setAttribute('src',img1.src);  
      imgOld=document.getElementById('img2');   
      image2.replaceChild(imgNew, imgOld);  
      
      //На место первой ставим новую        
      NewTd = document.createElement('td');        
      NewTd.setAttribute('id', 'idtdintable1');                
      imgNew = document.createElement('img');
      imgNew.setAttribute('id', 'img1');
      imgNew.setAttribute('src',dataSource);        
      NewTd.appendChild(imgNew);        
      imgOld=document.getElementById('img1');        
      image1.replaceChild(imgNew, imgOld);
     }else
     {        
      //Переносим вторую на первую картинку еа
      NewTd = document.createElement('td');        
      NewTd.setAttribute('id', 'idtdintable1');    
      imgNew = document.createElement('img');
      imgNew.setAttribute('id', 'img1');
      imgNew.setAttribute('src',img2.src);  
      imgOld=document.getElementById('img1');   
      image1.replaceChild(imgNew, imgOld);
         
      //Переносим третью на вторую
      NewTd = document.createElement('td');        
      NewTd.setAttribute('id', 'idtdintable2');    
      imgNew = document.createElement('img');
      imgNew.setAttribute('id', 'img2');
      imgNew.setAttribute('src',img3.src);  
      imgOld=document.getElementById('img2');   
      image2.replaceChild(imgNew, imgOld);   
     
      //На место третьей ставим новую        
      NewTd = document.createElement('td');        
      NewTd.setAttribute('id', 'idtdintable3');                
      imgNew = document.createElement('img');
      imgNew.setAttribute('id', 'img3');
      imgNew.setAttribute('src',dataSource);        
      NewTd.appendChild(imgNew);        
      imgOld=document.getElementById('img3');        
      image3.replaceChild(imgNew, imgOld);        
     }        
    }
    

    Первое, что нам понадобилось - это снабдить и ячейки таблицы и каждое место (тэги IMG), где предполагается вывод картинки, индивидуальными ID:

    <tr><td align="center"><font size ="+1">
       Ajax примеры главы 2</font></td></tr> 
     <tr>
     <td>
      <table border="0" align="center" id ="tableformove"> 
       <tr>
        <td id ="idtdintable3" align="center"><img id='img3' /></td>
        <td id ="idtdintable2" align="center"><img id='img2' /></td>
        <td id ="idtdintable1" align="center"><img id='img1' /></td>
        </tr>    
       </table> 
     .....
    

    Далее, как и ранее, мы последовательно переносим картинки, которые уже отображены на страничке, влево или вправо (зависит от направления - переменная "direction") методом замены дочерних узлов ("replaceChild"). Но, для использования этого метода, мы вынуждены:

    • Сначала создать виртуальный узел (в данном случае узел "TD") для замены его дочернего узла IMG. Для замены требуется, чтобы виртуальный узел имел тот же ID, что и узел, где будем выполнять замену.

      //Для помещения информации в ячейку с ID равным "idtdintable3"
      NewTd = document.createElement('td');        
      NewTd.setAttribute('id', 'idtdintable3');    
      
    • Далее создаем узел "IMG", который имеет тот же ID, что и у дочернего узла, куда мы планируем перенести рисунок. Но сам рисунок (свойство "SRC" узла), берем с узла источника рисунка.

      imgNew = document.createElement('img');
      imgNew.setAttribute('id', 'img3');
      imgNew.setAttribute('src',img2.src);  
      
    • Последним этапом - меняем дочерние узлы, перенося, тем самым, рисунок.

      imgOld=document.getElementById('img3');   
      image3.replaceChild(imgNew, imgOld);                
      

    Что касается добавления подгружаемой картинки, то это, в приведенной схеме, выполняем аналогично - заменой источника рисунка с картинки, уже отображенной на сайте, на картинку, полученную от сервера:

    imgNew.setAttribute('src',dataSource);        
    

    Результат - код выполняет те же функции, что и код параграфа 2 главы 2. (см. повторенный рисунок 2.2.):

    ajax0202.gif

    Решение сайта на данном этапе можно скачать по этой ссылке ~ 169 кб.


    В начало

    Материал, скорее всего, будет продолжен по мере применения автором в своей практики создания сайтов технологии AJAX.

    Литература