首頁  >  文章  >  web前端  >  動態綁定HTML的方法

動態綁定HTML的方法

高洛峰
高洛峰原創
2017-03-08 15:49:531234瀏覽

在Web前端開發中,我們經常會遇見需要動態的將一些來自後端或是動態拼接的HTML字串綁定到頁面DOM顯示,特別是在內容管理系統(CMS:是Content Management System的縮寫),這樣的需求,更是遍地皆是。

對於對angular的讀者肯定首先會想到ngBindHtml,對,angular為我們提供了這個指令來動態綁定HTML,它會將計算出來的表達式結果用innerHTML綁定到DOM。但是,問題並不是這麼簡單。在網路安全性中XSS(Cross-site scripting,腳本注入攻擊),它是在網路應用程式中很典型的電腦安全漏洞。 XSS攻擊指的是透過對網頁注入可執行客戶端程式碼且成功地被瀏覽器執行,來達到攻擊的目的,形成了一次有效XSS攻擊,一旦攻擊成功,它可能會獲取到用戶的一些敏感資訊、改變使用者的體驗、誘導使用者等非法行為,有時XSS攻擊還會合其他攻擊方式同時實施例如SQL注入攻擊伺服器和資料庫、Click劫持、相對連結劫持等實施釣魚,它帶來的危害是巨大的,也是web安全的頭號大敵。更多的Web安全問題,請參考wiki https://en.wikipedia.org/wiki/Cross-site_scripting%E3%80%82

在angular中默認是不相信添加的HTML內容,對於新增的HTML內容,首先必須利用$sce.trustAsHtml,告訴angular這是可信的HTML內容。否則你將會得到$sce:unsafe的異常錯誤。

Error: [$sce:unsafe] Attempting to use an unsafe value in a safe context.

下面是一個綁定簡單的angular連結的demo:

HTML:

<div ng-controller="DemoCtrl as demo">
    <div ng-bind-html="demo.html"></div>
</div>

JavaScript:

angular.module("com.ngbook.demo", [])
    .controller("DemoCtrl", ["$sce", function($sce) {
        var vm = this;

        var html = &#39;<p>hello <a href="https://angular.io/">angular</a></p>&#39;;
        vm.html = $sce.trustAsHtml(html);

        return vm;
    }]);

對於簡單的靜態HTML,這個問題就解決了。但對於複雜的HTML,這裡的複雜是指帶有angular表達式、指令的HTML模板,對於它們來說,我們不僅希望綁定大DOM顯示,同時還希望得到angular強大的雙向綁定機制。 ngBindHhtml並不會和$scope關聯雙向綁定,如果在HTML中存在ngClick、ngHref、ngSHow、ngHide等angular指令,它們並不會被compile,點擊這些按鈕,也不會發生任何反應,綁定的表達式也不會在更新。例如嘗試將上次的連結變成:ng-href=“demo.link”,連結並不會被解析,在DOM看見的仍會是原樣的HTML字串。

在angular中的所有指令要生效,都需要經過compile,在compile中包含了pre-link和post-link,連接上特定行為,才能工作。大部分情況下compile,是會在angular啟動時,自動compile的。但如果是對於動態新增的模板,則需要手動的compile。 angular中為我們提供了$compile服務來實現這項功能。下面是一個比較通用的compile範例:

HTML:

<body ng-controller="DemoCtrl as demo">
    <dy-compile html="{{demo.html}}">
    </dy-compile>
    <button ng-click="demo.change();">change</button>
</body>

JavaScript:

angular.module("com.ngbook.demo", [])
    .directive("dyCompile", ["$compile", function($compile) {
        return {
            replace: true,
            restrict: &#39;EA&#39;,
            link: function(scope, elm, iAttrs) {
                var DUMMY_SCOPE = {
                        $destroy: angular.noop
                    },
                    root = elm,
                    childScope,
                    destroyChildScope = function() {
                        (childScope || DUMMY_SCOPE).$destroy();
                    };

                iAttrs.$observe("html", function(html) {
                    if (html) {
                        destroyChildScope();
                        childScope = scope.$new(false);
                        var content = $compile(html)(childScope);
                        root.replaceWith(content);
                        root = content;
                    }

                    scope.$on("$destroy", destroyChildScope);
                });
            }
        };
    }])
    .controller("DemoCtrl", [function() {
        var vm = this;

        vm.html = &#39;<h2>hello : <a ng-href="{{demo.link}}">angular</a></h2>&#39;;

        vm.link = &#39;https://angular.io/&#39;;
        var i = 0;
        vm.change = function() {
            vm.html = &#39;<h3>change after : <a ng-href="{{demo.link}}">&#39; + (++i) + &#39;</a></h3>&#39;;
        };
    }]);

這裡建立了一個叫dy-compile的指令,它首先會監聽綁定屬性html值的變化,當html內容存在的時候,它會嘗試先創個子scope,然後利用$compile服務來動態連接傳入的html,並替換掉當前DOM節點;這裡創建子scope的原因,是方便在每次銷毀DOM的時,也能容易的銷毀掉scope,去掉HTML compile帶來的watchers函數,並在最後的父scope銷毀的時候,也會嘗試銷毀該scope。

因為有了上邊的compile的編譯和連接,則ngHref指令就可以生效了。這裡只是試著給出動態compile angular模組的例子,具體的實作方式,請參考你的業務來聲明特定的directive。


以上是動態綁定HTML的方法的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn