本文執行個體講述了AngularJS動態綁定HTML的方法。分享給大家供大家參考,具體如下:
在Web前端開發中,我們經常會遇見需要動態將一些來自後端或者是動態拼接的HTML字串綁定到頁面DOM顯示,特別是在內容管理系統(CMS:是Content Management System的縮寫),這樣的需求,更是遍地皆是。
對於對angular的讀者肯定首先會想到ngBindHtml,對,angular為我們提供了這個指令來動態綁定HTML,它會將計算出來的運算式結果用innerHTML綁定到DOM。但是,問題並不是這麼簡單。在Web安全中XSS(Cross-site scripting,指令碼插入式攻擊),它是在Web應用程式中很典型的電腦安全性漏洞。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 = '<p>hello <a href="https://angular.io/">angular</a></p>'; 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: 'EA', 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 = '<h2>hello : <a ng-href="{{demo.link}}">angular</a></h2>'; vm.link = 'https://angular.io/'; var i = 0; vm.change = function() { vm.html = '<h3>change after : <a ng-href="{{demo.link}}">' + (++i) + '</a></h3>'; }; }]);
這裡建立了一個叫dy-compile的指令,它首先會監聽綁定屬性html值的變化,當html內容存在的時候,它會嘗試首先創個一個子scope,然後利用$compile服務來動態串連傳入的html,並替換掉當前DOM節點;這裡建立子scope的原因,是方便在每次銷毀DOM的時,也能容易的銷毀掉scope,去掉HTML compile帶來的watchers函數,並在最後的父scope銷毀的時候,也會嘗試銷毀該scope。
因為有了上邊的compile的編譯和串連,則ngHref指令就可以生效了。這裡只是嘗試給出動態compile angular模組的例子,具體的實現方式,請參照你的業務來聲明特定的directive。
希望本文所述對大家AngularJS程式設計有所協助。