如何使用XUL,SDK或WebExtensions技术从Firefox附加组件中的JavaScript动态修改CSS规则集(例如使用类选择器)?试图支持Firefox 29.0b1到49.0a1。
我想解决的问题(来自Firefox附加组件中的XUL文档,有时与网页不同):
file.xul:
(此行位于顶部)
<?xml-stylesheet href="chrome://{GUID}/skin/text.css" type="text/css"?>
text.css:
(文件中的相关课程)
.myTextClass {
max-width: 800px;
}
code:
// Modify the class selector rule set to add another rule,
// i.e. font-family: DejaVu Sans Mono
// Later on, after user input, change or remove this font in this one class
这可能是#20927075的副本,但没有令人满意的答案,但我也对SDK或WebExtensions技术感兴趣,以确保我想要添加到现有的功能基于XUL的附加组件可以使用较新的API实现。
我想实现一个基本的“字体选择器”UI功能,并让它将新字体应用于该类。我有一个简单的CSS规则集,带有一个类选择器,它定义了一个带有一个规则的类(现在,但可能有其他手动/静态添加的规则集),我想添加另一个规则,并且有加载项的界面更新。
我所知道的选项,但都显得过于笨拙。
1)document.getElementById,手动设置style
属性。我为演示区做这个,没关系。
2)与上面类似,但是getElementByClassName。但是,这不是一个类!这是使用一个类来查找节点,我更改了每个元素的属性,无论是样式还是类。这似乎很慢。我可以使用每种可能的字体创建一个庞大的CSS文件,然后更改类属性,但这是愚蠢的。比仅更改样式属性更糟糕。
3)有样式表服务,但我不知道它是否仍然存在或将被淘汰或删除(它是基于XPCOM的?),它不是Services.jsm的一部分,它是一个非常钝的工具当我只想从一个类定义中修改一个规则时,它只能加载或卸载整个样式表。
4)有jQuery,但是没有。就是不行。甚至不打算提出这个建议。小插件的开销太大,不知道该技术是否适用于XUL接口代码。
5)像document.styleSheets这样的东西似乎没错,但是没有得到我想要的东西(除非我弄错了?)。一切似乎都是只读的。更多信息如下。
6)通过摆弄document.getElementsByTagName('head')手动破坏整个样式表,这再次破坏整个css表而不是一个类的一个规则。
如果确实没有其他选择,我可能必须使用上面的方法2。但我希望有一个选项允许使用JavaScript在XUL中对CSS进行细粒度控制。
我正在尝试,了解如何执行此操作:
for ( i = 0; i < document.styleSheets.length; i++ ) {
styleSheet = document.styleSheets[ i ];
console.log( 'style sheet: ' + i + ' ' + styleSheet.href );
if ( styleSheet.href === 'chrome://{GUID}/skin/text.css' ) {
for ( j = 0; j < styleSheet.cssRules.length; j++ ) {
styleRule = styleSheet.cssRules[ j ];
console.log( 'style sheet: ' + i + ' ' + 'styleRule: ' + styleRule.cssText );
}
}
}
在此编辑过程中,我现在获取代码以显示定义类的规则,而昨晚我收到了无效的属性错误。我的术语混淆了,认为规则是课堂内的项目。但无论如何,从那时起,我不确定如何继续。
以上代码(在file.js
中引用file.xul
<script>
标记)输出与此类似的console.log(在Firefox 29.0b1中):
"style sheet: 0 chrome://git-addonbar/skin/addonbar.css" file.js:189
09:49:47.101 "style sheet: 1 chrome://browser/content/browser.css" file.js:189
09:49:47.101 "style sheet: 2 chrome://browser/content/places/places.css" file.js:189
09:49:47.101 "style sheet: 3 chrome://browser/skin/devtools/common.css" file.js:189
09:49:47.101 "style sheet: 4 chrome://browser/skin/customizableui/panelUIOverlay.css" file.js:189
09:49:47.101 "style sheet: 5 chrome://browser/skin/browser.css" file.js:189
09:49:47.101 "style sheet: 6 chrome://browser/skin/browser-lightweightTheme.css" file.js:189
09:49:47.101 "style sheet: 7 chrome://global/skin/global.css" file.js:189
09:49:47.101 "style sheet: 8 chrome://{GUID}/skin/text.css" file.js:189
09:49:47.102 "style sheet: 8 styleRule: .myTextClass { max-width: 800px; }" file.js:194
09:49:47.102 "style sheet: 9 null" file.js:189
答案 0 :(得分:2)
5)像document.styleSheets这样的东西似乎没有得到我想要的东西(除非我弄错了?)。一切似乎都是只读的。
这是正确的选择。虽然styleSheets
属性是只读的(意味着您不能像这样分配:document.styleSheets = val
),但您获得的样式表对象确实允许修改。
由于您只关心一个(现代!)浏览器,因此以跨浏览器的方式比Changing a CSS rule-set from Javascript更容易。一个简单的例子:
function changeCSS() {
let myClassRule = document.styleSheets[0].cssRules[0];
if (myClassRule.style.color == "red")
myClassRule.style.color = "blue";
else
myClassRule.style.color = "red";
}
.my-class {
color: red;
}
<p class="my-class">First paragraph</p>
<p class="my-class">Second paragraph</p>
<button onclick="changeCSS()">Change the stylesheet!</button>
您必须对其进行扩展才能找到您关注的样式表和规则 - 上面链接的问题有a minimal example of doing that。
答案 1 :(得分:2)
要回答我自己的问题,这是最终工作并解决了我的问题的代码。关键信息如下:
document.styleSheets[ i ].href
document.styleSheets[ i ].cssRules[ j ].selectorText
document.styleSheets[ i ].cssRules[ j ].style.fontFamily
这一切都始于document.styleSheets类似数组的对象(类似于数组,因为它实际上不是一个JavaScript数组),其余的都是简单的DOM。可以进行通用功能。 href可以是可选的,具体取决于你是否知道加载外部工作表的位置,并且你知道你可以安全地担心只有一个独特的选择器,那么你可以避免搜索Firefox加载的~10张其他工作表。这是最简单的用例。
// Load font and apply style sheet class
// Am using the .href to find the sheet faster because location is known and rule is unique
var myCSShref = 'chrome://{GUID}/skin/text.css';
var mySelector = '.myTextClass';
// fonts stored as a string in a user pref, later split to array inline
// fonts could be stored as array during runtime, remove splits accordingly
// fonts get appended to a XUL menulist element
// list index 0 is for default, 1+ for fonts below
var fonts = 'monospace|Anonymous Pro|Apple Menlo|Bitstream Vera Sans Mono|Consolas|DejaVu Sans Mono|Droid Sans Mono|Everson Mono|Liberation Mono|Lucida Console|Source Code Pro';
var font_index = 2; // Anonymous Pro, the 2 is pulled from a user pref
// for loop vars
var i, styleSheet, j, cssRule, oldFontFamily, newFontFamily;
// console.logs for demonstration purposes only
// The following code only needed to be run once for me,
// but it can easily be changed to a reusable function.
if ( document.styleSheets ) {
for ( i = 0; i < document.styleSheets.length; i++ ) {
styleSheet = document.styleSheets[ i ];
console.log( 'style sheet: ' + i + ' ' + styleSheet.href );
if ( styleSheet.href === myCSShref ) {
for ( j = 0; j < styleSheet.cssRules.length; j++ ) {
cssRule = styleSheet.cssRules[ j ];
console.log( 'style sheet: ' + i + ' cssRule.selectorText: ' + cssRule.selectorText );
if ( cssRule && cssRule.selectorText === mySelector ) {
oldFontFamily = ( cssRule.style.fontFamily ) ? cssRule.style.fontFamily : '';
// font_index 0 is the menu default option, so we have 1 extra
newFontFamily = ( font_index === 0 ) ? 'inherit' : fonts.split( '|' )[ font_index - 1 ];
console.log( 'style sheet: ' + i + ' cssRule.style.fontFamily: ' + oldFontFamily + ' (before)' );
console.log( 'style sheet: ' + i + ' cssRule.style.fontFamily: ' + newFontFamily + ' (after)' );
cssRule.style.fontFamily = newFontFamily;
}
}
}
}
}
答案 2 :(得分:0)
3)有样式表服务,但我不知道它是否仍然存在或将被淘汰或删除(它是基于XPCOM的?),它不是Services.jsm的一部分,它是一个非常钝的工具当我只想从一个类定义中修改一个规则时,它只能加载或卸载整个样式表。
目前,其他插件API是表单服务或windowutils.loadSheet的抽象。当然,mozilla最终可能会在通过其他方式保持抽象的同时将其删除。但是,现在看来,未来还有一年的时间。
addon-sdk提供了使用page-mod模块
加载样式的选项Webextensions通过tabs.insertCSS强制支持或manifest
以声明方式支持但这些都是针对内容框架的。如果你想修改浏览器chrome本身,你无论如何都必须使用xpcom API,因为没有针对它的专用插件API。