务逻辑 ,并使用 JavaScript 将其移动到客户端浏览器。
例如,我们希望在网站上显示给定城市的天气,涉及以下事项:
- 调用一些的公共API(可带参数)。 本例中我们选择 OpenWeatherMap 。
- 从返回结果中提取相应的气象数据。
- 将数据显示在浏览器中。
其结果将如下图所示:
在 Drupal 中,我们可以创建一个区块,使用 drupal_http_request() 函数来获取数据,然后将它的结果传递给一个主题函数进行渲染。这很简单,也易于维护,只是这项功能即没有数据库参与,也没有Session管理,为什么要让 Drupal 来关心这些事情?
如果我们的网站依赖于缓存以提高性能,每当区块内容更新时,我们都不得不进行缓存清除。相对的,让我们将这个功能交给 JS 和 HTML 来处理,让客户端浏览器来对数据的获取、加工和缓存负责。
遇见 AngularJS
AngularJS 是一个MVC JavaScript框架,它将应用程序中的控制器、模板及数据模型优雅的进行分类。通过AngularJS,我们已经从 Drupal 项目中移除了大量的后台逻辑。虽然有很多东西需要学,但目前为止,我们已经取得了相当不错的成绩。
完整的示例地址 https://gist.github.com/juampynr/6003761 。接下来我们逐步来看如何实现。
引导 AngularJS 应用
我们可以通过添加 directive(指令), 来引导 AngularJS 应用。将以下属性添加到 html.tpl.php 文件中:
<html data-ng-app="myapp" xmlns="http://www.w3.org/1999/xhtml" xml:lang="<?php print $language->language; ?>" version="XHTML+RDFa 1.0" dir="<?php print $language->dir; ?>"<?php print $rdf_namespaces; ?>>
属性 data-ng-app=”myapp” 告诉 AngularJS 来引导我们命名为“myapp ”的应用程序 。目前只需要做这么多就够, 我们会在稍后实现我们的 AngularJS应用。
在Drupal中实现业务骨架
通过一些简单的代码在Drupal模块中实现一个区块。thememymodule_block_view()函数还包括一个JavaScript文件(AngularJS控制器)和一个模板:
/**
* Implements hook_block_view().
*/
function mymodule_block_view($delta = '') {
$block = array();
switch ($delta) {
case 'weather':
$path = drupal_get_path('module', 'mymodule');
$block['subject'] = t('Weather status');
$block['content'] = array(
'#theme' => 'weather_status',
'#attached' => array(
'js' => array(
'https://ajax.bootcdn.cn/ajax/libs/angularjs/1.0.7/angular.min.js',
$path . '/mymodule.js',
),
),
);
break;
}
return $block;
}
Drupal所要做的工作就这些,为 AngularJS应用打好运行基础。
在浏览器中处理
当页面被传递到客户端,AngularJS 控制器将从 OpenWeatherMap 抓取数据,然后对数据进行处理:
/**
* Renders the weather status for a city.
*/
var app = angular.module('myapp', [])
.controller('MyModuleWeather', function($scope, $http, $log) {
// Set default values for our form fields.
$scope.city = 'Madrid';
$scope.units = 'metric';
// Define a function to process form submission.
$scope.change = function() {
// Fetch the data from the public API through JSONP.
// See http://openweathermap.org/API#weather.
var url = 'http://api.openweathermap.org/data/2.5/weather';
$http.jsonp(url, { params : {
q : $scope.city,
units : $scope.units,
callback: 'JSON_CALLBACK'
}}).
success(function(data, status, headers, config) {
$scope.main = data.main;
$scope.wind = data.wind;
$scope.description = data.weather[0].description;
}).
error(function(data, status, headers, config) {
// Log an error in the browser's console.
$log.error('Could not retrieve data from ' + url);
});
};
// Trigger form submission for first load.
$scope.change();
});
渲染结果
我们的模板直接引用控制器(AngularJS的绑定方式)和输出在$scope对象中设置的变量。
<div ng-controller="MyModuleWeather">
<label for="city">City</label>
<input type="text" ng-model="city" /></br>
<label for="units">Units</label>
<input type="radio" ng-model="units" value="metric"/> Metric
<input type="radio" ng-model="units" value="imperial"/> Imperial</br>
<button ng-click="change()">Change</button>
<h3>{{data.name}}</h3>
<p>{{description}}</p>
<p>Temperature: {{main.temp}}</p>
<p>Wind speed: {{wind.speed}}</p>
</div>
搞定!现在我们就有一个在浏览器中处理的功能完整的区块。如果我们将这种模式应用于页面上其他经常变化的区块,便能够简化Drupal的工作,让页面的缓存效率更高,实现更好的性能。当需要为不同显示不同的内容时,通过这种模式,还可以对内容进行 lazy_load(延迟加载) ,使页面其余部分更容易缓存。
使用外部API注意事项
当在客户端浏览器中执行跨域请求时,请记住,有时浏览器的安全机制会成为你的阻碍。有两种流行的方法来克服这个问题。一种是通过 CORS 跨域资源共享 :可以在Drupal.org上找到 CORS模块 。另一种方法是使用 JSONP,也是我们在本例中使用的就是这个方法,AngularJS 和 JQuery 都支持。
为什么不使用jQuery?
从技术上讲,使用 JQuery 也可以实现相同的功能 。只不过那需要更多的代码:你将需要在页面被构建时隐藏模板,为提交按钮定义监听器、净化数据、以及自行处理模板绑定等操作。即使以这个简单例子而 言,AngularJS 方法不仅简单,且更富有条理。你也可以在 AngularJS中使用jQuery 。
你也可以查看本例子的jQuery版本 ,并对两者进行比较。
来源:https://www.zhi12.cn/node/8547