Internet Explorer 10: руководство для разработчиков

13 сентября 2011 г.

Модель DOM

Internet Explorer 10 и приложения Metro для Windows Developer Preview содержат несколько новых возможностей модели DOM, а именно:

Важно. Эти возможности аналогичным образом работают в Internet Explorer 10 и приложениях Metro с использованием HTML.

Расширенный API проверки попаданий

Модель DOM в Internet Explorer 10 и приложениях Metro поддерживает метод elementFromPoint, который возвращает элемент, содержащий заданные x- и y-координаты окна просмотра. Этого вполне достаточно для одиночных элементов, например для изображения на веб-странице, на котором щелкает пользователь. Но для игр, графических редакторов и других приложений, где может использоваться несколько слоев, этот метод не позволяет получить все элементы, пересекающиеся с заданной точкой на экране.

В Internet Explorer 10 представлены методы msElementsFromPoint и msElementsFromRect, которые возвращают список узлов всех элементов, пересекающихся соответственно с заданными x- и y-координатами или с заданной прямоугольной областью.

Метод «msElementsFromPoint»

Метод msElementsFromPoint принимает в качестве аргументов x- и y-координаты точки и возвращает список узлов элементов, которые пересекаются с этой точкой. Список сортируется в z-порядке, так что верхний элемент является первым по счету.

msElementsFromPoint(x, y) Возвращает объект NodeList — список элементов, которые содержат точку с координатами x и y.


В следующем примере кода создается последовательность разноцветных перекрывающихся блоков div. Если щелкнуть один из таких блоков, вызывается метод msElementsFromPoint, который возвращает все элементы в точке щелчка. При этом цвет фона меняется на серый. Поскольку возвращаются все элементы, включая body и html, цвет фона меняется только у элементов с nodeName, равным div.

<!DOCTYPE html >
<html >
<head>
    <title>Hittest example</title>
    <style type="text/css">
      button
      {
        position:absolute;
        top:600px;
        left:20px;
      }
      div
      {
        display:block;
        position:absolute;
        border:2px solid black;
        opacity:0.8;       
      }
      #div1
      {
        background-color:Red;
        left:200px;
        top:200px;
        height:200px;
        width:300px;
      }   
      #div2
      {
        background-color:Pink;
        left:150px;
        top:150px;
        height:200px;
        width:300px;
      }   
      #div3
      {
        background-color:Green;
        left:250px;
        top:250px;
        height:50px;
        width:80px;
      }
      #div4
      {
        background-color:Yellow;
        left:400px;
        top:300px;
        height:250px;
        width:250px;
      }
      #div5
      {
        background-color:Purple;
        left:275px;
        top:100px;
        height:500px;
        width:20px;
      }
      #div6
      {
        background-color:Aqua;
        left:200px;
        top:175px;
        height:50px;
        width:400px;
      }
      #div7
      {
        background-color:Fuchsia;
        left:430px;
        top:100px;
        height:375px;
        width:30px;
      }           
      #div8
      {
        background-color:Lime;
        left:175px;
        top:290px;
        height:40px;
        width:450px;
      }       
    </style>
</head>
<body>
  <h1>getElementsFromPoint test</h1>
    <button id="refresh" onclick="refresh();">Refresh</button>
    <div id="div1"></div>
    <div id="div2"></div>
    <div id="div3"></div>
    <div id="div4"></div>
    <div id="div5"></div>
    <div id="div6"></div>
    <div id="div7"></div>
    <div id="div8"></div>
<script type="text/javascript">

    window.addEventListener("click", testHit, false);
    function refresh()
    {
      window.location.reload(false);           //reload page
    }
    function testHit(e)
    {
      if (document.msElementsFromPoint)  //feature testing
      {
        var hitTargets = document.msElementsFromPoint(e.clientX, e.clientY);
        // get elements from point                
        for (var i = 0; i < hitTargets.length; i++)
        {
          if(hitTargets[i].nodeName.toUpperCase() == "DIV")
          {
            hitTargets[i].style.backgroundColor = "gray";
          } //if it's a div, gray it out.              
        }
      }              
    }</script>
</body>
</html>

Так как метод msElementsFromPoint возвращает все элементы, пересекающиеся с точкой, в том числе элемент html и другие, в коде отбирается только элемент div с помощью свойства nodeName

Метод «msElementsFromRect»

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

msElementsFromRect(left,top,width, height); Возвращает массив элементов, пересекающихся с прямоугольником, который определяется значениями left, top, width и height.


Чтобы в предыдущем примере можно было использовать метод msElementsFromRect, необходимо добавить параметры width и height. Например, так:

function testHit(e) {
   if (Document.msElementsFromRect) //feature testing
   {
      var hitTargets = document.msElementsFromRect(e.clientX - 25, e.clientY - 25, 50, 50);
      // captures elements within 50px block
      for (var i = 0; i < hitTargets.length; i++) {
         if(hitTargets[i].nodeName.toUpperCase() == "DIV") {
            hitTargets[i].style.backgroundColor = "gray";
            }  //if it's a div, gray it out.
         }
      }
   }

При таком обновлении функции «testHit» по щелчку мыши возвращаются элементы, пересекающиеся с прямоугольной областью размером 50 пикселей.

Значения с плавающей запятой в CSSOM

Internet Explorer 10 и приложения Metro сообщают метрики положения и размера для модели DOM с субпиксельной точностью. Объектная модель CSS (CSSOM) в Internet Explorer 10 и приложениях Metro поддерживает единицы пикселей с плавающей запятой.

В старых веб-стандартах и реализациях традиционно предполагалось, что визуализация веб-контента на заданном экране должна производиться с выравниванием по границам целых пикселей. Это отражалось в CSSOM — объектной модели, используемой в целях получения метрик положения и размера для модели DOM. Хотя Internet Explorer давно поддерживает широкий спектр API модели CSSOM (дополнительные сведения см. в статье Measuring Element Dimension and Location with CSSOM in Internet Explorer 9 (Измерение размеров и местоположения элементов с помощью CSSOM в Internet Explorer 9)), ранее эти метрики определялись с выравниванием по целым пикселям.

В Internet Explorer 8 была введена поддержка аппаратно-независимых пикселей (DIP). Эти «виртуальные пиксели» имеют размер 1/96 дюйма и позволяют гораздо точнее измерять местоположение текста по сравнению с физическими пикселями. Когда контент визуализируется на экране, метрики разметки преобразуются с масштабным коэффициентом (соответствующим текущему масштабу, выбранному пользователем) и затем округляются до целого числа пикселей для отображения.

Механизм визуализации Internet Explorer 9 передает значительную часть работы по визуализации графическому оборудованию ПК, используя API Direct2D. Direct2D поддерживает визуализацию с субпиксельной точностью как для блочной модели CSS, так и для текста (для получения дополнительных сведений о визуализации текста в Internet Explorer 9 см. статью About Text Rendering in Internet Explorer 9 -- О визуализации текста в Internet Explorer 9).Вместо того чтобы просто округлять единицы разметки до ближайшего пикселя при визуализации, API Direct2D обеспечивает непосредственное выполнение позиционно-размерных вычислений механизмом визуализации и отображение контента в соответствии с результатами этих вычислений.

При масштабе 100% проблемы с получением информации о местоположении и размере объектов с точностью до пикселя через CSSOM возникают редко, но при увеличении и уменьшении масштаба они могут стать заметнее для пользователей и, следовательно, представлять проблему для разработчиков. Поддержка значений с плавающей запятой для метрик положения и размера в свойствах CSSOM уровня элемента, реализованная в Internet Explorer 10, может помочь в решении этих проблем (свойства уровня элемента — это свойства наподобие elementOb.clientLeft; в отличие от них такие свойства, как rangeOb.getBoundingClientRect().left, всегда возвращают значения с субпиксельной точностью).

По умолчанию обработка свойств CSSOM с субпиксельной точностью отключена. Чтобы включить ее, используйте следующее новое свойство.

msCSSOMElementFloatMetrics Логическое свойство, указывающее, возвращают ли свойства CSSOM метрики с плавающей запятой. Значение по умолчанию равно 0.

Прослушиватели запросов носителя

В Internet Explorer 9 представлена поддержка запросов носителя CSS 3 для изменения стилей отображения элементов, таких как размер шрифта или полей, в зависимости от устройства или носителя. Прослушиватели запросов носителя, добавленные в Internet Explorer 10 и приложения Metro, позволяют с помощью сценария реагировать на изменение носителя или среды, в которых работает страница.

Создание прослушивателей запросов носителя и подписка на них

Прослушиватели запросов носителя предоставляют две новые возможности: обработку запроса носителя на этапе выполнения с использованием JavaScript и подписку прослушивателей на изменения в результатах этой обработки.

Для обработки запроса носителя на этапе выполнения создается объект MediaQueryList с использованием нового метода объекта window — msMatchMedia.

msMatchMedia(sList) Принимает в качестве аргумента строку, содержащую один или несколько запросов носителя, и возвращает объект MSMediaQueryList


Метод msMatchMedia принимает строку с запросами носителя и возвращает объект MediaQueryList. В следующем примере создается запрос носителя, позволяющий проверить, не оказываются ли ширина или высота окна меньше определенного значения.

mql = window.msMatchMedia("(min-width:450px)");

Объект MediaQueryList предоставляет следующие свойства.

matches Возвращает значение «true», если список запросов носителя соответствует состоянию объекта currentwindow; в противном случае возвращает значение «false».
media Возвращает сериализованную версию списка запросов носителя, который использовался для создания объекта MediaQueryList.
addListener(callback) Добавляет функцию обратного вызова (callback) в список прослушивателей объекта MediaQueryList. Эта функция вызывается всякий раз, когда меняется результат обработки запроса носителя.
removeListener(callback) Удаляет функцию обратного вызова (callback) из списка прослушивателей данного объекта MediaQueryList.


Свойство matches представляет собой логическое значение, возвращающее результат обработки запроса носителя. В приведенном выше примере свойство matches возвращает значение «true», если ширина окна больше или равна заданному минимальному значению.

if (mql.matches)
{
  // Window is fine.
} else
{
  // Window is too narrow.      
}

Чтобы обнаруживать изменения в результатах обработки запроса носителя, вы можете подписать прослушиватель на объект MediaQueryList. Метод addListener принимает в качестве аргумента функцию обратного вызова и обращается к ней, когда результат обработки запроса носителя меняется. В следующем примере демонстрируется подписка на изменения результата обработки описанного выше запроса носителя.

mql.addListener(sizeChange); // Size change is the callback function.function sizeChange(mql)
{
  if (mql.matches)
  {
    // The window is big enough for content.
  }
  else
  {
    // The window has gotten too small for content.
  }
}

Прослушиватель вызывает функцию обратного вызова при любом фактическом изменении состояния носителя. Например, эта функция вызывается, если после изменения размеров окна его ширина стала меньше заданного значения атрибута minwidth. Функция вызывается снова, если окно становится шире минимального размера. Объект MediaQueryList передается в качестве параметра функции обратного вызова.

Применимые веб-стандарты

Объект MediaQueryList и метод MatchMedia определены в спецификации визуального представления CSSOM (http://dev.w3.org/csswg/cssom-view/#the-mediaquerylist-interface).

События, вызываемые указателями или жестами

В Windows 8, Internet Explorer 10 и приложениях Metro впервые используется встроенная в веб-платформу поддержка обработки сенсорного ввода и ввода с помощью пера. Теперь разработчику больше не нужно предусматривать отдельный код для обработки каждого типа ввода: в Internet Explorer 10 вводится понятие указателя. Указатель — это любая точка контакта с экраном, осуществляемого с помощью мыши, пальца или пера. Теперь разработчики могут обеспечить пользователям удобство работы на любой аппаратной платформе и с любыми типами устройств: для этого достаточно описать единый набор событий, вызываемых указателями, и эти события будут реагировать на движения мыши, прикосновение пальца или пера.

События, вызываемые указателями

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

  • MSPointerDown (вниз)
  • MSPointerMove (перемещение)
  • MSPointerUp (вверх)
  • MSPointerOver (поверх)
  • MSPointerOut (наружу)

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

Совместимость с мышью

После генерации событий указателя, Internet Explorer 10 генерирует события, вызываемые мышью для первоначального контакта (например, первого касания к экрану). Это позволяет продолжить функционировать веб-сайтам, управляемым исключительно мышью. При желании события мыши можно отключить командой event.preventMouseEvent() во время события MSPointerDown.

Обнаружение функциональности

Наилучший способ определить, поддерживаются ли события указателя, приведен ниже.

If (window.navigator.msPointerEnabled) {
  //Pointer events are supported.
}

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

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

<style>
  html {
    overflow: hidden;
    -ms-content-zooming: none; /* Disable pan/zoom */
  }
</style>
<canvas id="drawSurface" width="500px" height="500px" style="border:1px solid black;"></canvas>
<script type='text/javascript'>
window.addEventListener('load', function() {
  var canvas = document.getElementById("drawSurface"),
  context = canvas.getContext("2d");
  if (window.navigator.msPointerEnabled) {
    canvas.addEventListener("MSPointerMove", paint, false);
  }
  else {
    canvas.addEventListener("mousemove", paint, false);
  }
  function paint(event) {
    context.fillRect(event.clientX, event.clientY, 5, 5);
  }
});
</script>

Наиболее распространенные методы оптимизации сенсорного ввода

Internet Explorer 10 обеспечивает по умолчанию наиболее распространенную обработку базовых сенсорных взаимодействий. Например:

  • панорамирование для областей с активированной прокруткой;
  • изменение масштаба при изменении растояния между касающимися экрана пальцами;
  • показ контекстного меню по нажатию и удержанию;
  • выбор прикосновением.

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

Панорамирование и изменение масштаба

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

.disablePanZoom {
  overflow: hidden; /* Disables panning */
  -ms-content-zooming: none; /* Disables zooming */
}

Контекстные меню

Если вы нажали и удерживаете определенные элементы в Internet Explorer, браузер отобразит квадратный элемент, указывающий, что готово появиться контекстное меню. Если после этого перестать удерживать элемент, появляется контекстное меню. Если вы перетаскиваете указатель в сторону, визуальный элемент пропадает и контекстное меню не появляется.

Если вы хотите предоставить собственное контекстное меню, Internet Explorer 10 позволяет это сделать. Для этого вызовите команду event.preventDefault() для события контекстного меню и запустите код для отображения вашего контекстного меню. Internet Explorer 10 автоматически запустит ваше контекстное меню по прикосновению, а по нажатию и удержанию элемента отобразит такую же визуальную подсказку.

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

element.addEventListener("MSGestureHold", function(e) { e.preventDefault(); }, false);
 //Disables visual
element.addEventListener("contextmenu", function(e) { e.preventDefault(); }, false);
 //Disables menu

Выбор прикосновением

Internet Explorer 10 позволяет выбрать слово с помощью прикосновения — для этого достаточно коснуться текста или экрана рядом с ним. В некоторых случаях такое поведение браузера может конфликтовать с функциями вашего приложения (например, выделять текст меню или названия в играх). Отменить выбор текста можно точно так же, как в Internet Explorer 9:

element.addEventListener("selectstart", function(e) { e.preventDefault(); }, false);
 //Disables selection

События, вызываемые жестами

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

Наиболее простые жесты — это «статичные» жесты.

  • MSGestureTap — пользователь касается экрана пальцем либо пером или же щелкает мышью.
  • MSGestureDoubleTap — пользователь два раза (в течение определенного времени) касается экрана пальцем либо пером или же два раза щелкает мышью.
  • MSGestureHold — пользователь нажимает экран пальцем и не сдвигает палец в течение определенного времени.

Можно добиться распознавания более сложных жестов с помощью событий MSGestureStart, MSGestureChange и MSGestureEnd. Эти события содержат информацию о преобразовании жестов, таком как перевод, масштабирование, вращение, ускорение и т. п. Например, приведенный ниже код распознает преобразования жестов и записывает информацию о них.

<div id="log"></div>
<script>
document.addEventListener("MSGestureChange",logGesture,false);
var log = document.getElementById("log");
function logGesture(event) {
   var gesture = "Translation: " + event.translationX + "px, " + event.translationY + "px<br>";
  gesture += "Scale: " + event.scale + "x<br>";
  gesture += "Rotation: " + event.rotation*360/Math.PI + " deg<br>";
  gesture += "Velocity: " + event.velocityX + ", " + event.velocityY;
  log.innerHTML = gesture;
}
</script>