簡體   English   中英

無法使用 JavaScript 訪問自定義 HTML 標記內的 DOM 元素

[英]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元素中看到diviframe 但是,如果我嘗試訪問 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM