【问题标题】:Angular 2 - bypassSecurityTrustHtml along with bypassSecurityTrustScriptAngular 2 - bypassSecurityTrustHtml 和 bypassSecurityTrustScript
【发布时间】:2017-12-31 09:32:48
【问题描述】:

我有一个按钮(在左侧导航侧),单击它,我想在右侧(内容部分)显示一个模板 (.html)。模板 (.html) 路径将从 Web 服务中获取,并且每次都会不同(因此没有硬编码值)。

该模板 (.html) 可以有它自己的脚本标签。在 Angular 1.x 之前,使用 ng-include 标记很容易,但 Angular 2 似乎不再支持它了。

我可以使用以下解决方法显示 HTML 的内容(以及 CSS)-

this.sanitizer.bypassSecurityTrustHtml(url);

但是脚本没有被加载或执行。

提前感谢您的帮助。

【问题讨论】:

    标签: javascript html typescript angular2-template angular2-directives


    【解决方案1】:

    当您的 HTML 内容中有单个脚本标记时,[innerHTML] 选项可能对您有用。但是,如果您有多个 Script 标签来加载 HTML 内容,那么这不是一个可行的选择,因为它不能保证加载和执行脚本的顺序。为此,您必须将 HTML 附加到任何元素中,并按顺序逐个加载脚本。

    这里正确解释了以下解决方案 - https://ghinda.net/article/script-tags/

    你的 HTML 应该看起来像 -

    <div id="scripts"></div>
    <div id="content"></div>
    

    在第一个 div 中,将附加所有脚本,在第二个 div 中,将附加所有 HTML 内容。

    首先将您的 HTML 转换为字符串,并将所有脚本标签推送到 scriptArr[]。

    // run the scripts inside the dom node
    
        if (scriptArr.length > 0) {
            var $container = document.getElementById('scripts')
            $container.innerHTML = scriptArr
            runScripts($container)
        }
    
    /* helpers */
    
    // runs an array of async functions in sequential order
    function seq(arr, callback, index) {
        // first call, without an index
        if (typeof index === 'undefined') {
            index = 0
        }
    
        arr[index](function () {
            index++
            if (index === arr.length) {
                callback()
            } else {
                seq(arr, callback, index)
            }
        })
    }
    
    // trigger DOMContentLoaded
    function scriptsDone() {
        var DOMContentLoadedEvent = document.createEvent('Event')
        DOMContentLoadedEvent.initEvent('DOMContentLoaded', true, true)
        document.dispatchEvent(DOMContentLoadedEvent)
    }
    
    /* script runner */
    
    function insertScript($script, callback) {
        var s = document.createElement('script')
        if (!s.type) {
            s.type = 'text/javascript'
        }
        if ($script.src) {
            s.onload = callback
            s.onerror = callback
            s.src = $script.src
        } else {
            s.textContent = $script.innerText
        }
    
        // re-insert the script tag so it executes.
        document.head.appendChild(s)
    
        // clean-up
        $script.parentNode.removeChild($script)
    
        // run the callback immediately for inline scripts
        if (!$script.src) {
            callback()
        }
    }
    
    // https://html.spec.whatwg.org/multipage/scripting.html
    var runScriptTypes = [
                'application/javascript',
                'application/ecmascript',
                'application/x-ecmascript',
                'application/x-javascript',
                'text/ecmascript',
                'text/javascript',
                'text/javascript1.0',
                'text/javascript1.1',
                'text/javascript1.2',
                'text/javascript1.3',
                'text/javascript1.4',
                'text/javascript1.5',
                'text/jscript',
                'text/livescript',
                'text/x-ecmascript',
                'text/x-javascript'
            ]
    
    function runScripts($container) {
        // get scripts tags from a node
        var $scripts = $container.querySelectorAll('script')
        var runList = []
        var typeAttr
    
        [].forEach.call($scripts, function ($script) {
            typeAttr = $script.getAttribute('type')
    
            // only run script tags without the type attribute
            // or with a javascript mime attribute value
            if (!typeAttr || (runScriptTypes ? runScriptTypes.indexOf(typeAttr) !== -1 : 'text/javascript')) {
                runList.push(function (callback) {
                    insertScript($script, callback)
                })
            }
        })
    
        // insert the script tags sequentially
        // to preserve execution order
        seq(runList, scriptsDone)
    }
    
    let fragment = document.createRange()
        .createContextualFragment(html);
    
    // fragment.baseURI = 'http://toolsqaplp/publish/Dev_Testing/n1d/DS_MAC/en/CATMMGSkillets_en.edu/CATMMGEdc0020_en.doc/src/';
    document.getElementById('content')
        .appendChild(fragment);
    

    【讨论】:

    • 感谢您的回答。
    【解决方案2】:

    official document 表示 bypassSecurityTrustHtml() 应该适用于您的情况。

    我还假设您必须使用[innerHTML] 属性来填充目标容器中的内容。

    我有类似的需求,我需要单个 HTML 标记和单个脚本标记。我为此使用了bypassSecurityTrustResourceUrl()

    return this.sanitizer.bypassSecurityTrustResourceUrl(url)
    

    我很确定它也适用于您的情况,因为您正在获取可执行源。

    你也可以试试bypassSecurityTrustScript()bypassSecurityTrustHtml()的组合。

    【讨论】:

      猜你喜欢
      • 2017-02-12
      • 2019-04-21
      • 2017-08-07
      • 2016-10-27
      • 1970-01-01
      • 2016-12-01
      • 2016-11-15
      • 2016-10-11
      • 1970-01-01
      相关资源
      最近更新 更多