В предыдущей статье мы реализовали виджет Dart в нашем приложении Symfony. Давайте разберемся с остальными сейчас. Это может продвинуться вперед, поэтому возьмите чашку кофе и обратите пристальное внимание — я рекомендую вам следовать только после завершения части 1!
Обойти JSONP и отобразить член объекта в шаблоне
Если сервер (и, следовательно, конфигурация, программирование) управляется нами самими, процесс получения данных из RESTful API с того же сервера будет простым. Мы можем включить CORS в заголовке возвращаемого ответа. Выполнено! Но если RESTful API удаленного сервера не устанавливает этот заголовок, мы столкнемся с ошибкой CORS при попытке вызвать этот вызов API из приложения Dart.
Одним из часто обсуждаемых методов является использование JSONP . У Dart также есть несколько пакетов, jsonp
функциональность jsonp
. Вы можете найти эти пакеты здесь , выполнив поиск «jsonp».
Однако в нашей реализации мы сделаем это по-другому из-за «хакерской» природы JSONP.
Можно сказать, что любой, кто занимается разработкой веб-сайтов, должен иметь хотя бы один сайт под своей юрисдикцией.
В моем втором виджете Dart, который должен быть интегрирован в мою домашнюю страницу, я пытаюсь получить информацию о погоде с двух разных удаленных серверов (и ни один из них не поддерживает CORS). Очевидно, я не могу контролировать эти два сервера, поэтому я делаю следующее:
Сначала создайте контроллер в Symfony для сбора данных с этих двух удаленных серверов:
public function WeatherAction($type, $param) { if ($type == 1) // Local weather info { $weather = file_get_contents("http://m.weather.com.cn/data/$param.html"); //101190401 for Suzhou, my hometown } else { $weather = file_get_contents("http://api.openweathermap.org/data/2.5/weather?q=$param&units=metric"); //suzhou,china } $response = $this->render('trrsywxBundle:Default:json.html.twig', array('res' => $weather)); $response = $this->setExtraHeader($response); return $response; }
Все эти два сайта возвращают строки JSON при вызове, но ни один из них не установил заголовок CORS. В Dart такой вызов API будет неудачным, но в среде Symfony он успешен — CORS ограничен только JavaScript, серверные языки могут по-прежнему потреблять ресурсы в других доменах. Также обратите внимание на то, что, оборачивая возвраты с удаленных серверов путем предоставления дополнительных заголовков, мы можем включить CORS.
Затем в Dart мы создаем еще одно приложение Polymer, чтобы получить информацию, полученную от Symfony, и выполнить ее дальнейшую обработку:
void getWeather() { var path1='http://rsywx/app_dev.php/json/weather/1/$code'; var path2='http://rsywx/app_dev.php/json/weather/2/$city'; HttpRequest.getString(path1).then((String res)=>processWeather1(res)); HttpRequest.getString(path2).then((String res)=>processWeather2(res)); if(one) one=false; else one=true; } void processWeather1(String res) { w1=new Weather1.created(res); } void processWeather2(String res) { w2=new Weather2.created(res); } }
После получения данных с нашего собственного сайта Symfony процесс становится простым.
В этой реализации каждое «обновление» будет получать информацию о погоде с обоих серверов. Он может быть тонко настроен для устранения избыточных вызовов API, определяя, что мы должны показывать для клика «Обновить» (переменная one
переключает свой логический статус каждый раз, когда мы getWeather
функцию getWeather
, которая вызывается при каждом запросе «Обновить»).
one
них также используется в нашем шаблоне Dart Polymer, чтобы решить, какая информация о погоде должна отображаться, поскольку эти две части информации будут совместно использовать один и тот же слот в нашем потоке HTML. HTML-шаблон для отображения информации о погоде выглядит примерно так:
<polymer-element name="weather-tag" attributes="city code"> <template> <meta charset="utf-8"> <template if='{{!one}}'> <div class="ui message"> //Display local weather information </div> </template> <template if='{{one}}'> <div class="ui message"> //Display local weather information from another source </div> </template> </template> <script type="application/dart" src="weather.dart"></script> </polymer-element>
Мы объявили два класса, чтобы упростить создание нашей информации о погоде и упростить доступ. Класс Weather2
показан ниже:
class Weather2 { @observable var desc, city, temp, humidity; Weather2.created(String s) { Map w=JSON.decode(s); this.temp=w['main']['temp'].toStringAsFixed(1); this.humidity=w['main']['humidity']; this.city=w['name']; this.desc=w['weather'][0]['description']; } }
По сути, мы просто извлекаем определенные данные из возвращенной строки JSON и помещаем их в члены класса.
Особое внимание следует уделить заявлениям учеников. Мы украсили их @observable
. Это сделано для того, чтобы дерево Dart во время компиляции не сбрасывало ссылку на эти члены класса, поскольку (и, скорее всего, причина) в том, что на них нет явных ссылок нигде в выражении Polymer в нашей программе Dart, когда оно компилируется в JavaScript. Спасибо Günter Zöchbauer за подсказку в моем вопросе, поднятом в StackOverflow .
Это не требуется для запуска приложения в Dartium. Но это ОБЯЗАТЕЛЬНО, если мы скомпилируем его в JS.
С помощью определенного класса Weather мы можем отобразить объект в шаблоне Polymer более удобным способом:
<template if='{{one}}'> <div class="ui message"> <p>Today in {{w2.city}}: {{w2.desc}}, temperature {{w2.temp}} celcius, humidity {{w2.humidity}}% <br><i title="Refresh" class="refresh icon small link" on-click="{{getWeather}}"></i></p> </div> </template>
Без использования класса мы можем назвать наши переменные как w2city
, w2temp
и т. Д. Но это не очень удобно и не удобно для разработчиков, верно?
Два Дротика, Один HTML? Ограничение дротика
Пока процесс идет гладко. Теперь мне нужно интегрировать два созданных выше виджета Dart в одну домашнюю страницу. Не долго думая, я изменил свой HTML-шаблон примерно так:
<!DOCTYPE html> <html lang="zh-CN"> <head> <script src="/packages/shadow_dom/shadow_dom.debug.js"></script> <script src="/packages/custom_element/custom-elements.debug.js"></script> <script src="/packages/browser/interop.js"></script> <meta charset="utf-8"> <link rel="stylesheet" type="text/css" href="/css/semantic.css"> <link rel="stylesheet" type="text/css" href="/css/rsywx.css"> <script src="/getqotd.html_bootstrap.dart.js"></script> <script src="/getweather.html_bootstrap.dart.js"></script> <title>...</title> </head> <body id="home"> <polymer-element name="qotd-tag"> <template> ... </template> </polymer-element> <polymer-element name="weather-tag" attributes="city code"> <template> ... </template> </polymer-element> {% block content %} <div class="ui inverted page grid masthead segment"> <div class="ui grid"> <div class="row"> <div class="ten wide column"> <qotd-tag></qotd-tag> <weather-tag code="101190401" city="Suzhou,china"></weather-tag> </div> </div> </div> </div>
Мы вставили необходимые файлы, в частности, два скомпилированных JS-файла и объявили теги, а затем вставили теги там, где они необходимы, точно так же, как описано ранее.
Выглядит многообещающе, верно?
К сожалению нет.
В приведенной выше реализации только виджет, JS которого импортирован первым ( qotd
), может отображаться правильно. Если мы переключим последовательность двух импортов JS, чтобы weather
импортировалась JS первой, может отображаться только виджет weather
.
Я полагаю, что проблема связана с двумя скомпилированными файлами JS, имеющими много конфликтов в именах функций, объявлениях прототипов и т. Д. Например, мы можем найти следующие объявления в обоих файлах:
ght:function(a){return new P.C7(this,P.WV.prototype.h,a,"h")}, zw:function(a,b){if(this.Gv>=4)throw Hb(this.q7()) this.pb(a,b)},
Таким образом, только один JS может выжить и функционировать. Только мне странно, почему отказывает 2-й JS (вместо переопределения всего в 1-м JS).
Чтобы обойти это, нам нужно создать еще одно приложение Dart / Polymer, импортирующее оба файла Dart, созданные на предыдущих шагах, для QOTD и погоды. Затем нам нужно обернуть эти два виджета Dart в новый виджет.
Репозиторий Github содержит окончательное приложение Dart, которое работает нормально. Я разместил видео на Youtube, чтобы продемонстрировать результат (извините, но на главной странице в основном на китайском, но вы увидите, как Dart переходит на страницу Symfony и реагирует на взаимодействие с пользователем. Возможно, вам придется переключиться на 720p, чтобы получить более четкое представление) .)
Это, очевидно, большой недостаток в скомпилированном Dart JS.
Это не гибко и затрудняет расширение. Сейчас мы интегрируем два виджета. Что, если мы хотим увидеть некоторые котировки акций позже? Оценка моей любимой команды? Лента новостей? Является ли единственным вариантом разработка нового или изменение существующего виджета Dart каждый раз, когда нам нужно добавить или удалить компонент виджета?
Этот подход, конечно, будет работать, но с очень низкой эффективностью. Кроме того, не все веб-разработчики являются разработчиками Dart одновременно. Попросить веб-разработчика открыть Dart IDE и запустить кодирование Dart для вставки простого нового компонента, нецелесообразно.
Почему у нас не может быть разработки Dart, такой, чтобы Dart (и программисты Dart) могли создавать различные автономные виджеты (компоненты), а веб-разработчик мог просто взять скомпилированные файлы JS / html / CSS / image и просто изменить веб-страницы и начать формулировать «новый» виджет? Если бы это могло быть сделано, Дарт достиг бы широкого распространения гораздо быстрее.
Это подтвержденная проблема в Dart. Запрос на добавление функции был отправлен в Dart Google Group для привлечения их внимания и дальнейшего улучшения. Выручите, проголосовав по нему.
Вывод
В этой серии мы продемонстрировали, как интегрировать Dart / Polymer в Symfony, чтобы обеспечить динамическое содержание нашей страницы и взаимодействие с пользователем. Была дана подробная пошаговая инструкция, чтобы помочь пользователям управлять интеграцией, в частности, вставить шаблон Polymer в движок Twig.
Кроме того, мы рассмотрели несколько тем в программировании Dart: обойти JSONP и отобразить объекты в шаблоне Polymer.
Наконец, мы подчеркнули ограничение в текущей компиляции Dart JS: два или более отдельных приложения Dart не могут жить в одном HTML, если не создано новое упаковывающее приложение Dart. Я надеюсь, что этот вопрос будет решен как можно скорее.
Это подводит нас к концу этой серии. Не стесняйтесь комментировать и поднимать вопросы!