首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >编写JS库以创建HTML表单

编写JS库以创建HTML表单
EN

Code Review用户
提问于 2017-02-07 22:18:17
回答 1查看 211关注 0票数 8

我目前正在编写一个JS库,以便在HTML中创建一个表单。这个图书馆需要:

  • 跨浏览器,至少与IE10兼容(早期版本可视为奖励)。
  • 多语言:您应该能够更改表单语言。
  • 能够加载外部javascript依赖项*
  • 与我的API通信
  • 快地
  • 尽可能简单地使用

所以,我现在所做的就是:

代码语言:javascript
复制
window.MyBasicLibrary = (function() 
{
'use strict';

    // Utilitarian function not to loose the scope 
    function bind(context, name){
        return function(){
            return context[name].apply(context, arguments);
        };
    }

    // Utilitarian function to get DOM by class
    function getElementsByClassName(node, classname) 
    {
        var a = [];
        var re = new RegExp('(^| )'+ classname +'( |$)');
        var els = node.getElementsByTagName("*");

        for (var i = 0, j = els.length; i < j; i++)
        {
            if (re.test(els[i].className))
                a.push(els[i]);
        }
        return (a);
    }

    /*
    ** Utilitarian function to serialize a form
    ** See : https://code.google.com/archive/p/form-serialize/
    */
    function serialize(form) 
    {
        if (!form || form.nodeName !== "FORM") {
            return;
        }
        var i, j, q = [];
        for (i = form.elements.length - 1; i >= 0; i = i - 1) {
            if (form.elements[i].name === "") {
                continue;
            }
            switch (form.elements[i].nodeName) {
            case 'INPUT':
                switch (form.elements[i].type) {
                case 'text':
                case 'hidden':
                case 'password':
                case 'button':
                case 'reset':
                case 'submit':
                    q.push(form.elements[i].name + "=" + encodeURIComponent(form.elements[i].value));
                    break;
                case 'checkbox':
                case 'radio':
                    if (form.elements[i].checked) {
                        q.push(form.elements[i].name + "=" + encodeURIComponent(form.elements[i].value));
                    }                       
                    break;
                case 'file':
                    break;
                }
                break;           
            case 'TEXTAREA':
                q.push(form.elements[i].name + "=" + encodeURIComponent(form.elements[i].value));
                break;
            case 'SELECT':
                switch (form.elements[i].type) {
                case 'select-one':
                    q.push(form.elements[i].name + "=" + encodeURIComponent(form.elements[i].value));
                    break;
                case 'select-multiple':
                    for (j = form.elements[i].options.length - 1; j >= 0; j = j - 1) {
                        if (form.elements[i].options[j].selected) {
                            q.push(form.elements[i].name + "=" + encodeURIComponent(form.elements[i].options[j].value));
                        }
                    }
                    break;
                }
                break;
            case 'BUTTON':
                switch (form.elements[i].type) {
                case 'reset':
                case 'submit':
                case 'button':
                    q.push(form.elements[i].name + "=" + encodeURIComponent(form.elements[i].value));
                    break;
                }
                break;
            }
        }
        return q.join("&");
    }

    // Element should be the result of getElementByID.
    var mb = function(element)
    {
        this.mainContainer = element;
    };


    mb.prototype.regional = {
        mcta_1: "Form A <This One Works>",
        mcta_2: "Form B",
        mcta_3: "Form C",
        submitFormA: "Submit"
    };

    mb.prototype.mainContainer = undefined;
    mb.prototype.currentForm = undefined;
    mb.prototype.APIEndpoint = 'https://www.example.com/api/';

    mb.prototype.initialize =  function()
    {
        this.createMainPageHTML();
    };

    mb.prototype.hideContainers = function()
    {
        var list = getElementsByClassName(this.mainContainer, "mbform_container");
        for (var i = 0; i < list.length; i++)
        {
            list[i].style["display"] = "none";
        }
    }

    mb.prototype.createMainPageHTML = function()
    {
        var element = document.getElementById('mbform_mainpage');

        this.hideContainers();

        if (typeof(element) != 'undefined' && element != null)
        {
            element.style["display"] = "block";
        }
        else
        {
            var mcta1 = '<div id="mbform_mcta1" class="button">'+ this.regional.mcta_1 +'</div>';
            var mcta2 = '<div id="mbform_mcta2" class="button">'+ this.regional.mcta_2 +'</div>';
            var mcta3 = '<div id="mbform_mcta3" class="button">'+ this.regional.mcta_3 +'</div>';
            var mpHTML = '<div id="mbform_mainpage" class="mbform_container">'+mcta1 + mcta2 + mcta3 +'</div>';
            // TODO Load CSS

            // Add HTML to DOM
            this.mainContainer.innerHTML = mpHTML; // takes an HTML string
            // TODO Load JS Dependencies

            // Add Event listener
            document.getElementById('mbform_mcta1').addEventListener("click", bind(this, "createFormA"), false);
            document.getElementById('mbform_mcta2').addEventListener("click", bind(this, "createFormB"), false);
            document.getElementById('mbform_mcta3').addEventListener("click", bind(this, "createFormC"), false);
        }


    };

    mb.prototype.createFormA = function()
    {
        var element = document.getElementById('mbform_FormAContainer');

        this.hideContainers();
        this.currentForm = "mbform_FormA";

        if (typeof(element) != 'undefined' && element != null)
        {
            element.style["display"] = "block";
        }
        else
        {
            var iemail = '<input type="text" value="" name="email" id="mbform_iemail"/><br/>';
            var ifirstname = '<input type="text" value="" name="firstname" id="mbform_ifirstname"/><br/>';
            var ilastname = '<input type="text" value="" name="lastname" id="mbform_ilastname"/><br/>';
            var formHTML = '<form id="mbform_FormA">'+iemail + ifirstname + ilastname + '</form>'
            // TODO : Disable form default bahaviour (Submit when Enter Keypress + submit button), button is placed outside form for testing purpose.
            var submitButton = '<button id="mbform_FormASubmit">'+ this.regional.submitFormA +'</button>';

            var formContainerHTML = '<div id="mbform_FormAContainer" class="mbform_container">'+ formHTML + submitButton +'</div>';

            this.mainContainer.innerHTML += formContainerHTML; // Append HTML to existing

            document.getElementById('mbform_FormASubmit').addEventListener("click", bind(this, "saveForm"), false);
        }
    };

    mb.prototype.createFormB = function()
    {
        console.log(this.mainContainer); // Is scope ok ?
    };

    mb.prototype.createFormC = function()
    {
        console.log(this.mainContainer); // Is scope ok ?
    };

    mb.prototype.getPostFromCurrentForm = function()
    {
        var data = serialize(document.getElementById(this.currentForm));
        console.log(data);
        return (data);
    }

    mb.prototype.saveForm = function()
    {
        var xhr = new XMLHttpRequest();
        var params = this.getPostFromCurrentForm();

        xhr.open('POST', this.APIEndpoint, true);
        xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
        xhr.onload = function () {
            console.log("Loading...");
        };
        // Current APIEndpoint is example.com, do not send the form.
        //xhr.send(params);
    }

    return (mb);
})();

下面是如何初始化库

代码语言:javascript
复制
(function() {
            var dom = document.getElementById('myForm');
            var mb = new MyBasicLibrary(dom);
            mb.initialize();
})();

我尽了最大的努力来尊重javascript最佳实践,但我不确定我是否做得很好。你对此有何看法?

此外,在变量中包含原始HTML似乎是一种糟糕的做法,但是为了性能目的,我需要最小化向服务器提出的请求的数量。这意味着我无法存储HTML服务器端并通过AJAX发送它。这是最好的解决办法吗?

我已经创建了一个JSFiddle,以防您想要修改它。

https://jsfiddle.net/xd4ojka2/

EN

回答 1

Code Review用户

发布于 2017-02-11 08:49:55

库违反了单一责任原则公开/封闭校长不要重复你自己

答复:

  • 张贴数据
  • 序列化数据
  • 创建标记
  • 维持状态
  • UI效应
  • 日志记录

开放/关闭:

元素-nodeName-类型的组合目前对于库的使用者来说很难扩展以允许它们处理更多。

表单-目前只能处理3,可以使处理0到多少硬件可以处理。

不要重复:

如果将问题的代码与这个答案进行比较,就可以看出。增加了一些局部变量和函数来减少冗余,还使用了本机文档方法。

代码语言:javascript
复制
window.MyBasicLibrary = (function() 
{
'use strict';

    // Utilitarian function not to loose the scope 
    function bind(context, name){
        return function(){
            return context[name].apply(context, arguments);
        };
    }

    // Utilitarian function to get DOM by class
    function getElementsByClassName(node, classname) 
    {
        return node.getElementsByClassName(classname);// works IE9+
    }

    /*
    ** Utilitarian function to serialize a form
    ** See : https://code.google.com/archive/p/form-serialize/
    */
    function serialize(form) 
    {
        if (!form || form.nodeName !== "FORM") {
            return;
        }
        var i, j, name, value, q = [];
        var elements = form.elements;
        var push = function()
        {
            q.push(name + "=" + encodeURIComponent(value));
        };
        for (i = elements.length - 1; i >= 0; i = i - 1) {
            var element = elements[i];
            name = element.name;
            if (name === "") {
                continue;
            }
            value = element.value;
            switch (element.nodeName) {
            case 'INPUT':
                switch (element.type) {
                case 'text':
                case 'hidden':
                case 'password':
                case 'button':
                case 'reset':
                case 'submit':
                    push();
                    break;
                case 'checkbox':
                case 'radio':
                    if (element.checked) {
                        push();
                    }                       
                    break;
                case 'file':
                    break;
                }
                break;           
            case 'TEXTAREA':
                push();
                break;
            case 'SELECT':
                switch (element.type) {
                case 'select-one':
                    push();
                    break;
                case 'select-multiple':
                    var options = element.options;
                    for (j = options.length - 1; j >= 0; j = j - 1) {
                        var option = options[j];
                        if (option.selected) {
                            value = option.value;
                            push();
                        }
                    }
                    break;
                }
                break;
            case 'BUTTON':
                switch (element.type) {
                case 'reset':
                case 'submit':
                case 'button':
                    push();
                    break;
                }
                break;
            }
        }
        return q.join("&");
    }

    // Element should be the result of getElementByID.
    var mb = function(element)
    {
        this.mainContainer = element;
    };


    mb.prototype.regional = {
        mcta_1: "Form A <This One Works>",
        mcta_2: "Form B",
        mcta_3: "Form C",
        submitFormA: "Submit"
    };

    mb.prototype.mainContainer = undefined;
    mb.prototype.currentForm = undefined;
    mb.prototype.APIEndpoint = 'https://www.example.com/api/';

    mb.prototype.initialize =  function()
    {
        this.createMainPageHTML();
    };

    mb.prototype.hideContainers = function()
    {
        var list = getElementsByClassName(this.mainContainer, "mbform_container");
        for (var i = 0; i < list.length; i++)
        {
            list[i].style["display"] = "none";
        }
    }

    mb.prototype.createMainPageHTML = function()
    {
        var element = document.getElementById('mbform_mainpage');

        this.hideContainers();

        if (typeof(element) != 'undefined' && element != null)
        {
            element.style["display"] = "block";
        }
        else
        {
            var button = function (id, text)
            {
                return '<div id="mbform_mcta' + id + '" class="button">'+ text +'</div>';
            };
            var mcta1 = button(1, this.regional.mcta_1);
            var mcta2 = button(2, this.regional.mcta_2);
            var mcta3 = button(3, this.regional.mcta_3);
            var mpHTML = '<div id="mbform_mainpage" class="mbform_container">'+mcta1 + mcta2 + mcta3 +'</div>';
            // TODO Load CSS

            // Add HTML to DOM
            this.mainContainer.innerHTML = mpHTML; // takes an HTML string
            // TODO Load JS Dependencies

            // Add Event listener
            var listener = function(id, letter)
            {
                document.getElementById('mbform_mcta' + id).addEventListener("click", bind(this, "createForm" + letter), false);
            };
            listener(1, "A");
            listener(2, "B");
            listener(3, "C");
        }


    };

    mb.prototype.createFormA = function()
    {
        var element = document.getElementById('mbform_FormAContainer');

        this.hideContainers();
        this.currentForm = "mbform_FormA";

        if (typeof(element) != 'undefined' && element != null)
        {
            element.style["display"] = "block";
        }
        else
        {
            var text = function(name)
            {
                return '<input type="text" value="" name="' + name + '" id="mbform_i' + name + '"/><br/>';
            };
            var iemail = text("email");
            var ifirstname = text("firstname");
            var ilastname = text("lastname");
            var formHTML = '<form id="mbform_FormA">'+iemail + ifirstname + ilastname + '</form>'
            // TODO : Disable form default bahaviour (Submit when Enter Keypress + submit button), button is placed outside form for testing purpose.
            var submitButton = '<button id="mbform_FormASubmit">'+ this.regional.submitFormA +'</button>';

            var formContainerHTML = '<div id="mbform_FormAContainer" class="mbform_container">'+ formHTML + submitButton +'</div>';

            this.mainContainer.innerHTML += formContainerHTML; // Append HTML to existing

            document.getElementById('mbform_FormASubmit').addEventListener("click", bind(this, "saveForm"), false);
        }
    };

    mb.prototype.createFormB = function()
    {
        console.log(this.mainContainer); // Is scope ok ?
    };

    mb.prototype.createFormC = function()
    {
        console.log(this.mainContainer); // Is scope ok ?
    };

    mb.prototype.getPostFromCurrentForm = function()
    {
        var data = serialize(document.getElementById(this.currentForm));
        console.log(data);
        return (data);
    };

    mb.prototype.saveForm = function()
    {
        var xhr = new XMLHttpRequest();
        var params = this.getPostFromCurrentForm();

        xhr.open('POST', this.APIEndpoint, true);
        xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
        xhr.onload = function () {
            console.log("Loading...");
        };
        // Current APIEndpoint is example.com, do not send the form.
        //xhr.send(params);
    };

    return (mb);
})();
票数 2
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/154761

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档