这篇文章是由同行评审埃德温·雷诺索 , 蒂姆Severien和Divy Tolia 。 感谢所有SitePoint的同行评审人员使SitePoint内容达到最佳状态!
过去,跨平台软件开发通常意味着用不同的语言针对不同的操作系统编写相同的应用程序。 可以想象,对于项目经理,开发人员和客户来说,这都是一个困难的处境。
然后,在2011年, Roger Wang引入了一种称为Node-Webkit的东西。 Node-Webkit(此后已重命名为NW.js)是Node.js和嵌入式WebKit浏览器的组合,允许开发人员使用Web技术(即HTML,CSS和JavaScript)来开发本机应用程序。 恩,那就对了! 我们必须使用现代浏览器支持的所有功能来编写本机应用程序。 例如,CSS3动画,WebGL,WebRTC,视频,音频以及更多内容都可以集成到本机应用程序中。
在本教程中,我将演示如何利用NW.js的功能来制作选项卡式浏览器,该选项卡式浏览器可以部署在所有主要操作系统上。 与以往一样,可以在我们的GitHub repo上找到本教程的代码。
最初设定
顾名思义,NW.js基于Node,因此您需要在操作系统上安装它。 我们还将使用npm(节点包管理器)。 如果您需要帮助来设置这些内容,请查看我们的教程: npm入门指南 。
接下来,我们将为我们的项目创建一个文件夹:
mkdir sitepoint-browser && cd sitepoint-browser
我们还需要一些应该全局安装的依赖项(即Yeoman,Grunt和Bower):
npm install -g yo grunt bower
其中, Yeoman (又名Yooman)是一种动态支撑日常项目的工具,从而避免了始终必须手动创建可重复使用的项目结构的障碍。 Grunt是Yeoman使用的任务运行程序。 它还使用npm和Bower安装所需的依赖项。
接下来,我们将安装Yo的generator-wean 。 您可以在全局或本地执行此操作。 在这里,我将在全球范围内进行:
npm install -g generator-wean
NW.js本身有少数生成器,但是generator-wean(由我撰写)与ExpressJS和AngularJS捆绑在一起,从而减轻了安装和配置它们的压力。 WEAN代表Webkit,Express,Angular和Node,就像流行的MEAN一样 。
现在,我们的骨架应用程序可以使用以下命令生成:
yo wean
Yo是一个互动的人,生成器会询问您一些问题,以帮助您制定最适合您想要的项目。 在这里您可以接受默认值。
资料夹结构
文件夹结构如下所示:
.
├── app
│ ├── app.js
│ ├── index.html
│ ├── public
│ │ ├── css
│ │ │ └── app.css
│ │ ├── js
│ │ │ └── app.js
│ │ ├── libs
│ │ │ ├── angular
│ │ │ ├── bootstrap
│ │ │ └── jquery
│ │ └── partials
│ │ └── header.html
│ ├── routes
│ │ └── index.js
│ └── views
│ └── index.ejs
├── node_modules
├── bower.json
├── Gruntfile.js
├── package.json
└── README.md
对于这个项目,我们主要对public
目录的内容感兴趣。 生成器将用一堆样板文件(一个非常简单的Angular应用程序)填充这些文件,但我们将在逐步解决该问题。
我们现在可以使用以下命令运行骨架应用程序:
grunt run
或只是grunt
此命令可在应用程序开发的任何时候用于预览更改。 它执行NW.js项目,该项目依次使用Express进行路由,就像制作Web应用程序时一样。 这是一个很好的示例,说明了如何在初始化后将它们插入app/index.html
,从而在NW.js中使用Node模块。
NW.js还具有开发人员工具和工具栏,与在Chrome中构建Web应用程序时一样,我们可以在其中找到刷新,调试,检查,记录等控件。 您可以通过在骨架应用程序中单击汉堡包图标来访问它们。
处理UI
本教程最重要的方面是能够从本机应用程序浏览互联网。 webview和iframe
代码是我们计划的理想选择。 webview
标签是有效的,但对游戏来说还是一个新事物,因为它是最近才添加到NW.js中的 。 但是,自HTML 4以来, iframe
标签就已经存在并具有广泛的支持。 我们将使用它,因为它对大多数开发人员都是众所周知的。
Bootstrap将作为我们UI的基础。 我们将使用来自Bootswatch的名为Slate的自定义引导主题。 下载Slate并将其放在app/public/css/bootstrap.css
。
对于我们的图标,我们将使用Font Awesome 。 从项目根目录运行:
bower install --save fontawesome
就像其他Bower依赖项一样,这会将Font Awesome下载到我们的libs
文件夹中。 这是因为我们在项目根目录的.bowerrc
文件中指定了以下行(否则默认为bower_components
)。
{
"directory" : "app/public/libs"
}
幸运的是,Bootstrap将处理大多数UI任务,但是我们需要调整一些组件和内容才能真正使浏览器看起来不错。 为此,我们将编写一些简单且简短的CSS并将其放在app/public/css/app.css
:
html,
.tab-content,
.tab-pane,
body > div {
height: 100%;
}
iframe {
background: white;
}
.controls {
position: fixed;
top: 10px;
right: 8px;
}
.controls > i {
padding: 0 3px;
}
.controls > i:last-child {
color: red;
}
.controls > i:hover {
color: white;
cursor: pointer;
}
.close-tab:hover {
color: red;
cursor: pointer;
}
html
, body
, tab-content
和tab-pane
高度设置为100%,以确保无论我们的浏览器应用程序大小如何,内容都应填满窗口的高度。 默认情况下,宽度为100%,因此无需明确指定宽度。 我们还将为浏览器控件提供最小化的样式,我们将在一段时间内看到它。
为了确保所有CSS文件都已加载,请将以下内容复制到app/views/index.ejs
。 这应该替换已经存在的两个样式表。
<link rel="stylesheet" href="css/bootstrap.css">
<link rel="stylesheet" href="libs/font-awesome/css/font-awesome.css">
<link rel="stylesheet" href="css/app.css">
安装我们的依赖
如前所述,我的WEAN生成器与AngularJS捆绑在一起,我们将在我们的浏览器应用程序中使用它。 我们还将利用Bootstrap的标签组件显示浏览器的标签。 但是,在尝试将Bootstrap JavaScript组件引入Angular项目时,存在一个已知的问题 ,这就是Angular团队创建Angular Bootstrap UI的原因 。
让我们将其添加到我们的项目中。 从根目录运行:
bower install --save angular-bootstrap
AngularJS具有良好的安全性,并对被认为可能有害的事物进行了限制。 在我们的应用程序中的某个时刻,我们必须清理HTML并阻止Angular在遇到将可信HTML注入到我们的代码中时引发错误。 ngSanitize是处理这种情况的模块 (我们将很快遇到)。 这也应该使用Bower安装:
bower install --save angular-sanitize
如果Bower要求您选择该库的版本,请选择解析为angular#1.4.6的版本。
就像处理CSS文件一样,让我们在app/views/index.ejs
的body
结束标记之前添加JS依赖app/views/index.ejs
:
<html ng-app="browser">
...
<body ng-controller="main">
<script src="libs/jquery/dist/jquery.min.js"></script>
<script src="libs/angular/angular.js"></script>
<script src="libs/angular-sanitize/angular-sanitize.js"></script>
<script src="libs/angular-bootstrap/ui-bootstrap-tpls.js"></script>
<script src="js/app.js"></script>
</body>
</html>
请注意, ng-app
属性已设置为browser
, ng-controller
属性已设置为main
。 现在也是清除其余样板代码的好时机。
设置方法的最后一件事是将刚下载的依赖项注入到Angular应用app/public/js/app.js
:
angular.module('browser', ['ui.bootstrap', 'ngSanitize'])
.controller('main', function(){});
至此,我们有了应用程序的框架。 我们的CSS文件(库文件和自定义文件)均已安装和/或创建。 JavaScript文件及其依赖项也已可用并添加到应用程序中。 如果此时运行grunt
,应该会看到一个空白窗口。 令人兴奋,是吗?
现在,开发过程中剩下的就是app.js
标记的其余部分,并在app.js
创建行为。
标记
NW.js使用HTML作为其视图。 我们已经使用生成器( app/views/index.ejs
)创建了一个,并将一些文件加载到其中。 现在,我们需要添加标记,这将有助于我们在本机应用程序中启动网页。
<uib-tabset>
<iframe-tab tabs="tabs">
</iframe-tab>
</uib-tabset>
uib-tabset
标签是Angular Bootstrap UI库提供的Angular指令,用于帮助实现tabs组件,而iframe-tab
将在我们的应用程序中创建,以自定义Bootstrap的UI tab
指令以适合我们。 将使用tabs
范围配置iframeTab
指令,该tabs
范围在iframe-tab
标记中显示为属性。
实施指令
Chrome和Firefox等选项卡式浏览器更易于导航并提高用户的工作效率。 我们自己的浏览器不应该被遗忘。 在app/public/js/app.js
文件中,我们将创建一个最小指令来实现制表。
.directive('iframeTab', function () {
return {
restrict: 'E',
scope: {
tabs: '='
},
replace: true,
template: '<uib-tab ng-repeat="tab in tabs" active="tab.active">' +
'<uib-tab-heading>{{tab.url}} <i class="fa fa-times close-tab"' +
'ng-click="closeTab($index)"></i></uib-tab-heading>' +
'<iframe src="{{trustSrc(tab.url)}}"' +
'style="width:100%; height:100%" nwdisable nwfaketop></iframe>' +
'</uib-tab>'
};
})
我们在这里所做的是创建一个可重复使用的模板,该模板可以使用Angular动态创建。 iframe
src属性上的trustSrc()
方法将在我们的控制器中创建。
解释指令在Angular中的工作方式超出了本文的范围。 如果您需要复习,请查看: AngularJS指令实用指南 。
一些支持服务
Angular将服务用于代码组织,可重用性,与API的通信以及其控制器之间的逻辑共享。 我们需要自己制作三个:一个( prompt
)使用提示来获取URL输入,另外两个( GUI
和Window
)与NW.js的GUI和Window API通信,以便我们可以创建自定义的最小化全屏和关闭按钮:
.factory("prompt", function ($window, $q) {
function prompt(message, defaultValue) {
var defer = $q.defer();
var response = $window.prompt(message, defaultValue);
if (response === null) {
defer.reject();
} else {
defer.resolve(response);
}
return (defer.promise);
}
return (prompt);
})
.factory('GUI', function () {
return require('nw.gui');
})
.factory('Window', function (GUI) {
return GUI.Window.get();
});
最后的控制器
顾名思义,控制器将控制应用程序中的数据流。 我们将注入以下依赖项: $scope
, $sce
(向AngularJS提供严格的上下文转义服务的服务),提示,Window(我们在上面创建的两个服务)。
.controller('main', function ($scope, $sce, prompt, Window) {
//implementation here
})
我们将首先创建一种方法来信任资源URL(我们已经在指令中实现了该方法):
$scope.trustSrc = function (src) {
return $sce.trustAsResourceUrl(src);
}
将SitePoint设为主页真是太棒了,因此我们将为我们的指令创建一个tabs
数组,以使用SitePoint的URL作为第一个值进行循环。
$scope.tabs = [
{
url: 'http://www.sitepoint.com/'
}
];
现在,我们可以使用提示服务启动新选项卡,以从用户获取URL。 我们将active
属性设置为true,以便新选项卡获得焦点:
$scope.newTab = function () {
prompt("Please enter a url", "http://www.sitepoint.com")
.then(function (url) {
var tab = {url: url, active:true}
$scope.tabs.push(tab);
},
function () {
alert("Error opening site!");
});
};
关闭选项卡涉及使用Array#splice
函数从选项卡的数组中删除值,如下所示:
$scope.closeTab = function (index) {
$scope.tabs.splice(index, 1);
};
控制器的其余部分用于向控件添加行为,以最小化,启用/禁用全屏并关闭窗口:
$scope.minimize = function () {
Window.minimize();
};
$scope.toggleKioskMode = function () {
Window.toggleKioskMode();
};
$scope.close = function () {
Window.close();
};
即使添加了实现,我们仍未将这些控件添加到标记中。 现在让我们来做(在app/views/index.ejs
):
<div class="controls">
<i class="fa fa-plus" tooltip-placement="bottom"
uib-tooltip="New tab" ng-click="newTab()"></i>
<i class="fa fa-minus" ng-click="minimize()"></i>
<i class="fa fa-square-o" ng-click="toggleKioskMode()"></i>
<i class="fa fa-times" ng-click="close()"></i>
<div>
就是这样! 现在,您可以从终端使用grunt
命令启动浏览器。
建立平台
如果您回到本文开头,我提到可以在所有主要操作系统上部署NW.js应用程序。 在NW.js项目页面上有关于如何执行此操作的详尽说明,或者您可以使用generator-wean的预配置build
任务(我现在将演示)。
从项目根目录运行grunt build
将针对其所构建的OS构建应用程序,而grunt build:all
将为所有平台构建。 命令grunt build:{platform}
(例如grunt build:mac
)将针对特定的操作系统构建。 可能的选项是win
, osx
, linux32
, linux64
。 有关更多信息,请参阅generator-wean自述文件 。
举例来说,如果您使用的是64位Linux系统,请运行:
grunt build
这将生成一个builds/test/linux64
目录,其中包含一个可执行文件,与您的项目名称相对应。
结论
借此,我希望不仅展示NW.js的功能,而且展示Web技术在制作本机应用程序中的功能。 我们不仅学习了如何制作本机浏览器,而且还看到了NW.js,Yeoman和其他工具。 别忘了, 本教程的源代码在GitHub上 -我建议您下载并进行实验。
您正在使用NW.js吗? 您是否认为它会对本机应用程序提出严峻挑战? 我希望在下面的评论中听到您的想法。
From: https://www.sitepoint.com/tabbed-browser-node-webkit-angularjs/