[英]Cannot access DOM elements inside custom HTML tag with JavaScript
我有幾個后端 Salesforce (SF) 頁面,下拉列表非常長(例如多達 1,000 個選項),我想在 Chrome 書簽中使用 JS 代碼將過濾器框添加到頁面上的任意 SELECT (代碼如下)。 我認為,問題在於我要訪問的節點位於名為force-aloha-page
的自定義 HTML 元素內。
就我而言,我要訪問的第一個元素是自定義元素內的 IFRAME。 (這不是跨站點安全問題,因為即使來源不好,JS 仍然會得到 IFRAME,只是其中沒有任何內容。)
例如,我可以檢查代碼並看到自定義 HTML 元素,看到 iframe,我可以看到頁面上 iframe 的內容。 如果我只是將節點轉儲到控制台中,它會顯示 JS 無法訪問的 DOM 元素:
document.getElementsByTagName("FORCE-ALOHA-PAGE")[0]
<force-aloha-page data-data-rendering-service-uid="203" data-aura-rendered-by="505:0" force-alohapage_alohapage-host><div force-alohapage_alohapage class="iframe-parent slds-template_iframe slds-card"><iframe force-alohapage_alohapage height="100%" width="100%" scrolling="yes" allowtransparency="true" name="vfFrameId_1569557364522" title="Page Configuration" allowfullscreen="true" lang="en-US" allow="geolocation *; microphone *; camera *">…</iframe></div></force-aloha-page>
我可以在force-aloha-page
元素中看到div
和iframe
。 但是,如果我嘗試訪問 iframe,就會發生這種情況:
document.getElementsByTagName('IFRAME')
0
document.querySelectorAll("iframe")
0
JS可以看到自定義元素:
document.getElementsByTagName("FORCE-ALOHA-PAGE").length
1
但里面什么都沒有:
document.getElementsByTagName("FORCE-ALOHA-PAGE")[0].childNodes.length
0
即使上面的“節點轉儲”有效,但這不會:
document.getElementsByTagName("FORCE-ALOHA-PAGE")[0].innerHTML
""
一旦我到達 iframe,我可能會遇到其他問題,但我必須先通過那個自定義標簽。
我試過的
我在 Chrome 中創建了 JS 書簽,該書簽適用於主頁中的 SELECT 和具有良好 XSS 的 IFRAME 內部。 但不適用於自定義標簽內的 SELECT。 這是我在編寫書簽代碼時使用的測試頁面。
測試頁1.html
<html>
<body>
<select>
<option value="1">1</option>
<option value="10">10</option>
<option value="2">2</option>
<option value="20">20</option>
</select>
<br /><br />
<select>
<option value="Apples">Apples</option>
<option value="Berries">Berries</option>
<option value="Candies">Candies</option>
<option value="Danishes">Danishes</option>
</select>
<br /><br />
<iframe src="testpage2.html"></iframe>
</body>
</html>
testpage2.html
<html>
<body>
<select>
<option value="3">3</option>
<option value="30">30</option>
<option value="4">4</option>
<option value="40">40</option>
</select>
<br /><br />
<select onchange="selectChange(this)">
<option value="Eclaires">Eclaires</option>
<option value="Frozen Custard">Frozen Custard</option>
<option value="Grapes">Grapes</option>
<option value="Heath Bar">Heath Bar</option>
</select>
<script type="text/javascript">
function selectChange(el) {
console.log("Select value: " + el.value);
}
</script>
</body>
</html>
書簽代碼(擴展以提高可讀性):
javascript:(function(){
//return an array of all selects in the main page or in iframes
var selects=function(d){
var a=[],
s=d.getElementsByTagName('SELECT'),
b=d.getElementsByTagName('IFRAME');
for(var i=0;i<s.length;i++)
a.push(s[i]);
for(var i=0;i<b.length;i++){
try{
a=a.concat(selects(b[i].contentWindow.document));
}catch(e){
console.log(e);
}
}
return a;
},
//makes the SELECT border blink and scrolls it into view
blink=function(els,i){
if(i>=els.length)return;
var el=els[i],s=el.style,t=200,
nb='3px solid blue',eb=s.border+'';
el.scrollIntoView();
s.border=nb;
setTimeout(function(){s.border=eb;},t);
setTimeout(function(){s.border=nb;},t*2);
setTimeout(function(){
s.border=eb;
if(confirm("This one?")){
filter(el);
}else{
blink(els,i+1);
}
},t*3);
},
//helper for creating options on a select
opt=function(v,t,p){
var y=document.createElement('OPTION');
y.value=v;
y.text=t;
p.appendChild(y);
},
//creates the new filter input and adds it to the page
filter=function(el){
console.log('Filtering...');
var d=document,c=d.createElement('INPUT'),o=[];
c.type='text';
c.placeholder='Filter list';
c.style.width=el.style.width;
c.style.display='block';
el.parentNode.insertBefore(c,el);
//filters the option list when something is typed
c.onkeyup=function(ev){
var j=c.value+'',h=el.options,x=0;
if(o.length==0){
for(var e=0;e<h.length; e++){
with(h[e]){
o.push({'v':value,'t':text});
}
}
}
for(var g=h.length-1;g>=0;g--)el.remove(g);
for(var i=0;i<o.length; i++){
if(j.length==0){
opt(o[i].v,o[i].t,el);
}else{
if(match(o[i].t,j)){
if(x==0) opt('','',el);
opt(o[i].v,o[i].t,el);
x++;
}
}
}
if(x>0) el.options[0].text='<'+x+' Match(es) Found>';
};
},
//determines if the option text matches the filter criteria, with wildcard support
match=function(a,b){
a=(a+'').toLowerCase();
b=(b+'').toLowerCase();
if(b.indexOf('*')<0){
return a.indexOf(b)>=0;
}else{
var r='.*',c=b.split('*');
for(var i=0;i<c.length;i++){
r+='.*'+(c[i].length>0?'('+c[i]+')':'');
}
r+='.*';
return (new RegExp(r)).test(a);
}
},
d=document,s=selects(d),v=[];
//gets only SELECTs that are visible on the page
for(var i=0;i<s.length;i++){
if (window.getComputedStyle(s[i]).display !== 'none')
v.push(s[i]);
}
console.log('SELECTs: '+s.length);
console.log('Visible SELECTs: '+v.length);
//Begin.
blink(v,0);
})();
在我的 JS 代碼中,我還嘗試創建一個遍歷所有子節點的遞歸 function,但是,正如我上面發布的控制台示例所示,JS 為自定義元素返回 0 個子節點。
force-aloha-page
元素可能是一個Web 組件,這可以解釋為什么你不能訪問里面的 DOM,因為它是一個Shadow DOM 。
嘗試使用shadowRoot
屬性訪問它,如下所示:
class ForceAlohaPage extends HTMLElement { constructor() { super(); this.attachShadow({ mode: 'open' }).innerHTML = '<iframe force-alohapage_alohapage height="100%" width="100%" scrolling="yes" allowtransparency="true" name="vfFrameId_1569557364522" title="Page Configuration" allowfullscreen="true" lang="en-US" allow="geolocation *; microphone *; camera *"></iframe>'; } } customElements.define("force-aloha-page", ForceAlohaPage); console.log(document.getElementsByTagName('iframe').length); console.log(document.getElementsByTagName("force-aloha-page")[0].childNodes.length); console.log(document.getElementsByTagName("force-aloha-page")[0].innerHTML); console.log(document.getElementsByTagName('force-aloha-page')[0].shadowRoot.childNodes[0]);
<force-aloha-page></force-aloha-page>
下面的代碼段應該可以工作。
// Query all iframes in the DOM var iframesNodes = document.querySelectorAll("iframe"); // Transfrom nodeList into an array var iframes = Array.prototype.slice.call(iframesNodes); console.log(iframes); // Loop through all iframes iframes.map(function(iframe){ // Get the document of the current iframe var innerDoc = iframe.contentDocument || iframe.contentWindow.document; /*... Then do what ever you want with the iframe document... */ innerDoc.body.style.backgroundColor = "#ff0000" });
<exampletag> <iframe src="/" /> </exampletag> <iframe src="/" />
如果你想使用自定義標簽,你應該閱讀這個: https://www.smashingmagazine.com/2014/03/introduction-to-custom-elements/
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.