【问题标题】:How to make out of an HTML text a DOM object如何将 HTML 文本变成 DOM 对象
【发布时间】:2023-03-11 01:07:02
【问题描述】:

我有一个应用程序,其中页面生成器创建一个保存在数据库中的起始页面。保存的信息就是 DOM 对象的outerHTML。要创建编辑函数,我需要一个反函数,它根据 HTML 信息重新创建 DOM 对象。不幸的是,将解密的信息分配给outerHTML 部分没有任何结果,因为 DOM 对象中的更改被忽略了。

我的问题:如何从保存的 outerHTML 信息中重新创建 DOM 对象?如果这是不可能的,那么做这种事情的正确方法是什么?

编辑 感谢你的回复!这是一些显示我在做什么的代码的 sn-ps。原型 MainWidget 正在从 HTML 页面获取信息并希望分配信息。使用的函数是另一个名为 Widgets 的对象(原型)的一部分。

var asserts = new Asserts();
var calls = new Calls();
var constants = new MainConst();
var strings = new Strings();
var widgets = new MainWidget();

MainWidget.method('assign2Widget', function (call, label, value, isValid) {
    isValid = toBoolean(isValid), value = strings.toString(value);

    if (calls.isValid(call) && strings.hasMinimalLength(label, 2)) {
        var section = (!label.includes('Builder')  // A marker, not an element!
                        && !label.includes(constants.NewsTicker))
            ? widgets.getSgSectionByLabel(document, label)
            : null;
        value = strings.decode(decodeURIComponent(value));      //<<<< Code decoded from DB

        if (asserts.isObject(section)) {
            section.outerHTML = value;
        } else if (label.includes(constants.Elements)) {
            if (asserts.isValid(infos.Elements) && infos.Elements.length > 0) {
                // HERE, THE CODE FROM DB SHOULD BE ADDED TO WIDGET.
                // The "label" gives the label of the widget, and the "value" is
                // what is to be assigned to.
            }
        } else if (label.includes(constants.NewsTicker)) {
            […]
        }
        […]
});

Widget.method('getElementTypeByLabel', function (thing, elementType, label) {
    if (asserts.isObject(thing)
        && strings.hasMinimalLength(elementType, 2)
        && strings.hasMinimalLength(label, 2)) {

        var element, elements = document.getElementsByTagName(elementType);

        if (asserts.isValid(elements)
            && asserts.isDefined(elements.length) && elements.length === 0) {

            elements = thing.children;
        }
        for (var i = 0; asserts.isDefined(elements.length) && i < elements.length; i++) {
            element = elements*;

            if (element.getAttribute !== null) {
                var labelName = element.getAttribute(constants.label);

                if (label === labelName && element !== null) {
                    return element;
                }
            } else {
                return null;
            }
        }
        // If the element was not found, search recursively the elements!
        for (var i = 0; asserts.isDefined(elements.length) && i < elements.length; i++) {
            return this.getElementTypeByLabel(elements*, elementType, label);
        }
    } else {
        // Error! //messages.invalidFunctionCall(functionName);
    }
    return null;
});

Widget.method('getSgSectionByLabel', function (element, label) {
    return this.getElementTypeByLabel(element, 'sg-section', label);
});

编辑 2:在编辑现有页面时,我只使用了在 sg-section 中所做的更改来重新创建内容。

MainWidget.js:
[…]
MainWidget.method('assign2Widget', function (call, label, value, isValid) {
    isValid = toBoolean(isValid), value = strings.toString(value);

    if (calls.isValid(call) && strings.hasMinimalLength(label, 2)) {
        var section = (!label.includes('Builder')  // A marker, not an element!
                        && !label.includes(constants.NewsTicker))
            ? widgets.getSgSectionByLabel(document, label)
            : null;
        value = strings.decode(decodeURIComponent(value));

        if (asserts.isObject(section)) {
            section.outerHTML = value;
        } else if (label.includes(constants.Elements)) {
            if (asserts.isString(value) && value.includes(LeftBracket)) {
                value = arrays.toArray(value);  //value.replace(LeftBracket, '').split(RightBracket);
            }
            if (arrays.isArray(value)) {
                for (var i = 0; i < value.length; i++) {
                    infos.insertGridItem(value[i]);
                }
            }
            […]

MainInfos.js:
[…]
function MainInfos() {
    this.Elements;                      // Object for startGridGenerator
    this.insertGridItem;                // Function of startGridGenerator
    this.PrototypeName = 'MainInfos';
}

MainInfos.inherits(Infos);

MainWidget.method('assign2Widget', function (call, label, value, isValid) {
    isValid = toBoolean(isValid), value = strings.toString(value);

    if (calls.isValid(call) && strings.hasMinimalLength(label, 2)) {
        var section = (!label.includes('Builder')  // A marker, not an element!
                        && !label.includes(constants.NewsTicker))
            ? widgets.getSgSectionByLabel(document, label)
            : null;
        value = strings.decode(decodeURIComponent(value));

        if (asserts.isObject(section)) {
            section.outerHTML = value;
        } else if (label.includes(constants.Elements)) {
            if (asserts.isString(value) && value.includes(LeftBracket)) {
                value = arrays.toArray(value);  //value.replace(LeftBracket, '').split(RightBracket);
            }
            if (arrays.isArray(value)) {
                for (var i = 0; i < value.length; i++) {
                    infos.insertGridItem(value[i]);
                }
            }
        } else if (label.includes(constants.NewsTicker)) {
            […]
        }
});

startGridGenerator.js:
[…]
(function () {
    var moduleName = 'ivmGridBuilder';

    var controllerName = moduleName + Controller;

    angular.module(moduleName, [
        'ionic',
        'ui.sortable',
        'ivmColorpicker',
        'ivmIconpicker'
    ])
        .controller(controllerName, function ($scope,
                                              $ionicScrollDelegate,
                                              $ionicModal,
                                              $sce,
                                              CommunicationService) {
            […]
            /**
             * Inserts an existing grid item to the item's array
             *
             * @param item
             */
            $scope.insertGridItem = function (item) {
                if (asserts.isObject(item)) {
                    $scope.items.push(item);
                    infos.Elements.push(item);
                    $ionicScrollDelegate.resize()
                } else {
                    // First call with no valid item & "remember" this function
                    // by having a link to in in object MainInfos!
                    infos.insertGridItem = $scope.insertGridItem;
                }
            };

【问题讨论】:

    标签: javascript angularjs dom


    【解决方案1】:

    解决方案应该是,你得到一个包含内容的 HTML 字符串。然后您使用$sce.trustAsHtml(); 并分配给一个范围变量,这将确保HTML 是安全的,然后您可以使用下面的带有指令ng-bind-html 的HTML 将HTML 字符串呈现为实际的HTML。

    这是一个相同的工作示例。

    var app = angular.module("angularApp", []);
    app.controller("appController", function($scope, $sce) {
      $scope.content = "This text is <em>html capable</em> meaning you can have <a href=\"#\">all</a> sorts <b>of</b> html in here.";
      $scope.output = $sce.trustAsHtml($scope.content);
    });
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
    <h2>Rendering HTML with angularJS</h2>
    <div ng-app="angularApp" ng-controller="appController">
      <div ng-bind-html="output"></div>
    </div>

    另一种选择是使用ng-sanitize

    如果您使用ng-sanitize - 通过将 HTML 解析为标记来清理输入。然后将所有安全令牌(来自白名单)序列化回正确转义的 html 字符串。这意味着没有不安全的输入可以进入返回的字符串。

    请参阅以下问题以获得更详细的说明。

    SO Answer


    var app = angular.module("angularApp", ['ngSanitize']);
    app.controller("appController", function($scope) {
      $scope.content = "This text is <em>html capable</em> meaning you can have <a href=\"#\">all</a> sorts <b>of</b> html in here.";
    });
    <script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.6.6/angular.min.js"></script><script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.6.6/angular-sanitize.min.js"></script>
    <h2>Rendering HTML with angularJS</h2>
    <div ng-app="angularApp" ng-controller="appController">
      <div ng-bind-html="content"></div>
    </div>

    如上例所示,无需调用$sce.trustAsHtml();,因为ngSanitize 会自动处理。

    如果这种方法对您有帮助,或者您是否遇到任何问题,请告诉我!

    【讨论】:

      【解决方案2】:

      您可以使用DOMParser() 创建#document,或使用&lt;template&gt; 元素从字符串创建#document-fragment

      const parser = new DOMParser();
      const doc = parser.parseFromString(/* outerHTML */, "text/html");
      

      【讨论】:

      • 谢谢!我将尝试是否可以使用它来将 DOM 中的空 sg-section 对象替换为保存的 sg-section outerHTML 信息。
      【解决方案3】:

      您可以将字符串添加到页面中的隐藏 Div 中,然后使用 javascript 从该 Div 中获取您想要的元素。就像在这段代码中一样:

      var str ='abc 123<div id="test">coursesweb.net</div><span class="cls">some text</span>';
      document.querySelector('body').insertAdjacentHTML('beforeend', '<div style="display:none;">'+str+'</div>');
      var ob_test = document.getElementById('test');
      alert(ob_test.innerHTML);
      

      【讨论】:

      • 感谢您的回复!我有所谓的sg-section 对象,它由页面生成器创建,我保存在数据库中。是否可以使用隐藏元素的技巧将现有的空对象更改为数据库中的空对象?
      • 试试这个:document.querySelector('#sg-section_id').outerHTML ='html string';。或者,如果 sg-section 是 JS 中的对象:sg-section.outerHTML ='html string';
      • 感谢您的回答!我想是保存整个 sg-section 还是只保存更改的内容更好,并且可以使用后者,这样我就只保存了 JavaScript 对象。
      猜你喜欢
      • 2022-10-14
      • 1970-01-01
      • 2016-10-21
      • 1970-01-01
      • 2011-01-16
      • 2010-09-17
      • 2012-05-25
      • 2018-06-23
      • 1970-01-01
      相关资源
      最近更新 更多