《Windows 8 开发权威指南:HTML5 和JavaScript卷》——2.4 HTML5

简介: 首先,通过调用 storageFile.openAsync 方法,从文件打开流。打开操作完成后,它将返回文件的内容流。必须确保声明某个函数(这里是readFromStream)以捕获流(类型IRandomAccessStream),以便可以在该方法完成后从该流进行读取。

本节书摘来自异步社区《Windows 8 开发权威指南:HTML5 和JavaScript卷》一书中的第2章,第2.4节,作者:尹成 , 李亚男 , 王腾 , 丁宽帅 , 尹子磊著,更多章节内容可以访问云栖社区“异步社区”公众号查看

2.4 HTML5

2.4.1 HTML5添加音频
通过使用HTML5,无需任何第三方插件或外接程序,你就可以向你的网页添加音乐播放器。

1.< audio>元素简介
HTML5 audio元素提供一个可编写脚本的对象,无需外接程序或插件即可播放音频文件。简单地说,使用单个标签和一组属性在网页上为用户提供播放器。通过使用JavaScript,你可以管理audio对象和分配事件,以提供全方位的控制和状态跟踪。

HTML5 audio元素与HTML5 video元素共享媒体属性和方法,所以你可能发现你用于监视进度、文件加载或播放查找等项目的代码是可以彼此互换的。除了方法和属性之外,与大多数JavaScript对象一样,有许多可以进行注册的事件,可以简化你的代码。

2.最简单的音频播放器
与大部分新的HTML5支持一样,如果用户的浏览器不支持HTML5 audio元素,则audio元素允许你使用错误消息或其他播放技术进行回滚。你可以在audio标记之间放置一个错误消息,或者插入外部播放器控件的代码。下面的代码示例显示了播放音频文件的简单网页。

<!doctype html>
<html>
<head>
   <title>2.4.1HTML5添加音频</title>
</head>
<body>
  <h1>Audio Element Sample</h1>
  <!--显示有播放控件的音频播放器-->
  <audio src=”demo.mp3” controls autoplay loop>
    您的浏览器不支持audio元素。
  </audio>
</body>
</html>

将audio元素直接添加到HTML代码中,使用src属性指定要播放的音频文件,并使用controls特性以使用内置的播放器控件。如果你使用的是浏览器的内部播放器,则无需其他脚本。各个浏览器中的内部播放器可能会在样式或功能上有所不同。

在Windows Internet Explorer 9中的音频元素支持两个其他特性:autoplay和loop。Autoplay告诉Windows Internet Explorer在加载audio对象后立即加载并播放音频文件。这与使用bgsound HTML元素相似。与bgsound不同的是,pause和play控制让网页用户关闭声音。Loop特性会从头开始连续播放声音文件。如果你不需要任何内部控件,则不要使用这些特性。

在该示例中,文件“demo.mp3”是你自己的占位符。如果音频文件与网页的源代码在同一目录,则只需文件名即可。如果音频文件位于其他目录中,请包括路径,例如,“musicdemo.mp3”。如果文件位于其他站点上,则使用完全限定的域名和路径,如“http:www.contoso.commusicdemo.mp3”。

3.使用源元素指定多种音频文件格式
在将HTML5 audio元素添加到网页中时,可以指定一条在浏览器不支持audio标记时显示的错误信息。代码如下:

<audio src=”demo.mp3” controls=”controls” autoplay=”autoplay” loop=”loop”>

浏览器不支持HTML5的元素audio

</audio>

如果你的浏览器根本不支持audio,这将很有效。但是,如果支持audio元素,但不支持文件格式,则不会显示你指定的错误消息。由于在支持HTML5的所有浏览器中仅存在几种支持的格式,因此要赢得最大范围的受众,则可以使用source元素指定要尝试的多种文件格式。下面的代码演示了3种格式。浏览器将自动选择它支持的格式,如果根本就不支持音频,则它将调用错误消息。

<!doctype html>
<html>
<head>
   <title>HTML5支持多种音频格式</title>
</head>
<body>
   <h1>利用source标签添加多种音频格式</h1>
   <!—浏览器会自动识别本身支持的格式-->
   <audio controls=”controls”>
  <source src=”demo.mp3” type=”audio/mp3”>
  <source src=”demo.ogg” type=”audio/ogg”>
  <source src=”demo.mp4” type=”audio/mp4”>
  <!—若以上格式都不支持-->
  HTML5 audio not supported!
   </audio>
</body>
</html>

2.4.2 HTML5添加视频
直到现在,仍然不存在一项旨在网页上播放视频的标准。大多数的视频是通过插件(如Flash)来播放的。然而并非所有浏览器都拥有同样的插件。

HTML5规定了一种通过video元素来包含视频的标准方法。

1.支持的视频格式
目前,video标签支持3种视频格式,如表2.12所示是各个浏览器对3种格式的支持。

screenshot

说明:

Ogg:带有Theora视频编码和Vorbis音频编码的Ogg文件。

MPEG4:带有H.264视频编码格式和AAC音频编码的MPEG4文件。

WebM:带有VP8视频编码和Vorbis音频编码的WebM文件。

2.如何工作
用以下代码就可以实现在网页中显示视频:

<!DOCTYPE html>
<html lang=”en” xmlns=http://www.w3.org/1999/xhtml>
<head>
   <meta charset=”utf-8”/>
</head>
<body>
   <video src=”what the hell.mp4” width=”320” height=”240” controls=”controls”>
   你的浏览器不支持video元素。
   </video>
</body>
</html>

以上代码在网页中的效果如图2-34所示。

screenshot

3.< video>标签的属性
< video>标签的属性说明如表2.13所示。

screenshot

4.其他说明
与audio元素一样,video元素也支持多个source元素。

2.4.3 HTML5添加位置感知
地理定位是HTML5提供的最令人激动的特性之一。用相对简单的JavaScript代码,可以创建出能确定用户地理位置详细信息的Web应用,包括经纬度和海拔等。一些Web应用甚至能通过监控用户位置随时间的移动来提供导航功能。

下面我们来看一下如何一步一步地实现此功能。

(1)先创建一个HTML5页面,代码如下。

<!DOCTYPE html>
<html lang=”en” xmlns=http://www.w3.org/1999/xhtml>
<head>
   <meta charset=”utf-8”/>
   <title>HTML5地理定位</title>
   <script type=”text/javascript”>
   </script>
</head>
<body>
</body>
</html>

说明:这里需要用到JavaScript脚本语言。

(2)把JavaScript地理定位函数放到页面< head>< /head>里面的脚本位置,代码如下。

<script type=”text/javascript”>
   function getLocation(){
  //检查浏览器是否支持地理位置定位
  if(navigator.geolocation){
   navigator.geolocation.getCurrentPosition(dispalyLocation, displayError);
  }else{
   Document.getElementById(“locationData”).innerHTML=”对不起,您的浏览器不支持地理定位”;
  }
   }
</script>

说明:

代码首先会检查导航器地理位置对象是否显示出来,如果显示出来则浏览器支持。如果地理位置对象被支持,那么代码会使用它来调用getCurrentPostion方法。

getCurrentPostion方法有两个参数。第一个参数是在地理位置信息被获取时调用的函数,第二个参数是产生错误时调用的函数。

如果地理位置对象不被支持,那么函数就会把错误信息写入页面的div要素中。

(3)向HTML主体部分添加下列代码。

<body>
   <input type=”button” value=”getLocation” onclick=”getLocation()”/>
   <div id=”locationData”>显示地理位置信息</div>
</body>

说明:

使用按钮调用函数而且会把位置数据写入div要素中,div要素最初具有简单的占位符文本。

当一个网站首次试图检索用户的位置数据时,浏览器会询问用户是否同意共享数据。只有在用户同意的情况下,检索用户位置的函数才会执行。

(4)关于getCurrentPosition方法中的第一个参数displayLocation。

当浏览器接收到这个函数时,用户位置数据会传给下面所示的函数。将其添加到getLocation函数后面。

function displayLocation(position){
   var latitude=position.coords.latitude;//纬度
   var longitude=position.coords.longitude;//经度
   var displayText=”纬度:”+latitude+”;”+”经度”+longitude;
   document.getElementById(“locationData”).innerHTML=displayText;
}

说明:这个代码先创建两个变量,用来表示纬度和经度。然后这个函数会把经纬度文本写入页面。当然你也可以用这些地理位置数据用作其他作用。

(5)关于getCurrentPosition方法中的第二个参数displayError。

使用地理位置设备的时候可能会出现错误。例如,用户或许不同意共享自己的地理位置数据,浏览器可能不能检索数据等。因此我们需要添加一个函数来处理对应的错误。

在getLocation函数后面添加以下所示的代码:

function displayError(error){
   var locationElement = document.getElementById(“locationData”);
   locationElement.innerHTML = “产生了错误。”;
}

说明:该函数首先会获取页面div要素的引用,以便写入合适的错误信息。

(6)至此,一个最基本的HTML5地理位置定位的代码就完成了。代码概览如下。

<!DOCTYPE html>
<html lang=”en” xmlns=http://www.w3.org/1999/xhtml>
<head>
   <meta charset=”utf-8”/>
   <title>HTML5地理定位</title>
   <script type=”text/javascript”>
  function getLocation(){
   //检查浏览器是否支持地理位置定位
   if(navigator.geolocation){
    navigator.geolocation.getCurrentPosition(dispalyLocation, displayError);
   }else{
    Document.getElementById(“locationData”).innerHTML=”对不起,您的浏览器不支持地理定位”;
   }
  }
  function displayLocation(position){
   var latitude=position.coords.latitude;//纬度
   var longitude=position.coords.longitude;//经度
   var displayText=”纬度:”+latitude+”;”+”经度”+longitude;
   document.getElementById(“locationData”).innerHTML=displayText;
  }
  function displayError(error){
   var locationElement=document.getElementById(“locationData”);
   locationElement.innerHTML=”产生了错误”;
  }
  </script>
</head>
<body>
   <input type=”button” value=”getLocation” onclick=”getLocation()”/>
   <div id=”locationData”>显示地理位置信息</div>
</body>
</html>

(7)运行结果(笔者用的是IE10 RP版本)。

首先询问你是否同意站点跟踪你的实际位置,如图2-35所示。这里我们单击“允许一次”按钮。
screenshot

接下来,需要几秒钟的时间,出现你的地理位置信息,如图2-36所示。

screenshot

(8)其他说明。

内置的position对象属性如表2.14所示。

screenshot

说明:只有3个属性是必须有值的:coords.latitude,coords.longitude和coords.accuracy。其余的可以是null,这取决于你的设备和后端位置服务器的能力。其中,heading和speed属性则需要根据你先前的位置计算出来。

2.4.4 捕获照片和视频
本节介绍如何通过捕获设备(例如,摄像头)捕获照片和视频,以及如何在使用JavaScript的Microsoft Design风格应用中呈现音频流信息。

1.使用相机对话框捕获照片或视频
使用CameraCaptureUI API,从你嵌入或附加相机捕获照片或视频的最简单方法。

(1)打开Visual Studio 2012。

(2)创建新项目,在“新建项目”对话框中,从JavaScript项目类型中选择一个空白应用程序。

(3)插入JavaScript和HTML。打开你的文件Default.html,将其内容修改为以下代码。

<!DOCTYPE html>
<html>
<head>   
   <title>WinWebApp1</title>
   <!-- WinJS引用 -->
   <link rel="stylesheet" href="/winjs/css/ui-dark.css" />
   <script src="/winjs/js/base.js"></script>
   <script src="/winjs/js/wwaapp.js"></script>
   <!-- WinWebApp1引用-->
   <link rel="stylesheet" href="/css/default.css" />
   <script type = "text/javascript" >
       //利用默认JPEG格式捕获照片
       function takepicture() {
           var captureUI = new Windows.Media.Capture.CameraCaptureUI();
           captureUI.captureFileAsync(Windows.Media.Capture.CameraCaptureUIMode.photo). then(function (capturedItem) {
               if (capturedItem) {
                   document.getElementById("message").innerHTML = "用户拍摄了一张照片。"
               }
               else {
                   document.getElementById("message").innerHTML = "用户没有拍摄照片。"
               }
           });
       }
   </script>
</head>
<body>
   <input type="button" onclick="takepicture()" value="拍照" /><br />
   <span id="message"></span>
</body>
</html>

(4)声明摄像机功能。

使用程序清单设计器添加摄像机功能。选择“功能”选项卡,然后从列表中选择“摄像机”。

(5)生成应用。

选择“生成”>“生成解决方案”以生成项目。

(6)测试应用。

选择“调试”>“开始调试”测试该方案。单击“拍照”按钮拍摄照片。

2.使用MediaCapture API捕获视频
可以使用Windows.Media.Capture API控制异步捕获操作,选择编码配置文件,并发送最终视频到文件中。

(1)声明摄像机功能。

使用应用程序清单设计器添加摄像机功能。选择“功能”选项卡,然后从列表中选择“摄像机”。

(2)初始化MediaCaptureSettings。

MediaCaptureSettings属性为MediaCapture对象提供配置设置。使用MediaCaptureInitialization Settings类初始化这些属性,如下面的示例代码所示。

//初始化MediaCaptureInitialzationSettings
function initCaptureSettings() {
    captureInitSettings = null;
    captureInitSettings = new Windows.Media.Capture.MediaCaptureInitializationSettings();
    captureInitSettings.audioDeviceId = "";
    captureInitSettings.videoDeviceId = "";
    captureInitSettings.streamingCaptureMode = Windows.Media.Capture.StreamingCaptureMode. audioAndVideo;
    captureInitSettings.photoCaptureSource = Windows.Media.Capture.PhotoCaptureSource. videoPreview;
    captureInitSettings.realTimeModeEnabled = true;
    if (deviceList.length &gt; 0)
        captureInitSettings.videoDeviceId = deviceList[0].id;
}

(3)创建并初始化MediaCapture对象。

MediaCapture对象包含捕获视频需要的方法和异步操作。使用MediaCapture.InitializeAsync方法可以初始化MediaCapture对象。默认情况下,InitializeAsync使用默认的视频捕获设备并且将捕获音频或视频。

//创建并初始化MediaCapture对象
function initMediaCapture() {
    oMediaCapture = null;
    oMediaCapture = new Windows.Media.Capture.MediaCapture();
    oMediaCapture.initializeAsync(captureInitSettings).then (function (result) {
       createProfile();
    }, errorHandler);    
}

(4)创建编码配置文件。

编码配置文件包含有关如何对目标文件进行编码的所有设置。MediaPropertiesAPI提供了几个用于创建MediaEncodingProfile对象的选项。以下代码为MP4视频创建配置文件。

//创建编码文件格式
function createProfile() {
    profile = Windows.Media.MediaProperties.MediaEncodingProfile.createMp4(
        Windows.Media.MediaProperties.VideoEncodingQuality.qvga);
}

(5)开始录制。

要开始将视频捕获到文件中,请为捕获到的视频创建一个文件。然后调用StartRecordToStorage FileAsync方法,并传入目标存储文件和MediaEncodingProfile中。

//开始录制视频
function startMediaCaptureSession() {
   Windows.Storage.KnownFolders.videosLibrary.createFileAsync("cameraCapture.mp4", Windows.Storage.CreationCollisionOption.generateUniqueName).then(function (newFile) {
        storageFile = newFile;
        oMediaCapture.startRecordToStorageFileAsync(profile, storageFile).then(function (result) {           
        }, errorHandler);
    }  );   
}

(6)停止录制。

要停止捕获视频,请调用StopRecordAsync方法,代码如下所示。

function stopMediaCaptureSession(){
   oMediaCapture.stopRecordAsync().then(function(result){}, errorHander);
}

2.4.5 HTML5本地存储的应用
localStorage用于持久化本地存储,除非主动删除数据,否则数据是永远不会过期的。通过前面小节的学习,我们了解了本地存储的基本特性,下面我们就通过具体的例子来讲解HTML5 localStorage的用法。

1.localStorage的用法
localStorage是以键值对(key/value)的形式存储的,每个键值对称为一个项(item)。其属性如表2.15所示。

screenshot

2.如何使用localStorage
(1)并不是所有的浏览器都支持HTML5的本地存储,所以在使用它之前,你需要一点点检测工作,来确保你的应用正常运行。下面的代码可以用来测试浏览器是否支持HTML5本地存储。

function checkIfSupport(){
   if(‘localStorage’ in window){
  alert(‘您的浏览器支持localStorage’);
   }else{
  alert(‘您的浏览器不支持localStorage’);
   }
}

在下面的html代码中调用此函数。

<button type=”button” onclick=”checkIfSupport()”>check</button>
说明:以上两段代码比较简单,就不作过多的解释了。

(2)接下来,对localStorage中存储的项的数目进行检查。利用下面的代码可以实现。

<script type=”text/javascript”>
   function getLength(){
  alert(localStorage.length);
   }
</script>
<body>
   <button type=”button” onclick=”checkIfSupport()”>check</button>
   <button type=”button” value=”HTML5” id=”name” onclick=”rememberMe()”>记住我</button>
   <button type=”button” onclick=”forgetMe()”>忘记我</button>
   <button type=”button” onclick=”checkIfSupport()”>localStorage的长度</button>
</body>

说明:这里主要是运用了localStorage的length属性来获取localStorage的长度。运行结果是0。

(3)接下来向localStorage中写入项。利用如下所示的代码可以向本地存储中写入数据。

function rememberMe(){
   //检查浏览器是否支持localStorage
   if(‘localStorage’ in window){
  localStorage.setItem(‘username’, username);
  alert(‘恭喜,本地存储已经记住您的名字’);
   }
}

说明:这里主要利用了localStorage.setItem方法来新建一个项放到本地存储。此时若执行第二步中的getLength方法,运行结果为1。

(4)既然本地存储里已经存放了一个项,那么我们可以通过以下所示的代码将此项删除。

function forgetMe(){
   localStorage.removeItem(‘username’);
   alert(‘我已经忘记你了!’);
}

说明:这里主要利用localStorage.removeItem方法来删除本地存储的项。此时若执行第二步中的getLength方法,运行结果又变成了1。

(5)为了让读者有一个清晰的架构,以下代码是本小节所有JavaScript代码的集合。

<script type=”text/javascript”>
 var username = document.getElementById(‘name’).value;
 //检查浏览器是否支持localStorage
 function checkIfSupport(){
  if(‘localStorage’ in window){
   alert(‘您的浏览器支持localStorage’);
   }else{
   alert(‘您的浏览器不支持localStorage’);
   }
  }
 function rememberMe(){
  //检查浏览器是否支持localStorage
  if(‘localStorage’ in window){
   localStorage.setItem(‘username’, username);
   alert(‘恭喜,本地存储已经记住您的名字’);
   }
  }
 function forgetMe(){
  localStorage.removeItem(‘username’);
  alert(‘我已经忘记你了!’);
  }
 function getLength(){
  alert(localStorage.length);
  }
</script>

(6)总结,通过实例,我们演示了localStorage的基本用法。对于其他未提及的用法,你可以自己搜集资料学习。

2.4.6 管理启动、挂起和回复
当用户将应用移下屏幕时,Windows 8会在内存中挂起应用。这样可允许其他应用在前台运行。当应用挂起时,它驻留在内存中,并且Windows已停止其运行。

当用户将挂起的应用带回至前台时,他们希望应用在他们停止的位置恢复运行。只要应用保持挂起,Windows就会在内存中自动保留应用的数据,然后在应用恢复时还原该数据。应用偶尔还会终止,因此你的应用应使用挂起事件来保存其当前的状态。

1.如何激活应用
(1)注册激活的事件。

每次应用启动时,都会引发activated事件。如果系统需要将相关的应用参数传递到新激活合约,当应用运行时,也会引发此事件。你可以使用activated事件来还原应用的先前状态,并检索与应用要为其激活的合约相关的激活参数。

在全局范围内注册activated事件。下面所示的代码将activeHandler设置为激活处理程序,可以检索之前的ApplicationExecution状态和激活参数:

Var app = WinJS.Application;
App.addEventListener(“activated”, activatedHandler, false);
app.start();

(2)在应用挂起然后终止的情况下还原应用程序数据。

在应用挂起后Windows可以由于多种原因将其终止。发生这种情况的示例如下:用户手动关闭应用,用户注销或者系统的运行资源不足。如果用户在Windows已终止应用后启动该应用,则会收到activated事件。使用sessionState对象确定你是否需要还原应用的数据或使用其默认值启动。如果定义了sessionState变量,则使用这些变量还原应用的数据并刷新其显示的内容。如果未定义,则加载默认值。

当用户切换到已终止的应用时,系统将发送 activated 事件检查sessionState对象,查看是否已定义了会话状态变量。如果已定义,则应用应该加载其保存的应用程序数据并刷新显示的内容,代码如下所示。

function activatedHandler(eventArgs){
  if(eventArgs.detail.kind==Windows.ApplicationModel.Activatation.ActivationKind. launch){
  if(app.sessionState){
    //恢复到之前的UI
    }else{
    //恢复到默认UI
    }
  }
}

(3)检索激活参数。

当系统激活应用时,可能存在其他用于激活的上下文。每种类型的激活合约都有一组自己独一无二的参数,用于向你提供有关你的应用的更多信息。每个合约的eventArgs类都在Windows.UI. WebUI命名空间中定义。以下代码展示了如何从默认磁贴启动中检索参数。

app.onactivated = function (args) {
        if (args.detail.kind === activation.ActivationKind.launch) {
            if (args.detail.previousExecutionState !== activation.ApplicationExecution State.terminated) {
                // TODO: 此应用程序最近已启动。在此处初始化
                //您的应用程序。
            } else {
                // TODO: 此应用程序已从挂起状态重新激活。
                // 在此处恢复应用程序状态。
            }
            args.setPromise(WinJS.UI.processAll());
        }
    };

如果要处理初始启动的激活,则系统将显示你的初始屏幕直至应用完全激活。在某些情况下,应用必须异步工作(例如,从文件中读取设置)以便正确初始化其 UI。这项工作需要在激活期间完成,以便初始屏幕在UI完成前不会关闭。你可以使用激活eventArgs上的setPromise()方法推迟激活的完成。在上述代码段中,setPromise()用于推迟激活的完成,直至对 processAll() 的异步调用完成为止。

如果使用VS模板,则会为你调用 setPromise()。如果在初始屏幕关闭前存在需要完成的异步工作,则在新的页面片段的“已处理”事件期间完成此工作。确保从此异步活动中返回promise以延迟“已处理”事件的完成直至活动完成。在应用导航到特定页面片段时调用已处理事件,以便确保特定于激活的所有代码仅在激活触发的导航上运行。在正常导航中,应跳过该代码。

2.如何挂起应用
(1)注册checkpoint事件。

在全局范围内注册checkpoint事件,代码如下所示。此事件指示系统将挂起你的应用。在应用挂起后,系统将确定释放系统资源。出于此原因,因此在检查点事件期间保存你的应用数据尤为重要。

var app = WinJS.Application;
app.addEventListener(“checkpoint”, checkpointHandler);

(2)在挂起之前保存应用程序数据。

当你的应用处理 checkpoint 事件时,它将有机会将其重要的应用程序数据保存到 checkpoint 事件的处理程序函数中。应用可以使用 sessionState 对象来同步保存简单的应用程序数据。sessionState 对象会保留数据,以便应用在终止后激活期间可以访问这些数据,代码所下示。

function checkpointHandler(eventArgs){
   var stateObject = new Object();
   //将应用程序数据保存到seesionState
   app.sessionState.stateObject = stateObject;
}

(3)释放独占资源和文件句柄。

当你的应用处理checkpoint 事件时,它还将有机会释放独占资源和文件句柄。独占资源的示例为摄相机、I/O 设备、外部设备以及网络资源。显式释放独占资源和文件句柄有助于确保你的应用未使用它们时其他应用可以访问。当在终止后又激活应用时,它应该打开其独占资源和文件句柄。

3.如何恢复应用
每当用户切换到桌面或其他应用时,系统都会挂起你的应用。每当用户切回到你的应用时,系统就会恢复你的应用。当系统恢复你的应用时,你的变量和数据结构的内容与系统将你的应用挂起之前的内容相同。系统会将你的应用完全恢复到你离开时的状态,使用户感觉你的应用好像一直在后台运行一样。但是,应用可能已挂起很长一段时间,因此,它应当刷新在应用挂起之后可能已发生更改的任何显示内容(如新闻源或用户位置)。

如果你的应用没有任何需要刷新的显示内容,则它无需处理 resuming 事件。

(1)注册resuming事件

该事件指示应用在挂起后已恢复。

Windows.UI.WebUI.WebUIApplication.addEventListener(“resuming”, resumingHandler, false);
(2)挂起之后刷新显示的内容。

当你的应用收到resuming事件时,它将有机会刷新其显示的内容,代码如下所示。

function resumingHandler(){
   //TODO: 刷新数据
}

2.4.7 支持设备
你可以在你的应用中支持许多设备。运动和方向传感器可让你的应用响应移动。光传感器可让你的应用响应周围光的变化。地理位置可让你的应用响应用户的位置。

下面分别介绍支持的设备及其功能。

1.枚举设备
使用Windows.Devices.Enumeration和Windows.Devices.Enumeration.Pnp命名空间,可枚举设备。枚举设备主要是因为选择应用要使用的设备;有关设备的发现和通知;检索信息。

2.加速计
使用加速计可以检测一个或两个轴上运动的变化。可以使用加速计和JavaScript编写的应用响应用户移动。基于加速计的应用通常仅使用一个或两个轴进行输入。但是,它也可以使用振动事件作为另一个输入源。

3.陀螺测试仪
使用陀螺测试仪可以检测方向和转数的变化。加速计和陀螺测试仪在一起使用可作为游戏控制器。可以使用陀螺测试仪和用 JavaScript 编写的应用检测用户移动变化。陀螺测试仪补充加速计作为游戏控制器;加速计可以测量线性运动,而陀螺测试仪测量角度矢量(或旋转运动)。

4.倾斜计
使用倾斜计可以检测X轴、Y轴和Z轴上运动的变化。可以使用测斜仪和用 JavaScript 编写的应用确定俯仰、滚转和偏航。一个常见的示例是飞行模拟器,它将测斜仪的三条轴(X、Y 和 Z)映射到飞行器的升降舵、副翼和方向舵输入。

5.光传感器
使用光传感器可以检测和响应氛围光的变化。开发人员可以创建使用传感器检测和响应氛围光变化的应用。 例如,当用户拿着平板电脑走到门外时,应用程序可通过增加文本和背景之间的对比度来做出响应。

6.地理位置
检测用户的地理位置。开发人员可以创建检测用户地理位置的 Microsoft Design 风格应用。例如,某个应用程序可以绘出用户在地图上的位置、在照片或电子邮件中附加地理坐标标记,或通过更新兴趣点列表响应用户位置的更改。

7.打印机
使用打印机功能可以改进用户的打印体验。从 Windows 8 Release Preview 开始,打印模型经过了重新设计,更便于向 Microsoft Design 风格应用中添加打印功能。另外,新的打印模型提供了一个可扩展的开发人员平台,该平台允许开发人员自定义打印体验。自定义操作包括更改打印设置在打印窗口中的显示顺序或者添加特定于应用的自定义设置。特定于应用的打印机设置使开发人员能够展示对于其应用非常重要的设置,从而帮助开发人员与其用户进行更好的连接。

8.可移动存储
Windows 8支持访问使用 Windows 便携设备(WPD)的媒体和存储设备上的内容,包括媒体传输协议(MTP)设备和大容量存储类(MSC)设备。

2.4.8 访问文件和文件夹
1.使用文件选取器访问文件
Microsoft Design 风格应用可以调用文件选取器窗口,以便使用户可以浏览其系统并选取文件或文件夹以供应用在其上操作,或者使用户可以使用新名称、新文件类型或新位置保存文件(“另存为”)。应用还可以将文件选取器用作一个接口,从而使应用能够向其他应用提供文件、保存位置,甚至文件更新。

2.文件选取器窗口
应用调用文件选取器窗口,使用户可以选择文件以供应用在其上操作。如图 2-37所示为一个已调用的文件选取器,使用该选取器可以选择照片。

screenshot

所有文件选取器窗口在屏幕顶部和底部都有一个公共UI区域,该区域向用户显示重要信息(如窗口的标题、用户可以浏览的位置列表和用户已选择的项目)。位于文件选择器窗口顶部和底部的这些公共UI区域就像电影周围的上下黑边,并且这些区域为用户浏览的页面添加边框。用户可以从文件选取器上下黑边左上部分的列表中选择位置,如图2-38所示。

screenshot

3.调用文件选取器以访问文件
通过调用文件选取器,用户可以选取文件和文件夹以供应用处理。当用户为应用提供对文件夹的访问权限时,该应用还会获取对其子文件夹的访问权限。文件选取器为用户提供对于你的应用可以访问哪些文件和文件夹的显式控制。而如果你的应用像大多数应用一样处理单独的文件或很小的文件列表,则可能将文件选取器用作你的应用访问文件和文件夹的主要方式,从而使你能够避免在应用清单中声明功能,并且很可能会在将你的应用提交给Windows应用商店时简化应用的审核流程。

下面通过一个示例来说明如何使用文件选取器让用户选取一个或多个文件以供应用打开。

(1)创建文件选取器并进行自定义,以显示可供用户从中选取的文件。

var openPicker = new Windows.Storage.Pickers.FileOpenPicker();
openPicker.viewMode = Windows.Storage.Pickers.PickerViewMode.thumbnail;
openPicker.suggestedStartLocation = Windows.Storage.Pickers.PickerLocationId.picturesLibrary;
openPicker.fileTypeFilter.replaceAll([".png", ".jpg", ".jpeg"]);

说明:

通过设置文件选取器的属性viewMode、suggestedStartLocation、fileTypeFilter来自定义文件选取器。

因为我们需要一种对用户可以选取的文件的丰富直观的显示,所以我们在该示例中将viewMode设置为thumbnail。如果使用文件选取器来显示诸如图片或视频等可视文件,则应考虑将viewMode设置为thumbnail;否则,请使用PickerViewMode.list。

因为这里要显示用户的图片文件,所以可以将suggestedStartLocation属性设置为picturesLibrary(图片库)。当然,它只是一个起始位置,用户可以从文件选取器内部浏览到其他位置。

因为我们希望显示特定类型的图片文件,所以我们使用fileTypeFilter.replaceAll()方法来指定要在文件选取器中显示的文件类型。

(2)显示文件选取器以选取一个文件。

//显示文件选取器以选取一个文件
openPicker.pickSingleFileAsync().then(function (file) {
        if (file) {
            //应用对于选取的文件获得了读写权限
            sdkSample.displayStatus("Picked photo: " + file.name);
        } else {
            sdkSample.displayStatus("File was not returned");
        }
    });

说明:在创建并自定义某个文件选取器之后,让用户通过使用fileOpenPicker.pickSingleFileAsync调用显示文件选取器来选取一个文件。用户选取文件时,fileOpenPicker.pickSingleFileAsync返回一个表示已选取文件的storageFile对象,通过使用then或done来捕获和处理此文件。

4.获取文件和文件夹列表
获取某个特定位置(如文件夹、库、设备或网络位置)的文件和文件夹。

(1)获取包含文件夹。

如果要获取特定文件夹的内容列表,则必须首先获取该文件夹。下面的代码为获取图片库的代码:

var pictureLibrary = Windows.Storage.KnownFolders.picturesLibrary;

以上代码中,我们使用KnownFolders获取图片库。可以使用KnownFolders属性获取表示某些用户资源的文件夹。

如果希望使用KnownFolders属性访问库、设备或网络位置,则应在其应用部件清单中声明相应的功能。

(2)获取文件夹内容的列表。

//获取文件夹内容的列表
pictureLibrary.getItemsAsync().then(function(items){};

如上面的一行代码所示,可以调用getItemsAsync()来获取文件夹中所有内容的列表。若不需要全部项,则可以调用getItemsAsync(startIndex,maxItemsToRetrive)来按索引获取某个范围内的文件夹内容。

在文件夹上调用 getItemsAsync 方法时,会将要接收的项列表限于该文件夹中的文件和子文件夹,且该列表不包括那些子文件夹中包含的所有文件和文件夹。

如果需要文件夹中的文件列表,则可以调用**getFilesAsync 方法。如果需要文件夹列表,则可以调用getFoldersAsync方法。

(3)使用列表。

//使用列表,显示每个文件或文件夹的信息
items.forEach(function(item){
   if(item.isOfType(Windows.Storage.StorageItemTypes.folder)){
  output(id(picturesLibrary.name), item.name+”\\”);
   }else {
  output(id(picturesLibrary.name), item.FileName);
   }
});

上面的几行代码在整个项列表中循环访问来执行其他任务,用forEach来循环访问列表中的项。传递给forEach的函数将项列表视为一个参数,并将对列表中的每个item执行此函数。

可以通过分别在每个 item 上调用方法来处理它们。在上一示例中,我们通过将 isOfType 方法的结果(同时存在于文件和文件夹上)与 StorageItemTypes 枚举值相比较,确定item是文件夹(StorageFolder对象)还是文件(StorageFile 对象)。我们使用此比较将关于项的不同信息传递给 output 帮助程序函数,但也可以同时执行许多其他任务。

5.启动文件的默认应用
了解如何启动文件的默认应用。

(1)获取文件。

首先,获取该文件的Windows.Storage.StorageFile对象。如果该文件包含在程序包中,则可以使用Package.installedLocation属性获取Windows.Storage.StorageFolder,并且使用getFileAsync方法获取StorageFile对象。如果该文件在已知的文件夹中,则可以使用Windows.Storage.KnownFolders类的属性StorageFolder,并且使用getFileAsync方法获取StorageFile对象。

(2)以默认方式启动该文件。

调用 Windows.System.Launcher.launchFileAsync(IStorageFile)方法以启动默认的应用。如下所示的代码会调用launchFileAsync 方法启动应用包中包含的图像文件 test.png:

//要打开的文件
var imageFile = “images\\test.png”;
//获取图片文件
Windows.ApplicationModel.Package.current.installedLocation.getFileAsync(imageFile).th  
   //使用默认程序打开文件
   Windows.System.Launcher.launchFileAsync(file).then(function(success){
  If(success){
   //启动成功
  }else{
   //启动失败
  }
   });
});

(3)利用“打开方式”启动文件。

当用户希望选择默认应用以外的应用来打开某个特定文件时,你应该使用“打开方式”对话框。例如,如果你的应用允许用户启动某个图像文件,则默认的处理程序将可能是查看器应用。在某些情况下,用户可能需要编辑图像而不只是查看图像。使用“打开方式”选项及应用栏或上下文菜单中的备用命令,让用户在此类情况下打开“打开方式”对话框以选择编辑器应用。

如下所示的代码演示了在LauncherOptions.displayApplicationPicker 设置为true的情况下调用 Launcher.launchFileAsync(IStorageFile, LauncherOptions)方法以启动用户从“打开方式”对话框中选择的应用:

//要打开的文件
var imageFile = “images\\test.png”;
//获取图片文件
Windows.ApplicationModel.Package.current.installedLocation.getFileAsync(imageFile).th  
   //设置打开选项为true
   var options = new Windows.System.LauncherOptions();
   options.displayApplicationPicker = true;
   Windows.System.Launcher.launchFileAsync(file).then(function(success){
  If(success){
   //启动成功
  }else{
   //启动失败
  }
   });
});

(4)未安装用以处理所启动文件的应用。

在某些情况下,用户可能未安装用以处理所启动文件的应用。默认情况下,为处理此类情况,Windows 会向用户提供一个链接,帮助其在应用商店中搜索相应的应用。如果你希望为用户提供具体的建议,告知他们在此情况下应获取何种应用,则可以随启用的文件传递该建议。调用 Launcher.launchFileAsync(IStorageFile, LauncherOptions)方法,将LauncherOptions.preferred ApplicationPackageFamilyName 设置为应用商店中推荐的应用的包系列名称。然后,将LauncherOptions的PreferredApplicationDisplayName属性设置为该应用的名称。Windows 会使用此信息将在应用商店中搜索应用这一常规选项替换为从应用商店中获取推荐的应用这一具体选项。

//要打开的文件
var imageFile = “images\\test.png”;
//获取图片文件
Windows.ApplicationModel.Package.current.installedLocation.getFileAsync(imageFile).th  
   //设置打开选项为true
   var options = new Windows.System.LauncherOptions();
   options.prefferedApplicationPackageFamilyName = ‘Contoso.FileApp_8wknc82pole’;
   options.prefferedApplicationDisplayName=’Contoso File App’;
   Windows.System.Launcher.launchFileAsync(file).then(function(success){
  If(success){
   //启动成功
  }else{
   //启动失败
  }
   });
});

(5)注意事项。

应用不能选择启动的应用。用户通过为协议方案设置默认的处理程序来确定启动哪个应用。用户可以选择 Microsoft Design 风格应用或桌面应用。

启动文件时,你的应用必须是前台应用,即对于用户必须是可见的。此要求有助于确保用户保持控制。为满足此要求,需确保将文件的所有启动都直接连结到应用的UI中。 无论何种情况下,用户都必须采取某种操作来发起文件启动。 如果文件所包含的代码或脚本由系统自动执行(如 .exe、.msi和.js文件),则你无法启动这些文件类型。此限制可防止用户遭受可能修改系统的潜在恶意文件的损害。如果包含的脚本由可隔离脚本的应用程序来执行(如 .docx 文件),则你可以使用此方法来启动这些文件类型。Word 等应用程序可防止 .docx 文件中的脚本修改系统。

如果该应用不可见,则该调用将引发拒绝访问异常。

6.读取和写入文件
(1)创建文件。

在读写之前,应先创建一个全局变量sampleFile,此变量表示写入和读取的文件。利用以下代码会创建sample.txt文件,并存储返回的storageFile对象。

Windows.Storage.KnownFolders.documentLibrary.createFileAsync(“sample.txt”, Windows.Storage.CreateCollisionOption.replaceExisting).then(function(file){
 sampleFile = file;
});

在文档库中创建文件之前,必须在应用清单中声明必要的功能。

(2)写入文件。

通过第一步我们创建了一个可写入的文件并获取到了表示该文件的storageFile对象。

下面介绍3种不同的写入文件方式。

直接将文本写入文件

通过使用fileIO类的writeTextAsync方法,将文本写入文件。以下代码主要是调用wirteTextAsync (file,contents)来将一些随机的文本写入sample.txt。

Windows.Storage.FileIO.writeTextAsync(sampleFile, “Swift as a shadow”).then(function (){});
尽管writeTextAsync方法没有返回值,但仍可以在将文本写入文件之后使用then或done来声明函数并执行其他任务。

使用缓冲区将字节写入文件

首先要获取写入文件的字节缓冲区。以下代码示例中我们通过使用convertStringToBinary来获取基于随机字符串的字节缓冲区。

var buffer = Windows.Security.Cryptography.CryptographicBuffer.convertStringToBinary(
   ‘我将被写入文件’, Windows.Security.Cryptography.BinaryStringEncoding[‘’]
);

然后我们通过调用fileIO类的writeBufferAsync方法,将字节从你的字节缓冲区写入文件。以下代码是将字节缓冲区写入到sampleFile。

Windows.Storage.FileIO.writeBufferAsync(sampleFile,buffer).then(function(){
   //字节写入之后执行其他任务的代码。
});

尽管writeBufferAsync方法没有返回值,但仍可以在将文本写入文件之后,使用then或done来声明函数并执行其他任务。

使用事物处理流将文本写入文件

首先,通过调用 storageFile.openTransactedWriteAsync 方法,打开到文件的流。打开操作完成后,它将返回文件的内容流。如下所示的代码演示了如何打开到sampleFile的文件流。

sampleFile.openTransactedWriteAsync().then(writeToStream);
可以看到,上面的一行代码中有一个函数writeToStream,我们接下来需要声明并定义此函数,以便可以在流打开之后对文件进行写操作。如下所示的代码使用transaction创建新的dataWriter对象并调用该对象的writeString方法,从而将文本写入流:

function writeToStream(transaction){
   var dataWriter = new Windows.Storage.Streams.DataWriter(transaction.stream);
   dataWriter.writeString(“我被写入到文本”);
   dataWriter.storeAsync().then(function(){
  transaction.commitAsync().done(function(){
   //此时流中的文本已经写入到文件
   transaction.close();
  });
   });
}

最后通过调用dataWriter.storeAsync和transaction.commitAsync方法将文本保存到文件中并关闭流。

(3)从文件读取。

接下来我们讲解当你有一个可读取的文件以及一个表示该文件的storageFile时从该文件读取的方法。

下面主要介绍3种不同的从文件读取方式。

从文件读取文本

通过使用fileIO类的readTextAsync方法,从文件读取文本。如下所示的代码仍以sampleFile为例,演示从文件读取文本。可以使用 then 或 done 来声明函数以捕获和处理从文件读取的文本。在 readTextAsync 方法完成之后,会将该文本作为 String 对象(示例中的 contents)传递给此函数。

Windows.Storage.FileIO.readTextAsync(sampleFile).then(function(contents){
   //处理读取到的文本。
});

通过使用缓冲区从文件读取字节

通过调用 fileIO 类的 readBufferAsync 方法,将字节从你的文件读入到缓冲区。可以使用 then 或 done 来声明函数以在 readBufferAsync 方法完成之后捕获和处理 buffer(类型 IBuffer)数据。如下所示的代码捕获 buffer 并使用 dataReader 对象来读取 buffer 的长度:

Windows.Storage.FileIO.readBufferAsync(sampleFile).then(function(buffer){
   var dataReader = Windows.Storage.Streams.DataReader.fromBuffer(buffer);
   var output = dataReader.readString(buffer.length);
}

使用流从文件读取文本

首先,通过调用 storageFile.openAsync 方法,从文件打开流。打开操作完成后,它将返回文件的内容流。必须确保声明某个函数(这里是readFromStream)以捕获流(类型IRandomAccessStream),以便可以在该方法完成后从该流进行读取。

sampleFile.openAsync(Windows.Storage.FileAccessMode.readWrite).then(readFromStream);
接着,我们就要声明函数readFromStream。从readStream获取要读取的对象dataReader,然后通过调用dataReader的loadAsync和readString方法读取文本。最后不要忘记关闭流。

function readFromStream(readStrem){
   var dataReader = new Windows.Storage.Streams.DataReader(readStream);
   dataReader.loadAsync(readStream size).done(function(numBytesLoaded){
  var fileContent = dataReader.readString(numBytesLoaded);
  //可以添加对读取的文本进行处理的代码
  dataReader.close();
});
}
相关文章
|
3天前
|
JavaScript 前端开发
js开发:请解释事件冒泡和事件捕获。
JavaScript中的事件处理有冒泡和捕获两种方式。事件冒泡是从子元素向上级元素传递,而事件捕获则从外层元素向内层传递。`addEventListener`的第三个参数可设定事件模式,`false`或不设为冒泡,`true`为捕获。示例代码展示了如何设置。
19 2
|
1天前
|
前端开发 JavaScript
js开发中的异步处理
JavaScript中的异步处理包括回调函数、Promise和async/await。回调函数是早期方法,将函数作为参数传递给异步操作并在完成后执行。Promise提供链式处理,通过resolve和reject管理异步操作的成功或失败。async/await基于Promise,允许写更简洁的同步风格代码,通过try-catch处理错误。Promise和async/await是现代推荐的异步处理方式。
|
2天前
|
存储 JavaScript 索引
js开发:请解释什么是ES6的Map和Set,以及它们与普通对象和数组的区别。
ES6引入了Map和Set数据结构。Map的键可以是任意类型且有序,与对象的字符串或符号键不同;Set存储唯一值,无重复。两者皆可迭代,支持for...of循环。Map有get、set、has、delete等方法,Set有add、delete、has方法。示例展示了Map和Set的基本操作。
16 3
|
2天前
|
JavaScript 前端开发
js开发:请解释什么是ES6的Generator函数,以及它的用途。
ES6的Generator函数是暂停/恢复功能的特殊函数,利用yield返回多个值,适用于异步编程和流处理,解决了回调地狱问题。例如,一个简单的Generator函数可以这样表示: ```javascript function* generator() { yield &#39;Hello&#39;; yield &#39;World&#39;; } ``` 创建实例后,通过`.next()`逐次输出&quot;Hello&quot;和&quot;World&quot;,展示其暂停和恢复的特性。
12 0
|
2天前
|
缓存 JavaScript 前端开发
js开发:请解释什么是Webpack,以及它在项目中的作用。
Webpack是开源的JavaScript模块打包器,用于前端项目构建,整合并优化JavaScript、CSS、图片等资源。它实现模块打包、代码分割以提升加载速度,同时进行资源优化和缓存。Webpack的插件机制可扩展功能,支持热更新以加速开发流程。
13 2
|
3天前
|
JavaScript 前端开发
js开发:请解释this关键字在JavaScript中的用法。
【4月更文挑战第23天】JavaScript的this关键字根据执行环境指向不同对象:全局中指向全局对象(如window),普通函数中默认指向全局对象,作为方法调用时指向调用对象;构造函数中指向新实例,箭头函数继承所在上下文的this。可通过call、apply、bind方法显式改变this指向。
7 1
|
3天前
|
JavaScript 前端开发
js开发:请解释同步和异步编程的区别。
同步编程按顺序执行,易阻塞;异步编程不阻塞,提高效率。同步适合简单操作,异步适合并发场景。示例展示了JavaScript中同步和异步函数的使用。
13 0
|
前端开发 JavaScript 算法
JavaScript 权威指南第七版(GPT 重译)(七)(3)
JavaScript 权威指南第七版(GPT 重译)(七)
29 0
|
前端开发 JavaScript 算法
JavaScript 权威指南第七版(GPT 重译)(七)(1)
JavaScript 权威指南第七版(GPT 重译)(七)
52 0
|
8天前
|
存储 前端开发 JavaScript
JavaScript 权威指南第七版(GPT 重译)(六)(4)
JavaScript 权威指南第七版(GPT 重译)(六)
76 2
JavaScript 权威指南第七版(GPT 重译)(六)(4)