广东网站开发:渐进式Web应用程序初学者指南

2019.08.13 mf_web

160

渐进式网络应用程序可能是移动网络的下一个重点。最初由Google于2015年提出,由于相对容易开发以及应用程序用户体验几乎立即获胜,它们已经引起了很多关注。渐进式Web应用程序利用最新技术将最佳的Web和移动应用程序结合在一起。可以把它想象成一个使用网络技术构建的网站,但它的行为和感觉就像一个应用程序。浏览器以及服务工作者和Cache和Push API的最新进展使Web开发人员能够允许用户将Web应用程序安装到其主屏幕,接收推送通知甚至脱机工作。

广东网站开发与各个应用商店中的本机应用程序相比,渐进式Web应用程序利用了更大的Web生态系统,插件和社区以及相对容易部署和维护网站。对于那些在移动设备和网络上发展的人来说,您会感激网站可以在更短的时间内构建,不需要通过向后兼容性来维护API(所有用户都将运行相同版本的网站)代码,与本机应用程序的版本碎片不同),应用程序通常更容易部署和维护。

为何选择Progressive Web Apps?

一项研究表明,平均而言,在用户首次与应用程序联系和开始使用该应用程序的用户之间的每一步中,应用程序都会丢失20%的用户。用户必须首先在应用商店中找到应用,下载,安装然后最后打开它。当用户找到您的渐进式Web应用程序时,他们将能够立即开始使用它,从而消除了不必要的下载和安装阶段。当用户返回应用程序时,系统将提示他们安装应用程序并升级到全屏体验。

但是,本机应用程序绝对不是坏事。具有推送通知的移动应用程序的保留率比没有推送的同类产品高出三倍,而用户重新打开移动应用程序的可能性是网站的三倍。此外,精心设计的移动应用程序消耗的数据更少,速度更快,因为某些资源驻留在设备上。

渐进式Web应用程序利用移动应用程序的特性,从而提高用户保留率和性能,而无需维护移动应用程序所涉及的复杂性。

用例

什么时候应该构建一个渐进的Web应用程序 对于您希望用户经常返回的应用程序,通常建议使用Native,而渐进式Web应用程序则没有任何不同。Flipkart为其流行的电子商务平台Flipkart Lite 使用渐进式网络应用程序,SBB使用渐进式网络应用程序进行在线登记过程,允许用户在没有互联网连接的情况下访问其门票。

在评估您的下一个应用程序是否应该是渐进式Web应用程序,网站或本机移动应用程序时,首先要确定您的用户和最重要的用户操作。作为“渐进式”,渐进式Web应用程序适用于所有浏览器,只要用户的浏览器使用新的和改进的功能和API进行更新,体验就会得到增强。

因此,与传统网站相比,渐进式网络应用的用户体验没有任何妥协; 但是,您可能必须决定支持离线的功能,并且您必须方便导航(请记住,在独立模式下,用户无权访问后退按钮)。如果您的网站已经具有类似应用程序的界面,那么应用渐进式网络应用程序的概念只会让它变得更好。

如果关键用户操作需要某些功能但由于缺乏跨浏览器支持而无法使用某些功能,则原生移动应用程序可能是更好的选择,可确保为所有用户提供相同的体验。

渐进式Web应用程序的特征

在我们进入代码之前,了解渐进式Web应用程序具有以下特征非常重要:

  • 进步。根据定义,渐进式Web应用程序必须在任何设备上运行并逐步增强,利用用户设备和浏览器上提供的任何功能。

  • 可发现的。因为渐进式网络应用程序是一个网站,所以它应该可以在搜索引擎中被发现。与原生应用程序相比,这是一个主要优势,在可搜索性方面仍然落后于网站。

  • 可链接的。作为从网站继承的另一个特征,精心设计的网站应该使用URI来指示应用程序的当前状态。这将使Web应用程序在用户书签或共享应用程序的URL时保留或重新加载其状态。

  • 反应迅速。渐进式Web应用程序的UI必须符合设备的外形和屏幕尺寸。

  • 类似应用程序。渐进式Web应用程序应该看起来像本机应用程序,并且可以在应用程序外壳模型上构建,只需最少的页面刷新。

  • 连通性无关。它应该在低连接或离线(我们最喜欢的特性)的区域中工作。

  • 重新参与。移动应用用户更有可能重复使用他们的应用,而渐进式网络应用旨在通过推送通知等功能实现相同的目标。

  • 可安装。可以在设备的主屏幕上安装渐进式Web应用程序,使其随时可用。

  • 新鲜。发布新内容并且用户连接到Internet时,应在应用程序中提供该内容。

  • 安全。由于渐进式Web应用程序具有更亲密的用户体验,并且因为所有网络请求都可以通过服务工作者拦截,因此必须通过HTTPS托管应用程序以防止中间人攻击。

我们的代码!

我们的第一个渐进式网络应用程序Sky High将模拟机场的到达时间表。用户第一次访问我们的网络应用程序时,我们希望向他们显示从API检索的即将到来的航班列表。如果用户没有Internet连接并且他们重新加载Web应用程序,我们希望向他们显示上次使用连接下载时的航班时刻表。

Sky High截图
Sky High,我们虚构的渐进式网络应用程序(大预览版)

基础

渐进式Web应用程序的第一个特征是它必须适用于所有设备,并且必须在允许它的设备和浏览器上进行增强。因此,我们使用传统的HTML5和JavaScript来构建我们的网站,模拟从模拟API中检索数据。在整个应用程序中,我们使用一小部分Knockout来处理我们的Model-View-ViewModel(MVVM)绑定 - 一个轻量级JavaScript框架,它允许我们将JavaScript模型绑定到HTML视图。我们选择使用Knockout,因为它相对简单易懂并且不会使代码混乱; 但是,您可以将其替换为任何其他框架,例如React或AngularJS。

我们的网站遵循Google的材料设计指南,这是一套指导设计和互动的原则。材料设计不仅可以作为应用程序和设备的统一标准,还可以提供设计含义。我们已经使用Sky High的到货视图的材料设计来为我们的渐进式网络应用程序提供本机应用程序的外观和感觉。

最后,我们测试了我们的应用程序,以确保它是无抖动的,并且滚动是丝般光滑的。已经证明,无Jank渲染可以提高用户参与度。目标是每秒渲染60帧。

对于此演示,我们将检索静态JSON文件,而不是真正的API。这只是为了简单起见。在现实世界中,您将查询API或使用WebSockets。

的INDEX.HTML

<!DOCTYPE html><html lang="en"><head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Sky-High Airport Arrivals</title>
    <link async rel="stylesheet" href="./css/style.css">
    <link href="https://fonts.googleapis.com/css?family=Roboto:300,600,300italic,600italic" rel="stylesheet" type="text/css"></head><body>
    <header>
        <div class="content">
            <h3>Arrivals</h3>
        </div>
    </header>
    <div class="container">
        <div id="main" class="content">
            <ul class="arrivals-list" data-bind="foreach: arrivals">
                <li class="item">
                    <span class="title" data-bind="html: title"></span>
                    <span class="status" data-bind="html: status"></span>
                    <span class="time" data-bind="html: time"></span>
                </li>
            </ul>
        </div>
    </div>
    <script src="./js/build/vendor.min.js"></script>
    <script src="./js/build/script.min.js"></script></body></html>
复制

该index.html文件相对标准。我们已经创建了一个HTML列表,并arrivals使用Knockout通过该属性将我们的View Model属性绑定到它data-bind=“foreach: arrivals”。视图模型arrivals在page.js下面的文件中声明并在Page模块中公开。在我们的HTML页面,为每个项目arrivals阵列,我们已经约束title,status以及time属性的HTML视图。

PAGE.JS

(var Page = (function() {
    // declare the view model used within the page
    function ViewModel() {
        var self = this;
        self.arrivals = ko.observableArray([]);
    }
    // expose the view model through the Page module
    return {
        vm: new ViewModel(),
        hideOfflineWarning: function() {
            // enable the live data
            document.querySelector(".arrivals-list").classList.remove('loading')
            // remove the offline message
            document.getElementById("offline").remove();
            // load the live data
        },
        showOfflineWarning: function() {
            // disable the live data
            document.querySelector(".arrivals-list").classList.add('loading')
                // load html template informing the user they are offline
            var request = new XMLHttpRequest();
            request.open('GET', './offline.html', true);
            request.onload = function() {
                if (request.status === 200) {
                    // success
                    // create offline element with HTML loaded from offline.html template
                    var offlineMessageElement = document.createElement("div");
                    offlineMessageElement.setAttribute("id", "offline");
                    offlineMessageElement.innerHTML = request.responseText;
                    document.getElementById("main").appendChild(offlineMessageElement);
                } else {
                    // error retrieving file
                    console.warn('Error retrieving offline.html');
                }
            };
            request.onerror = function() {
                // network errors
                console.error('Connection error');
            };
            request.send();
        }
    }})();
复制

该page.js文件公开了Page模块,其中包含我们的ViewModel vm和两个函数,hideOfflineWarning以及showOfflineWarning。View Model ViewModel是一个简单的JavaScript文字,将在整个应用程序中使用。arrivalsViewModel上的属性是Knockout observableArray,它自动将我们的HTML绑定到JavaScript数组,允许我们在JavaScript中将项目推送到我们的数组并自动更新页面的HTML。

功能hideOfflineWarning和showOfflineWarning使我们的应用程序的其他部分来调用这些函数来更新显示我们是否在线连接的页面的UI。在我们的HTML元素中showOfflineWarning添加一类淡化列表,然后通过XHR 检索HTML文件。假设已成功检索文件(),我们将其附加到HTML。当然,如果我们不使用服务工作者且用户未连接到Internet,则无法检索,因此用户将看到浏览器的离线页面。loadingarrivals-listoffline.htmlresponse.status === 200offline.html

我们从API检索数据并将其绑定到View Models和Views的业务逻辑可以在arrivals.jsKnockout中找到,并且是使用Knockout的标准MVVM功能。在arrivals.js文件中,我们只是初始化我们将在整个应用程序中使用的服务和视图模型,并且我们公开了一个函数Arrivals.loadData()- 它检索数据并将其绑定到视图模型。

Web App清单

让我们的网络应用程序更像应用程序。Web应用程序清单文件是遵循W3C规范的简单JSON文件。有了它,可以作为独立应用程序以全屏模式运行Web应用程序,分配一个图标,该图标将在设备上安装应用程序时显示,并为应用程序分配主题和背景颜色。此外,Android上的Chrome会主动建议用户通过网络应用安装横幅安装网络应用。要显示安装提示,您的Web应用程序需要:

  • 有一个有效的Web应用程序清单文件,

  • 通过HTTPS提供服务,

  • 有一个有效的服务工作者注册,

  • 已经访问了两次,每次访问之间至少有五分钟。

Web应用程序安装横幅
Web应用程序安装横幅(查看大图)

的MANIFEST.JSON

{
    "short_name": "Arrivals",
    "name": "Arrivals at Sky High",
    "description": "Progressive web application demonstration",
    "icons": [
        {
            "src": "launcher-icon.png",
            "sizes": "48x48",
            "type": "image/png"
        },
        {
            "src": "launcher-icon-96.png",
            "sizes": "96x96",
            "type": "image/png"
        },
        {
            "src": "launcher-icon-144.png",
            "sizes": "144x144",
            "type": "image/png"
        },
        {
            "src": "launcher-icon-192.png",
            "sizes": "192x192",
            "type": "image/png"
        },
        {
            "src": "launcher-icon-256.png",
            "sizes": "256x256",
            "type": "image/png"
        }
    ],
    "start_url": "./?utm_source=web_app_manifest",
    "display": "standalone",
    "orientation": "portrait",
    "theme_color": "#29BDBB",
    "background_color": "#29BDBB"}
复制

让我们分解这个清单文件:

  • short_name是一个人类可读的应用程序名称。在Chrome for Android中,这也是主屏幕上图标随附的名称。

  • name 也是应用程序的可读名称,并定义应用程序的列出方式。

  • description 提供Web应用程序的一般描述。

  • icons定义了一个不同大小的图像数组,用作应用程序的图标集。在Chrome for Android中,该图标将在初始屏幕,主屏幕和任务切换器中使用。

  • start_url 是应用程序的起始URL。

  • display定义的默认显示模式为Web应用程序:fullscreen,standalone,minimal-ui或browser。

  • orientation定义Web应用程序的默认方向:portrait或landscape。

  • theme_color是应用程序的默认主题颜色。在Android上,这也用于为状态栏着色。

  • background_color定义Web应用程序的背景颜色。在Chrome中,它还定义了初始屏幕的背景颜色。

  • related_applications 我们的示例中未实现,但用于在各种应用商店中指定本机应用程序备选方案。

添加对文件标签的manifest.json引用:index.htmlhead

<link rel="manifest" href="./manifest.json">
复制

一旦用户将Web应用程序添加到其主屏幕,他们就可以立即从他们的设备重新与您的应用程序进行交互,而无需直接打开浏览器。您可以看到这不仅仅是一个网络书签。

服务人员

渐进式网络应用程序的一个令人兴奋的方面是它们可以脱机工作。使用服务工作者,可以显示在应用程序的先前会话中检索的数据(使用IndexedDB),或者显示应用程序shell并通知用户他们没有连接到Internet(我们采用的方法)在这个演示中)。一旦用户重新连接,我们就可以从服务器检索最新数据。

所有这一切都可以通过服务工作者实现,服务工作者是事件驱动的脚本(用JavaScript编写),可以访问域范围的事件,包括网络提取。通过它们,我们可以缓存所有静态资源,这可以大大减少网络请求并显着提高性能。

应用程序Shell

应用程序shell是为用户界面提供动力所需的最低HTML,CSS和JavaScript。本机移动应用程序包括应用程序shell作为其可分发的一部分,而网站通常通过网络请求它。渐进式Web应用程序通过将应用程序shell的资源和资产放在浏览器的缓存中来弥补这一差距。在我们的Sky High应用程序中,我们可以看到我们的应用程序shell包含顶部标题栏,字体以及优雅渲染这些所需的任何CSS。

要开始使用服务工作者,我们首先需要创建服务工作者的JavaScript文件sw.js,放在根目录中。

SW.JS

// Use a cacheName for cache versioningvar cacheName = 'v1:static';// During the installation phase, you'll usually want to cache static assets.self.addEventListener('install', function(e) {
    // Once the service worker is installed, go ahead and fetch the resources to make this work offline.
    e.waitUntil(
        caches.open(cacheName).then(function(cache) {
            return cache.addAll([
                './',
                './css/style.css',
                './js/build/script.min.js',
                './js/build/vendor.min.js',
                './css/fonts/roboto.woff',
                './offline.html'
            ]).then(function() {
                self.skipWaiting();
            });
        })
    );});// when the browser fetches a URL…self.addEventListener('fetch', function(event) {
    // … either respond with the cached object or go ahead and fetch the actual URL
    event.respondWith(
        caches.match(event.request).then(function(response) {
            if (response) {
                // retrieve from cache
                return response;
            }
            // fetch as normal
            return fetch(event.request);
        })
    );});
复制

让我们更仔细地看看我们的服务人员。首先,我们设置一个cacheName变量。这用于确定是否对我们的缓存资产进行了任何更改。对于此示例,我们将使用静态名称,这意味着我们的资产不会更改或需要更新。

self.addEventListener('install', function(e) {
    // declare which assets to cache}
复制

该install如果已经安装了服务人员在服务工作者和安装阶段触发事件将触发一次。因此,刷新页面不会再次触发安装阶段。在安装阶段,我们可以声明将缓存哪些资产。在上面的示例中,我们正在缓存一个CSS文件,两个JavaScript文件,我们的字体文件,我们的离线HTML模板,当然还有应用程序根目录。self.skipWaiting()迫使等待的服务工作者变得活跃。

到目前为止,我们已经声明了我们的服务工作者,但在我们看到它生效之前,我们需要在JavaScript中引用它。在我们的申请中,我们注册了main.js

// Register the service worker if available.if ('serviceWorker' in navigator) {
    navigator.serviceWorker.register('./sw.js').then(function(reg) {
        console.log('Successfully registered service worker', reg);
    }).catch(function(err) {
        console.warn('Error whilst registering service worker', err);
    });}window.addEventListener('online', function(e) {
    // Resync data with server.
    console.log("You are online");
    Page.hideOfflineWarning();
    Arrivals.loadData();}, false);window.addEventListener('offline', function(e) {
    // Queue up events for server.
    console.log("You are offline");
    Page.showOfflineWarning();}, false);// Check if the user is connected.if (navigator.onLine) {
    Arrivals.loadData();} else {
    // Show offline message
    Page.showOfflineWarning();}// Set Knockout view model bindings.ko.applyBindings(Page.vm);
复制

我们还包括两个事件侦听器来检查会话的状态是否已经从online以offline反之亦然。事件处理程序然后调用的不同功能通过检索数据Arrivals.loadData()以及启用或通过禁用该离线消息Page.showOfflineWarning和Page.hideOfflineWarning分别。我们的应用程序还使用navigator.onLine检查用户当前是否在线,并检索数据或相应地显示脱机警告。在最后一行中main.js,我们将Knockout绑定应用于View Model Page.vm。

如果我们是第一次加载我们的应用程序(使用Chrome开发者工具),我们将看不到任何新内容。但是,在重新加载时,我们将看到已从服务工作者检索到许多网络资源。这是我们的应用程序shell。

应用程序shell
Chrome开发者工具中的应用程序shell网络资源(查看大图)

离线测试

在没有Internet连接的情况下运行应用程序的用户(假设它们已经在页面上)将简单地导致应用程序shell和显示的离线警告 - 这是对Chrome的徘徊t-rex的改进。用户建立网络连接后,我们会禁用警告并检索最新数据。

失败优雅
渲染自定义HTML页面而不是Chrome的默认页面(查看大图)

当离线用户访问其网站时,Guardian采用了一种特别有趣的方法,提供了填字游戏:

卫报的离线填字游戏
卫报的离线填字游戏(查看大图)

推送通知

推送通知允许用户选择从他们信任的应用程序及时更新,帮助他们重新与应用程序互动。通过网络推送通知,即使浏览器关闭,您也可以与受众群体进行互动。

推送通知
在Emojoy上推送通知(查看大图)

推特API在Chrome,Opera和三星的浏览器中得到支持,目前正在Firefox和Microsoft Edge中开发。不幸的是,没有迹象表明该功能将在Safari中实现。

性能

与服务工作者最简单的胜利之一是我们可以轻而易举地提高性能。在服务工作者实施之前将我们的网站与自身进行比较,然后我们在页面加载时检索超过200 KB; 现在减少到13 KB。在常规3G网络上,页面加载需要3.5秒; 现在需要500毫秒。

这些性能改进非常激烈,因为应用程序本身非常小并且功能有限。然而,通过正确使用缓存,可以显着提高性能和感知性能,尤其是对于具有低连接性的用户。

灯塔

谷歌的Chrome团队已经整合了一个测试渐进式网络应用程序的工具。Lighthouse在Node.js中运行或作为Chrome插件运行,也可以在GitHub上找到。

要运行Lighthouse测试,您的网站需要在线提供,这意味着您无法进行测试localhost。

首先,下载npm包:

npm install -g GoogleChrome/lighthouse
复制

安装完成后,运行Chrome(版本52以后):

npm explore -g lighthouse -- npm run chromelighthouse https://incredibleweb.github.io/pwa-tutorial/
复制

灯塔运行的输出将在命令行中显示,并将根据您实施的渐进式Web应用程序功能和属性对您的网站进行评级 - 例如,您是使用manifest.json文件还是离线使用您的页面。

结论

本文仅是渐进式网络应用程序的开胃菜。我们可以做更多的事情来创建用户正在寻找的类似app的体验,无论是通过Push API支持推送通知,使应用程序可重新参与,还是使用IndexedDB和后台同步来改善离线体验。

跨浏览器支持

广东网站开发这些仍然是渐进式网络应用程序的早期阶段,跨浏览器支持仍然有限,特别是在Safari和Edge中。但是,Microsoft公开支持渐进式Web应用程序,并且应该在年底之前实现更多功能。

  • 服务工作者和Cache API。支持Chrome,Firefox,Opera和三星的浏览器。在Microsoft Edge的开发中,预计将于2016年底上市。正在考虑使用Safari。

  • 添加到主屏幕。支持Chrome,Firefox,Opera,Android浏览器和三星的浏览器。微软似乎表明,渐进式网络应用程序将作为商店列表提供。尚未制定Safari的计划。

  • 推送API。主要支持Chrome,Firefox,Opera和三星的浏览器。在Microsoft Edge的开发中。尚未制定Safari的计划。

如果更多的开发人员利用渐进式网络应用程序提供的功能 - 相对容易实现并提供即时奖励 - 那么用户将更喜欢在支持的浏览器中使用这些网络应用程序,希望说服其他浏览器供应商进行调整。

最新案例

寒枫总监

来电咨询

400-6065-301

微信咨询

寒枫总监

TOP