之前在WP8的时候做过WebBrowser相关的笔记,在WP8.1的WebView和WebBrowser有些不一样,在这里做一些笔记

下面分为几个部分

  1、禁止缩放

  2、JS通知后台C#代码(notify)

  3、C#调用JS方法

    动态加载JS文件,动态注册事件方法(eval)

  4、WebView导航

  5、手势(WinJS)

  6、常见问题

1、禁用缩放  

body {
/* Block area from manipulation actions (zoom, pan) */
touch-action: pan-y;
}

  这个值可以禁用掉缩放和横向手势

  关于touch-action参见:https://msdn.microsoft.com/en-us/library/windows/apps/xaml/hh767313.aspx?f=255&MSPPError=-2147217396

2、JS通知后台C#代码(notify) 

window.external.notify(msg);

注意:这里的方法名是小写的,在WP8上后面的Notify方法的首字母是大小写都可以

3、C#调用JS方法(InvokeScriptAsync)

  通过后台代码动态加载css,js,动态绑定事件和方法

  3.1、先定义传输的数据格式

/// <summary>
/// JS消息格式
/// </summary>
public class JsInvokeModel
{
[JsonProperty("type")]
public string Type { get; set; } [JsonProperty("content1")]
public string Content1 { get; set; } [JsonProperty("content2")]
public string Content2 { get; set; } [JsonProperty("content3")]
public string Content3 { get; set; }
}

  3.2、XAML

<WebView x:Name="WebView" DOMContentLoaded="WebView_OnDOMContentLoaded" ScriptNotify="WebView_OnScriptNotify" />

  3.3、下面是事件方法

//DOM树加载完成后执行
private async void WebView_OnDOMContentLoaded(WebView sender, WebViewDOMContentLoadedEventArgs args)
{
//1、动态加载css
var js = @"var myCss = document.createElement(""link"");
myCss.rel = ""stylesheet"";
myCss.type = ""text/css"";
myCss.href = ""ms-appx-web:///Assets/Html/css/default.css"";
document.body.appendChild(myCss);";
await sender.InvokeScriptAsync("eval", new[] { js }); //2、动态加载js库(json2)
js = @"var myScript = document.createElement(""script"");
myScript.type = ""text/javascript"";
myScript.src = ""ms-appx-web:///Scripts/json2.min.js"";
document.body.appendChild(myScript);";
await sender.InvokeScriptAsync("eval", new[] {js}); //3、调用js执行自定义代码(为图片添加点击事件,并通知)
js = @"var imgs = document.getElementsByTagName(""img"");
for (var i = 0, len = imgs.length; i < len; i++) {
imgs[i].onclick = function (e) {
var jsonObj = { type: 'image', content1: this.src };
window.external.notify(JSON.stringify(jsonObj));
};
}";
await sender.InvokeScriptAsync("eval", new[] {js}); //4、动态加载手势
js = @"var myScript = document.createElement(""script"");
myScript.type = ""text/javascript"";
myScript.src = ""ms-appx-web:///Assets/Html/js/gesture.js"";
document.body.appendChild(myScript);
window.external.notify(myScript.src+"""");";
await sender.InvokeScriptAsync("eval", new[] { js }); //5、为body添加手势监听
js = @"var target = document.getElementsByTagName(""body"")[0];
prepareTarget(target, eventListener);";
await sender.InvokeScriptAsync("eval", new[] { js });
}

  3.4、Notify监听

private void WebView_OnScriptNotify(object sender, NotifyEventArgs e)
{
//这个事件函数可以监听到JS通知的消息,消息类型为文本
//这里统一消息格式为:JsInvokeModel
var model = JsonConvert.DeserializeObject<JsInvokeModel>(e.Value);
switch (model.Type)
{
case "image":
Info.Text = e.Value;
break;
case "swiperight":
//右滑
Info.Text = e.Value;
break;
case "swipeleft":
//左滑
Info.Text = e.Value;
break;
case "text":
Info.Text = e.Value;
break;
}
}

  WebView虽然提供了同步方法InvokeScript,但是在WP8.1没有实现

   通过InvokeScriptAsync,可以做更多操作,例如,相信对于更换颜色(夜间模式),修改字体大小等

4、WebView导航

两种方式
//后退
//WebView.GoBack();
await WebView.InvokeScriptAsync("eval", new []{"history.go(-1)"}); //刷新
//WebView.Refresh();
await WebView.InvokeScriptAsync("eval", new[] { "history.go()" }); //前进
//WebView.GoForward();
await WebView.InvokeScriptAsync("eval", new[] { "history.go(1)" });

5、手势

  由于WebView的内部结构与WebBrowser不同,WebView无法监听到Manipulation事件

  场景:当我们需要在PivotItem中放置WebView的时候,左右滑动无法切换PivotItem,下面通过JS手势监听WebView上面的手势操作,然后传到后台代码进行处理,这里没有做实时处理,只是监听了手势离开时的速度判断左右滑动

  5.1、定义手势监听事件方法

var gesture;
//记录手势操作开始位置
var gestureStartX; //触发Id,防止重复触发,触发Id与手势Id
var gestureId = 1;
var lastGestureId = 0; //速度触发
var gestureVector = 1.5; //注册手势事件
function prepareTarget(target, eventListener) {
//var target = document.getElementById(targetId);
target.addEventListener("MSGestureStart", eventListener, false);
target.addEventListener("MSGestureEnd", eventListener, false);
target.addEventListener("MSGestureChange", eventListener, false);
target.addEventListener("MSInertiaStart", eventListener, false);
//target.addEventListener("MSGestureTap", eventListener, false);
//target.addEventListener("MSGestureHold", eventListener, false);
target.addEventListener("pointerdown", onPointDown, false);
target.addEventListener("pointerup", onPointUp, false); gesture = new MSGesture();
gesture.target = target;
} function onPointUp(e) {
//把触发时间参数传到gesture
gesture.addPointer(e.pointerId);
} function onPointDown(e) {
//把触发时间参数传到gesture
gesture.addPointer(e.pointerId);
} //手势事件
//具体的属性参见:https://msdn.microsoft.com/zh-cn/library/ie/hh772076%28v=vs.85%29.aspx
function eventListener(evt) {
var myGesture = evt.gestureObject;
if (evt.type == "MSGestureStart") {
//开始触发,记录初始位置
gestureStartX = evt.clientX;
}
else if (evt.type == "MSInertiaStart") {
if (lastGestureId == gestureId || evt.velocityX == "undefined") {
return;
} else {
//释放时触发惯性事件,判断手势释放时的速度
if (evt.velocityX > gestureVector) {
var jsonObj = { type: "swiperight" };
window.external.notify(JSON.stringify(jsonObj));
lastGestureId = gestureId;
} else if (evt.velocityX < -gestureVector) {
jsonObj = { type: "swipeleft" };
window.external.notify(JSON.stringify(jsonObj));
lastGestureId = gestureId;
}
}
}
else if (evt.type == "MSGestureChange") {
//if (lastGestureId == gestureId) {
// return;
//} else {
// var change = evt.clientX - gestureStartX;
// window.external.notify("clientX:" + change);
//}
} else if (evt.type == "MSGestureEnd") {
//手势结束,Id+1
gestureId = gestureId + 1;
myGesture.reset();
}
}

gesture.js

  5.2、在WebView加载完成后,动态加载改JS文件,获取body标签,然后监听事件(参见3.3)

  5.3、当事件触发的时候改变Pivot.SelectedIndex,这样就能实现在WebView上滑动切换PivotItem

private void WebView_OnScriptNotify(object sender, NotifyEventArgs e)
{
//这个事件函数可以监听到JS通知的消息,消息类型为文本
//这里统一消息格式为:JsInvokeModel
var model = JsonConvert.DeserializeObject<JsInvokeModel>(e.Value);
switch (model.Type)
{
case "image":
Info.Text = e.Value;
break;
case "swiperight":
Info.Text = e.Value;
if (pivot.Items != null)
{
if (pivot.SelectedIndex > )
{
pivot.SelectedIndex--;
}
else
{
pivot.SelectedIndex = pivot.Items.Count - ;
}
}
break;
case "swipeleft":
Info.Text = e.Value;
if (pivot.Items != null)
{
if (pivot.SelectedIndex < pivot.Items.Count - )
{
pivot.SelectedIndex++;
}
else
{
pivot.SelectedIndex = ;
}
}
break;
case "text":
Info.Text = e.Value;
break;
}
}

6、常见问题

  6.1、alert和prompt方法在WebView失效,如果需要,可以使用 window.external.notify('message');然后再后台代码进行处理

   6.2、如果是导航到本地路径(ms-appdata:///local/),需要注意

    6.2.1、必须要将html需要的资源和html文件放在同一个文件夹下,html的资源路径不管是不是”/”开头,webview都认为是相对路径

    6.2.2、如果html中要的本地文件,如果在对应目录中不存在,wp上会直接跳出应用,大概过1分钟左右崩溃,且捕获不到异常。Windows上没有这现象

    6.2.3、不支持js的window.exteranl.notify功能

webView1.Navigate(new Uri("ms-appdata:///local/data/html/sample.htm"));

    不知道为什么WebView在导航到本地路径的时候  window.external.notify 会失效,如果需要可以考虑使用 内容流的方式加载本地文件

    下面做简单的演示

      1、定义内容留转换器

    public class HtmlStreamUriResolver : IUriToStreamResolver
{
public IAsyncOperation<IInputStream> UriToStreamAsync(Uri uri)
{
string path = uri.AbsolutePath;
return GetContent(path).AsAsyncOperation(); } // 根据 uri 返回对应的内容流
private async Task<IInputStream> GetContent(string path)
{
if (path.StartsWith("http"))
{
// http 方式获取内容数据
var client = new HttpClient();
var response = await client.GetAsync(new Uri(path), HttpCompletionOption.ResponseHeadersRead);
return (await response.Content.ReadAsStreamAsync()).AsInputStream();
}
else if (path.StartsWith("/local/cachedata/html/"))
{
path = string.Format("ms-appdata://{0}", path);
// 获取本地数据
var fileRead = await StorageFile.GetFileFromApplicationUriAsync(new Uri(path));
return await fileRead.OpenAsync(FileAccessMode.Read);
}
else
{
// 获取本地数据
var fileRead = await StorageFile.GetFileFromApplicationUriAsync(new Uri(path, UriKind.Absolute));
return await fileRead.OpenAsync(FileAccessMode.Read);
}
}
}

HtmlStreamUriResolver

      2、生成,导航,html中的所有引用都通过HtmlStreamUriResolver返回,具体逻辑在里面处理,通过这样导航的页面可以使用 window.external.notify 方法

  //生成内容流
var htmlStreamUriResolver = new HtmlStreamUriResolver();
var uri = webView.BuildLocalStreamUri("tag", "/local/cachedata/html/sample.html");
webView.NavigateToLocalStreamUri(uri, htmlStreamUriResolver);

7、Demo

  http://files.cnblogs.com/files/bomo/WebViewDemo.zip

8、参考链接

  手势事件参数说明:https://msdn.microsoft.com/zh-cn/library/ie/hh772076%28v=vs.85%29.aspx?f=255&MSPPError=-2147217396

  WinJS手势:https://msdn.microsoft.com/zh-cn/library/ie/hh968249(v=vs.85).aspx

  Win8.1和WP8.1在UniversalAPP中WebView的研究:http://blog.csdn.net/hzdinglai/article/details/41073739

  重新想象 Windows 8.1 Store Apps (81) : WebView:http://www.cnblogs.com/webabcd/p/3803384.html

关于WP8的WebBrowser,请移步:http://www.cnblogs.com/bomo/p/3949994.html

个人能力有限,如果上文有误或者您有更好的实现,可以给我留言

转载请注明出处:http://www.cnblogs.com/bomo/p/4320077.html

【WP8.1】WebView笔记的更多相关文章

  1. webview笔记

    1. 用户上传文件 webChromeClient的onShowFileChooser这个方法,这将打开一个文件选择器,如果要取消这个请求则是调用filePathCallback.onReceiveV ...

  2. Android WebView 笔记

    WebView(网络视图)能载入显示载入网页.将网页内容载入到手机client,它使用了WebKit渲染引擎载入显示网页,实现WebView有下面方法: 首先要实如今手机client显示必需要求注冊一 ...

  3. Android SDK组件:webview笔记

    1.安卓手机中内置了一款webkit内核的浏览器,在SDK中封装为WebView组件. 2.该组件可以在自己的应用程序中显示本地或者Internet上的网页,也可以把它当作一个浏览器来时用. 3.We ...

  4. <WP8开发学习笔记>获取手机的常用型号(如Lumia920,而非RM-822)

    之前WP7时代可以用API获得WP手机的型号如lumia510,但是到了WP8后用APi只能获得硬件版本号了如RM-822,这种型号可以让我们更详细的了解具体的硬件版本,比如国行和港行,设备版本号不一 ...

  5. 1. WP8.1学习笔记

    数据绑定 含义:将对象绑定到控件上 2.基本名词 控件:绑定目标 对象:绑定源(数据源) 控件与对象属性的联系:路径 如何绑定 创建对象,设置控件 在控件需要数据绑定的地方使用拓展语法 <But ...

  6. 0. WP8.1学习笔记

    应用程序生命周期: 运行: 在程序NotRunning状态下点击图标,应用将处于Running状态,这会触发一个Actived事件 挂起: 在程序Running状态下, 点击返回键或win键会触发一个 ...

  7. wp8.1 学习笔记 001 动态生成图片 并更改图片位置

    1.在xaml中划分表格 <Grid Name="gr"> <Grid.ColumnDefinitions> <ColumnDefinition> ...

  8. <WP8开发学习笔记>ApplicationBar(任务栏)的切换以及“黑条问题”

    ApplicationBar(以下简称AppBar)是WP应用相当常见的控件,也很方便.常见的做法是pivot或者panorama的页面切换的时候,AppBar跟随切换对应的按钮或者不显示按钮,如下图 ...

  9. <WP8开发学习笔记>动态修改启动时导航的第一个页面(如登录前启动页为LoginPage,登录后变为MainPage)

    很多时候我们需要在启动程序的时候根据状态改变初始导航页面,比如程序在启动的时候判断用户是否登录, 如果未登录则跳转到LoginPage.xaml否则跳转到MainPage界面. 这时候就要分析程序的启 ...

随机推荐

  1. zookeeper源码分析之三客户端发送请求流程

    znode 可以被监控,包括这个目录节点中存储的数据的修改,子节点目录的变化等,一旦变化可以通知设置监控的客户端,这个功能是zookeeper对于应用最重要的特性,通过这个特性可以实现的功能包括配置的 ...

  2. C#创建dll类库

    类库让我们的代码可复用,我们只需要在类库中声明变量一次,就能在接下来的过程中无数次地使用,而无需在每次使用前都要声明它.这样一来,就节省了我们的内存空间.而想要在类库添加什么类,还需取决于类库要实现哪 ...

  3. 【WPF】日常笔记

    本文专用于记录WPF开发中的小细节,作为备忘录使用. 1. 关于绑定: Text ="{Binding AnchorageValue,Mode=TwoWay,UpdateSourceTrig ...

  4. spring maven pom.xml设置

    spring pom.xml设置 <?xml version="1.0" encoding="UTF-8"?> <project xmlns= ...

  5. 简单酷炫的canvas动画

    作为一个新人怀着激动而紧张的心情写了第一篇帖子还请大家多多支持,小弟在次拜谢. 驯鹿拉圣诞老人动画效果图如下 html如下: <div style="width:400px;heigh ...

  6. Android使用静默安装时碰见的问题

    升级时碰见的异常 private void installPackage(String appName,final File apk) { if (!apk.exists()) { setHasNew ...

  7. Git(1)

    安装Git 完毕 (在开始菜单打开的话,打开的不是你想要的路径,切换路径很麻烦) 1.D盘新建 GitTest 文件夹 2.打开GitTest , 在空白的地方右键, 3.单击 Git Bash He ...

  8. Linux实战教学笔记03:操作系统发展历程及系统版本选择

    标签(空格分隔): Linux实战教学笔记-陈思齐 第1章 Linux简介 1.1 什么是操作系统? 简单讲:操作系统就是一个人与计算机硬件的中介. 操作系统,英文名称Operating System ...

  9. 浅谈iptables 入站 出站以及NAT实例

    --------------本文是自己工作上的笔记总结,适合的可以直接拿去用,不适合的,适当修改即可!--------------- iptbales默认ACCEPT策略,也称通策略,这种情况下可以做 ...

  10. Spring代理模式及AOP基本术语

    一.代理模式: 静态代理.动态代理 动态代理和静态代理区别?? 解析:静态代理需要手工编写代理类,代理类引用被代理对象. 动态代理是在内存中构建的,不需要手动编写代理类 代理的目的:是为了在原有的方法 ...