jQuery、bootstrap 选项卡和 CodeMirror.refresh()

jQuery, bootstrap tabs and CodeMirror.refresh()

我在单击树视图中的 link 时创建选项卡。在该选项卡中,创建了另外两个选项卡,并且在它们中有转换为 CodeMirror 的文本区域。在创建 CodeMirror 实例时,我遇到了很多问题,通常我的问题与 .refresh() 事件有关。

CodeMirror 没有完全加载到不活动的选项卡中,因此我在创建实例时添加了一些更改,并将它们全部收集在数组中,稍后我在代码循环中使用 .refresh()以便 CodeMirror 编辑器完全加载。

在我这样做之前,CodeMirror 被添加到我在单击时创建的所有选项卡中的所有文本区域,但我总是刷新所有 CodeMirror 实例,而不仅仅是新选项卡中的实例。这导致在另一个选项卡中输入的值被清除。

因此,对于新的更改,我只刷新在新选项卡中创建的当前 CodeMirror 实例。但是现在,通过此更改,所有仍处于打开状态的旧选项卡中的 CodeMirror(顺便说一句,可以关闭选项卡)消失了。所以现在我想知道,CodeMirror.refresh() 会刷新整个页面吗?

下面是我的代码的一部分,创建 CodeMirror 实例的部分。我认为创建选项卡的代码与此功能障碍没有任何关系:

/* 添加 CodeMirror 转换所有文本框,需要超时,直到加载所有 dom 元素 */

setTimeout(function () {
    var textAreaId = 0;
    $(".AI-textarea").each(function () {
        $(this).attr("id", "text" + textAreaId);
        ++textAreaId;
    });

    var queryArr = [];
    var dimensionArr = [];

    var queryBuilder = $(tabPanelDiv).find(".QueryBuilder");
    queryBuilder.each(function (index, el) {
        var editorQuery = CodeMirror.fromTextArea(el, {
            lineNumbers: true,
            tabMode: "indent",
            mode: "text/x-sql",
            theme: "eclipse"
        });
        queryArr.push(editorQuery);
    });

    var dimensionBuilder = $(tabPanelDiv).find(".DimensionBuilder");
    dimensionBuilder.each(function (index, el) {
        var editorQuery = CodeMirror.fromTextArea(el, {
            lineNumbers: true,
            tabMode: "indent",
            mode: "text/x-sql",
            theme: "eclipse"
        });
        dimensionArr.push(editorQuery);
    });

    for (var i = 0; i < queryArr.length; i++) {
        queryArr[i].refresh();
    }

    for (var a = 0; a < dimensionArr.length; a++) {
        dimensionArr[a].refresh();
    }

}, 100);

我必须让 setTimeout 函数中的代码等待创建文本区域。该函数在点击事件中。

是否有人可以指出可能导致 CodeMirror 从旧选项卡中的 Dom 消失的原因?是 CodeMirror.refresh() 事件还是点击事件做了我不知道的事情?正在创建新选项卡时,最后一个 CodeMirror 实例是否丢失?

下面是两个选项卡的屏幕截图,第一个显示了全新选项卡的外观。第二个显示旧选项卡的外观,应该看起来一样。

编辑

这是完整的点击事件,如果有帮助,也许是代码中较早的部分导致了这个?很抱歉混用 javascript 和 jquery,可能需要重写。

  $(".treeviewLinks").click(function (e) {
        e.preventDefault();
        var targetElement = e.target || e.srcElement;

        /*** Create everything for the upper tabs that open when tree view link is clicked ***/

        if ($(".tabHelper").find("#upperTab").length == 0) {
            var ul = document.createElement("ul");
            ul.className = "nav nav-tabs";
            ul.id = "upperTab";
            ul.setAttribute("role", "tablist");
            $(".tabHelper").append(ul);
        }

        var ul = $("#upperTab");
        var id = $('#upperTab li').size() + 1;

        var li = document.createElement("li");
        var a = document.createElement("a");
        var span = document.createElement("span");

        li.setAttribute("role", "presentation");
        a.href = "#" + id;
        a.setAttribute("aria-controls", id);
        a.setAttribute("role", "tab");
        a.setAttribute("data-toggle", "tab");
        span.className = "glyphicon glyphicon-remove pull-right exit";
        a.innerHTML = targetElement.innerHTML;

        if ($(".tabHelper").find(".tab-content").length == 0) {
            var tabContentDiv = document.createElement("div");
            tabContentDiv.className = "tab-content";
        }

        $(".tabHelper").append(tabContentDiv);

        var tabContentDiv = $(".tabHelper").find(".tab-content").first();
        var tabPanelDiv = document.createElement("div");

        tabPanelDiv.className = "tab-pane"
        tabPanelDiv.id = id;
        tabPanelDiv.setAttribute("role", "tabpanel");

        ul.append(li);
        li.appendChild(a);
        a.appendChild(span);
        tabContentDiv.append(tabPanelDiv);

        var upperTab = document.getElementById("upperTab");
        var tabContent = document.getElementsByClassName("tab-content")[0];
        var cId = $(tabContent).size() + 1;

        if (id == 1) {
            var tmpLi = upperTab.firstChild;
            tmpLi.className = "active";
        }
        else if (id > 1) {
            $(li).siblings().removeClass("active");
            li.className = "active";
        }

        if (cId == 1) {
            var tmpTabPane = tabContent.firstChild;
            tmpTabPane.className += " active";
        }
        else if (cId > 1) {
            $(tabPanelDiv).siblings().removeClass("active");
            tabPanelDiv.className += " active";
        }

        /*** Create ul for nav-tabs and tab-content for query and dimension builder tabs ***/

        var qdUl = document.createElement("ul");
        qdUl.className = "nav nav-tabs query-dimension-tabs";
        qdUl.setAttribute("role", "tablist");

        var qdDiv = document.createElement("div");
        qdDiv.className = "tab-content query-dimsension-tabs-content";

        for (var i = 0; i < tabContent.childNodes.length; i++) {
            var item = $(tabContent.childNodes[i]);

            if (item.children().length < 1) {
                item.append(qdUl);
                item.append(qdDiv);
            }
        }

        /*** Create li in nav-tabs and tab-panel in tab-content for query and dimension builder tabs ***/

        var qLi = document.createElement("li");
        var dLi = document.createElement("li");
        qLi.setAttribute("role", "presentation");
        qLi.className = "active";
        dLi.setAttribute("role", "presentation");

        var navTabs = $(".query-dimension-tabs");

        var qA = document.createElement("a");
        var dA = document.createElement("a");
        qA.setAttribute("role", "tab");
        qA.setAttribute("data-toggle", "tab");
        qA.innerHTML = "Query Builder";
        dA.setAttribute("role", "tab");
        dA.setAttribute("data-toggle", "tab");
        dA.innerHTML = "Dimension Builder";

        for (var i = 0; i < navTabs.length; i++) {
            var item = $(navTabs[i]);

            if (item.children().length < 1) {
                item.append(qLi);
                item.append(dLi);
                qLi.appendChild(qA);
                dLi.appendChild(dA);
            }
        }

        var qdId = 0;
        $(".query-dimension-tabs").each(function () {
            $(this).find("a").each(function () {
                $(this).attr("href", "#tab" + qdId);
                $(this).attr("aria-controls", "tab" + qdId);
                ++qdId;
            });
        });

        var tabPane1 = document.createElement("div");
        var tabPane2 = document.createElement("div");
        tabPane1.className = "tab-pane active";
        tabPane1.setAttribute("role", "tabpanel");
        tabPane2.className = "tab-pane";
        tabPane2.setAttribute("role", "tabpanel");

        $(".tab-content:not(:first)").each(function () {
            $(this).append(tabPane1);
            $(this).append(tabPane2);
        });

        var pId = 0;
        $(".query-dimsension-tabs-content").each(function () {
            $(this).find(".tab-pane").each(function () {
                $(this).attr("id", "tab" + pId);
                ++pId;
            });

            if (!($.contains($(this), "form"))) {
                var firstPane = $($(this).children()[0]);
                var secondPane = $($(this).children()[1]);
                firstPane.load("/Webfront/QueryBuilder");
                secondPane.load("/Webfront/DimensionBuilder");
            }           
        });

        //var url = '@Url.Action("QueryDimensionTab", "Webfront")'; 

        /*** Add CodeMirror to convert all textboxes, needs timeout until all dom elements are loaded ***/

        setTimeout(function () {
            var textAreaId = 0;
            $(".AI-textarea").each(function () {
                $(this).attr("id", "text" + textAreaId);
                ++textAreaId;
            });

            var queryArr = [];
            var dimensionArr = [];

            var queryBuilder = $(tabPanelDiv).find(".QueryBuilder");
            queryBuilder.each(function (index, el) {
                var editorQuery = CodeMirror.fromTextArea(el, {
                    lineNumbers: true,
                    tabMode: "indent",
                    mode: "text/x-sql",
                    theme: "eclipse"
                });
                queryArr.push(editorQuery);
            });

            var dimensionBuilder = $(tabPanelDiv).find(".DimensionBuilder");
            dimensionBuilder.each(function (index, el) {
                var editorQuery = CodeMirror.fromTextArea(el, {
                    lineNumbers: true,
                    tabMode: "indent",
                    mode: "text/x-sql",
                    theme: "eclipse"
                });
                dimensionArr.push(editorQuery);
            });

            for (var i = 0; i < queryArr.length; i++) {
                queryArr[i].refresh();
            }

            for (var a = 0; a < dimensionArr.length; a++) {
                dimensionArr[a].refresh();
            }

        }, 100);
    });

我找到了导致 CodeMirror 旧实例消失的原因。这是因为我在 jQuery .each() 中加载表单,它循环遍历所有具有这些表单的 div。我将负载移到它外面并修复了它。

旧代码:

    var pId = 0;
    $(".query-dimsension-tabs-content").each(function () {
        $(this).find(".tab-pane").each(function () {
            $(this).attr("id", "tab" + pId);
            ++pId;
        });

        if (!($.contains($(this), "form"))) {
            var firstPane = $($(this).children()[0]);
            var secondPane = $($(this).children()[1]);
            firstPane.load("/Webfront/QueryBuilder");
            secondPane.load("/Webfront/DimensionBuilder");
        }           
    });

新代码:

    var pId = 0;
    $(".query-dimsension-tabs-content").each(function () {
        $(this).find(".tab-pane").each(function () {
            $(this).attr("id", "tab" + pId);
            ++pId;
        });           
    });

    var formToLoad = $($(tabPanelDiv).children()[1]);
    var firstPane = $($(formToLoad)[0].firstChild);
    var secondPane = $($(formToLoad)[0].lastChild);
    firstPane.load("/Webfront/QueryBuilder");
    secondPane.load("/Webfront/DimensionBuilder");

如果有人对我如何以不同的方式在 jQuery 中动态加载这些部分视图有建议或想法,我们将不胜感激。我认为这可能不是最好的方法。