Большой пост в блоге , для меня, был написан один ППК спине около двух лет примерно , в котором он объяснил , как contains()
и compareDocumentPosition()
методы работы в своих браузерах. С тех пор я провел много исследований этих методов и использовал их несколько раз. Как выяснилось, они невероятно полезны для ряда задач (особенно связанных с конструированием селекторных движков с чистой DOM).
DOMElement.contains (DOMNode)
Первоначально представленный Internet Explorer, этот метод определяет, содержится ли один узел DOM в другом элементе DOM. Этот метод может быть особенно полезен при попытке оптимизировать обходы CSS Selector, которые выглядят как «# id1 # id2». С помощью этого метода вы можете использовать getElementById
оба элемента, .contains()
чтобы определить, что # id1 действительно содержит # id2.
Есть одно замечание: .contains()
вернет true, если узел DOM и элемент DOM идентичны (хотя технически элемент не может содержать себя).
Вот простая реализация реализации, которая работает в Internet Explorer, Firefox, Opera и Safari.
( a, b
)
{
return a.
содержит ?
a! = b && a.
содержит
( б
) :
!!
( a.
CompareDocumentPosition
( arg
) &
16
) ;
}
Обратите внимание, что мы используем compareDocumentPosition
, что мы будем обсуждать дальше.
DOMNode.compareDocumentPosition (DOMNode)
Этот метод является частью спецификации DOM Level 3 и позволяет определить, где находятся два узла DOM по отношению друг к другу. Этот метод гораздо более мощный .contains()
. Одним из возможных применений этого метода является изменение порядка узлов DOM в определенном порядке (как это было сделано в PPK).
С помощью этого метода вы можете определить целый ряд информации, относящейся к положению элемента. Вся эта информация возвращается с использованием битовой маски.
Для тех, кто не знаком с этим, битовая маска — это способ хранения нескольких точек данных в одном номере. Вы заканчиваете тем, что включаете / выключаете отдельные биты числа, давая вам окончательный результат.
Вот результаты NodeA.compareDocumentPosition(NodeB)
вместе со всей информацией, к которой вы можете получить доступ:
Биты | номер | Смысл |
000000 | 0 | Элементы идентичны. |
000001 | 1 | Узлы находятся в разных документах (или один находится вне документа). |
000010 | 2 | Узел B предшествует Узлу A. |
000100 | 4 | Узел А предшествует Узлу Б. |
001000 | 8 | Узел B содержит Узел A. |
010000 | 16 | Узел А содержит Узел Б. |
100000 | 32 | Для частного использования браузером. |
Теперь это означает, что возможным результатом может быть что-то вроде:
Поскольку узел, который содержит другой, как «содержит» его (+16), так и предшествует ему (+4), конечным результатом является число 20. Это может иметь больше смысла, если вы посмотрите на то, что происходит с битами:
000100 (4) + 010000 (16) = 010100 (20)
Это, несомненно, делает для единственного наиболее запутанного метода DOM API — однако это тот, чья ценность будет вполне заслужена.
Прямо сейчас DOMNode.compareDocumentPosition
доступно в Firefox и Opera. Тем не менее, есть некоторые приемы, которые мы можем использовать для полной реализации в Internet Explorer:
Resig
function comparePosition
( a, b
)
{
return a.
CompareDocumentPosition ?
а.
CompareDocumentPosition
( b
) :
a.
содержит ?
( a! = b && a.
содержит
( b
) &&
16
) +
( a! = b && b.
содержит
( a
) &&
8
) +
( a.
sourceIndex > =
0 && b.
sourceIndex > =
0 ?
( a.
sourceIndex <b.
sourceIndex &&
4
) +
( a.
sourceIndex > b.
sourceIndex &&
2
) :
1
) +
0 :
0 ;
}
Internet Explorer предоставляет нам несколько методов и свойств, которые мы можем использовать. Начнем с .contains()
метода (как мы уже обсуждали ранее), который дает нам содержит (+16) и «содержится» (+8). Internet Explorer также имеет .sourceIndex
свойство для всех элементов DOM, соответствующее положению элемента абсолютно в документе. Например, document.documentElement.sourceIndex == 0
. Поскольку у нас есть эта информация, мы можем завершить еще две части compareDocumentPosition
головоломки: перед (+2) и затем (+4). Кроме того, если элемент в настоящее время не находится в документе, он .sourceIndex
будет равен -1, что дает нам ответ 1. Наконец, с помощью процесса дедукции мы можем определить, равен ли элемент самому себе, возвращая пустую битовую маску 0.
Эта функция будет работать в Internet Explorer, Firefox и Opera. У нас будет только ограниченная функциональность в Safari (поскольку он имеет только .contains()
, и нет .sourceIndex
, мы получим только «содержит» +8 и «содержится» +16 — все остальные результаты будут возвращать «1», представляющий разъединение).
PPK представляет собой прекрасный пример того, как эта новая функциональность может быть использована при создании getElementsByTagNames
метода. Давайте адаптируем его для работы с нашим новым методом:
Функция getElementsByTagNames
( list, elem
)
{
elem = elem || документ;
var tagNames = список.
split
(
‘,’
) , results =
[
] ;
for
(
var i =
0 ; i <tagNames.
length ; i ++
)
{
var tags = elem.
getElementsByTagName
( tagNames
[ i
]
) ;
для
(
варj =
0 ; j <теги.
длина ; j ++
)
результаты.
push
( теги
[ j
]
) ;
}
вернуть результаты.
sort
(
function
( a, b
)
{
return
3 —
( comparePosition
( a, b
) &
6
) ;
}
) ;
}
Теперь мы можем использовать это для построения по порядку оглавления для сайта:
getElementsByTagname
(
«h1, h2, h3»
) ;
Хотя и Firefox, и Opera предприняли некоторую инициативу для реализации этого метода, я с нетерпением жду появления большего количества браузеров, которые помогут продвинуть это вперед.
Примечание: в jQuery вы можете сделать $ (» : header «), чтобы выбрать все элементы заголовка по порядку.