【问题标题】:Escaping & > characters in ng-bind in AngularJs在 AngularJs 的 ng-bind 中转义 & > 字符
【发布时间】:2013-10-09 06:21:51
【问题描述】:

我有一个用例,我们可以在字符串中包含“&”和“>”字符。例如。强生公司,value > 3。因此,虽然来自服务器的响应被编码,因此值变为 'value &ampgt; 3'。

ng-bind 不支持以下内容:

value > 3 将为ngBind 呈现,而浏览器呈现与value > 3 相同的内容。

http://jsfiddle.net/HKahG/2/

Ng:bind <div ng-bind="model"></div> 
Ng:bind-html <div ng-bind-html="model"></div>
<div> From Div: value &gt; </div>

为什么ng-bind 中不存在此默认浏览器行为?。我不想使用ng-bind-html&lt; 的值有问题,它不是 html)或ng-bind-unsafe-html

我的应用程序具有动态键值字段,这些字段将显示在应用程序的不同部分。因此,使用单独的指令或装饰器来显示所有字符串字段比使用ngBind 需要额外的开销。

问题:

1) 有没有其他方法可以在不使用附加指令的情况下做同样的事情,或者这是处理编码数据的正确方法?

2) 我可以覆盖ng-bind 的行为或默认装饰它吗?

【问题讨论】:

    标签: javascript html angularjs ng-bind


    【解决方案1】:

    编辑:请直接进入答案底部以获得最佳版本;答案是按时间顺序排列的;最后,经过几次迭代,我得到了最佳代码。谢谢。

    • 我可以覆盖 ng-bind 的行为或默认装饰它吗?

    是的。我已经完成了一个非常简单的实现,它使ng-bind 可以按照您的意愿行事。嗯...我不确定这是否正是你想要的,但至少它可以满足我的理解。

    工作小提琴:http://jsfiddle.net/93QQM/

    这里是代码:

    module.directive('ngBind', function() {
        return {
            compile: function(tElement, tAttrs) {
                tAttrs.ngBind = 'myBind(' + tAttrs.ngBind + ')';
                return { 
                    pre: function(scope) {
                        scope.myBind = function(text) {
                            return angular.element('<div>' + text + '</div>').text();
                        }
                    }
                };
            }
        }
    });
    

    这并不完全是一个“附加指令”——这是“覆盖 ng-bind 的行为”的方式。它不会添加新指令,它只是扩展现有 ngBind 指令的行为。

    compile 函数中,我们修改ng-bind 属性的值,将其包装到函数调用中。有了这个,我们可以访问原始模型值,并有机会将其修改后返回。

    我们在预链接阶段通过作用域使函数可用,因为如果我们在后链接阶段这样做,该函数将仅在原始 ngBind 指令检索到之后才可用来自属性的值(这将是一个空字符串,因为找不到该函数)。

    myBind 函数简单而智能:它创建一个元素,使用文本 - 未更改 - 作为元素主体,只通过 text 函数立即检索 - 将返回内容就像“浏览器呈现”它。

    这样,您可以像往常一样使用 ngBind,例如 &lt;div ng-bind="model.content" /&gt;,但要修改此行为。


    改进版

    不是将myBind 函数附加到每个应用了 ngBind 的作用域,而是在每个预链接阶段,我们只能将它附加到$rootScope 一次,使其立即可用于所有作用域。

    新的工作小提琴:http://jsfiddle.net/EUqP9/

    新代码:

    module.directive('ngBind', ['$rootScope', function($rootScope) {
        $rootScope.myBind = function(text) {
            return angular.element('<div>' + text + '</div>').text();
        };
        return {
            compile: function(tElement, tAttrs) {
                tAttrs.ngBind = 'myBind(' + tAttrs.ngBind + ')';
            }
        };
    }]);
    

    比以前的版本干净多了!当然,您可以将myBind 函数名称更改为您想要的任何其他名称。该功能的“成本”是这样的:将这个简单的功能添加到根范围 - 由您决定它是否物有所值。


    又一个版本

    受 Chemiv 的回答的影响...为什么不从任何范围中删除该功能并使其成为过滤器呢?它也有效。

    又一个新的工作小提琴:http://jsfiddle.net/hQJaZ/

    还有新代码:

    module.filter('decode', function() {
        return function(text) {
            return angular.element('<div>' + text + '</div>').text();
        };
    }).directive('ngBind', function() {
        return {
            compile: function(tElement, tAttrs) {
                tAttrs.ngBind += '|decode';
            }
        };
    });
    

    现在您可以从菜单中选择三个选项。

    【讨论】:

    • 为什么不把最好的(最后的)版本放在最上面呢?正如许多其他答案所做的那样。
    • @DmitryGonchar - 好建议;我现在无法正确编辑答案;我刚刚在顶部快速添加了一条评论,警告最好的版本在底部。
    【解决方案2】:

    这个 HTML:

    &gt;
    

    它可能没有 HTML 标签,但它仍然是 HTML。如果你想使用ng-bind,你的服务器需要返回未编码的文本。即&amp;gt; 而不是&amp;gt;

    使用ng-bind-html 或修改您的服务器以返回纯文本而不首先对其进行 html 编码。

    编辑:快速演示,说明在 JavaScript 中使用 &amp;gt;&amp;gt;

    div1.innerHTML = "&gt;";  // write HTML
    div2.textContent = ">";   // write plain text
    console.log(div1.innerHTML === div2.innerHTML);
    console.log(div1.textContent === div2.textContent);
    

    http://jsfiddle.net/XhEcV/

    【讨论】:

    • >是用于显示“>”的保留字符,有助于不要与标签混淆。浏览器正确渲染,最后我们希望在 html 内容的页面部分显示内容。由于可能发生 XSS 漏洞,我无法从服务器返回未编码的文本(我知道 Angular 可以防止这种情况发生)。感谢您的回答。
    • 因此,您的服务器返回 HTML。使用ng-bind-html
    • 服务器返回 JSON 编码数据,用于显示在内容中。但无论如何,ng-bind-html 会引发 Parser 错误:文本显示为 'val
    • 你是说你的服务器编码的是&amp;gt;,而不是&lt;?如果是这样,那么您将混合使用无法可靠解析的 html 和纯文本。
    • 您在输入中输入 > 然后看到它在 ng-bind 中完美呈现的示例不是一个合适的示例......当您输入已经解码并呈现为平面的字符时text 因此为什么可以在 ng-bind 中看到它...如果您希望在 ng-bind 中看到元素,您要么需要让后端将 html 元素作为解码的纯文本返回,要么创建一个指令将其解码为平面转之前先写文字
    【解决方案3】:

    ng-bind 使用 .text() 方法替换文本,而您的代码包含 &amp;gt; 这是 HTML 标记,但 ng-bind 无法正确呈现。当您实际输入 HTML 内容时,您应该在此位置使用 ng-bind-html。否则,您可以将 > 替换为 '>'。

    例如:- model = model.replace(/&amp;gt;/g, '&gt;');

    但在这种情况下,您必须替换所有不需要的 HTML 标记,因为 ng-bind-html 在您的情况下已经可以正常工作了。

    【讨论】:

      【解决方案4】:

      是的,让我们用过滤器“装饰”它:

      .filter("decode",function(){
          return function(str){         
            var el = document.createElement("div");
            el.innerHTML = str;
            str =   el.textContent || el.innerText;
            return str;        
          }
      });
      

      并像这样使用它:&lt;div ng-bind="model|decode"&gt;&lt;/div&gt;

      工作示例:http://jsfiddle.net/HKahG/5/

      受此答案启发:https://stackoverflow.com/a/784698/1206613

      【讨论】:

      • 你不应该先检查textContent,因为它是官方财产吗?
      • 我已经更新了问题,很抱歉我错过了某些内容。我知道这样做,但是默认情况下如何为 ng-bind 做到这一点。
      • @DarkKnight 我的英语不太好,但在我看来这是默认行为。 ngBind 属性告诉 Angular 用给定表达式的值替换指定 HTML 元素的文本内容(来自这里:docs.angularjs.org/api/ng.directive:ngBind)。所以“装饰”它是传统的做法..
      • @alex 已编辑(但问题不在于它;))
      • @Cherniv - 我看到的是 - 默认情况下,ngBind 或 {{}} 应与上述过滤器(您已编写)一起使用。我的用法只会看起来像 '
        (该过滤器应该是隐式的)。
      【解决方案5】:

      我记得有一个名为 ngBindHtmlUnsafe 的指令可用于此类用例。

      http://code.angularjs.org/1.0.8/docs/api/ng.directive:ngBindHtmlUnsafe

      请参考这里。不确定这是否在以后的不稳定版本中可用。 这是可用的最新稳定版本的链接。

      【讨论】:

        【解决方案6】:

        为什么不直接使用 $sce.trustAsHtml?

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2015-01-28
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多