创建或更新给定HTML

时间:2016-04-08 10:55:18

标签: javascript jquery html html5 dom

代码是获取HTML文件和configObject,并根据此配置对象需要修改此htmlFile内容(代码正常工作)

这是输入: 请注意,在数组的firstobj中(有没有提供 next 属性的情况,表示将新脚本放在底部)下一个表示将脚本标记放在脚本之后ID “ui-boot”

var extendedHtmlObject = [{
                    type: 'script',
                    action: 'new',
                    content: 'console.log(‘hello world’);',
                    next: "ui-boot"
                }, {
                    type: 'script',
                    id: "ui-boot",
                    action: 'upd',
                    innerElem: [{
                        type: 'attr',
                        id: 'data--ui-comersion',
                        content: '1.17'
                    }, {
                        type: 'attr',
                        id: 'src',
                        content: '/test/test2/-co.js'
                    }]
                }

这是主要功能:

getExtend: function(htmlContent, extendedHtmlObject) {
    var self = this;
    if (extendedHtmlObject) {
        extendedHtmlObject.forEach(function(configs) {
            switch (configs.type) {
                case 'script':
                    htmlContent = self._handleScriptElement(htmlContent, configs);
                    break;
                case 'head':
                    break;
            }
        });
    }
    return htmlContent;
},

此方法确定是否需要根据输入对象

创建新脚本或更新现有脚本属性
_handleScriptElement: function(htmlFilecontent, configEntry) {

    var oExtendedHTML = htmlFilecontent;
    switch (configEntry.action) {
        case 'new':
            oExtendedHTML = this._createNewScript(htmlFilecontent, configEntry);
            break;
        case 'upd':
            var sParsedHtml = this._htmlParser(oExtendedHTML);
            oExtendedHTML = this._updateScript(oExtendedHTML, configEntry, sParsedHtml);
            oExtendedHTML = this._convertHtmlBack(oExtendedHTML);
            break;
    }
    return oExtendedHTML;
},

这是使用两个选项创建新脚本的方法 1.第一个fork需要解析html 2.第二个没有。

_createNewScript: function(htmlFilecontent, configEn) {
    var sScriptContent = this._createScript(configEntry.content);
    if (configEn.next != null) {
        var sParsedHtml = this._htmlParser(htmlFilecon);
        $(sScriptContent).insertAfter(sParsedHtml.find('#' + configEn.next));
        htmlFilecontent = this._convertHtmlBack(sParsedHtml);
    } else {
     //when the script is at the end of file
        var iHeadEndTagPos = htmlFilecon.search("(| )* )*head(|*>");
        htmlFilecon = htmlFilecon.substr(0, iHeadEndTagPos) + sNewScript + htmlFilecon.substr(iHeadEndTagPos);
    }
    return htmlFilecon;
},

这段代码是多余的,效率不高(我对JS来说还是新手),我可以用JS prototype改进它吗? 我想在开始时解析一次,在结束时解析parseBack(循环输入对象),但问题是在createNewScript第二个叉子中不需要使用解析器...

requireJS

模块内的代码

更新 为了更清楚,外部API有两个输入和一个输出

  
      
  1. HTML文件内容
  2.   
  3. config对象,用于确定如何更新HTML,例如创建新脚本(作为数组中的第一个对象)   extendedHtmlObject)或更新现有的脚本内容,如   属性值)
  4.   
  5. 输出应该是带有所有修改的扩展HTML
  6.   

**更新2 ** 如果我能提供更多数据以使其更清晰,请告诉我。

1 个答案:

答案 0 :(得分:0)

也许看一下那里的众多模板系统。

或者,简化您的html创建。如果使用innerHTML创建DOM节点,请将HTML文件内容放在一个长字符串中,其中包含所有值/类名/等的占位符的完整标记。

例如:<script src="{{src}" id="{{id}}"></script>然后只需用值替换所有占位符。然后你可以用这个字符串更新目标的innerHTML。

如果您使用DOM节点创建document.createElement(),请提前创建所有这些模板节点(documentFragments在这里非常方便)。然后有一个函数将检查'extendedHtmlObject'设置并在更新时选择页面上已有的节点,或选择premade nodeList。将html结构作为节点后,将其交给另一个函数,该函数将使用“extendedHtmlObject”中的新值更新结构内的所有节点。然后,您可以将节点附加到其目标。

在这两种情况下,你都可以使用来回的html解析和分支。

伪代码:

(function myModule() {
    var templates = {},
        createTemplates = function() {
            // Create all templates you'll use and save them.
            // If you create nodes, also include a mapping from each node to its respective value
            // eg: children[0] = 'label', children[1] = 'value'
        },
        updateTemplate = function( template, values ) {
            // INNERHTML: for each placeholder 'valueName' in string template, replace placeholder by values[valueName]
            // NODE CREATION: use the node mapping in the template to select each node in the template and replace its current value with values[valueName]
            return template;
        },
        getTemplate = function( type, reference ) {
            return (type === 'new') ? templates[reference] : $('#' + reference);
        },
        update = function( config ) {
            var html = getTemplate(config.action, (config.next || config.id)),
                updated = updateTemplate(html, config);
            if (config.next) $('#' + config.next).insertAfter(html);
            else $('#' + config.id).innerHTML = html /* OR */ $('#' + config.id).appendChild(html);
        },
        init = function() {
            createTemplates();
        };
}());

TLDR :首先创建新的或抓取现有的HTML,然后更新字符串或节点,然后确定它必须去哪里。让一切尽可能一般。

  • html创建函数应该能够创建任何html元素/更新任何模板,而不仅仅是脚本节点。

  • 更新功能不应该关心html之前是否存在更新或新生成。

  • 将html放回网站的功能不应该在创建函数中。

通过这种方式,您可能最初只会使用一个大的switch语句来调用具有不同参数的相同函数,这可以通过向'extendedHtmlObject'添加另一个配置设置来轻松替换。

<强>更新

我已经创建了一个可用结构的示例。它使用DOM方法(createElement等)来创建包含更新的输入字符串的新文档。您可以根据需要更改它以更好地匹配您的特定输入/输出。它更像是一个例子,说明如何使用一些常规功能和很多配置设置来创建任何你想要的东西。

这不会使用我之前讲过的模板,因为这需要更长的时间。如果你想要模板,只需看看handlebars.js或mustache.js。

但它更符合你自己的结构,所以我希望你更容易选择你喜欢的部分。

var originalHTML = '<script id="ui-boot" src="path/to/script/scriptname.js"></script>',

    imports = {},

// IMPORTANT NOTE:
// Using a string as the body of a script element might use eval(), which should be avoided at all costs.
// Better would be to replace the 'content' config setting by a 'src' attribute and ahve the content in a seperate file you can link to.
    configAry = [
        { // script-new
            type: 'script',
            action: 'new',
            content: 'console.log(‘hello world’);',
            next: "ui-boot"
        }, 
        { // script-upd
            type: 'script',
            id: "ui-boot",
            action: 'upd',
            innerElem: [
                {
                    type: 'attr',
                    id: 'data--ui-comersion',
                    content: '1.17'
                }, 
                {
                    type: 'attr',
                    id: 'src',
                    content: '/test/test2/-co.js'
                }
            ]
        }
    ],

// Extra helpers to make the code smaller. Replace by JQuery functions if needed.
    DOM = {
        'create' : function create( name ) {
            return document.createElement(name);
        },
        // Create a new document and use the string as the body of this new document.
        // This can be replaced by other functions of document.implementation if the string contains more than just the content of the document body.
        'createDoc' : function createDoc( str ) {
            var doc = document.implementation.createHTMLDocument('myTitle');
            doc.body.innerHTML = str;
            return doc;
        },          
        'insertAfter' : function insertAfter(node, target, content ) {
            target = content.querySelector(target);
            if (target.nextSibling) target.nextSibling.insertBefore(node);
            else target.parentNode.appendChild(node);
            return content;
        },
        'replace' : function replace( node, target, content ) {
            target = content.querySelector(target);
            target.parentNode.replaceChild(node, target);
            return content;
        },
        'update' : function update( node, textContent, attributes ) {
            if (textContent) node.textContent = textContent;
            return (attributes) ? 
                Object.keys(attributes).reduce(function( node, attr ) {
                    node.setAttribute(attr, attributes[attr]);
                    return node;
                }, node) :
                node;
        }
    },

// The actual module
    moduleHTMLExtender = (function( imports ) {
        var createExtension = function createExtension( extension, content ) {
                switch (extension.action) {
                    case 'new' :
                        return {
                            'method' : 'insertAfter',
                            'node' : DOM.update(DOM.create(extension.type), extension.content),
                            'target' : '#' + extension.next
                        };
                    break;
                    case 'upd' :
                        return {
                            'method' : 'replace',
                            'node' : DOM.update(content.querySelector('#' + extension.id).cloneNode(), null, extension.innerElem.reduce(function( map, config ) {
                                if (config.type === 'attr') map[config.id] = config.content;
                                return map;
                            }, {})),
                            'target' : '#' + extension.id
                        }
                    break;
                    default:
                        return false;
                    break;
                }
            },
            addExtensions = function addExtensions( content, extensions ) {
                return extensions.reduce(function( content, extension ) {
                    return DOM[extension.method](extension.node, extension.target, content);
                }, content);
            },
            // Returns new document as an [object Document]
            extendContent = function extendContent( content, extensions ) {
                var doc = DOM.createDoc(content),
                    toExtend = (extensions) ? 
                        extensions.map(function( extension ) {
                            return createExtension(extension, doc);
                        }) :
                        null;
                var res = null;
                if (toExtend) return addExtensions(doc, toExtend);
                else return doc;
            };
        // Export public interface. Replace this by your require.js code or similar.
        return {
            'extendContent' : extendContent
        };
    }( imports )),

    extendedHTMLDoc = moduleHTMLExtender.extendContent(originalHTML, configAry);

console.log(extendedHTMLDoc.documentElement.outerHTML);
// output = '<html><head><title>myTitle</title></head><body><script id="ui-boot" src="/test/test2/-co.js" data--ui-comersion="1.17"></script><script>console.log(hello world);</script></body></html>';