Как с помощью jQuery сделать флеш-ролик резиновым.
To view this page ensure that Adobe Flash Player version 10.0.0 or greater is installed. |
Во флеш-роликах фиксированного размера мало пользы в резиновых сайтах. А ведь сайтов, растягивающихся по ширине экрана - пожалуй побольше, чем сайтов с фиксированной шириной. А это значит, что растяжка флеш-ролика по ширине - это самая первая практическая задачка при программировании большинства Flex-приложений.
При освоении Flex-платформы я приобрел несколько отличных книг с рецептами Flex-программирования - при возникновении вопроса о ресайзе я бегло просмотрел их и, увы, совершенно не обнаружил в них рецепта, который бы растягивал ролики в сайтах с резиновым дизайном. Поэтому я решил это как сумел - буквально за пять минут. Но я подумал, что мое решение может быть полезно и другим Flex-программистам.
Для того, чтобы растягивать ролик, его надо в html-верстке вложить в любой контейнер, который займет свое место в сайте, обычно в виде такого контейнера используется DIV или TD. И далее сообщить в ActionScript текущий размер html-контейнера.
Резиновые сайты устроены примерно так: у сайта есть левое фиксированное поле для рекламы <td width="100px">, затем идет растягивающаяся по ширине полоса с флеш-роликом <td id="ContentContainer" width="100%"> далее собственно флеш-ролик <div id="flashContent" /> и далее правое рекламное поле сайта <td width="100px"> - так устроено огромное большинство сайтов, например тот же http://www.votpusk.ru.
Я мог бы обрезинить ролик с помощью ЯзваСкрипта, но я применил jQuery, которая скрывает различия браузеров. Для этого я использовал самую минимальную версию jQuery размером 79 кб. Собственно исходный код этой странички, на которой вы видите резиновый ролик выглядит вот так:
1: <head>
2: ...
3:
4: <script type="text/javascript" src="history/history.js"></script>
5: <script type="text/javascript" src="jquery-1.4.4.min.js"></script>
6: <script type="text/javascript" src="swfobject.js"></script>
7:
8: ...
9:
10: <script type="text/javascript">
11: $(document).ready(function () {
12: $(window).resize(flashresize);
13: })
14: </script>
15:
16: <script type="text/javascript">
17: function flashresize () {
18: var ContentContainer = $("#ContentContainer")[0];
19: var Votpusk_Image_Slider = $("#Votpusk_Image_Slider")[0];
20: Votpusk_Image_Slider.containerresize(ContentContainer.clientWidth, ContentContainer.clientHeight);
21: }
22: </script>
23:
24: <script type="text/javascript">
25: var swfVersionStr = "10.0.0";
26: var xiSwfUrlStr = "playerProductInstall.swf";
27: var flashvars = {};
28: flashvars.BestFotoNumber="http://foto.votpusk.ru/BestFotoNumber.ashx";
29: flashvars.DebugService="0";
30: flashvars.BaseUrl="http://foto.votpusk.ru/GetImage.ashx?w=100%26j=";
31: flashvars.ClickBaseUrl="http://foto.votpusk.ru/foto_slide.aspx";
32: var params = {};
33: params.quality = "high";
34: params.bgcolor = "#ffffff";
35: params.allowscriptaccess = "always";
36: params.allowfullscreen = "true";
37: var attributes = {};
38: attributes.id = "Votpusk_Image_Slider";
39: attributes.name = "Votpusk_Image_Slider";
40: attributes.align = "middle";
41: swfobject.embedSWF(
42: "Votpusk_Image_Slider.swf", "flashContent",
43: "100%", "126px",
44: swfVersionStr, xiSwfUrlStr,
45: flashvars, params, attributes);
46: swfobject.createCSS("#flashContent", "display:block;text-align:left;");
47: </script>
48:
49: ...
50:
51: </head>
52: <body>
53:
54: ...
55:
56: <table cellpadding="0" cellspacing="0" border="0" style="width: 100%; height: 262px;">
57: <tr>
58: <td>
59: <img src="100.gif">
60: </td>
61: <td id="ContentContainer" style="width: 100%; height: 262px;">
62: <div id="flashContent">
63: <p>
64: To view this page ensure that Adobe Flash Player version 10.0.0 or greater is installed.
65: </p>
66: <script type="text/javascript">
67: var pageHost = ((document.location.protocol == "https:") ? "https://" : "http://");
68: document.write("<a href='http://www.adobe.com/go/getflashplayer'><img src='"
69: + pageHost + "www.adobe.com/images/shared/download_buttons/get_flash_player.gif' alt='Get Adobe Flash player' /></a>");
70: </script>
71: </div>
72: <noscript>
73: <object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" width="100%" height="100%"
74: id="Votpusk_Image_Slider">
75: <param name="movie" value="Votpusk_Image_Slider.swf" />
76: <param name="FlashVars" value="BestFotoNumber='http://foto.votpusk.ru/BestFotoNumber.ashx'&DebugService='0'&BaseUrl='http://foto.votpusk.ru/GetImage.ashx?w=100%26j='&ClickBaseUrl='http://foto.votpusk.ru/foto_slide.aspx'" />
77: <param name="quality" value="high" />
78: <param name="bgcolor" value="#ffffff" />
79: <param name="allowScriptAccess" value="always" />
80: <param name="allowFullScreen" value="true" />
81: <!--[if !IE]>-->
82: <object type="application/x-shockwave-flash" data="Votpusk_Image_Slider.swf" width="100%"
83: height="100%">
84: <param name="quality" value="high" />
85: <param name="bgcolor" value="#ffffff" />
86: <param name="allowScriptAccess" value="always" />
87: <param name="allowFullScreen" value="true" />
88: <!--<![endif]-->
89: <!--[if gte IE 6]>-->
90: <p>
91: Either scripts and active content are not permitted to run or Adobe Flash Player
92: version 10.0.0 or greater is not installed.
93: </p>
94: <!--<![endif]-->
95: <a href="http://www.adobe.com/go/getflashplayer">
96: <img src="http://www.adobe.com/images/shared/download_buttons/get_flash_player.gif"
97: alt="Get Adobe Flash Player" />
98: </a>
99: <!--[if !IE]>-->
100: </object>
101: <!--<![endif]-->
102: </object>
103: </noscript>
104: </td>
105: <td>
106: <img src="100.gif">
107: </td>
108: </tr>
109: </table>
110: ...
111:
112: </body>
Как вы видите, здесь в строках 24-47 вызывается стандартный скрипт, создаваемый FlexBuilder - а вот в строках 10-22 - та самая хитрость на jQuery, которую я докрутил в стандартый шаблон Flex-проекта.
Обратите внимание, что выше вы видите ИТОГОВЫЙ текст, сгенерировнный FlexBuilder по команде Export Release Build - а ИСХОДНЫЙ текст строк 16-22 (который подается на вход FlexBuilder в файле index.template.html) - состоит из адской смеси кода jQuery и шаблонов ANT) и выглядит совершенно вот так:
16: <script type="text/javascript">
17: function flashresize () {
18: var ContentContainer = $("#ContentContainer")[0];
19: var ${application} = $("#${application}")[0];
20: ${application}.containerresize(ContentContainer.clientWidth, ContentContainer.clientHeight);
21: }
22: </script>
Итак, в строке 5 подключается jQuery, в строках 10-14 добавляется слушатель событий изменения размера html-элемента ContentContainer, а в строках 16-22 он срабатывает при ресайзе и вызывает функцию containerresize html-обьекта c именем Votpusk_Image_Slider, в котором лежит байт-код SWF-файла (и в котором Flash-плеер, исполняя этот байт-код) создал функцию containerresize.
Надо понимать, что при загрузке страницы html-обьекта c именем Votpusk_Image_Slider не существует, есть только div c именем flashContent, на месте коротого скрипт swfobject создаст или тег object:
1: <object width="100%" height="126px" align="middle" type="application/x-shockwave-flash"
2: id="Votpusk_Image_Slider" name="Votpusk_Image_Slider" data="Votpusk_Image_Slider.swf">
3: <param name="quality" value="high">
4: <param name="bgcolor" value="#ffffff">
5: <param name="allowscriptaccess" value="always">
6: <param name="allowfullscreen" value="true">
7: <param name="flashvars" value="BestFotoNumber=http://foto.votpusk.ru/BestFotoNumber.ashx&DebugService=0&BaseUrl=http://foto.votpusk.ru/GetImage.ashx?w=100%26j=&ClickBaseUrl=http://foto.votpusk.ru/foto_slide.aspx">
8: </object>
И лишь после создания этого обьекта, с помощью jQuery этому обьекту будут добавлен слушатель события resize. Конечно, по хорошему, здесь надо добавлять таймаут странички хотя бы на 0,5 секунды и лишь после таймаута добавлять слушатель событий. Но этим моментом с пренебрег - поэтому мое решение может порождать при загрузке странички ошибку (которая уходит как только swfobject закончит работу и будет создан тег, на который jQuery создает слушатель события).
Теперь пойдем внутрь байт-кода и посмотрим каким образом попросить виртуальную машину флеш-плеера создать у html-обьекта фукнцию containerresize.
1: <?xml version="1.0" encoding="utf-8"?>
2: <s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
3: xmlns:s="library://ns.adobe.com/flex/spark"
4: xmlns:mx="library://ns.adobe.com/flex/mx"
5: applicationComplete="application1_applicationCompleteHandler(event)"
6: minWidth.Image_Load="712" minHeight.Image_Load="125"
7: width.Image_Load="712" height.Image_Load="125"
8: minWidth.Debug="500" minHeight.Debug="500" >
9:
10: <fx:Script>
11:
12: <![CDATA[
...
28: protected function application1_applicationCompleteHandler(event:FlexEvent):void
29: {
30: try {
31: ExternalInterface.addCallback("containerresize", FlashContainerResize);
32: }
33: catch (error:SecurityError){
34: }
35:
...
57: try {
58: ExternalInterface.call("flashresize");
59: }
60: catch (error:SecurityError){
61: }
62: }
...
244: ]]>
245: </fx:Script>
...
283: </s:Application>
Здесь вы видите, что стартовой функцией по завершении создания Flex-приложения назначена функция, определенная в строке 28. Эта функция сразу же создает у html-обьекта javascript-функцию containerresize, на которую jQuery мапирует событие rezise обьекта ContentContainer.
По завершению этой процедуры ролик занимает тот размер, который ему положено в данный момент (а не тот размер, который ему определен в дизайн-тайме). Эта операция вызывается в строке 58.
Как же распорядится в коде размерами, которые нам пробросил jQuery из контейнера на внешний интерфейс виртуальной машины и которые в итоге попадают во внутренню функцию флекса - flashresize?
В этом коде я распорядился полученной информацией простейшим образом - выстроил по этому размеру контейнер Hbox - а мог бы например и убрать частично отображаемый рисунок (и подогнать интервалы между рисунками);
64: private function FlashContainerResize (width:int,heigth:int):void {
65: HGroup1.width=width-2;
66: //Alert.show(width.toString() + ":" + heigth.toString());
67: }
Надеюсь теперь все понятно. Теперь пару заморочек, которые могут возникать при общении байт-кода виртуальной машины с внешним кодом странички. Вообще-говоря, это запрещено. При попытках этого общения возникают замечательные сообщения "SecurityError: Error #2060: Security sandbox violation: ExternalInterface caller" :
С этой проблемой безопасности есть много механизмов борьбы. Прежде всего allowScriptAccess установлено в true в html-коде в строках 35, 79, 86 именно для этого. Но к сожалению, и это не всегда помогает. Чтобы виртуальная машина не падала окончательно в случае этой проблемы безопасности - необходимо брать в скобочки try обращения к внешнему интерфейсу виртуальной машины - как я это сделал в строках 30 и 57 флекс-кода.
Ну вот вроде бы и все, что можно сказать о резиновых Flash-роликах. Надеюсь чтение было полезным.
Еще пару примеров применения jQuery вы можете посмотреть на страничках - AJAX подсказка/автозаполнение на jQuery, Как сделать простейший Web-handler - формирующий XML или JSON, Заполнение связанных списков на MS AJAX и jQuery.
Про Flex вы можете почитать на страничке //www.vb-net.com/Flex/index.htm.
|