站点正在导入数据,暂时处于只读模式:这段时间里无法登录,也不能发帖或回复。
最近的评论
评论于There are so many ways to do it base64encode.org会把你的内容上传到他们服务器,感觉不靠谱。站长亲自实现了一个对于unicode编码也可以用的btoa函数 非常好www
- 2
评论于正在看直播,弹劾川普的议案已经在众议院通过 @爱狗却养猫 <#121737>
就我来看川普的政治生涯基本结束了,再次竞选这个基本不用再考虑了。弹劾更多是一种清算或者是象征意义吧。。。。
评论于正在看直播,弹劾川普的议案已经在众议院通过 ttttttttttttttttttttttttttttttttttttttttt
评论于正在看直播,弹劾川普的议案已经在众议院通过 ttttttttttttttttttttttttttttttttttttttttt
- 1
- 1
评论于test不要点进来 ttttttttttttttttttttttttttttttttttttttttt
- 1
评论于test不要点进来 ttttttttttttttttttttttttttttttttttttttttt
评论于test不要点进来 品韭
<>品韭 <!--品韭
品韭
品韭罪大恶极 换行和斜体都失效了
罪大恶极
评论于test不要点进来 ttttttttttttttttttttttttttttttttttttttttt
评论于test不要点进来 ttttttttttttttttttttttttttttttttttttttttt
评论于test不要点进来 品韭
<t121338>
评论于用户被社交媒体删帖封号以后有没有打官司司法救济的可能性? 我对美国制度了解不多,不过川普理论上可以起诉几大公司封他号行为吧?现实政治来看他这么做没有多大可能改变现状就是了。。。
- 1
评论于好的制度总是治未病,所以会争议不断 @thphd <#121299>
NSA 毕竟是这方面的前辈,政治上的内容不提,就技术手段上不知道高到哪里去了,棱镜门那会GFW玩的那些小把戏比起NSA不知道差到哪里去了 评论于【境外中文网络环境研究】如何评价品葱众用户10月初对本次美国大选的预测? ttttttttttttttttttttttttttttttttttttttttt
- 1
评论于【境外中文网络环境研究】如何评价品葱众用户10月初对本次美国大选的预测? 他们说什么不重要,做了什么才重要。共和党和川普已经被很多金主断了粮,我真心建议他们包括本站的川普支持在内,赶快给gop.com多捐一些钱。
- 3
评论于在网站上传图片或文件时,对方有可能获取文件路径吗? 理论上讲可能性很小,这是一些有关的说明:
https://developer.mozilla.org/en-US/docs/Web/API/FileReader
https://developer.mozilla.org/en-US/docs/Web/API/FileList
https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/file不过如果你真的很担心安全问题,比如浏览器自身出现漏洞,可以把浏览器放到沙盒或者虚拟机里运行
比如tails 自带的限制甚至不让浏览器访问download以外的文件夹
但如果是浏览器插件可以做到的事情就多多了。
https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Native_messaging - 1
评论于深入浅出 Greasemonkey 例 4.6. 获取页面中的所有链接
var allLinks, thisLink; allLinks = document.evaluate( '//a[@href]', document, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null); for (var i = 0; i < allLinks.snapshotLength; i++) { thisLink = allLinks.snapshotItem(i); // 使用 thisLink }document.evaluate方法是关键。它有一个代表 XPath 查询语句的字符串参数以及一些其它参数,接下来解释一下。这条 XPath 查询语句找到了具有href属性的 `` 元属,用随机的次序排列后返回。(也就是说,集合中的第一个元素并一定是页面中的第一个元素。)然后您可以用allLinks.snapshotItem(i)方法访问找到的元素。XPath 表达式所能做到的甚至会使您惊讶。请看下面这个例子,它获取了全部具有
title属性的元素。例 4.7. 获取所有具有
title属性的元素var allElements, thisElement; allElements = document.evaluate( '//*[@title]', document, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null); for (var i = 0; i < allElements.snapshotLength; i++) { thisElement = allElements.snapshotItem(i); switch (thisElement.nodeName.toUpperCase()) { case 'A': // 这是链接,在这里完成您的操作 break; case 'IMG': // 这是图片,在这里完成您的操作 break; default: // 其他类型的 HTML 元素,在这里完成您的操作 } }[ 如果已有一个元素的引用(例如 thisElement),可以用thisElement.nodeName来判断它的 HTML 标签。如果页面被当作text/html类型,标签名称就总是大写,不论它在原始页面是如何定义的。如果页面被当作application/xhtml+xml类型,那么标签名称就总是小写的。我总是用thisElement.nodeName.toUpperCase()这样我就可以不用管这些了。这是另一个 XPath 查询,它获取了具有特定
class属性的 `` 元素。例 4.8. 获取所有
class为sponsoredlink的 ``var allDivs, thisDiv; allDivs = document.evaluate( "//div[@class='sponsoredlink']", document, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null); for (var i = 0; i < allDivs.snapshotLength; i++) { thisDiv = allDivs.snapshotItem(i); // 使用 thisDiv }附注:在 XPath 查询语句外使用双引号,这样在语句内就可以使用单引号了。
document.evaluate方法中有很多参数。第二个参数(在前两个例子中都是document)可以是任意元素。XPath 查询只返回这个元素的子元素结点。如果已有一个元素的引用(比如,从document.getElementById或者document.getElementsByTagName数组的一项中得到的引用),您就可以限制查询只返回这个元素的子元素。第三个参数是对名称空间解析函数的引用,只有在
application/xhtml+xml类型页面执行的用户脚本中才会用到。即使对它不了解也没关系,因为那种类型的页面不是很多,您可能一次也遇不到。如果您很想知道它的用法,Mozilla XPath 文档解释了它的用法。第四个参数是结果的返回方式。在前面的两个例子中都使用了
XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE,它返回的元素是随机次序的。我99%都是使用这种方式,但是,可能出于某种原因,想以在页面上出现的顺序返回结果,您可以使用XPathResult.ORDERED_NODE_SNAPSHOT_TYPE。Mozilla XPath 文档还提供了一些其他返回方式的例子。第五个参数用来合并两次 XPath 查询的结果。传入以前调用
document.evaluate结果,它将返回两次查询的合并结果。在前面的两个例子中,这个参数都用了null,这意味着我们只想获得本次 XPath 查询的结果。现在明白了吗?XPath 既可简单,也可难,这就看您怎么用了。我强烈推荐您阅读这个优秀的 XPath 教程,可以学到更多的 XPath 语法。关于
document.evaluate的其他参数, 我很少用除非您已经在这里看到他们了。事实上,您可以定义一个函数来封装它们。例 4.9.
xpath函数function xpath(query) { return document.evaluate(query, document, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null); }现在您可以简单的调用
xpath('//a[@href]')来获得页面上的全部链接,或者用xpath('//*[@title]')获得具有title属性的元素。您仍然需要用snapshotItem方法访问结果中的每个元素;它不是一个规则的 Javascript 数组。实例
- Access Bar
- BetterDir
- Blogdex Display Title
- Butler
- Frownies
- Offsite Blank
- Rotten Reviews
- Stop The Presses
参考资料
4.7. 在元素前插入内容
如果已找到某个元素(不论用何种方法),您想在它前面插入额外的内容。您可以使用
insertBefore函数。例 4.10. 在主内容前插入 ``
假设有个元素的 ID 为
"main"。var main, newElement; main = document.getElementById('main'); if (main) { newElement = document.createElement('hr'); main.parentNode.insertBefore(newElement, main); }实例
4.8. 在元素后插入内容
如果已找到某个元素,您想在它后面插入额外的内容。您也可以使用
insertBefore函数,要与nextSibling属性联合使用。例 4.11. 在导航条后面插入 ``
假设有个元素的 ID 为
"navbar"。var navbar, newElement; navbar = document.getElementById('navbar'); if (navbar) { newElement = document.createElement('hr'); navbar.parentNode.insertBefore(newElement, navbar.nextSibling); }[ 即使 someExistingElement是它的父元素的最后一个孩子(在它之后没有下一个元素),仍然可以在someExistingElement.nextSibling之前插入新内容。在这种情况下,someExistingElement.nextSibling将返回一个空值,insertBefore函数将把新内容追加到最后。(以许这对你来说没有太大意义,但我想让您知道的是,尽管这种方法似乎是不太对,但它却总是有效的。)实例
4.9. 删除元素
使用
removeChild函数,您可以使 Greasemonkey 一下子删除页面中完整的一块。例 4.12. 删除广告侧边栏
假设有个元素 ID 为
"ads"。var adSidebar = document.getElementById('ads'); if (adSidebar) { adSidebar.parentNode.removeChild(adSidebar); }[ 用 removeChild移除一个元素也会删除它里面的所有内容。例如您移除一个 `` 元素,此时也会将表格单元格(` 元素)一起移除。[ 如果要移除广告,比起写用户脚本来,更容易的办法是安装 AdBlock 然后导入 最新的过滤列表。 实例
4.10. 替换元素为新内容
如果已经获取了一个元素,可以使用
replaceChild函数来替换它的全部内容。例 4.13. 替换图片为替代(alt)文本
假设页面上有一个元素 ID 为
"annoyingsmily"。var theImage, altText; theImage = document.getElementById('annoyingsmily'); if (theImage) { altText = document.createTextNode(theImage.alt); theImage.parentNode.replaceChild(altText, theImage); }[ 如果要用一大段 HTML 替换一个元素,您可以构造 HTML 为一个字符串,然后设置元素的 innerHTML属性。实例
4.11. 快速插入复杂的 HTML
The
innerHTML属性让您可以将 HTML 以字符串的形式表示,然后将它们直接插入到页面中。这样就不需要为每一个 HTML 元素创建单独的 DOM 对象,然后再一个一个的设置它们的属性。例 4.14. 在页面顶部加上标语
var logo = document.createElement("div"); logo.innerHTML = '<div style="margin: 0 auto 0 auto; ' + 'border-bottom: 1px solid #000000; margin-bottom: 5px; ' + 'font-size: small; background-color: #000000; ' + 'color: #ffffff;"><p style="margin: 2px 0 1px 0;"> ' + 'YOUR TEXT HERE ' + '</p></div>'; document.body.insertBefore(logo, document.body.firstChild);关键的地方是第二行,在这行我将
logo.innerHTML设置为字符串。Firefox 将这个字符串解析成 HTML 然后创建所有必需的对象,就像它重新加载一个页面一样。这样我就可以将我的新logo(一个包含另一个,这个包含有一个)插入到页面的任何位置 — 页面开始,结尾或者我选择的任意元素之前或其后。总之,页面上任何位置。实例
4.12. 在没有服务器的情况下添加图片
Firefox 支持
data:URLs, 它可以把一段数据嵌入到 URL 中,而不需要单独从服务器上来获取。您也许从来都没有听说过data:URLs ,因为 Internet Explorer 不支持,所以几乎没人使用它们。但是在用户脚本中它们却非常有用。例 4.15. 在页面顶部添加图形 logo
var logo = document.createElement('img'); logo.src = 'data:image/gif;base64,R0lGODlhDQAOAJEAANno6wBmZgAAAAAAACH5BAAAAAAA'+ 'LAAAAAANAA4AQAIjjI8Iyw3GhACSQecutsFV3nzgNi7SVEbo06lZa66LRib2UQAAOw%3D%3D'; document.body.insertBefore(logo, document.body.firstChild);在这个例子中,`` 元素的
src是data:URL,它以编码形式的包含了一整幅图像的信息。当这个新元素被插入到页面中时,它会像其他图片一样显示但它却不用存储在服务器上。事实上,可以在您的用户脚本中嵌入图片,它们可以和其它的代码一样发布到网上。[ 使用 data:URI kitchen 来建立您自己的data:URLs。实例
参见
4.13. 添加 CSS 样式
我常常发现需要在页面中添加我自己的 CSS 样式。您可以添加新样式,覆盖掉已有的样式或者样式化用户脚本插入的新元素。
例 4.16. 放大段落文字
function addGlobalStyle(css) { var head, style; head = document.getElementsByTagName('head')[0]; if (!head) { return; } style = document.createElement('style'); style.type = 'text/css'; style.innerHTML = css; head.appendChild(style); } addGlobalStyle('p { font-size: large ! important; }');这个函数只一个字符串参数,包含要插入到页面中的样式规则。它一成不变地把您的样式规则插入到页面
段的元素中。Firefox 自动判别这些变化,解释样式规则,并应用到页面中。您应该把许多不同的样式规则包含到一次函数调用中;只要把连接成一个字符串然后传给函数。[ 可以使用 addGlobalStyle函数样式化插入到页面中的元素或者部分原页面中已有的元素。然而,如果要样式化已有的元素,应该在您定义的每条规则上使用! important关键字,保证您的样式覆盖原页面中已定义的规则。实例
参见
4.14. 获取元素样式
当多个 CSS 规则同时应用到某个元素上时,获取这个元素的实际样式有时候是有帮助的。您可能会简单的认为,通过元素的
style属性就可以得到,这样的话您就错了。它只会返回style属性的内容。要获得元素的最终样式(包括在外部定义的样式),您需要使用getComputedStyle函数。为了演示,我们创建一个简单的测试页面。它首先对页面中所有的
元素定义了同一个样式,但随后对其中的一个元素用它的style属性重新定义了样式。<html> <head> <title>样式测试页</title> <style type="text/css"> p { background-color: white; color: red; } </style> </head> <body> <p id="p1">这行是红色的。</p> <p id="p2" style="color: blue">这行是蓝色的。</p> </body> </html>例 4.17. 获取由元素的
style属性定义的样式var p1elem, p2elem; p1elem = document.getElementById('p1'); p2elem = document.getElementById('p2'); alert(p1elem.style.color); // 提示为空字符串 alert(p2elem.style.color); // 提示 "blue"用这种方法获得的信息并不是很有用,所以您不应该再用
element.style来获取单独的样式。 (您可以用它来设置元素的样式,详见设置元素样式。)那么您该用什么方法来取代它呢?
getComputedStyle()。例 4.18. 获取元素的真实样式
var p1elem, p2elem, p1style, p2style; p1elem = document.getElementById('p1'); p2elem = document.getElementById('p2'); p1style = getComputedStyle(p1elem, ''); p2style = getComputedStyle(p2elem, ''); alert(p1style.color); // 提示 "rgb(255, 0, 0)" alert(p2style.color); // 提示 "rgb(0, 0, 255)"实例
4.15. 设置元素样式
如果只需要设置单个元素的少数样式,可以“手动地”在这个元素的
style属性中设置多个子属性。例 4.19. 设置单个元素的样式
假设有个元素 ID 为
"logo"。var logo = document.getElementById('logo'); logo.style.marginTop = '2em'; logo.style.backgroundColor = 'white'; logo.style.color = 'red';[ 并不是每个样式的属性名称都是显然的。通常,它们有相似的模式,例如 margin-top对应someElement.style.marginTop。但是也有例外:float属性对应到someElement.style.cssFloat,因为float是 Javascript 的保留字。实例
参考资料
4.16. 处理已渲染的页面
由于 Firefox 保存已渲染页面的内在方式,应该在页面加载完成以后,才能对页面上的 DOM 做出大规模的改动,那么这个操作应该发生在页面完成载入之后,这是由已执行页面在 Firefox 内的存储方式决定的。您可以用
addEventListener函数来延迟函数的执行。例 4.20. 替换全部页面为自定义的内容
var newBody = '<html>' + '<head>' + '<title>My New Page</title>' + '</head>' + '<body>' + '<p>This page is a complete replacement of the original.</p>' + '</body>' + '</html>'; window.addEventListener( 'load', function() { document.body.innerHTML = newBody; }, true);仔细看这段代码,您可能自然地想知道它是怎么执行的。我声明了一个匿名函数来做为
window.addEventListener的第二个参数传入,它访问了在这个函数外定义的变量newBody。这种方法称为 “闭包(closure)”, 在 Javascript 中是完全有效的。一般说来,在“外层”函数中定义的“内层”函数可以访问外层函数的所有局部变量 -- 甚至在外层函数执行结束以后。这是一个很有用的特性,可以通过它来创建事件句柄和用来在运行时建立的数据构架的其他函数。[ 删除和替换 document.body.innerHTML并不会更改页面。原页面在 `` 中定义的所有内容仍然是有效的,包括页面的标题,CSS 样式,以及脚本。可以分开修改或者移除。实例
4.17. 匹配大小写无关的属性值
在 HTML 中,许多属性的值是大小写无关的,有的还允许首尾空格。如果想获取到所有这样的值,需要在 XPath 查询中使用一点技巧。
例 4.21. 获取 method 为 "POST" 或 "post" 的表单(form)
var postforms = document.evaluate( "//form[translate(@method, 'POST ', 'post')='post']", document, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null);本次 XPath 查询可以获取所有以 POST 方式提交的表单。首先,我们需要用
translate函数将method属性的值中的字母大写变成小写。(XPath 2.0 有lowercase函数,但我还从来没用成功过。)其次,我们需要将首尾的空格去掉。我们可以将其整合到调用translate函数中,只要在第一个参数中加个额外的空格。因为在第二个参数中没有对应的字母,这样一来所有的空格就被去掉了。最后,我们就能将获得的属性值同'post'做比较。实例
4.18. 获取当前域名
用户脚本操作多个域名(或者所有域名)时,常常需要检测当前页面的域名。可以用
window.location.href获取当前页面的完整 URL,或者用window.location.host只获取域名。例 4.22. 获取当前域名
var href = window.location.host;实例
4.19. 改写链接
如果获取到页面上的链接,可以通过设置它的
href属性来改写链接。例 4.23. 在链接末尾添加查询参数
假设有个链接的 id 为
"article"。var a = document.getElementById('article'); if (a.href.match(/\?/i)) { // 链接已经包含其它参数,所以添加 "&printer=1" a.href += '&printer=1'; } else { // 连接没有包含任何参数,所以添加 "?printer=1" a.href += '?printer=1'; }实例
4.20. 重定向页面
通过设置
window.location.href属性,您可以用 Greasemonkey 来自动重定向到指定的页面。例 4.24. 重定向一个站点到它的安全站点
window.location.href = window.location.href.replace(/^http:/, 'https:');实例
4.21. 俘获用户点击
虽然改写链接很简单,您也可以走的更远,使用
addEventListener函数,俘获页面上任何地方的每次点击。(这也能俘获点击链接。)您可以考虑下怎么做:是否让可点击元素的点击操作“失效” ,或者做些完全不同的操作。例 4.25. 当用户点击页面上任意地方时做点事
document.addEventListener('click', function(event) { // event.target 是被点击的元素 // 把你的代码放在这里 // 如果您想阻止默认点击动作 // (例如链接转向),使用下面这两条命令: event.stopPropagation(); event.preventDefault(); }, true);注释:用 匿名函数 作为传入
document.addEventListener函数的一个参数。4.22. 覆盖内建的 Javascript 方法
您可以用
prototype属性 覆盖原有的对象方法。例 4.26. 当表单提交时做点事
function newsubmit(event) { var target = event ? event.target : this; // 在这里定义想做的操作 alert('Submitting form to ' + target.action); // 调用真正的提交函数 this._submit(); } // 捕获所有表单的 onsubmit 事件 window.addEventListener('submit', newsubmit, true); // 如果脚本调用 someForm.submit(),onsubmit 事件不会发生, // 所以我们需要重新定义 HTMLFormElement 类的 submit 方法。 HTMLFormElement.prototype._submit = HTMLFormElement.prototype.submit; HTMLFormElement.prototype.submit = newsubmit;在这里做了两件事。首先,我加入了一个用来捕获
submit事件的监听函数。当用户点击表单的提交按钮时,触发submit事件。然而,当别的脚本调用表单的submit()方法时,并不会触发submit事件。 所以,我做的第二件事是覆盖HTMLFormElement类的submit方法。但是等等,还有几点需要说明。事件监听函数和重新定义的方法都指向同一个函数,
newsubmit。如果newsubmit被一个submit事件调用,event参数将会被包含在事件对象中,这个事件对象包含事件的信息(例如,event.target是被提交的表单)。然而,如果脚本手动调用了submit方法,event事件会被忽略掉,但是全局变量this将会指向这个表单。因此,在我的newsubmit函数中,我先判断event是否为空;如果为空,就用this来得到这个表单。[ 正常情况下,当用户提交一个表单时,例如,点击表单中的 提交 按钮或者按 回车键),都会触发submit事件。但是,当脚本调用aForm.submit()提交表单时,却不会触发submit事件。因此,您必须做两件事来捕获表单的提交事件:给submit事件增加事件监听,并且修改HTMLFormElement类的原型来重定向submit()方法到您的自定义函数上。参考资料
4.23. 解析 XML
Firefox 自动将当前页面解析为 DOM,但是您也可以手动创建 DOM 而不使用任何 XML 字符串,可以是您自己建立的,也可以是您从远端主机得到的 XML。
例 4.27. 将任意字符串解析为 XML
var xmlString = '<passwd>' + ' <user id="101">' + ' <login>mark</login>' + ' <group id="100"/>' + ' <displayname>Mark Pilgrim</displayname>' + ' <homedir>/home/mark/</homedir>' + ' <shell>/bin/bash</shell>' + ' </user>' + '</passwd>' var parser = new DOMParser(); var xmlDoc = parser.parseFromString(xmlString, "application/xml");这里关键的地方是
DOMParser对象,有个parseFromString方法。(它也有其他的方法,但在这里我们用不到。)parseFromString方法有两个参数:解析用的 XML 字符串,和内容类型。两者都是必需的。[ DOMParser的parseFromString方法将内容的类型作为它的第二个参数。这个方法可以接受application/xml,application/xhtml+xml和text/xml。由于深究起来,理由会很荒唐,您应该始终使用application/xml。这个模式非常强大,如果把它与
GM_xmlhttpRequest函数结合起来解析远程源的 XML。例 4.28. 解析远程源的 XML
GM_xmlhttpRequest({ method: 'GET', url: 'http://greaseblog.blogspot.com/atom.xml', headers: { 'User-agent': 'Mozilla/4.0 (compatible) Greasemonkey/0.3', 'Accept': 'application/atom+xml,application/xml,text/xml', }, onload: function(responseDetails) { var parser = new DOMParser(); var dom = parser.parseFromString(responseDetails.responseText, "application/xml"); var entries = dom.getElementsByTagName('entry'); var title; for (var i = 0; i < entries.length; i++) { title = entries[i].getElementsByTagName('title')[0].textContent; alert(title); } } });这段代码会载入http://greaseblog.blogspot.com/atom.xml的 Atom feed,把它解析为 DOM,然后查询 DOM 得到条目列表。再对每个条目做 DOM 查询,获得条目的标题(title),然后在对话框中显示出来。
参见
第 5 章 实例教学
5.1. 案例:GMail Secure
强制网站使用安全链接
GMail Secure 强制 GMail 使用安全的链接,重定向
http://gmail.google.com/到https://gmail.google.com/。Google 提供了 GMail,他们的 webmail 服务,可以通过非安全连接使用(
http://地址)或者通过安全连接使用(https://地址)。我试着记着在公用场所(例如网吧)查看邮件时要用安全链接。但是为什么不让电脑帮您记着呢?我写了个用户脚本,当它检测到当我通过非安全链接访问 GMail 时,它就自动帮我重定向到安全链接。例 5.1. 重定向 GMail 到等同的
https://地址// ==UserScript== // @name GMailSecure // @namespace http://diveintogreasemonkey.org/download/ // @description force GMail to use secure connection // @include http://gmail.google.com/* // ==/UserScript== window.location.href = window.location.href.replace(/^http:/, 'https:');这个用户脚本很简单,大部分的“工作”由
@include这行完成:// @include http://gmail.google.com/*只有匹配
@include的时候,这个用户脚本才会执行。所以当脚本执行的时候,我就知道我写错了地址(通过非安全连接访问 GMail)。完成这一切,只要一行代码, 重定向当前页面到相同的 URL,只是用https://前缀替换掉http://。window.location.href = window.location.href.replace(/^http:/, 'https:');参见
- 1
评论于(删除) ttttttttttttttttttttttttttttttttttttttttt
评论于美国总加速师川普,终于把自己的推特帐号给加速没了 @Ambulance <#121086> 川普再怎么说也可以搞媒体发布会,大家习惯了他推特治国似乎忘了正常总统应该怎么做