发布时间:2019-11-01 14:32编辑:环球彩票登陆浏览(170)
这些更新已经可以在 Firefox 的 beta 版本中进行测试,Firefox66 将于2019年3月19日发布。
使用HTML5离线缓存管理库对部分手机浏览器的测试结果如下:
扩展的数据将会自动从 JSON 文件迁移到 indexedDB,开发人员不需要做任何操作,整个过程在 Firefox 66 安装过程中进行。使用 storage.local() API 的扩展会体会到其优点,特别当存储大结构的小更改时,广告屏蔽插件就是这样的数据结构。
在web前端开发的过程中,开发者localstorage的接口使用相对熟悉,故HTML5离线缓存管理库采用类localstorage的接口,异步的调用方式。
设置(key,value)值对
cache.setItem(key, value, suc, err)
key: string类型
value: string类型
suc:设置成功的回调函数
err:设置失败的回调函数
获取键值为key的值
cache.getItem(key, suc, err)
key: string类型
suc:获取成功的回调函数
err:获取失败的回调函数
删除键值为key的项
cache.removeItem(key, suc, err)
key: string类型
suc:删除成功的回调函数
err:删除失败的回调函数
清除所有记录
cache.clear(suc, err)
suc:清除所有记录成功的回调函数
err:清除所有记录失败的回调函数
Firefox66 中新变化的 已经上传至 Youtube,由于新的存储系统,使用安装了屏蔽广告的浏览器打开浏览器所需的时间比以前要少。
支持离线缓存是HTML5中的一个重点,离线缓存就是让用户即使在断网的情况下依然可以正常的运行应用。传统的本地存储数据的方式有 localstorage,sessionstorage和cookie。但是这些传统的方式有着致命的弊端。首先这些传统的存储方式的最大使用空间有 限,最多不超过5M;其次它们处理大规模的结构化数据的能力有限。鉴于传统方式的局限性,HTML5提出了三种新的离线缓存解决方案:Web SQL,indexedDB和File System。
其中Web SQL已经不包含在HMLT5规范中,成了一个独立的规范,Web SQL使用的SQL是SQLite。由于无法统一各个浏览器厂商实现的SQL语言,故Web SQL已经被废弃,由indexedDB取代,但是目前很多浏览器支持Web SQL,而且相对于indexedDB和 File System来说,Web SQL的效率最高,访问速度最快,稳定性也最好。
indexedDB也支持本地存储大量对象,并使用健壮的数据访问机制检索数据。但是目前支持Indexedb的浏览器很少,而且规范还在持续更新中,暂时还没有形成一个统一的标准。
在离线环境中,WebDataBase 虽然能够存储并有效地管理和维护客户端的数据集合,但是仍不能满足对包含大段数据文件的存储和多种不同格式 文件的保存,于是我们就需要离线的文件管理系统来维护我们工作了,基于HTML5的File System API 就充当这这个角色。File System非常适合大量的存储媒体文件。对于手机端而言,不同的浏览器的实现有所不同,有的浏览器是将文件写入到ROM中,如QQ手机浏览器,有的浏览 器是将文件写到SD卡中,如百度浏览器。所以理论上File System可用的空间非常大。
当您在 清单 4 中建立一个端口时,记得侦听 main.js
中的 watchthis
。在清单 7
中,您可以使用 addon.port.emit
从弹出页面发送消息:
更快的浏览速度,减少内存占用。
鉴于前端开发者比较习惯使用同步API,而Web SQL,indexedDB和File System都提供异步API,为了方便开发者,笔者为“HTML5 离线缓存管理库”提供了一个同步插件,方便开发者同步调用相关API,供参考。
“HTML5 离线缓存管理库”的同步插件使用说明:
优点:
(1) 方便开发者使用“HTML5 离线缓存管理库”进行同步操作,开发者可以像调用localstorage的方式同步调用相关接口。
(2) 调用者只需初始化一次,在初始化成功后便可进行余下操作。
(3) 由于开发者调用的接口其实都是从内存中取得数据,故速度比较快,flush等操作让后台处理。
缺点:
(1) 离线缓存方式fileSystem,indexdb和webSQL系统提供的API就是异步的方式,为了封装接口提供同步的API,必然有效率上的损失。 因为启动时会一次性加载离线缓冲库中的所有数据,故获取数据的时间会相应变长,对于少量数据,可以忽略不计,如果数据量特别大,即该插件会明显减慢加载速 度。
(2) 数据会全部拷贝到内存中,会占用部分浏览器内存。
建议:
该插件式为了方便同步使用离线缓存库,对于小数据量很方便,对于大数据来说,不推荐使用该插件,建议都采用异步的方式调用离线缓存库提供的接口API。
注:正常使用该库的时候必须保证synCache初始化成功。
tabs.on("ready", function checkForBlock(tab) { for (site in GB.getBlockedSites()) { if (tab.url.match(site)) { tab.url = GB.getWatchThisInstead(); } } });
1
2
3
4
5
6
7
8
|
tabs.on("ready", function checkForBlock(tab) {
for (site in GB.getBlockedSites()) {
if (tab.url.match(site)) {
tab.url = GB.getWatchThisInstead();
}
}
});
|
功能和性能类似于您在 Chrome 中所进行的操作,API 的使用也类似于 Chrome(调用一个方法,传递一个回调函数)
最后,将这个小徽章添加到浏览器右下角,创建一个 Widget
,如清单 6 所示:
require
语句var data = require("self").data, tabs = require("tabs"), GB = require("GB").GB, popupPanel = require("panel").Panel({ height: 500, contentURL: data.url("popup.html") });
1
2
3
4
5
6
7
|
var data = require("self").data,
tabs = require("tabs"),
GB = require("GB").GB,
popupPanel = require("panel").Panel({
height: 500,
contentURL: data.url("popup.html")
});
|
清单 3 中的语句依次告诉 main.js 为您提供:
GB
对象popupPanel
对象,该代码也可创建弹出窗口。此外,由于创建的弹出窗口也可作为选项页面,因而必须构建一些监听程序。在 Chrome 中,您可以利用后台页面并告诉它您想要做什么。在 Firefox 中,可以将消息发送到 main.js 文件来实现同样的目的。例如,清单 4 展示了一个将默认登录页面设置为用户选择屏蔽网站的监听程序:
即将发布的 Firefox 66 将使用 indexedDB 作为数据存储方式,放弃使用传统的 JSON 文件。
测试采用的写数据的方式是key-value对,其中value的值150k左右。
由于Web SQL,indexedDB和File System的可用空间容量与手机Temporary storage有关,故测试数据与手机机型和浏览器本身的状态有关,故上述数据仅供参考。测试的过程中还发现有些浏览器HTML5跑分,分数虽然拿到了, 但是实际并没有完全实现相关标准。
测试结果显示,手机浏览器对Web SQL,indexedDB和File System支持情况参差不齐,除了chrome支持所有的三种标准之外,其它的手机浏览器支持都不全,对于开发者来说,如果想要用到这些技术,必须先探 测浏览器是否支持该标准,只有支持了才可以使用相关的API。为了使开发者透明地使用底层的离线缓存空间,使用者不用自己去测探浏览器究竟支持哪种或者哪 几种标准,现在作者开发了一个HTML5离线缓存管理库,用户便可以像调用localstorage一样调用相关的接口即可获取数据,为开发者提供最大的 便利。
Firefox 扩展被称为附件。Chrome、Safari 和 Internet Explorer 都使用扩展 这一术语。本系列在提及 Firefox 附件时将交替使用这两个术语。
对于本文,您需要下载和安装 Firefox V12 或更高版本(参阅 参考资料)。(本文示例也是基于 Firefox V12)您也需要一些可以编辑 HTML、CSS 和 JavaScript 的工具。如果您有使用 Firefox 或者 Firefox 附件的经验将会很有帮助。如果没有这方面的经验,那么请浏览 Mozilla Add-ons 页面上提供的扩展(参阅 参考资料)。试用一下本文提供的几个上下文扩展。
您的参考文档是 Mozilla Add-on SDK 开发人员指南(参阅 参考资料)。您可使用 Add-on Builder( 一个基于 Web 的工具,用于构建 Firefox 扩展)完成大多数工作。Add-on Builder 是 Jetpack(一个 Firefox 项目)的一部分。Jetpack 的目的是使仅使用 HTML、CSS 和 JavaScript 编写扩展变得更为容易(正如您为 Chrome 扩展所做的一样)。也可使用 其他方法 来构建 Firefox 扩展。
从 下载 部分获取完整源代码。
对于普通的用户来说,这种变化意味着扩展将会网页加载得更快,同时减少 Firefox 内存占用量。当你打开更多的标签时,浏览器会消耗越来越多的内存,例如 Google Chrome。
HTML5离线缓存管理库采用的优先适配的策略,优先级为Web SQL > File System> indexedDB >localstorage。即js会自动对浏览器就行检测,如果发现支持web SQL,则使用web SQL,如果不支持,则接着检测File System,如果支持则会使用File System,以此类推。
至于为什么将优先级设置为:web SQL > File System> indexedDB >localstorage,主要是基于以下几方面做考虑:
为了保证对外提供的是统一的接口,接口传入的数据格式是key-value对的形式,但是由于File System本身是以文件的方式存储数据,所以不太适合处理key-value这类数据。
本库采用的数据存储方式是将key-value保存为JSON格式,通过JSON.stringify将其转化为字符串,并保存到文件中,读取的时候,通过JSON.parse将文件中数据解析为JSON格式。
为了提高File System的存取效率,采用了两种优化策略。首先将数据存于多个文件之中,根据key建立hash映射,每次读取数据,直接从相应的文件中取,这种方式 相对于存到一个文件的方式优点是,文件小,故每次读取的数据量小;其次采取缓存的策略,初始化的时候,将文件读取到内存之中,之后每次读取数据的时候直接 从内存中取数据即可,这样相比于每次直接从文件中读取数据,效率得到了极大的提升,当更改数据的时候会将缓存中的数据flush到文件中。
回忆一下,Gawkblocker 支持您(以及其他用户)屏蔽某些您不喜欢访问的域,比如耗时的博客。Gawkblocker 有以下组件:
在 Chrome 中,Gawkblocker 扩展将向每个选项卡或窗口添加一个监听程序,并与黑名单进行匹配,这会将屏蔽的 URL 重定向到一个本地页面。现在,您将学习 Gawkblocker 扩展在 Firefox 中如何变化。
Gawkblocker 以特定的方式扩展至浏览器,进行一些将在其他扩展中进行的特定工作。正如 第 1 部分 所述,您需要回答以下这些问题:
完成 Firefox 的 Gawkblocker 构建流程后就可以回答这些问题。
HTML5离线缓存管理库的同步插件链接:
目前,“手机酷站”iphone版使用了"HTML5离线缓存管理库"和“同步插件”,相关链接如下:
构建 Add-on Builder
界面的完整过程不在本文的讨论范围之内,但是在文件结构中有两点需要注意。Lib
目录是使用 require
导入库时 Firefox 所要查找的目录。您可以将
Gawkblocker 的核心 JavaScript 类放在该目录下。Data
目录是存放图像、HTML、CSS 和扩展可能提供的其他资产的位置。
当构建一个附件并对其进行测试时,可能会提示您安装 Add-on Builder 帮助程序。该帮助程序可在开发过程中卸载和安装附件。
由于HTML5相关标准在持续更新中,API随着标准的跟进,也有所变化,如下是一些比较大的改变。
File System
BlobBuilder构造函数被启用,应该使用Blob构造函数,例如:
旧的调用方式:
var bb = new BlobBuilder();
bb.append(JSON.stringify(t.cache[name]));
write.write(bb.getBlob('text/plain'));
新的调用方式:
var bb = new Blob([JSON.stringify(t.cache[name])], {type: "text/plain"});
write.write(bb);
Web SQL*
*
setVersion()方法被废弃,这导致我们在创建数据库和createObjectStore的流程有一些变动,而且多了一些新的回调方法。
//注意区别以前的方法,这里第二个参数不再是description,而是数据库版本号
var request = indexedDB.open('mydb',1);
request.onsuccess = function(e) { //数据库打开成功回调
DB.db = e.target.result; //我们用DB.db来存放indexdb
callback();
};
//第一次打开数据库或数据库升级时会触发,完成后根据情况触发success或者error
request.onupgradeneeded = function(e){
DB.db = e.target.result;
var db = DB.db;
//createObjectStore,以前需要在setVersion时才能执行。
if(!DB.db.objectStoreNames.contains('notes')){
// create object store
var store = db.createObjectStore('notes', {keyPath:'id', autoIncrement:true})
store.createIndex('updated', 'updated', { unique: false });
}
};
request.onerror = function(e){ //数据库打开错误回调
console.log(e);
}
popupPanel.port.on("watchthis", function () { GB.setWatchThisInstead(); console.log("watchthis"); });
1
2
3
4
|
popupPanel.port.on("watchthis", function () {
GB.setWatchThisInstead(http://www.youtube.com/watch?v=N-uyWAe0NhQ);
console.log("watchthis");
});
|
在我们讨论弹出页面时,也可以过一会将消息传递到该端口。
在 main.js 文件中,Gawkblocker 也可以访问选项卡以查看用户想要屏蔽哪个 URL(如果有的话)。清单 5 显示侦听选项卡以进行更新的代码:
要分发一个打包的扩展,从 Add-on Builder 下载。单击 Download 图标,获取任何人都可以安装的 XPI 文件。您也可以通过您希望的方式(邮件、托管、安装程序以及其他方法)分发。但是您需要负责处理更新和托管。
popupPanel.port.on("pop", function () { popupPanel.port.emit("blocklist", GB.getBlockedSites()); ... });
1
2
3
4
|
popupPanel.port.on("pop", function () {
popupPanel.port.emit("blocklist", GB.getBlockedSites());
...
});
|
在弹出对象中,可以侦听和修改页面,如清单 9 所示:
HTML5离线缓存管理库的测试链接:
在 第 1 部分 中,已经为 Gawkblocker 编写了一个看上去合理的可移植核心类文件。现在,如果在 Firefox 扩展中使用,您就会发现这个类文件实际上非常方便。
事实证明,您必须进行一些重要改变:
simple-storage
扩展 API 代替 localStorage
GB
对象添加到 exports
在 第 1 部分 的类文件中,定义了一个 Storage Manager 对象(名为 SM
)—
一个 localStorage
包装程序 — 来处理会话间的数据持久化。该代码在
Firefox 扩展内不能运行。相反,Firefox 提供一个名为 simple-storage
的
API,为您实现数据持久化。您可以轻松地更新 第 1 部分 中的 Storage Manager
对象,如清单 1 所示:
使用HTML5离线缓存库的测试页面如下:
使用方法:
1.测试setItem
主要测试setItem接口,设置key-value。
2.测试getItem
主要测试getItem接口,根据用户输入的key,点击“确定”,查询对应的记录,如果查询不到对应的记录,value框为空;如果查询到对应的记录,value框中显示查询的结果。
3.测试removeItem
主要测试removeItem接口,用户输入key,点击“确定”后删除key对应的记录。
4.测试clear
主要测试clear接口,点击“确定”,删除所有的记录。
5.自动测试
连续写入key-value数据,其中key为“1”,“2”,“3”递增,value为160.6k的固定字符串。点击“开始”,连续写入该 key-value数据,直到点击“结束”或者离线缓存写满为止;点击“结束”,停止自动写数据。如果重复“开始”操作,需要刷新页面。
所有相关链接如下:
"HTML5离线缓存管理库":
“同步插件”:
demo页面:
线上应用/“手机酷站”iphone版:
原文地址:
每个浏览器都有其自己的支持者、批评者、优势和劣势。它们的共同点是人们将越来越多的时间花费于其中。本系列文章将介绍如何为 Chrome、Firefox 和 Safari 构建相同的基础扩展。您将了解到扩展每个浏览器是什么样子,执行这些常见任务是困难还是简单,以及如何发布您的扩展。在本文中,您将构建一个 Firefox 扩展。
在 Chrome 中,可将重定向发送至部分扩展中的登录页面。Firefox 不会这样做,而是直接将它们发送到源页面(您在登录页面嵌入的 YouTube URL:“Hey You! Don’t Watch That! Watch This!” ) 。
可以在 main.js 中设置重定向初始条件,如清单 10 所示:
当使用 Add-on Builder 时,Firefox 会使得测试扩展变得较为容易。您会得到一个错误控制台、一个测试按钮和一个 Add-on Builder 帮助程序,每次保存时这个帮助程序就会重新加载扩展。图 5 展示了正在运行的 Add-on Builder 帮助程序:
除了本文展示的流程之外,也可以选择其他方法来为 Firefox 构建扩展。您可以下载 SDK 文件,Add-on Builder 可直接从 Developer Hub(参阅 参考资料)获取该文件。下载 SDK 文件,以便您可以在构建附件时选择使用 IDE。
您也可以构建一个传统的(或经典的 或 XUL)扩展。以这种方法构建扩展存在缺陷:安装扩展需要重启,编写扩展的过程较为复杂。但好处是您可以修改浏览器,这是使用 Add-on Builder 或 SDK 所不能实现的功能。例如,除了 Add-on 栏之外,也可以使用 XUL 将扩展图标放置到位。您可以在 Mozilla Development Network 上阅读有关 XUL 扩展的更多信息(参阅 参考资料)。
使用 Add-on Builder 构建的 Firefox 扩展可使用 CommonJS 约定导入所需的库。扩展中可以包括 HTML、CSS 和 JavaScript 文件的任意组合,但都是以 main.js 文件开始。
main.js 文件是 Firefox 扩展的核心。该文件告诉 Firefox 导入哪个模块,以及在何处执行扩展的初始化任务。回顾 第 1 部分 中的 Chrome 扩展。main.js 类似于 background.html 页面。main.js 在后台运行,与 Firefox 没有直接交互,而且在启动过程中仅运行一次。
也可以将大量页面显示在 Firefox
扩展的 panel
中。可以将这类页面作为一个弹出和选项窗口的组合页面,如图
1 所示:
在 Chrome 中,使用后台页面文件检查 URL,查看是否屏蔽。在 Firefox 中,在
main.js 文件中进行这一项检查。在 main.js
进行任何操作之前,必须使用一系列 require
语句导入计划使用的模块和
API,如清单 3 所示:
addon.port.on("blocklist", function (blocklist) { $("#blockedlist").children().remove(); $.each(blocklist, function (index, value) { $("#blockedlist").append("<div class='siterow' title='" value "'> <div class='sitename'>" index "</div><span class='sitedesc'> : " value "</span></div>"); showBlockList(blocklist); }); });
1
2
3
4
5
6
7
8
9
|
addon.port.on("blocklist", function (blocklist) {
$("#blockedlist").children().remove();
$.each(blocklist, function (index, value) {
$("#blockedlist").append("<div class='siterow' title='" value "'>
<div class='sitename'>" index "</div><span class='sitedesc'> :
" value "</span></div>");
showBlockList(blocklist);
});
});
|
弹出页面请求 main.js
获取屏蔽站点列表。然后通过该列表进行迭代并附加屏蔽站点细节来在弹出窗口中显示 div
。
Widget
require("widget").Widget({ id: "GBBrowserAction", label: "Gawkblocker", contentURL: data.url("images/GB-19.png"), panel: popupPanel });
1
2
3
4
5
6
|
require("widget").Widget({
id: "GBBrowserAction",
label: "Gawkblocker",
contentURL: data.url("images/GB-19.png"),
panel: popupPanel
});
|
当 main.js 文件一切就绪后,就可以深入研究弹出页面的变化。
您的 Firefox 附件已经完成了,现在应该看看如何给出问题的答案,与 Chrome 中的答案相比:
在浏览器 UI 中拥有一席之地有多难?
如果想要在浏览器底部的 Add-on Bar 中进行持久化,那么与 Chrome
中的难度相差无几。可以通过在 main.js 中创建 Widget
来实现。
持久化浏览器会话间的数据涉及到什么?
使用特定于 Firefox 的 simple-storage
API。如果想要让一个 Storage
Manager 类在 Chrome 和 Firefox 中运行,那么需要实施一些特性检测
不同的扩展部分彼此如何通信?
使用 port
创建这类通信并建立监听程序和发送程序。
您对用户数据的研究有多深入?
用户没有显式权限,所以您至少仍然可以访问用户访问的每个 URL。这非常重要。
SM
对象var SM = (function () { var SS = require("simple-storage"); var my = {}; my.get = function (key) { return SS.storage[key]; } ... return my; }());
1
2
3
4
5
6
7
8
9
10
11
12
|
var SM = (function () {
var SS = require("simple-storage");
var my = {};
my.get = function (key) {
return SS.storage[key];
}
...
return my;
}());
|
GB
对象不需要改变,但是您必须依照 CommonJS
约定将其添加到 exports
。清单 2 的最后一行处理该任务:
要使用 Add-on Builder,根据图 2 所示以及在 中提供的信息,必须完成注册过程。然后,可以登录到 Add-on Builder 创建自己的附件。
扩展准备就绪后,有几种方法可供选择来进行分发。如果您在配置文件中将 Add-on 标记为公开,就可以为潜在用户发送一个链接,这样他们就可以从链接安装 Add-on。您也可以通过下载的方式分发一个打包的扩展,或者将扩展上传到 addons.mozilla.org。
if (!GB.getWatchThisInstead()) { GB.setWatchThisInstead(""); }
1
2
3
|
if (!GB.getWatchThisInstead()) {
GB.setWatchThisInstead("http://www.youtube.com/watch?v=N-uyWAe0NhQ");
}
|
图 4 显示了重定向登录页面:
扩展仅仅只是在 Firefox 附件中进行操作的开始。距离测试 Add-on Builder 可给予您的极限还很远。如果想要深入研究,这里可提供更多信息。在 Add-on Builder、Add-on SDK 和更为复杂的 XUL 扩展之间,您可通过多种方法将触角延伸至 Firefox 。
敬请期待本系列第 3 部分,其中您可以将 Gawkblocker 移植到 Safari 浏览器中。
赞 收藏 评论
将一个扩展上传到 addons.mozilla.org 的过程与分发您自己的扩展相比涉及的技术较少,但是您需要经过一个审核流程和一些其他障碍。要完成这一过程,在配置文件中单击紧挨着扩展的 upload to AMO 链接,如图 6 所示:
在 Chrome
扩展中,弹出页面仅仅是一个屏蔽域列表。现在正是对该设计进行迭代的良好时机。对于
Firefox
扩展,将功能从选项页面迁移到弹出页面。然后将一个单击处理程序添加到弹出页面中显示的标题上,该页面将选项 div
和域列表互换。该选项允许用户站点访问屏蔽列表,并为屏蔽站点提供重定向地址。图
3 显示了 Gawkblocker 弹出页面中的选项:
GB
对象添加到 exports
var GB = (function (SM) { var my = {}; my.blockTheseSites = { "gawker.com" : "Gawker Media", "io9.com" : "SciFi Blog", "gizmodo.com" : "Gadget Blog", ... } ... }(SM)); exports.GB = GB;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
var GB = (function (SM) {
var my = {};
my.blockTheseSites = {
"gawker.com" : "Gawker Media",
"io9.com" : "SciFi Blog",
"gizmodo.com" : "Gadget Blog",
...
}
...
}(SM));
exports.GB = GB;
|
由于变化微乎其微,所以您可以轻松地将它们合并到 GB
对象,使其在 Firefox
或 Chrome 中均可运行(我将其留给您,可根据自己项目的需要进行实现。)
将文件重名为 GB.js,然后上传到 Lib 目录。这样您就可以看到在 main.js 中如何使用该对象了。
addon.port.emit
从弹出页面发送消息$("#watchthis").click(function () { addon.port.emit("watchthis"); $("#status").text("YOU'RE GOOD MATE. "); });
1
2
3
4
|
$("#watchthis").click(function () {
addon.port.emit("watchthis");
$("#status").text("YOU'RE GOOD MATE. ");
});
|
您也可以通过使用 port
侦听该列表,以便从 main.js
中获取屏蔽站点列表。在 main.js
中,当弹出页面告诉您一切准备就绪时就发送该列表,如清单 8 所示:
原文出处: IBM Developerworks
您也可以使用 Firefox 中的内容脚本,与在 Chrome
中使用的方法基本相同。内容脚本是可以添加到 Web 页面进行交互的 JavaScript
文件。在 Firefox 中,内容脚本可在页面上下文中有效地运行。但是访问 DOM
或从 DOM
中获取都可以进行代理以防止出现安全问题。内容脚本可使用 port
与其他扩展进行通信。
对于 Gawkblocker,您可以使用:
Firefox 实现比 Chrome 略微简单点,但是用户体验效果实际上是一样的。您可以从我的 Add-on Builder 配置文件(参阅 参考资料)中下载一个正在运行的 Gawkblocker 文件来查看活动的扩展,和我在此处介绍的其他部分一样。
遵照这里的上传指令。
本文由环球彩票登陆发布于环球彩票登陆,转载请注明出处:HTML5 离线缓存管理库环球彩票登陆
下一篇:没有了