Опять же, для тех, кому интересно...
Эх, наболело - не могу молчать: п№%;№% создатели javascript, а еще большие п№%;№% - те, кто, продолжая начатое, неудосужился сделать толковый базовый инструментарий. В результате - полный бардак: несовместимость реализации и жиденькие возможности. Правда все-таки с js возможностей больше, чем без.
Сегодня я хочу рассказать о возможности динамической подгрузки страниц и их частей.
Самый распространенный способ - использование фреймов - FRAMESET+FRAME и IFRAME. Достоинства и недостатки неоднократно обсуждались в интернете - в том числе и на нашем форуме. На мой взгляд главный недостаток - необходимость определять размер фрейма. Это затрудняет встраивание в страницу, особенно с динамически создаваемым содержимым.
Совственно, мне захотелось сделать страницу из нескольких связанных или несвязанных между собой логически блоков и сделать так, чтобы при работе с одним блоком и его обновлении не надо было перстраивать всю страницу.
Экспериментируя, я досыта намучился с IFRAME, OBJECT и прочими штатными вариантами подгрузки одной страницы к другой. Получалось криво. Я обычно тестирую на Mozilla, а когда начинает получаться тестирую еще и на IE. Поведение обоих браузеров сильно отличается - порой не возможно получить сносного результата на обеих. Намучился, но вынес из этого немного полезного.
И так, используя фреймы (я использую IFRAME) можно загрузить страницу, но добиться требуемого внешнего вида сложно или невозможно. Требуемый вид - вставить эту страницу в блочный или линейный элемент. Благодаря CSS фрейм можно включить в страницу и не отображать (стиль
display: none). Загрузить страницу во фрейм можно разными методами: ссылкой и формой с параметром TARGET, указывающим на нужный фрейм. Об этом сейчас не говорю. Остается только задача копирования данных из фрейма в нужный элемент...
На этом этапе то же есть подводные камни. Прежде всего, нужно дождаться загрузки страницы: если попытаться скопировать содержимое фрейма сразу после инициирования загрузки, то, быстрее всего, там вообще ничего не будет. Кроме того, Mozilla заявляет, что у IFRAME с уже загруженным документом нет свойства document. В общем, все очень странно.
Легче всего обратиться к загруженной странице из ней же самой: вставить скрипт, который по событию ONLOAD, либо просто распложенный в конце страницы и автоматически исполняющийся после загрузки. Его задача - найти кусок текста, преднозначенного для копирования и передать его в родительскую страницу. Опять же, чтобы не морочится с поиском места назначения в родительской странице (тем более если оно известно только ей), можно вызвать ф-ию из родительского документа:
window.parent.функция(параметры).
Вот пример:
Файл main.html
<HTML>
<HEAD>
<META HTTP-EQUIV="Content-type" CONTENT="text/html; charset=windows-1251" />
<STYLE>
IFRAME { display: none; }
</STYLE>
<SCRIPT TYPE="text/javascript">
var docs = new Array();
function loaded( obj, id )
{
with ( docs[id] )
{
src = obj;
a.href = 'javascript:void(0);';
}
show('', id);
}
function show( obj, id )
{
if ( docs[id] != null && docs[id].src != null )
{
var view = document.getElementById('view');
if ( view != null ) view.innerHTML = docs[id].src.innerHTML;
}
else if ( typeof(obj) == 'object' )
{
obj.href = 'file' + id + '.html';
obj.target = 'doc' + id;
docs[id] = { a: obj, src: null };
}
}
function unload( obj, id )
{
if ( docs[id] != null && docs[id].src != null )
{
var file = document.getElementById('file' + id);
file.innerHTML = '<IFRAME NAME="doc' + id + '"></IFRAME>';
docs[id].src = null;
}
}
</SCRIPT>
</HEAD>
<BODY>
<A HREF="javascript:void(0);" ONCLICK="show(this,'1');">load file 1</A>
<A HREF="javascript:void(0);" ONCLICK="show(this,'2');">load file 2</A><BR />
<A HREF="javascript:void(0);" ONCLICK="unload(this,'1');">unload file 1</A>
<A HREF="javascript:void(0);" ONCLICK="unload(this,'2');">unload file 2</A><BR />
<HR />
<DIV ID="view"></DIV>
<HR />
<SPAN ID="file1"><IFRAME NAME="doc1"></IFRAME></SPAN>
<SPAN ID="file2"><IFRAME NAME="doc2"></IFRAME></SPAN>
</BODY>
</HTML>
Файл file1.html
<HTML>
<HEAD>
<META HTTP-EQUIV="Content-type" CONTENT="text/html; charset=windows-1251"/>
</HEAD>
<BODY>
<SPAN ID="doc">
Тестовый файл 1 (windows-1251)
</SPAN>
<SCRIPT TYPE="text/javascript">
o = document.getElementById('doc');
if ( o != null )
{
window.parent.loaded(o, '1');
}
</SCRIPT>
</BODY>
</HTML>
Файл file1.html
<HTML>
<HEAD>
<META HTTP-EQUIV="Content-type" CONTENT="text/html; charset=utf-8"/>
</HEAD>
<BODY>
<SPAN ID="doc">
Тестовый файл 2 (utf-8)
</SPAN>
<SCRIPT TYPE="text/javascript">
o = document.getElementById('doc');
if ( o != null )
{
window.parent.loaded(o, '2');
}
</SCRIPT>
</BODY>
</HTML>
Много сил потратил на копирование блока текста и не удовлетворился результатом. Признаюсь, хоть и не люблю пользоваться чужими мозгами, заглянул в код rsdn.ru. Конечно, я не копировал их код, а переписал заново.
Пояснение к main.html: названия ссылок говорят сами за себя - загрузка и выгрузка файлов в скрытых фреймах. Нагляднее этот процесс будет, если закоментировать или удалить строку
IFRAME { display: none; }.
Заметьте, что файлы file1.html и file2.html у меня в разной кодировке, но не здесь - на форуме весь текст в одной кодировке.
Это, кстати, замечательное свойство - можно одновременно загружать документы в разных кодировках и их отображение согласуется браузером.
Тестировал на IE 6.0.2900.2180.xpsp_sp2_.... и Mozilla 1.7.8.
Совственно, это только малая часть того, что мне нужно - остальное буду рассказывать по мере понимания.