ios的javascriptios怎么清除应用缓存缓存

JavaScript实现图片预加载,有清除缓存功能_最火下载站
您的位置: >
> JavaScript实现图片预加载,有清除缓存功能
JavaScript实现图片预加载,有清除缓存功能
  JavaScript实现图片预加载,有清除缓存功能。如lightbox方式展现照片,无疑需要提前获得大图的尺寸,这样才能居中定位,由于javascript无法获取img文件头数据,必须等待其加载完毕后才能获取真实的大小然后展示出来,所以lightbox显示的图片的速度体验要比直接输出的差很多,而本文说提到的预加载技术主要针对获取图片尺寸。
  示例:
&!DOCTYPE html&
&html xmlns=&http://www.w3.org/1999/xhtml&&
&meta http-equiv=&Content-Type& content=&text/ charset=gbk& /&
&title&图片预加载&/title&
var imgReady = function (url, callback, error) {
var width, height, intervalId, check, div,
img = new Image(),
body = document.
// 从缓存中读取
if (plete) {
return callback(img.width, img.height);
// 通过占位提前获取图片头部数据
if (body) {
div = document.createElement('div');
div.style.cssText = 'visibility:position:left:0;top:0;width:1height:1overflow:hidden';
div.appendChild(img)
body.appendChild(div);
width = img.offsetW
height = img.offsetH
check = function () {
if (img.offsetWidth !== width || img.offsetHeight !== height) {
clearInterval(intervalId);
callback(img.offsetWidth, img.clientHeight);
img.onload =
div.innerHTML = '';
div.parentNode.removeChild(div);
intervalId = setInterval(check, 150);
// 加载完毕后方式获取
img.onload = function () {
callback(img.width, img.height);
img.onload = img.onerror =
clearInterval(intervalId);
body && img.parentNode.removeChild(img);
// 图片加载错误
img.onerror = function () {
error && error();
clearInterval(intervalId);
body && img.parentNode.removeChild(img);
window.onload = function () {
var imgUrl = '/uploads/common/images/14407.jpg?',
testReadyBtn = document.getElementById('testReadyBtn'),
clsCacheBtn = document.getElementById('clsCacheBtn'),
status = document.getElementById('status'),
statusReady = document.getElementById('statusReady'),
statusLoad = document.getElementById('statusLoad'),
imgWrap = document.getElementById('imgWrap');
var imgLoad = function (url, callback) {
var img = new Image();
if (plete) {
callback(img.width, img.height);
img.onload = function () {
callback(img.width, img.height);
img.onload =
testReadyBtn.onclick = function () {
var that =
that.disabled =
status.style.display = 'block';
statusLoad.innerHTML = statusReady.innerHTML = 'Loading...';
imgWrap.innerHTML = '&img src=&' + imgUrl + '& /&';
// 使用占位方式快速获取大小
imgReady(imgUrl, function (width, height) {
statusReady.innerHTML = 'width:' + width + '; height:' +
}, function () {
statusReady.innerHTML = 'Img Error!';
// 使用传统方式获取大小
imgLoad(imgUrl, function (width, height) {
statusLoad.innerHTML = 'width:' + width + '; height:' +
that.disabled =
}, function () {
statusLoad.innerHTML = 'Img Error!';
that.disabled =
clsCacheBtn.onclick = function () {
imgUrl += new Date().getTime();
status.style.display = 'none';
imgWrap.innerHTML = '';
&p&&button id=&testReadyBtn&&开始加载图片&/button& &button id=&clsCacheBtn&&清空缓存&/button&(如果图片加载过后,浏览器会缓存)&/p&
&div id=&status& style=&display:none&&
&p&&strong&imgReady:&/strong&&p&
&p id=&statusReady&&&/p&
&p&&strong&imgLoad:&/strong&&/p&
&p id=&statusLoad&&&p&
&/html& &br /&&center&如不能显示效果,请按Ctrl+F5刷新本页,更多网页代码:&a href='/' target='_blank'&/&/a&&/center&提示:可修改后代码再运行!
上一篇: 下一篇:JS清除IE浏览器缓存的方法
字体:[ ] 类型:转载 时间:
本文为大家详细介绍下js中自动清除ie缓存的几种方法,大家可以根据自己的需求自由选择适合自己的,希望对大家学习js有所帮助
js中自动清除ie缓存方法 — 常用 对于动态文件,比如 index.asp?id=... 或者 index.aspx?id=... 相信有经验的程序员都知道怎样禁止浏览器缓存数据了. 但是对于静态文件(css,jpg,gif等等), 在什么场合下面我们需要禁止浏览器缓存他们,怎么做? 方法一:Dojo中我们可以用简单的方法完成:在dojo.xhrGet(包括post)等方法中都包含preventCache属性,此属性的含义: “默认为启用浏览器缓存,否则将通过自动增加不同的参数来确保浏览器缓存失效” 我们只要把此属性赋值为:“true”即可。 方法二:document.write(" 其中 ver=113 的 113就是版本号,一般都是采用 CVS 或其他工具生成的开发版本号。 这样真正做到了应该缓存的时候缓存静态文件,当版本有更新的时候从获取最新的版本,并更新缓存。 对于图像 来有效利用和更新缓存. js清除浏览器缓存 二 为了减小浏览器与服务器之间网络传输压力,往往对静态文件,如js,css,修饰的图片做cache,也就是给这些文件的HTTP响应头加入 Expires和Cache-Control参数,并指定缓存时间,这样一定时间内浏览器就不会给服务器发出任何的HTTP请求(除了强制刷新),即使在 这段时间内服务器的js或css或图片文件已经更新多次,但浏览器的数据依然是原来最能初cache的旧数据,有没有办法让浏览器拿到已经修改后的最新数 据呢? 有,方法是用ajax请求服务器最新文件,并加上请求头If-Modified-Since和Cache-Control,如下:
代码如下: $.ajax({ type: "GET", url: "static/cache.js", dataType: "text", beforeSend :function(xmlHttp){ xmlHttp.setRequestHeader("If-Modified-Since","0"); xmlHttp.setRequestHeader("Cache-Control","no-cache"); } });
这里用了jquery. 这样浏览器就会把最新的文件替换掉本地旧文件。 当然,这里还一个问题就是js必须知道服务器更新了那个js、css、图片,利用cookie和时间版本应该可以解决. jquery自从1.2开始就有ifModified和cache参数了,不用自己加header ifModified Boolean Default: false Allow the request to be successful only if the response has changed since the last request. This is done by checking the Last-Modified header. Default value is false, ignoring the header. cache Boolean Default: true Added in jQuery 1.2, if set to false it will force the pages that you request to not be cached by the browser.
代码如下: $.ajax({ type: "GET", url: "static/cache.js", dataType: "text", cache:false, ifModified :true });
您可能感兴趣的文章:
大家感兴趣的内容
12345678910
最近更新的内容
常用在线小工具智能手机的发展
伴随着智能手机在国内的普及及其换代速度,HTML5技术在移动领域的发展终究比PC端来的更迅速些。
根据移动互联网第三方数据挖掘和整合营销机构艾媒咨询(iiMedia Research)发布的《2012中国智能手机市场年度研究报告》数据显示,截止2012Q4季度,中国智能手机用户数达到了3.8亿,同比增长72.7%;
<span style="color: #12中国智能手机用户规模发展状况
报告指出,在操作系统占有率方面,Android份额到达68.6%,iOS有所下滑,占12.8%,Symbian则难抑下滑趋势,占12.4%,Windows Phone作为后起之秀,份额只占3.8%,但后续占有率会持续扩大;
<span style="color: #12年中国智能手机市场操作系统分布状况
在系统平台分布方面,Android上V2.x是主流版本,iOS上V5是主流版本
<span style="color: #12年中国智能手机市场Android、iOS平台版本分布
(以上数据来自iiMedia Research《2012中国智能手机市场年度研究报告》)
Application Cache的问题
回到正题,HTML5伴随着智能手机的发展,在手机应用开发方面的优势越发凸显,尤其是其跨平台、版本更新等优势;在一些对性能要求稍低及项目人员紧张的产品中,使用WebApp的形式(大多为Native App+WebApp的混搭方式)不失为一种好的解决方案。
排除WIFI,对于国内那昂贵的流量费用,而且是极不稳定的GPRS来说,WebApp的开发不得不考虑一个问题:缓存。
开始我很兴奋,知道HTML5给我们提供了,通过manifest文件,我终于可以翱翔在离线数据的大海中。
理想很丰满,现实却总是很骨感;Application Cache这货可真不好管理,如果你还不清楚它的实际情况,可以参考下这篇文章,内容我就不翻译了,但标题我得翻译下:《Application Cache就是个人渣》。
关于Application Cache,有一个致命的缺点,那就是你不能选择更新哪些资源。你的manifest文件更新了,所有指定的资源都会给下载,对于流量是金的移动互联网来说,这不就是坑爹嘛。
localStorage
但上帝总在关了一扇门之后,给我们开启另一扇门,而这一扇门就是:localStorage。
localStorage的存储空间是按域名来计算的,不同平台容量不同,即使相同平台相同版本但由于手机厂商调教不一,造成实际使用中的大小也是不一样的。就拿笔者的MX2(Android 4.1)自带的浏览器来说,测试出来的结果是64M。虽然不同平台及版本存在差异,但对于大部分WebApp来说,这样的存储空间已经可以派上大用场了。
Android 2.3
(以上数据来自,测试地址点)
在使用localStorage前,我们还需要清楚webview对localStorage的影响,特别是对于那些嵌套在不同客户端的WebApp来说,webview对localStorage的支持与否也是不可忽视的一点。同时,对于业务较多的根域来说,不同WebApp之间可能会出现空间上的使用管理混乱问题,这需要在前期规划时对存储做好队列管理工作。
解决方案:WebAppCache
考虑到Application Cache的维护麻烦问题,在我最近的项目中就基本放弃了manifest的方式,转而使用类MVC的方式(估且这么叫吧)。
方案由app.json配置应用的每个资源信息,app.html进行整个应用的调度,包括版本对比、更新以及缓存队列管理。由于使用了Ajax来拉取文件,所以受同源访问限制,对跨域请求有要求的同学,可以使用,这里就不仔细展开了,只是提供其中一种简单的实现方式。
假设我们的目录结构如下:
|---app.manifest
|---app.html
|---WebAppCache.js
|---index.html
|---inner/
|---demo.html
|---zepto.min.js
|---touch.min.js
|---app.js
|---demo.js
|---global.css
|---inner/
|---demo.css
WebAppCache约定app.html与app.json处于相同的目录层级,其他的资源不作要求。
则实际请求地址如下:
index.html
-& /app/app.html 或 /app/app.html?v=index
inner/demo.html -& /app/app.html?v=inner.demo
app.json应用配置文件
// 配置app.json文件过期时间(分钟)
"expire": "30",
// 核心加载的js文件
"jsCore": ["zepto", "touch"],
// 核心加载的css文件
"cssCore": ["global"],
"jsConfig": {
// js基准路径
"path": "/app/js/",
// js缺省后缀
"suffix": ".js"
// css配置
"cssConfig": {
// css基准路径
"path": "/app/css/",
// css缺省后缀
"suffix": ".css"
// 页面配置
"pageConfig": {
// 页面基准路径
"path": "/app/page/",
// 页面缺省后缀
"suffix": ".html"
// 声明应用js资源
"zepto": {
// 指定拉取路径,url为空时以"基准路径+模块名+缺省后缀"拉取
"url": "/app/js/zepto.min.js",
// 版本号,-1时不作缓存
"v": "1.0.0"
"touch": {
"url": "/app/js/touch.min.js",
"v": "1.0.0"
"v": "1.0.0"
"v": "1.0.0"
// 声明应用css资源
"global": {
"url": "/app/css/global.css",
"v": "1.0.0"
"v": "1.0.1"
"inner.demo": {
"v": "1.0.0"
// 声明应用页面
"index": {
// 声明除去核心加载外需要加载的资源
"js": ["app"],
"css": ["app"]
"inner.demo": {
"js": ["app", "demo"],
"css": ["app", "inner.demo"]
app.html缓存调度
&!DOCTYPE html&
&html manifest="/app/app.manifest"&
&title&&/title&
&meta charset="utf-8"&
&script type="text/javascript" src="/app/WebAppCache.js"&&/script&
app.html我使用了Application Cache,这在不使用SPA方式对页面进行documwnt.write输出时,可以加快页面载入速度。当所有的资源处理完毕之后,会将内容渲染到当前页面输出。
WebAppCache.js之队列管理
为了兼容同一根域下多WebApp的场景,WebAppCache.js以应用为单位进行缓存管理,每次进行写操作时,都会缓存当前的key到队列里;同时资源队列以”资源缓存时间先后 + css核心资源(按依赖权重由低到高排列)+ js核心资源(按依赖权重由低到高排列)“进行排列;
在溢出时,按App使用时间先后进行队列淘汰;当所有非当前App淘汰完毕后,再对当前App资源进行资源队列淘汰;在淘汰当前App资源队列后仍无法存储时,最后尝试清空当前App缓存再试。
* 优化的缓存设置, 溢出捕获以及队列管理
function cache(n, v, prefix) {
prefix = (getType(prefix) == 'string') ? prefix : _appN
if (getType(v) == 'undefined') {
var r = _storage.getItem(prefix + n);
if (r === null) {
return JSON.parse(r);
} catch (e) {
// 缓存当前应用的写操作key值(无序)
if (prefix == _appName) {
var cacheKey = cache('CacheKey') || [];
cacheKey.push(n);
cacheKey = uniq(cacheKey);
_storage.setItem(_appName + 'CacheKey', JSON.stringify(cacheKey));
if (getType(v) != 'string') {
v = JSON.stringify(v);
_storage.setItem(prefix + n, v);
} catch (e) {
var appName = shiftAppCache();
if (appName !== false) { // 重新尝试缓存
cache(n, v);
} else { // 没有应用缓存可供删除时, 淘汰当前应用队列
var cq = cache('Core') || [],
sq = sourceQueue();
// 将Core与Source资源合并进行队列管理
sq = sq.concat(cq);
// 缓存区不足时,淘汰当前应用缓存重新发起请求
if (sq.length & 1) {
clearAppCache(_appName);
window.location.reload(false);
var item = sq.shift(),
key = _appName +
// 删除最早的缓存
_storage.removeItem(key);
_storage.removeItem(key + '.Version');
// 更新队列
sourceQueue(sq);
// 重新尝试缓存
cache(n, v);
* 清空应用缓存
function clearAppCache(appName) {
var cacheKey = cache('CacheKey', undefined, appName) || [];
each(cacheKey, function(k, v) {
_storage.removeItem(appName + v);
_storage.removeItem(appName + 'CacheKey');
* 按应用缓存队列清空应用缓存(跳过当前应用缓存)
function shiftAppCache() {
var appQueue = cache('App.Queue', undefined, '') || [];
appQueue = arrDel(_appName, appQueue); // 跳过当前应用缓存
if (appQueue.length & 0) {
var appName = appQueue.shift();
clearAppCache(appName);
cache('App.Queue', appQueue, '');
return appName
对于同一根域下多WebApp的场景,当用户同时开启多个应用造成空间不足时,当前的解决方案在localStorage支持的情况下可能会出现数据缓存不久就被淘汰的情况,这种情况可以通过转换为sessionStorage来进行优化。
有一点需要注意,在使用document.write输出文档流时,要在window.onload触发后方可进行页面渲染,否则原文档流不会被覆盖。
最后附上GitHub地址:
PS:感谢maple同学提供Banner~ ^_^iOS js与objective-c的交互(转) - 沧海一粟-啊添 - 博客园
随笔 - 114
在写 JavaScript 的时候,可以使用一个叫做 window 的对象,像是我们想要从现在的网页跳到另外一个网页的时候,就会去修改 window.location.href 的位置;在我们的 Objective-C 程序码中,如果我们可以取得指定的 WebView 的指标,也就可以拿到这个出现在 JavaScript 中的 window 对象,也就是 [webView windowScriptObject]。
这个对象就是 WebView 里头的 JS 与我们的 Objective-C程序之间的桥樑-window 对象可以取得网页里头所有的 JS 函数与对象,而如果我们把一个 Objective-C&对象设定成 windowScriptObject 的 value,JS 也便可以调用Objective-C对象的 method。于是,我们可以在Objective-C 程序里头要求 WebView 执行一段 JS,也可以反过来让 JS 调用一段用 Obj C 实作的功能。
※ 用Objective-C&取得与设定JavaScript&对象
要从 Objective-C取得网页中的 JavaScript 对象,也就是对 windowScriptObject 做一些 KVC 调用,像是 valueForKey: 与 valueForKeyPath:。如果我们在 JS 里头,想要知道目前的网页位置,会这么写:
  var&location = window.location.
用 Objective-C 就可以这么调用:
  NSString&*location = [[webView windowScriptObject] valueForKeyPath:@"location.href"];
如果我们要设定 window.location.href,要求开启另外一个网页,在 JS 里头:
  window.location.href =&'http://spring-studio.net';
在Objective-C:
  [[webView windowScriptObject] setValue:@"http://spring-studio.net"forKeyPath:@"location.href"];
由于Objective-C 与 JS 本身的语言特性不同,在两种语言之间相互传递东西之间,就可以看到两者的差别:
JS 虽然是 OO,但是并没有 class,所以将 JS 对象传到 Obj C 程序里头,除了基本字串会转换成 NSString、基本数字会转成 NSNumber,像是 Array 等其他对象,在 Objective-C&中,都是 WebScriptObject 这个 Class。意思就是,JS 的 Array 不会帮你转换成 NSArray。
从 JS 里头传一个空对象给 Objective-C&程序,用的不是 Objective-C&里头原本表示「没有东西」的方式,像是 NULL、nil、NSNull 等,而是专属 WebKit 使用的 WebUndefined。
所以,如果我们想要看一个 JS Array 里头有什麽东西,就要先取得这个对象里头叫做 length 的 value,然后用 webScriptValueAtIndex: 去看在该 index 位置的内容。
假如我们在 JS 里头这样写:
var&JSArray = {'zonble',&'dot',&'net'};
for&(var&i = 0; i & JSArray. i++) {
  console.log(JSArray[i]);
在Objective-C&里头就会变成这样:
WebScriptObject *obj = (WebScriptObject *)JSA
NSUInteger&count = [[obj valueForKey:@"length"] integerValue];
NSMutableArray&*a = [NSMutableArray&array];
for&(NSUInteger&i = 0; i & i++) {
&&&&NSString&*item = [obj webScriptValueAtIndex:i];
&&&&NSLog(@"item:%@", item);
※ 用Objective C&调用&JavaScript function
要用 Objective-C&调用网页中的 JS function,大概有几种方法。第一种是直接写一段跟你在网页中会撰写的 JS 一模一样的程序,叫 windowScriptObject 用 evaluateWebScript: 执行。
例如,我们想要在网页中产生一个新的 JS function,内容是:
function&x(x) {
&&&&return&x + 1;
所以在 Objective-C&中可以这样写;
[[webView windowScriptObject] evaluateWebScript:@"function x(x) { return x + 1;}"];
接下来我们就可以调用 window.x():
NSNumber&*result = [[webView windowScriptObject] evaluateWebScript:@"x(1)"];
NSLog(@"result:%d", [result integerValue]);&// Returns 2
由于在 JS 中,每个 funciton 其实都是对象,所以我们还可以直接取得 window.x 叫这个对象执行自己。
在 JS 里头如果这样写:
window.x.call(window.x, 1);
Objective-C&中便是这样:
WebScriptObject *x = [[webView windowScriptObject] valueForKey:@"x"];
NSNumber&*result = [x callWebScriptMethod:@"call"withArguments:[NSArray&arrayWithObjects:x, [NSNumbernumberWithInt:1],&nil]];
这种让某个 WebScriptObject 自己执行自己的写法,其实比较不会用于从 Objective-C&调用 JS 这一端,而是接下来会提到的,由 JS 调用 Objective-C,因为这样 JS 就可以把一个 callback function 送到 Objective-C&程序里头。
如果我们在做网页,我们只想要更新网页中的一个区块,就会利用 AJAX 的技巧,只对这个区块需要的资料,对 server 发出 request,并且在 request 完成的时候,要求执行一段 callback function,更新这一个区块的显示内容。从 JS 调用 Objective-C也可以做类似的事情,如果 Objective-C程序里头需要一定时间的运算,或是我们可能是在 Objective-C&里头抓取网路资料,我们便可以把一个 callback function 送到 Objective-C程序里,要求Objective-C程序在做完工作后,执行这段 callback function。
WebKit 里头,所有的 DOM 对象都继承自 DOMObject,DOMObject 又继承自 WebScriptObject,所以我们在取得了某个 DOM 对象之后,也可以从 Objective-C&程序中,要求这个 DOM 对象执行 JS 程序。
假如我们的网页中,有一个 id 叫做 &#s& 的文字输入框(text input),而我们希望现在键盘输入的焦点放在这个输入框上,在 JS 里头会这样写:
document.querySelector('#s').focus();
在Objective-C中写法:
DOMDocument *document = [[webView mainFrame] DOMDocument];
[[document querySelector:@"#s"] callWebScriptMethod:@"focus"withArguments:nil];
※ 用&JavaScript&存取&Objective C&的&Value
要让网页中的 JS 程序可以调用 Objective-C&对象,方法是把某个 Objective-C&对象注册成 JS 中 window 对象的属性。之后,JS 便也可以调用这个对象的 method,也可以取得这个对象的各种 Value,只要是 KVC 可以取得的 Value,像是 NSString、NSNumber、NSDate、NSArray、NSDictionary、NSValue&等。JS 传 Array 到 Objective-C&时,还需要特别做些处理才能变成 NSArray,从 Obj C 传一个 NSArray 到 JS 时,会自动变成 JS Array。
首先我们要注意的是将 Objective-C&对象注册给 window 对象的时机,由于每次重新载入网页,window 对象的内容都会有所变动-毕竟每个网页都会有不同的 JS 程序,所以,我们需要在适当的时机做这件事情。我们首先要指定 WebView 的 frame loading delegate(用 setFrameLoadDelegate:),并且实作 webView:didClearWindowObject:forFrame:,WebView 只要更新了 windowScriptObject,就会调用这一段程序。
假如我们现在要让网页中的 JS 可以使用目前的 controller 对象,会这样写:
- (void)webView:(WebView *)sender didClearWindowObject:(WebScriptObject *)windowObject forFrame:(WebFrame *)frame
&&&&[windowObject setValue:self&forKey:@"controller"];
如此一来,只要调用 window.controller,就可以调用我们的 Objective-C&对象。假如我们的 Objective-C&Class 里头有这些成员变数:
@interface&MyController :&NSObject
&&&&IBOutlet&WebView *webV
&&&&IBOUtlet&&NSWindow&*
&&&&NSString&*stringV
&&&&NSInteger&numberV
&&&&NSArray&*arrayV
&&&&NSDate&*dateV
&&&&NSDictionary&*dictV
&&&&NSRect&frameV
指定一下 Value:
stringValue =&@"string";
numberValue = 24;
arrayValue = [[NSArray&arrayWithObjects:@"text", [NSNumbernumberWithInt:30],&nil] retain];
dateValue = [[NSDate&date] retain];
dictValue = [[NSDictionary&dictionaryWithObjectsAndKeys:@"value1",@"key1",&@"value2",&@"key2",&@"value3",&@"key3",&nil] retain];
frameValue = [window frame];
用 JS 读读看:
var&c = window.
var&main = document.getElementById('main');
var&HTML =&'';
&&&&HTML +=&'&p&'&+ c.stringValue +&'&p&';
&&&&HTML +=&'&p&'&+ c.numberValue +&'&p&';
&&&&HTML +=&'&p&'&+ c.arrayValue +&'&p&';
&&&&HTML +=&'&p&'&+ c.dateValue +&'&p&';
&&&&HTML +=&'&p&'&+ c.dictValue +&'&p&';
&&&&HTML +=&'&p&'&+ c.frameValue +&'&p&';
&&&&main.innerHTML = HTML;
结果如下:
string 24 text,30
00:01:04 +0800 { key1 = value1; key2 = value2; key3 = value3; } NSRect: {{275, 72}, {570, 657}}
不过,如果你看完上面的范例,就直接照做,应该不会直接成功出现正确的结果,而是会拿到一堆 undefined,原因是,Objective-C 对象的 Value 预设被保护起来,不会让 JS 直接存取。要让 JS 可以存取 Objective-C&对象的 Value,需要操作 +isKeyExcludedFromWebScript: 针对传入的 Key 一一处理,如果我们希望 JS 可以存取这个 key,就回传 NO:
+ (BOOL)isKeyExcludedFromWebScript:(const&char&*)name
&&&&if&(!strcmp(name,&"stringValue")) {
&&&&&&&&return&NO;
&&&&return&YES;
除了可以读取 Objective-C对象的 Value 外,也可以设定 Value,相当于在 Objective-C中使用 setValue:forKey:,如果在上面的 JS 程序中,我们想要修改 stringValue,直接调用 c.stringValue = &new value& 即可。像前面提到,在这裡传给 Objective-C的 JS 对象,除了字串与数字外,class 都是 WebScriptObject,空对象是 WebUndefined。
※用&JavaScript调用&Objective C method
Objective-C&的语法沿袭自 SmallTalk,Objective-C 的 selector,与 JS 的 function 语法有相当的差异。WebKit 预设的实事是,如果我们要在 JS 调用 Objective-C&selector,就是把所有的参数往后面摆,并且把所有的冒号改成底线,而原来 selector 如果有底线的话,又要另外处理。
假使我们的 controller 对象有个 method,在 Objective-C&中写成这样:
- (void)setA:(id)a b:(id)b c:(id)c;
在 JS 中就这么调用:
controller.setA_b_c_('a',&'b',&'c');
实在有点丑。所以 WebKit 提供一个方法,可以让我们把某个 Objective-C&selector 变成好看一点的 JS function。我们要实作 webScriptNameForSelector:
+ (NSString&*)webScriptNameForSelector:(SEL)selector
&&&&if&(selector ==&@selector(setA:b:c:)) {
&&&&&&&&return&@"setABC";
&&&&return&
以后就可以这么调用:
controller.setABC('a',&'b',&'c');
我们同样可以决定哪些 selector 可以给 JS 使用,哪些要保护起来,方法是实作 isSelectorExcludedFromWebScript:。而我们可以改变某个 Objective-C&selector 在 JS 中的名称,我们也可以改变某个 value 的 key,方法是实作 webScriptNameForKey:。
有几件事情需要注意一下:
用 JavaScript 调用 Objective C 2.0 的 property
在上面,我们用 JS 调用 window.controller.stringValue,与设定里头的 value 时,这边很像我们使用 Objective-C&2.0 的语法,但其实做的是不一样的事情。用 JS 调用 controller.stringValue,对应到的 Objective-C&语法是 [controller valueForKey:@"stringValue"],而不是调用 Objective-C&对象的 property。
如果我们的 Objective-C&对象有个 property 叫做 stringValue,我们知道,Objective-C property 其实会在编译时,变成 getter/setter method,在 JS 里头,我们便应该要调用 controller.stringValue() 与 controller.setStringValue_()。
Javascript 中,Function 即对象的特性
JS 的 function 是对象,当一个 Objective-C&对象的 method 出现在 JS 中时,这个 method 在 JS 中,也可以或多或少当做对象处理。我们在上面产生了 setABC,也可以试试看把它倒出来瞧瞧:
console.log(controller.setABC);
我们可以从结果看到:
function setABC() { [native code] }
这个 function 是 native code。因为是 native code,所以我们无法对这个 function 调用 call 或是 apply。
另外,在把我们的 Objective-C&对象注册成 window.controller 后,我们会许也会想要让 controller 变成一个 function 来执行,像是调用 window.controller();或是,我们就只想要产生一个可以让 JS 调用的 function,而不是整个对象都放进 JS 里头。我们只要在 Objective-C&对象中,实作 invokeDefaultMethodWithArguments:,就可以回传在调用 window.controller() 时想要的结果。
现在我们可以综合练习一下。前面提到,由于我们可以把 JS 对象以 WebScriptObject 这个 class 传入 Obj C 程序,Objective-C 程序中也可以要求执行 WebScriptObject 的各项 function。我们假如想把 A 与 B 两个数字丢进 Objective-C&程序里头做个加法,加完之后出现在网页上,于是我们写了一个 Objective-C&method:
- (void)numberWithA:(id)a plusB:(id)b callback:(id)callback
&&&&NSInteger&result = [a integerValue] + [b integerValue];
&&&&[callback callWebScriptMethod:@"call"&withArguments:[NSArrayarrayWithObjects:callback, [NSNumber&numberWithInteger:result],nil]];
JS 里头就可以这样调用:
window.controller.numberWithA_plusB_callback_(1, 2,function(result) {
&&&&var&main = document.getElementById('main');
&&&&main.innerText =
※其他平台上&WebKit的用法
除了 Mac OS X,WebKit 这几年也慢慢移植到其他的作业系统与 framework 中,也或多或少都有 Native API 要求 WebView 执行 Js,以及从 JS 调用 Native API 的机制。
跟 Mac OS X 比较起来,IOS 上 UIWebView 的公开 API 实在少上许多。想要让 UIWebView 执行一段 JS,可以透过调用 stringByEvaluatingJavaScriptFromString:,只会回传字串结果,所以能够做到的事情也就变得有限,通常大概就拿来取得像 window.title 这些资讯。在 IOS 上我们没办法将某个 Objective-C&对象变成 JS 对象,所以,在网页中触发了某些事件,想要通知 Objective-C&这一端,往往会选择使用像「zonble://」这类 Customized URL scheme。
ChromeOS 完全以 WebKit 製作使用者介面,不过我们没办法在 ChomeOS 上写我们在这边所讨论的桌面或行动应用程序,所以不在我们讨论之列。(顺道岔题,ChromeOS 是设计来给 Netbook 使用的作业系统,可是像 Toshiba 都已经用 Android,做出比 Netbook 更小的 Smartbook,而且应用程序更多,ChromeOS 的产品做出来的话,实在很像 Google 拿出两套东西,自己跟自己对打)。
Android 的 WebView 对象提供一个叫做 addJavascriptInterface() 的 method,可以将某个 Java 对象注册成 JS 的 window 对象的某个属性,就可以让 JS 调用 Java 对象。不过,在调用 Java 对象时,只能够传递简单的文字、数字,複杂的 JS 对象就没办法了。而在 Android 上想要 WebView 执行一段 JS,在文件中没看到相关资料,网路上面找到的说法是,可以透过 loadUrl(),把某段 JS 用 bookmarklet 的形式传进去。
在 QtWebKit 里头,可以对 QWebFrame 调用 addToJavaScriptWindowObject,把某个 QObject 暴露在 JS 环境中,我不清楚 JS 可以传递哪些东西到 QObject 里头就是了。在 QtWebKit 中也可以取得网页里头的 DOM 对象(QWebElement、QWebElementCollection),我们可以对 QWebFrame 还有这些 DOM 对象调用 evaluateJavaScript,执行 Javascript。
GTK 方面,因为是 C API,所以在应用程序与 JS 之间,就不是透过操作包装好的对象,而是调用 WebKit 里头 JavaScript Engine 的 C API。
※&JavaScriptCore Framework
我们在 Mac OS X 上面,也可以透过 C API,要求 WebView 执行 Javascript。首先要 import&。如果我们想要简单改一下 window.location.href:
JSGlobalContextRef globalContext = [[webView mainFrame] globalContext];
JSValueRef exception = NULL;
JSStringRef script = JSStringCreateWithUTF8CString("window.location.href='http://spring-studio.net'");
JSEvaluateScript(globalContext, script, NULL, NULL, 0, &exception);
JSStringRelease(script);
如果我们想要让 WebView 里头的 JS,可以调用我们的 C Function:
- (void)webView:(WebView *)sender didClearWindowObject:(WebScriptObject *)windowObject forFrame:(WebFrame *)frame
&&&&JSGlobalContextRef globalContext = [frame globalContext];
&&&&JSStringRef name = JSStringCreateWithUTF8CString("myFunc");
&&&&JSObjectRef obj = JSObjectMakeFunctionWithCallback(globalContext, name, (JSObjectCallAsFunctionCallback)myFunc);
&&&&JSObjectSetProperty (globalContext, [windowObject JSObject], name, obj, 0,&NULL);
&&&&JSStringRelease(name);
那麽,只要 JS 调用 window.myFunc(),就可以取得们放在 myFunc 这个 C function 中回传的结果:
JSValueRef myFunc(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject,&size_t&argumentCount,&const&JSValueRef arguments[], JSValueRef* exception)
&&&&return&JSValueMakeNumber(ctx, 42);

我要回帖

更多关于 ios怎么清除缓存 的文章

 

随机推荐