奔跑中的奶酪

Firefox 火狐不完全开发手册

Firefox 火狐不完全开发手册

火狐开发

国内 Firefox 开发的教程少之又少,

要么全是英文的,要么太过官方,要么过于老旧,要么过于零散。

所以奶酪整理了一份详实接地气的 Firefox 开发手册,包括案例、源代码、源文件,还包括火狐相关的优秀资源。

希望可以给喜欢 Firefox 的人一些参考, Firefox 会因为有你的加入,而变得更好。

火狐开发

自从 Firefox 57.0 启用了全新框架,Firefox 的很多功能都受到了限制。

然而尽管如此,Firefox 还是有非常大的自定义空间,随着更多 API 的加入,Firefox 也会变得更加 Firefox。

1、要不要用 Firefox 开发者版本?

可以用,也可以不用。开发者版的好处在于它支持直接双开Firefox,并可直接安装未签名拓展和修改的拓展。

2、将官方安装版 Firefox 便捷化

利用 adonais 开发的工具 libportable,可以将 Firefox 便携化,可以避开配置文件之间的干扰。

3、如何双开 Firefox 配置?

• 常规方法:

新建一个快捷方式,右键点击,在“目标”一栏,空上一格,再加上 "-no-remote -p"(不包括分号)。

就会调出用户配置的对话框,你可以创建和删除用户配置。

如果在 "-no-remote -p" 后,再空一格加上"用户配置名称",就可以跳过选择用户配置对话框,直接一键双开。

• 快捷方法:

我写了一个 DOS 批处理文件,让上述过程一键启用,点击下载

• 简单方法:

使用拓展 ContextSearch web-ext 来调用多个浏览器和配置,使用方法 看这里

4、使用 Firefox 自开发者工具

按 F12 打开“开发者工具”。

点击“齿轮”图标,在“高级设置”里勾选“启用浏览器界面和附加组件调试工具箱”和“启用远程调试器”,然后在菜单栏里的 "工具" 中“Web开发者”选择“浏览器工具箱”。

三道杠—> Web开发者—>查看器(Ctrl+Shift+C 或 F12)
三道杠—> Web开发者—>浏览器工具箱(Ctrl+Shift+Alt+I)

5、如何安装未签名拓展?

使用 Firefox 开发者版本可以直接安装

如果使用的是正式版的话,打开 about:debugging 也可以临时安装本地扩展,但如果想要永久安装的话。

1)、用压缩软件解压 .xpi 文件,找到文件 manifest.json,将其中的 ID 修改为其他值,接着重新打包为 .zip 文件,
2)、打开 Firefox 开发者中心 ,登录帐号,在提交上传附加组件时,选择“我自己托管”。
3)、这时可能会提示一些附加组件验证错误信息,点击查看“完整验证报告”,接着修正提示的严重错误。
4)、修改后,重新打包,重新上传,后续可能会出现“您可能需要提交源代码”的问题,选择“不提交”。
5)、完成。

6、如何关闭 Firefox 自动更新?

在 firefox.exe 所在目录,新建一个名为 distribution 的文件夹,里面创建一个 policies.json 文件,内容:

{
"policies": {
"DisableAppUpdate": true
}
}

7、如何分享自己的配置?

不正确的配置分享,可能会导致个人私密的泄露,在分享你的配置前,你需要:

1)、按快捷键 Shift + Ctrl + Del,删除全部浏览记录。
2)、注销已登录的 Firefox 帐号,包括 Firefox Account,Pocket 等所有登录的同步帐号。
3)、打开“选项 —> 隐私与安全”,点击 “已经已保存的登录信息”,如果有,则删除。
4)、删除配置文件夹下的以下信息,价格可参考《浏览器故障》。
5)、又或者,你可以单独新建一个仅用于开发的配置。

常用工具

Firefox开发者版 和正式版区别不大,但无需命名可以直接双开Firefox
Line Icons V系列Firefox所用到的线性图标及源文件
Notepad2 编码工具,还有同类软件Notepad++,Sublime Text 3
Beyond Compare 文件对比工具
libportable 让官方安装版Firefox变成便携版
DB Browser for Sqlite Sqlite 查看编辑器
Regester 正则表达测试工具

常用代码

Firefox Quantum 由于 API 的变化,许多脚本代码都失效了,奶酪重新修复并整理了一份兼容 Firefox Quantum (Firefox 67+) 的列表清单。测试方法是使用快捷键 Shift + F4,在弹出的代码草稿纸窗口中将选项“环境”更改为“浏览器”,再将代码粘贴到上面,点击“执行—>运行”即可(Ctrl + R)。

一、导航命令:

// 1,后退
document.getElementById("Browser:Back").doCommand();
或者 getWebNavigation().canGoBack && getWebNavigation().goBack();
// 2,前进
document.getElementById("Browser:Forward").doCommand();
或者 getWebNavigation().canGoForward && getWebNavigation().goForward();
// 3,刷新当前页面
document.getElementById("Browser:Reload").doCommand();
// 4,跳过缓存刷新当前页面
document.getElementById("Browser:ReloadSkipCache").doCommand();
// 5,刷新所有页面
gBrowser.reloadAllTabs();
// 6,主页
BrowserHome(); 或者 document.getElementById("Browser:Home").doCommand();
// 7,停止载入当前页面
document.getElementById("Browser:Stop").doCommand();
// 8,添加书签
document.getElementById("Browser:AddBookmarkAs").doCommand();
// 9,打开文件
document.getElementById("Browser:OpenFile").doCommand();
// 10,保存文件
document.getElementById("Browser:SavePage").doCommand();
// 11,打印预览
document.getElementById("cmd_printPreview").doCommand();
// 12,打印
document.getElementById("cmd_print").doCommand();
// 13,显示/隐藏书签工具栏
var bar = document.getElementById("PersonalToolbar"); setToolbarVisibility(bar, bar.collapsed);
// 14,显示/隐藏菜单栏
document.getElementById("toolbar-menubar").setAttribute("autohide", document.getElementById("toolbar-menubar").getAttribute("autohide") == "true" ? "false" : "true");
// 15,显示/隐藏导航栏
var toolbar = document.getElementById("nav-bar"); toolbar.collapsed = !toolbar.collapsed; document.persist(toolbar.id, "collapsed");
// 16,显示/隐藏查找栏
if ("isFindBarVisible" in gFindBar) gFindBar.isFindBarVisible() ? gFindBar.closeFindBar() : gFindBar.onFindCmd(); else gFindBar.hidden ? gFindBar.onFindCommand() : gFindBar.close();
或者 gFindBar.hidden ? gFindBar.onFindCommand() : gFindBar.close();
// 17,清除搜索栏内容
document.getElementById("searchbar").value = "";
// 18,重启浏览器
Services.startup.quit(Services.startup.eAttemptQuit | Services.startup.eRestart);
// 19,关闭浏览器
goQuitApplication();
// 20,打开书签管理
document.getElementById("Browser:ShowAllBookmarks").doCommand();
// 21,打开Cookies管理
window.open("chrome://browser/content/preferences/siteDataSettings.xul ", "Browser:Cookies", "chrome,resizable=yes");
// 22,打开密码管理
window.open("chrome://passwordmgr/content/passwordManager.xul", "Toolkit:PasswordManager", "chrome,resizable=yes");
// 23,打开证书管理
window.open("chrome://pippki/content/certManager.xul", "mozilla:certmanager", "chrome,resizable=yes,all,width=600,height=400");
// 24,打开下载窗口
BrowserDownloadsUI();
// 25,打开我的足迹窗口
PlacesCommandHook.showPlacesOrganizer('History');

二、窗口命令:

// 1,新建窗口
document.getElementById("cmd_newNavigator").doCommand();
或者 OpenBrowserWindow();
// 2,关闭窗口
document.getElementById("cmd_closeWindow").doCommand();
// 3,窗口最小化
window.minimize(); 或者 minimize();
// 4,窗口常规化和最大化间切换
window.windowState == window.STATE_MAXIMIZED ? window.restore() : window.maximize();
// 5,窗口全屏
document.getElementById("View:FullScreen").doCommand();
// 6,在小窗口打开指定页面
格式是:toOpenWindowByType('标题', '地址);,比如 打开about:config 页面,
toOpenWindowByType('about:config', 'about:config');
如果要指定窗口大小,
window.open("about:config", "about:config", "chrome,resizable=yes,centerscreen").resizeTo(800, 600);
// 7,窗口占用屏幕左半部分
resizeTo(screen.availWidth / 2, screen.availHeight, moveTo(0, 0));
// 8,窗口占用屏幕右半部分
resizeTo(screen.availWidth / 2, screen.availHeight, moveTo(screen.availWidth / 2, 0));
// 9,显示所有标签页缩略图
allTabs.open(); // 可能失效

三、标签命令:

// 1,新建标签
document.getElementById("cmd_newNavigatorTab").doCommand();
或者 BrowserOpenTab();
// 2,关闭标签
document.getElementById("cmd_close").doCommand();
或者 gBrowser.removeCurrentTab();
// 3,恢复最后一次关闭的标签
document.getElementById("History:UndoCloseTab").doCommand();
// 4,将标签移动到左边
var tab = gBrowser.selectedTab; var pos = Math.max(0, tab._tPos - 1); gBrowser.moveTabTo(tab, pos);
// 5,将标签移动到右边
var tab = gBrowser.selectedTab; var pos = Math.max(0, tab._tPos + 1); gBrowser.moveTabTo(tab, pos);
// 6,激活上一个标签页
gBrowser.tabContainer.advanceSelectedTab(-1, true);
// 7,激活下一个标签页
gBrowser.tabContainer.advanceSelectedTab(1, true);
// 8,激话第一个标签页
gBrowser.selectedTab = gBrowser.tabContainer.firstChild;
// 9,激话最后一个标签页
gBrowser.selectedTab = gBrowser.tabContainer.childNodes[gBrowser.tabContainer.childNodes.length-1];
// 10,复制当前标签页
duplicateTabIn(gBrowser.selectedTab, 'tab');
// 11,关闭左边标签页
var tab = gBrowser.selectedTab.boxObject.previousSibling; if(tab) gBrowser.removeTab(tab);
// 12,关闭右边标签页
var tab = gBrowser.selectedTab.boxObject.nextSibling;if(tab) gBrowser.removeTab(tab);
// 13,关闭左侧标签页
for (let i = gBrowser.selectedTab._tPos - 1; i >= 0; i--) if (!gBrowser.tabs[i].pinned){ gBrowser.removeTab(gBrowser.tabs[i], {animate: true});}
// 14,关闭右侧标签页
gBrowser.removeTabsToTheEndFrom(gBrowser.selectedTab);
// 15,关闭其他标签页
gBrowser.removeAllTabsBut(gBrowser.selectedTab);
// 16,关闭所有标签页
gBrowser.removeAllTabsBut(gBrowser.selectedTab); gBrowser.removeCurrentTab();
// 17,在当前标签页右边新建标签页:
var x = gBrowser.selectedTab._tPos + 1; gBrowser.moveTabTo(gBrowser.selectedTab =gBrowser.addTab("https://www.baidu.com", {triggeringPrincipal: gBrowser.contentPrincipal}), x)
// 18,关闭重复标签页
var num = gBrowser.browsers.length;
var msg = "";
for (var i = 0; i < num; i++) { var a = gBrowser.getBrowserAtIndex(i); try { for (var j = 0; j < num; j++) { if (j != i) { var b = gBrowser.getBrowserAtIndex(j); if (a.currentURI.spec == b.currentURI.spec) { if (msg != "") msg += "\n"; msg += b.currentURI.spec; gBrowser.removeTab(gBrowser.tabContainer.childNodes[j]); num--; j-- } } } } catch (e) { Components.utils.reportError(e) } } if (msg != "") {} else alert("\u6CA1\u6709\u91CD\u590D\u6807\u7B7E\u9875");

四、页面命令:

// 1,向上滚动一屏
goDoCommand("cmd_scrollPageUp");
// 2,向下滚动一屏
goDoCommand("cmd_scrollPageDown");
// 3,向右滚动一屏
goDoCommand('cmd_scrollRight');
// 4,向左滚动一屏
goDoCommand('cmd_scrollLeft');
// 5,滚动至页首
goDoCommand("cmd_scrollTop");
// 6,滚动至页尾
goDoCommand("cmd_scrollBottom");
// 7,查看页面源代码
document.getElementById("View:PageSource").doCommand();
// 8,查看页面信息
document.getElementById("View:PageInfo").doCommand();
或者 BrowserPageInfo();
// 9,进入阅读模式
var url = "about:reader?url=" + gBrowser.currentURI.spec; gBrowser.addTab(url, {triggeringPrincipal: gBrowser.contentPrincipal});
// 10,关闭当前标签声音
gBrowser.selectedTab.toggleMuteAudio();

五、工具栏命令:

// 1,打开下载界面
document.getElementById("Tools:Downloads").doCommand();
// 2,打开附加组件
document.getElementById("Tools:Addons").doCommand();
或者 BrowserOpenAddonsMgr();
// 3,删除历史记录
document.getElementById("Tools:Sanitize").doCommand();
// 4,打开设置
openPreferences();

六、侧边栏命令:

// 1,侧边栏打开书签栏
SidebarUI.toggle("viewBookmarksSidebar");
// 2,侧边栏打开历史记录
SidebarUI.toggle("viewHistorySidebar");
// 3,关闭侧边栏
var sidebarBox = document.getElementById("sidebar-box"); if (!sidebarBox.hidden) toggleSidebar(sidebarBox.getAttribute("sidebarcommand")); //可能失效
// 4,侧边栏打开当前网页
安装拓展 Sidebar View,然后调用代码:
document.getElementById("side-view_mozilla_org-menuitem-_open-link-in-sidebar").click();

七、地址栏命令:

// 1,在当前标签打开网页
gBrowser.loadURI("https://www.baidu.com", {triggeringPrincipal: gBrowser.contentPrincipal});
// 2,在新标签打开网页 (后台)
gBrowser.addTab("https://www.baidu.com",{triggeringPrincipal: gBrowser.contentPrincipal});
// 3,在新标签打开网页 (前台)
gBrowser.selectedTab = gBrowser.addTab("https://www.baidu.com",{triggeringPrincipal: gBrowser.contentPrincipal});
// 4,在当前标签右侧打开网页
var x = gBrowser.selectedTab._tPos + 1; gBrowser.moveTabTo(gBrowser.selectedTab =gBrowser.addTab("https://www.baidu.com",{triggeringPrincipal: gBrowser.contentPrincipal}), x);
// 5,复制当前标签页标题
var gClipboardHelper = Components.classes['@mozilla.org/widget/clipboardhelper;1'].getService(Components.interfaces.nsIClipboardHelper); gClipboardHelper.copyString(gBrowser.contentTitle);
// 6,复制当前标签页地址
var gClipboardHelper = Components.classes['@mozilla.org/widget/clipboardhelper;1'].getService(Components.interfaces.nsIClipboardHelper); gClipboardHelper.copyString(gBrowser.currentURI.spec);
// 7,复制当前标签页标题和地址
(function(){var gClipboardHelper=Components.classes['@mozilla.org/widget/clipboardhelper;1'].getService(Components.interfaces.nsIClipboardHelper); var txt="";var url=gBrowser.currentURI.spec;var title=gBrowser.contentTitle;txt+=title+"\n"+url+"\n";gClipboardHelper.copyString(txt)})();
// 8,复制当前标签页源代码
(function(){var gClipboardHelper = Components.classes['@mozilla.org/widget/clipboardhelper;1'].getService(Components.interfaces.nsIClipboardHelper); var txt="";var url=gBrowser.currentURI.spec;var title=gBrowser.contentTitle;txt+=""+title+""+"\r";gClipboardHelper.copyString(txt);})();
// 9,复制当前标签页MD源代码
(function(){var gClipboardHelper = Components.classes['@mozilla.org/widget/clipboardhelper;1'].getService(Components.interfaces.nsIClipboardHelper); var txt="";var url=gBrowser.currentURI.spec;var title=gBrowser.contentTitle;txt+="["+title+"]"+"("+url+")";gClipboardHelper.copyString(txt);})();
// 10,复制所有标签页标题
var gClipboardHelper = Components.classes['@mozilla.org/widget/clipboardhelper;1'].getService(Components.interfaces.nsIClipboardHelper); var titles="";Array.slice(gBrowser.tabContainer.childNodes).forEach(function(tab){titles+=tab.label+"\n"});gClipboardHelper.copyString(titles);
// 11,复制所有标签页地址
var gClipboardHelper = Components.classes['@mozilla.org/widget/clipboardhelper;1'].getService(Components.interfaces.nsIClipboardHelper); var URLs="";Array.slice(gBrowser.tabContainer.childNodes).forEach(function(tab){var url=gBrowser.getBrowserForTab(tab).currentURI.spec;URLs+=url+"\n"});gClipboardHelper.copyString(URLs);
// 12,复制所有标签页标题和地址
var gClipboardHelper = Components.classes['@mozilla.org/widget/clipboardhelper;1'].getService(Components.interfaces.nsIClipboardHelper); var txt="";Array.slice(gBrowser.tabContainer.childNodes).forEach(function(tab){var url=gBrowser.getBrowserForTab(tab).currentURI.spec;txt+=tab.label+"\n"+url+"\n"});gClipboardHelper.copyString(txt);
// 13,复制所有标签页源代码
(function(){var gClipboardHelper=Components.classes['@mozilla.org/widget/clipboardhelper;1'].getService(Components.interfaces.nsIClipboardHelper);var txt="";Array.slice(gBrowser.tabContainer.childNodes).forEach(function(tab){var url=gBrowser.getBrowserForTab(tab).currentURI.spec;txt+=""+tab.label+""+"
"+"\r"});gClipboardHelper.copyString(txt)})();
// 14,复制所有标签页MD源代码
(function(){var gClipboardHelper=Components.classes['@mozilla.org/widget/clipboardhelper;1'].getService(Components.interfaces.nsIClipboardHelper);var txt="";Array.slice(gBrowser.tabContainer.childNodes).forEach(function(tab){var url=gBrowser.getBrowserForTab(tab).currentURI.spec;txt+="["+tab.label+"]"+"("+url+")\\"+"\r"});gClipboardHelper.copyString(txt)})();
// 15,打开剪切板内容
(function(){let url=readFromClipboard();try{switchToTabHavingURI(url,true)}catch(ex){var reg=/[a-zA-Z0-9][-a-zA-Z0-9]{0,62}(\.[a-zA-Z0-9][-a-zA-Z0-9]{0,62})+\.?/;if(!reg.test(url)){url='https://www.baidu.com/s?wd='+encodeURIComponent(url)}else{if(url.substring(4,0).toLowerCase()=="http"){url=encodeURIComponent(url)}else{url='http://'+encodeURIComponent(url)}}switchToTabHavingURI(url,true)}e.preventDefault();e.stopPropagation()});
// 16,一键打开常用标签组
var newtabs=["https://weibo.com/","https://www.inoreader.com/","https://www.twitter.com/","https://www.runningcheese.com/"];var i=0;while(i<=newtabs.length-1){gBrowser.selectedTab=gBrowser.addTrustedTab(newtabs[i]);i=i+1;};

八、其他命令:

// 1,模拟按钮点击
比如,模拟点击三道杠按钮,双引号之间的ID内容需要在当前界面可见。(包括下拉选项)
document.getElementById("PanelUI-menu-button").click();
或者 document.getElementById("PanelUI-menu-button").doCommand();
// 2,模拟键盘点击
比如,模拟点击回车键,DOM_VK_RETURN 代表 回车键,更多虚拟键码可参考 这里
window.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils).sendKeyEvent('keypress', KeyEvent.DOM_VK_RETURN, 0, 0); //可能失效
// 3,运行小书签命令
小书签的优点在于全平台兼容,各大浏览器都能运行,命令也非常多,可参考《中文网最全小书签合集》。比如,开启夜晚模式:
gBrowser.loadURI("javascript:(function(){var%20night=function(w){(function(d){var%20css='html{opacity:0.9!important;background:black!important;}body{background:white!important;}';var%20s=d.getElementsByTagName('style');for(var%20i=0,si;si=s[i];i++){if(si.innerHTML==css){si.parentNode.removeChild(si);return}};var%20heads=d.getElementsByTagName('head');if(heads.length){var%20node=d.createElement('style');node.type='text/css';node.appendChild(d.createTextNode(css));heads[0].appendChild(node)}})(w.document);%20for(var%20i=0,f;f=w.frames[i];i++){try{arguments.callee(f)}catch(e){}}};night(window)})();", {triggeringPrincipal: gBrowser.contentPrincipal});
// 4,运行相对路径文件 (以打开配置文件夹下的 user.js 为例)
FileUtils.getFile('ProfD',['user.js']).launch();
再比如打开脚本文件夹下的某个文件,代码是:(来自 File I/O
FileUtils.getFile('UChrm',['Local', 'Colors','Colors.exe']).launch();
// 5,运行绝对路径文件 (以打开IE为例)
var path="C:\\Program Files\\Internet Explorer\\iexplore.exe"; var file = Components.classes["@mozilla.org/file/local;1"].createInstance(Components.interfaces.nsIFile); file.initWithPath(path); file.launch();
// 6,使用其他浏览器打开当前页面 (以IE浏览器为例)
var path='C:\\Program Files\\Internet Explorer\\iexplore.exe';var file=Components.classes['@mozilla.org/file/local;1'].createInstance(Components.interfaces.nsIFile);file.initWithPath(path);var process=Cc['@mozilla.org/process/util;1'].createInstance(Ci.nsIProcess);process.init(file);process.run(false,[gBrowser.currentURI.spec],1);
// 7,运行系统文件 (以打开资源管理器为例)
var path ="..\\..\\explorer.exe"; var file = Components.classes["@mozilla.org/file/local;1"].createInstance(Components.interfaces.nsIFile);file.initWithPath(path.replace(/^\./, Components.classes["@mozilla.org/file/directory_service;1"].getService(Components.interfaces.nsIProperties).get("SysD", Components.interfaces.nsIFile).path));file.launch();
// 8,设置指定的整数值 (以设置链接以什么样的方式打开为例)
Services.prefs.setIntPref("browser.link.open_newwindow",3);
// 9,设置指定的字符串 (以设置默认主题为例)
// 字符串通常内容比较复杂,为避免不必要的错误,可以加上双引号。
Services.prefs.setCharPref("lightweightThemes.selectedThemeID","firefox-compact-light@mozilla.org");
// 10,设置指定的布尔值 (以设置侧边栏是否靠左为例)
Services.prefs.setBoolPref("sidebar.position_start",true);
// 11,布尔值切换 (以设置侧边栏靠左还是靠右为例)
var key = "sidebar.position_start"; Services.prefs.setBoolPref(key, ! Services.prefs.getBoolPref(key));
或者 Services.prefs.setBoolPref("sidebar.position_start", ! Services.prefs.getBoolPref("sidebar.position_start"));
如果在切换布尔值的时候,同时显示提醒的话
var key="sidebar.position_start";Services.prefs.setBoolPref(key,!Services.prefs.getBoolPref(key));if(getBoolPref(key)==true){alert('左侧打开侧边栏')}else{alert('右侧打开侧边栏')}
如果想让提醒显示在状态栏的话
var key="sidebar.position_start";Services.prefs.setBoolPref(key,!Services.prefs.getBoolPref(key));if(getBoolPref(key)==true){XULBrowserWindow.statusTextField.label="左侧打开侧边栏"}else{XULBrowserWindow.statusTextField.label="右侧打开侧边栏"}
// 12,根据键值来做 if 判断 (以侧边栏靠左时窗口常规化为例)
if (Services.prefs.getPrefType("sidebar.position_start") === true) {window.restore();} else {window.maximize();}
如果是多重判断的话用 &&,比如
(Services.prefs.getPrefType("general.useragent.override") == 0 && Services.prefs.getPrefType("general.platform.override") == 0) {window.restore();} else {window.maximize();}
// 13,重置指定键值 (以重置侧边栏停靠位置为例)
Services.prefs.clearUserPref("sidebar.position_start")
// 14,命令切换启用 (以显示或者隐藏查找栏为例)
gFindBar.open() || gFindBar.close();

注意事项:
(1). 以上代码如果太长不便于理解,可以借助 JS代码美化 工具来展开代码。
(2). 当引用的代码段有双引号时,使用 function() { 引用的代码 }; 来转义,有多重双引号时,外面一层用单引号。
(3). 当代码较长遇到隔断时,可以借助 JS代码净化 工具来压缩代码。
(4). 如果还是有隔断,可以使用 URL编码工具
(5). 你还可以通过使用”开发者工具箱“来查找更多命令,或者访问 MDN 开发者中心。

拓展资源

Mozilla MDN Mozilla 开发者网络
MDN Addons 开始编写你的第一个浏览器扩展
Mozilla Knowledge Base Mozilla 知识库
MozillaWiki Mozilla 产品开发指南
Mozilla Central Source Mozilla 源码索引
Bugzilla Main Page 火狐 Bug 反馈中心
Demos MDN MDN 开发网络技术演示
About:config entries about:config 说明
火狐参数目录 about:config 说明中文版
Ca-archive 传统拓展档案,下载已经被AMO移除了的传统拓展
Are We XBL Still? 新版Firefox API变化
火狐中文教程 非常详细,by @江3
Firefox Webext List 非常详细,WE拓展替代传统拓展进度表
DXR 源代码库
MozillaWiki Mozilla 项目Wiki文档
Web 技术文档 Firefox 开发所需语言技术
正则表达式 正则表达式入门教程
拓展推荐 奶酪2019年度最喜欢拓展

如何将 Chrome 拓展移植到 Firefox 上使用?

Firefox 支持 WebExtension API,它们大多数情况下与 Google Chrome 和 Opera 支持的扩展 API 兼容,因此使您的扩展在 Firefox 中运行只需很少的更改。如果一款拓展只有 Chrome 版,而没有 Firefox 版,那么我们可以尝试将其移植到 Firefox 浏览器上来。

1,我们可以使用 Moziila 官方提供的拓展兼容性测试网站 https://www.extensiontest.com,将后缀名为 .crx 的 Chrome 拓展上传检测。

2,将 .crx 的文件解压,然后重新压缩为 .xpi,接着上传至 附加组件开发者中心,同时选择“我自己托管”。

用户样式

Firefox 除了自带的“定制”功能外,你还可以通过强大的 userChrome.css 来自定义浏览器外观,Firefox 有着强大的自定义能力,这是其他任一一款浏览器都做不到的。

一、什么是 userChormeCSS

什么是 userChorme.css?

要理解它,首先要知道 Chrome 是什么意思,Chrome 是金属铬的意思,但在浏览器中指的是浏览器的框架,所以在 Firefox 的目录文件夹下会有 "chrome" 文件夹,谷歌的 Chrome 浏览器的命名就很讨巧,有点“面包牌面包”的意思。

这里我们延伸拓展一下,Firefox 默认有四个支持自定义功能的文件,它们都位于配置文件夹下的 “chrome” 文件夹里,总的说来就是:Chrome 代表浏览器界面,Content 代表网页内容,分别是:

userChrome.css -浏览器界面的样式表 (无管理拓展)
userContent.css -网页的样式表 (管理拓展:比如 xStyle)
userChrome.js -浏览器界面的脚本 (无管理拓展)
userContent.js -网页的脚本 (管理拓展:比如 ViolentMonkey)



比如,通过 userChrome.css 修改浏览器界面字体的大小:
window { font-size: 5mm !important; font-family: helvetica !important;}

比如,通过 userContent.css 修改网页字体的大小:
html>body { font-size: 100% !important; line-height: normal !important;}

二、如何编写用户样式

userChrome.css 位于浏览器配置文件夹下的“chrome”文件夹下,如果没有,你则需要手动新建。每次启动 Firefox,Firefox 都会加载这个样式表应用到全局浏览器中去,Firefox 57+ 版本以后,无法通过拓展直接修改,只能在 userChrome.css 上修改。如果CSS代码过长,可以使用 @import url("xxxx.css"); 来导入。需要注意的几个方面:

(1). 当你的 CSS 代码只做用于浏览器界面时,可以在代码放到下面的规则里,以避免与网页的样式表冲突。
@-moz-document url(chrome://browser/content/browser.xul) {/* 你的CSS代码 */}

(2). 需要在CSS样式表前声明 /* AGENT_SHEET */ 吗?
一般来说,userChrome.css 会覆盖Firefox的内置的样式表,特别是你使用了 !important 声明代码,但是还是有一些本地匿名元素,比如滚动栏,会不起作用,这时你就需要在样式表前加入 /* AGENT_SHEET */

(3). 在 userChrome.css 的同一文件夹内还会有一个叫 userContent.css 的文件,这个是将样式应用到网页上的,但使用 xStyle 等样式管理拓展更加方便,所以这个文件不常用。但是对于一些 Firefox 浏览器的内建页,比如 about:addons, about:preferences, about:newtab,样式管理拓展是不起作用的,这时就要用到 userContent.css 了,比如:
@-moz-document url(about:preferences),url-prefix(about:preferences) {/* 你的CSS代码 */}

(4). 如何即见即所得的编辑CSS样式表,避免每次修改后都要重启,就像旧版 Stylish 那样?
使用浏览器自带的“开发者工具”可以做到即见即所到,点击“保存”按钮可以将当前修改直接保存到样式表中去。
DOM

(5). 启用开发者工具需要按F12在设置中勾选两个选项,查找浏览器元素时,使用"DOM"更加方便准确,DOM标签默认并未勾选,查找弹出式菜单需要点击“弹窗自动隐藏”选项,更多使用方法可以参考 MDN
DOM

(6). 最常用的选择器 ID, class, name,他们之间的区别就是ID是你的身份证号码,class是你的姓别和民族,name就是你的名字,如果使用label选择器的话,需要用中括号括起来,像[label="XXXX"]这样。

(7). 要想知道当前选中的选择器是不是你想要的,可以给它定义一下属性,比如 color:#0063dc !important; 或者 display:none !important; 这样就很明显了,加 !important 是为了让这个属性值具有优先权。

(8). 在修改其他人的CSS样式表时,要想快速地知道某个属性具体是那条代码影响的,可以在100行代码中选择第50-100行,删除应用后,看看效果还在不在,如果还在,那么继续删除第25-50行的代码,直到效果消失后就可以缩小查找范围了。

(9). CSS编辑工具可以选项V系列Firefox自带的 Notepad2,也可以使用 Notepad++,还可以使用更加美观的 Atom。

(10). 一些选择符 是Firefox 特有的,只在Firefox上有效。比如以-moz-开头的,比如以两个横线"--sidebar-hover-width"开头的,详细列表查看:https://developer.mozilla.org/en-US/docs/Web/CSS/Mozilla_Extensions

三、案例:如何修改按钮图标?

以修改拓展 In My Pocket 图标为例,使用“开发者工具箱”选择 Pocket 图标,得到其ID为“_cd7e22de-2e34-40f0-aeff-cec824cbccac_-browser-action”,那CSS写法就是:

#_cd7e22de-2e34-40f0-aeff-cec824cbccac_-browser-action {
list-style-image: url("../images/pocket.png") !important;
}

双引号中间的指定图像可以是像上面代码所示的图片相对路径地址,也可以是以http://开头的绝对路径地址,也可以是以 data:image/png;base64 开头的图片base64编码。

四、通过“定制”和"about:config"来修改浏览器界面

Firefox 上的一些界面改变是可以通过“定制”和"about:config"来修改的,比如下载按钮是否自动隐藏,标签栏上方是否有拖拽空间,这里有一份中文解释说明可供参考:

1,通过“定制”

// 1,工具栏模式:
定制模式 > 密度 > (紧凑 / 普通 / 触控)
// 2,标签栏上方拖拽空间:
定制模式 > 拖拽空间 > 勾选选择
// 3,下载按钮一直可见:
定制模式 > 下载按钮 > 点击按钮取消勾选“自动隐藏”
// 4,RSS 图标放入地址栏:
可以安装拓展 Awesome RSS

2,通过”about:config“
地址栏输入 about:config,搜索相应的参数修改,布尔值为是和否,整数值为数值,字符串为字母和数字。右键点击选择“重置”可以恢复到默认数值。

// 1,标签栏最小宽度:(建议为100)
browser.tabs.tabMinWidth
//2,是否在标签上显示音频播放按钮:(建议选是)
browser.tabs.showAudioPlayingIcon
// 3,在当前标签右边插入相关标签:(建议选是)
browser.tabs.insertRelatedAfterCurrent
// 4,是否隐藏地址栏前的 http:// 标识:(建议选否)
browser.urlbar.trimURLs
// 5,新标签打开限制: (建议为0,用新标签来代替新窗口)
browser.link.open_newwindow.restriction
// 6,是否使用 Tabs 键来预览标签:(建议选否)
browser.ctrlTab.previews
// 7,关闭最后一个标签时关闭浏览器:(建议选否)
browser.tabs.closeWindowWithLastTab
// 8,使用旧版拨号页和主页界面:(建议选否)
browser.newtabpage.activity-stream.enabled
browser.newtabpage.activity-stream.aboutHome.enabled
// 9,HTML5 全屏警告:(修改时间,-1为不显示)
full-screen-api.warning.delay
full-screen-api.warning.timeout
// 10,书签栏显示最近添加的书签:(建议选否)
browser.bookmarks.showRecentlyBookmarked
// 11,是否显示标签动画:(建议选否)
toolkit.cosmeticAnimations.enabled
// 12,HTML5 全屏淡进和淡出动画时间:(修改时间,-1为不显示)
full-screen-api.transition-duration.enter
full-screen-api.transition-duration.leave
// 13,是否在附加组件页面移除“获取拓展”选项:(建议选否)
extensions.getAddons.showPane
// 14,搜索栏结果动画变暗高亮:(建议选否)
findbar.modalHighlight
// 15,是否在地址栏底部添加搜索引擎切换的按钮:(建议选否)
browser.urlbar.oneOffSearches
// 16,是否启用阅读模式按钮:
reader.parse-on-load.enabled
// 17,是否启用地理位置定位:(根据个人情况选择)
geo.enabled
// 18,是否启用Pocket按钮:(建议选否,功能很弱)
extensions.pocket.enabled
// 19,是否启用截图按钮:(建议选是,不错,支持永久图床)
extensions.screenshots.disabled
// 20,是否启用容器标签页:(建议选是,不错,也就是小号功能)
privacy.userContext.enabled
// 21,是否启用物联网扩展:(建议选否)
dom.flyweb.enabled
// 22,字体渲染:(默认即可,如果要使用MacType,要修改为 direct2d1.1,cairo,skia)
gfx.canvas.azure.backends
gfx.content.azure.backends

五、用户样式资源列表

UC脚本

新架构的 Firefox Quantum 最大的变化就是抛弃了原有的XUL语言界面,这使得以 .uc.xul 为后缀名的UC脚本完全失效,同时因为一些API的变化,也使得一部分以 .uc.js 为后缀名的UC脚失效。但总的来说,Firefox 官方对UC脚本的态度是开放的,UC脚本依然大有可为,因为UC脚本真的实在太好用了。

1. UC脚本到底是什么东西?
UC脚本的全称是 userchrome.js,从本质上来说,它和一般的 javascript 脚本一样,都是js语言,只不过它引用了 Firefox 专有的库,只能在 Firefox 上运行。

2. 让 Firefox Quantum 支持 UC脚本
使用的是 Endor8 的方案,通过配置脚本来完成userChrome的配置,共计4个文件。
..\Firefox\defaults\pref\config-prefs.js
..\Firefox\defaults\pref\channel-prefs.js
..\Firefox\config.js
..\Firefox\userChromeJS.js

3. 有哪些保持着更新的UC脚本开发者?
alice0775/userChrome.js
Endor8/userChrome.js
ardiman/userChrome.js
userChrome.js用スクリプト
harv/userChromeJS
scdhao/userChrome
胖子阿康/userChrome
RunningCheese/userChrome.js

一些已经停止更新的UC脚本开发者名单就没有列出来了,同样十分感谢脚本原开发者。
可能用得上的参考资料:ywzhaiqi/userChromeJSdefpt/userChromeJs
更多UC脚本,可搜索 Search · userChrome

官方网站

桌面版下载:Firefox 官方FTP下载Firefox 国际多语言下载火狐中文(谋智)版Firefox 每夜体验版
移动版下载:Firefox iOS版Firefox 安卓版附加组件下载:Firefox Addons

Mozilla Firefox Firefox 官方网站
火狐浏览器 Firefox 中文官方网站
The Mozilla Blog Mozilla 官方博客
Mozilla Blog Directory Mozilla 博客目录
Mozilla Add-ons Blog Mozilla 附加组件博客
Mozilla Future Releases Mozilla 发展方向博客
Mozilla Security Blog Mozilla 安全博客
Open Policy & Advocacy Mozilla 隐私保护博客
Mozilla Hacks Web开发技巧与资讯
Mozilla Community Mozilla 社区
Planet Mozilla Mozilla 社区人员博客汇总

新闻资讯

Firefox News Firefox 新闻 (英文)
Firefox News Firefox 新闻 (中文)
Firefox Facebook Firefox Facebook 社交网络
Firefox Twitter Firefox Twitter 社交网络
火狐的微博 Firefox 微博社交网络
Firefox Release Notes Mozilla 更新日志
Ghacks Firefox Firefox 资讯技巧
Solidot Firefox Solidot Firefox资讯
Solidot Mozilla Solidot Mozilla资讯
Techdows Firefox Techdows Firefox资讯
浏览器国内市场份额 StatCounter Global Stats 浏览器全球市场份额
Firefox 信仰充值中心 Firefox 知乎专栏

论坛社区

Mozilla Discourse Mozilla官方交流论坛
MozillaZine Forums 全球最大用户交流论坛
谋智火狐社区 火狐中国(谋智)官方论坛
Stackoverflow Firefox 英文问答
Reddit Firefox 英文版Firefox贴吧
Mozilla Firefox中文社区 最忠实
Mozilla Mozest 最可惜
卡饭论坛Firefox版 最技术
Firefox贴吧 最活跃
Mozilla 台灣社群 宝岛朋友
知乎 Firefox话题 知乎 Firefox话题
简书 Firefox专题 简书 Firefox专题
V2EX Firefox V2EX Firefox话题
Camp Firefox 德国 Firefox 论坛
Mozilla Support Moziila 技术支持论坛
Pale Moon forum Pale Moon forum

博客项目

个人博客:
Mike's Musings Mozilla元老级员工博客
iceweasel 编译版Firefox
奔跑中的奶酪 定制版
Kaiyuan Liu GM脚本
CingFox 定制版
阳光盒子 定制版
火狐范 资讯
反斗软件 资讯
wiki@nothing UC脚本(日文)




注:本文由 奔跑中的奶酪 作者:奔跑中的奶酪 发表,其版权均为作者所有,如需转载,请注明作者名字以及文章来源。
164
avataravatar

评论:

21 条评论,访客:0 条,站长:0 条
  1. 燧火孤眠
    燧火孤眠发布于: 

    现在pref(key,value)是不是不起作用了?我看 Ghack user.js里边没有pref(key,value)的示例了?

回复 落月之巅 取消回复