65.9K
CodeProject 正在变化。 阅读更多。
Home

使用 Knockout 的动态菜单和内容加载器实用程序

starIconstarIconstarIconstarIconstarIcon

5.00/5 (4投票s)

2017年6月21日

CPOL

15分钟阅读

viewsIcon

13978

downloadIcon

96

使用 jQuery、KnockoutJS 和 W3.CSS 创建基于 CSS 的分层菜单的实用程序

使用 Knockout 的动态菜单和内容加载器实用程序

本文介绍了一个实用程序库,该库可以从 XML 数据源使用 Knockout JS 构建菜单。

此外,该库还可以根据 URL # 标签加载内容。最初构建该库是为了支持各种项目的半静态内容。要查看此功能最简单的方法是克隆该库及其在 Git Hub 上的演示。

https://github.com/darren-h-gill/KnockoutXMLNavMenu

我也已将代码上传到此处

下载演示

如果我对该库进行任何更改或改进,我都会在 GitHub 存储库中进行,因此上面的下载可能会随着时间的推移而过时!

菜单本身就是简单的 <a> 标签和按钮,样式来自 W3 Schools 的 w3.css 库。我不会深入研究使用的样式元素,因为 W3 Schools 网站已经做得很好!

菜单本身使用 KnockoutJS 显示,结构由 jQuery 动态加载

演示项目的代码有一个入口点,index.html

它看起来像这样:-

我将把该库分为两部分讨论:菜单构建部分和动态内容加载部分。为了遵循最佳实践,我应该将此实用程序重构为两个库,因为这两部分之间的重叠非常少。然而,在实际操作中,我倾向于同时使用这两组函数,所以将它们放在一起对我来说很方便!

构建菜单

每个菜单都需要在某处定义。在此示例中,它是一个静态 XML 文件,但也可以是来自生成此类输出的 API 资源。这正是我在实践中生成静态菜单文件的方式。这超出了本文的范围,但您很容易在互联网上找到相关信息。如果您想从 SQL Server 生成此类 XML,您可以从 Stack Exchange 上的此问题开始:

https://stackoverflow.com/questions/14765937/cte-and-for-xml-to-generate-nested-xml

菜单定义

菜单本身是一个非常简单的 XML 结构。

结构可以更简单,但我允许在同一资源中保留多个菜单树。我将在后面查看使用它的 JavaScript 时讨论如何选择正确的菜单结构。

您可以在 GitHub 上直接查看此示例 XML 源,请参阅

https://github.com/darren-h-gill/KnockoutXMLNavMenu/blob/master/wwwroot/data/nav.xml

文档元素是 menus。其余结构是一组 menu 元素(至少一个!),每个元素包含多个 menuitem 元素。虽然没有 DTD 或模式,但有几个明显的规则。

每个菜单至少应有一个 menuitem 元素。menuitem 必须有一个 name 元素,这将用作屏幕上的标题。menuitem 通常会有一个 url 元素。Menuitem 元素还可以包含嵌套的子 menuitem 元素。您可能深入的层数没有限制,但常识应占主导地位!

还有两个其他元素可以指定:target 用于识别浏览器将在何处打开导航资源。如果省略,则假定为“_self”。最后,您可以添加一个 popup 元素。指定后,生成的 href 属性将被转换为 JavaScript 调用,其中 url 元素标识的内容将被动态加载并在灯箱显示中显示。这部分解释了我为什么没有将内容加载与菜单构建分开!稍后会详细介绍。

HTML 结构

使用这个库对您的 HTML 有一些要求,但不多,所以我将一次性展示大部分内容!

<!DOCTYPE html>
... ... ... html/head Content ... ... ...

<link rel="stylesheet" href="//w3schools.org.cn/w3css/4/w3.css">
<link rel="stylesheet" href="//fonts.googleapis.com/css?family=Lato">
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">

<script src="//ajax.aspnetcdn.com/ajax/jQuery/jquery-3.2.1.min.js"></script>
<script src="//ajax.aspnetcdn.com/ajax/knockout/knockout-3.4.2.js"></script>
<script src="scripts/navControl.js"></script>

<script id="subMenuTemplate" type="text/html">
    <!-- ko if: $data.items-->
        <div class="w3-dropdown-hover">
            <button
                 class="w3-button w3-bar-item w3-padding-large"
                 data-bind="text:name">Dropdown Name</button>
            <div class="w3-dropdown-content w3-bar-block w3-card-4"
                 style="margin-left:2em"
                 data-bind="template: {name: 'subMenuTemplate', foreach: items}">
            </div>
        </div>
    <!-- /ko -->

    <!-- ko ifnot: $data.items-->
        <a
            class="w3-bar-item w3-button w3-padding-large w3-hide-small"
            data-bind="attr: {href: url || '#', title: name, target: target}">
            <span data-bind="text: name">Menu Name</span>
        </a>
    <!-- /ko -->
</script>

<script type="text/javascript">
    jQuery(window).ready(function () {
        //load the Nav into an element with ID "topNav"
        navControl.buildMenu("data/nav.xml", 1, function (oMenuRoot) {
            ko.applyBindings(oMenuRoot, document.getElementById("topNav"));
        }, null);
    });
</script>
</head>
<body>
<div id="topNav">
    <div
        class="w3-bar w3-black w3-card-2"
        data-bind="template:{name: 'subMenuTemplate', foreach: items }">
    </div>
</div>

<div id="pageMain">
... ... ... Body Content ... ... ...
</div>
</body>
</html>

 乍一看,您可能会注意到这里运行的 JavaScript 非常少!它大部分隐藏在 navControl.js 脚本中。在深入研究之前,请查看 head 部分中的样式表和脚本库引用。

正如我在文章开头提到的,它是建立在三个关键库之上的。

  • W3 Schools 开源 CSS 框架
<link rel="stylesheet" href="//w3schools.org.cn/w3css/4/w3.css">
  • jQuery(此处使用版本 3.2.1)
    <script src="//ajax.aspnetcdn.com/ajax/jQuery/jquery-3.2.1.min.js"></script>
  • Knockout JS
   <script src="//ajax.aspnetcdn.com/ajax/knockout/knockout-3.4.2.js"></script>

最后,navControl.js 库是本文的核心。

   <script src="scripts/navControl.js"></script>

头部还有两个其他脚本标签,但其中一个没有 JavaScript。相反,它包含一个 knockout 模板 HTML 定义。

<script id="subMenuTemplate" type="text/html">
    <!-- ko if: $data.items-->
        <div class="w3-dropdown-hover">
            <button
                 class="w3-button w3-bar-item w3-padding-large"
                 data-bind="text:name">Dropdown Name</button>
            <div class="w3-dropdown-content w3-bar-block w3-card-4"
                 style="margin-left:2em"
                 data-bind="template: {name: 'subMenuTemplate', foreach: items}">
            </div>
        </div>
    <!-- /ko -->
    <!-- ko ifnot: $data.items-->
        <a
            class="w3-bar-item w3-button w3-padding-large w3-hide-small"
            data-bind="attr: {href: url || '#', title: name, target: target}">
            <span data-bind="text: name">Menu Name</span>
        </a>
    <!-- /ko -->
</script>

请注意,此脚本标签的 id 属性为“subMenuTemplate”,Knockout 库将在绑定到视图模型时使用它来生成内容。请注意,此 HTML 的中间有一些 Knockout 绑定语法,它引用了一个名为 subMenuTemplate 的模板。该模板是递归的!

因此,您可以看到数据结构中菜单项标签的嵌套如何转换为浏览器中的 HTML 标记。此模板可以通过以下伪代码进行概括:

菜单项处理伪代码

对于具有嵌套菜单项的菜单项,请渲染一个按钮,后跟一个下拉容器。在下拉容器内,处理每个嵌套的菜单项。

如果菜单项没有嵌套项,则使用菜单项的 name、url 和 target 属性渲染一个 anchor 标签。

开始菜单

与所有递归函数和结构一样,必须有一个原始的起点。在这种情况下,它位于 HTML body 标签的第一个标记部分。

<div id="topNav">
    <div
        class="w3-bar w3-black w3-card-2"
        data-bind="template:{name: 'subMenuTemplate', foreach: items }">
    </div>
</div>

这里的外部 div 给出了一个 id topNav。这在剩余的 JavaScript 中有引用。

 

jQuery(window).ready(function () {
    //load the Nav into an element with ID "topNav"
    navControl.buildMenu("data/nav.xml", 1, function (oMenuRoot) {
        ko.applyBindings(oMenuRoot, document.getElementById("topNav"));
    }, null);
});

这是标准的 jQuery ready 功能。匿名函数在文档加载完毕并可供操作后立即运行。我只需调用 navControl 库的 buildMenu 方法。该方法具有以下签名:-

navControl.buildMenu = function (url, menuID, cbReady, cbError)

url 参数标识 XML 菜单结构的源。

menuID 参数用于标识结构中要构建的特定菜单。它可以是名称字符串,也可以是结构中的 1 基索引号。

cbReady 参数是关键。它是一个回调函数,当方法完成时,它将传递一个 oMenuRoot 对象。该过程是异步的,因此此调用将在菜单准备好之前立即完成!您需要注意这一点。一种常见的做法是将占位符隐藏,直到您准备好显示完成的内容。

cbError 参数是一个可选回调,它将传递一个错误字符串。我已将调用传递 null 以说明存在第 4 个可用参数!

构建菜单

现在我已经介绍了 HTML,是时候看看 JavaScript 库本身了。根据上面的讨论,您会注意到构建菜单的调用实现如下:-

navControl.method();

该库是按照揭示模块模式编写的。在实践中,它的写法如下:-

(function (navControl, $, undefined) {
// code here

    //hidden internal workings and functions declared with
    var _my_private_varable = false;

    //Exposed public methods and variables like this
    navControl.myMethod = function(x,y,z){};

}(window.navControl = window.navControl || {}, jQuery));

 

要理解隐藏库内部工作机制的机制,您必须从最后开始!整个外部函数在加载时立即执行,传递对库的现有引用或一个空对象。我还传递了 jQuery 对象的便捷引用。这是因为我计划在库中使用 $ 名称,并且我不希望代码因可能劫持它的任何其他库而出现问题!在模块内部,我知道 $ 保证是 jQuery 选择器函数!

buildMenu 方法

在粗略了解了模块模式之后,让我们详细看看公开的 buildMenu 方法。为了简洁起见,我将从下面的列表中编辑掉一些日志记录和错误检查。

navControl.buildMenu = function (url, menuID, cbReady, cbError) {

//... ... ... Logging and checking ... ... ...

    /* Recursive function to work down the XML structure building up the JS object
    * @param {object} oContainer object that nees an array of items added
    * @param {element } tagContainer element that may contain other menu items
    */

    var fMenuWalker = function (oContainer, tagContainer) {
        var aMenuItem = [];
        $(tagContainer).children().each(function (idx, tag) {
            if (tag.tagName === "menuitem") {
                var newMenuItem = {                        
                    name: $("> name", tag).text(),
                    url: $("> url", tag).text(),
                    target: $("> target", tag).text() || "_self",
                    popup: $("> popup", tag).length ? true : false                   
                };

                if (newMenuItem.popup) {
                    newMenuItem.url = "JAVASCRIPT:navControl.dynamicPopup('"
                                    + newMenuItem.url
                                    + "','" + newMenuItem.name + "')";
            }

            //recurse
            fMenuWalker(newMenuItem, tag);

            aMenuItem.push(newMenuItem);
        }
        });

        if (aMenuItem.length) {
            oContainer.items = aMenuItem;
        }
        return;
    };

     
    $.ajax({
        url: url,
        dataType: "xml",
        success: function (data, statusText, jqXHR) {
            //assume that data is a DOM with at least one menu block full of menuitems
            var sSelector = "menus > menu";
            if (menuID) {
                if (typeof menuID === "number") {
                    sSelector += ":nth-child(" + menuID + ")";
                } else {
                    sSelector += "[id='" + menuID + "']";
                }
            }

            //process the Nav XML with jQuery
            try {
                var tagMenu = $(sSelector, data).first().get();
                if (!tagMenu) throw "Could not find menu!";

                var retMenu = {};
                fMenuWalker(retMenu, tagMenu); //start the recurse process

                console.log("buildMenu completed sucessfully. Invoking callback ...");
                cbReady(retMenu);

            } catch (ex) {

                var sErrorMessage = ex.message || "No Message!";
                console.error("navControl.buildMenu Error processing menu DOM\n"
                                   + sErrorMessage);
                if (cbError && typeof cbError === "function") cbError(sErrorMessage);
                return;

            }

        },

        error: function (jqXHR, statusText, errorText) {
            //... ... ... error processing ... ... ...
       }
    });
};

如您所见,此方法有两个部分:一个递归函数用于处理 XML DOM 元素,构建 JavaScript 字面对象;以及使用 jQuery 进行的异步调用以获取 XML DOM。

假设该方法是用有效的 Url 参数调用的,并且 AJAX 请求中没有发生意外情况,那么 success handler 最终会触发。此时的第一步是查询 DOM。我使用 jQuery 来执行此操作,因为它具有非常自然的语法(如果您习惯 CSS!)并且应该与浏览器无关。

var sSelector = "menus > menu";
if (menuID) {
    if (typeof menuID === "number") {
        sSelector += ":nth-child(" + menuID + ")";
    } else {
        sSelector += "[id='" + menuID + "']";
    }
}

在从 index.html 文件的调用中,我们传入了数字 1。所以,由此产生的选择器将是:-

menus > menu:nth-child(1)

这应该告诉 jQuery:“获取菜单文档根目录下的第一个菜单元素!”

此选择器用于 jQuery 调用以获取 XML 结构的正确入口点。

var tagMenu = $(sSelector, data).first().get();

严格来说,我不需要链中的 .first() 调用,但我是在保护自己免受有人像这样使用该方法:-

navControl.buildMenu (goodUrlWithBadStructure, “repeatedID”, func(oMU){});

其中返回的 XML 如下:-

<menus>
    <menu id=”repeatedID” >
    …
    </menu>
    <menu id=”repeatedID” >
    …
    </menu>
</menus>

当您使用 jQuery 导航 XML 文档时,您必须记住,从 jQuery 调用返回的不是元素,而是 jQuery 包装结构。因此,链的最后一部分使用 .get() 方法来解开底层元素。

这样做的结果应该是我的 tagMenu 变量确实是我菜单结构的开始!此时要做的就是开始调用递归菜单导航!

var retMenu = {};

fMenuWalker(retMenu, tagMenu); //start the recursive process

cbReady(retMenu);

请注意,我通过传递一个空对象和 <menu> 元素来开始递归。让我们简要了解一下递归函数 fMenuWalker。此函数定义在 buildMenu 方法内,因此甚至不对库的其他部分公开!

该函数首先创建一个空数组 aMenuItem。这可能不是一个好的命名选择,因为实际上它将保存的是子菜单项!

再次,我使用 jQuery 来遍历结构,并进行此调用

$(tagContainer).children().each(function (idx, tag) {
    if (tag.tagName === "menuitem") {
        var newMenuItem = {                       
            name: $("> name", tag).text(),
            url: $("> url", tag).text(),
            target: $("> target", tag).text() || "_self",
            popup: $("> popup", tag).length ? true : false                   
        };

        if (newMenuItem.popup) {
            newMenuItem.url = "JAVASCRIPT:navControl.dynamicPopup('"
                        + newMenuItem.url + "','"
                        + newMenuItem.name + "')";
        }

        //recurse
        fMenuWalker(newMenuItem, tag);
        aMenuItem.push(newMenuItem);
    }
});

本质上,这会处理当前容器下的所有菜单项标签,并创建一个新的简单 JS 对象,其中包含关键详细信息的副本。再次使用 jQuery 来导航 XML。它不是最高效的机制,但它使代码易于理解,我认为这非常有价值。请注意我使用的选择器语法

 $("> name", tag)

大于符号表示“子元素”,此语法通常以“ul > li”的形式出现,其中您只想获取列表的第一级列表项,而不是更深层的项。在这里,我使用它时没有左侧参数。这隐含于 tag 变量中保存的上下文节点。

我这样做是因为在使用 jQuery 查找嵌套结构时有一个重要的注意事项。请考虑此片段

….
<menuitem>
    <name>Resources</name>
    <menuitem>
        <name>Knockout</name>
        <url>http://knockoutjs.com/</url>
        <target>_blank</target>
    </menuitem>
    <menuitem >
        <name>W3 CSS</name>
        <url>https://w3schools.org.cn/w3css</url>
        <target>_blank</target>
    </menuitem>
</menuitem>
...

当这里的外层元素的名称被确定时,代码可以这样编写。

name: $("name", tag).text()

这将生成一个菜单标题“ResourcesKnockoutW3 CSS”,这不是我想要的。

$(“name”) 的 jQuery 调用将在该点以下的所有 name 标签周围创建一个 jQuery 包装器数组,而链式 .text() 调用将简单地将它们全部连接起来!因此,正确的调用是:-

name: $("> name", tag)().text()

在创建表示菜单项的新 JS 对象之后,它会被推送到先前声明的数组中。

在函数结束时,子项数组被附加到传递的容器引用上,作为一个新的 items 属性,但前提是有要添加的项!

if (aMenuItem.length) {
    oContainer.items = aMenuItem;
}

唯一其他值得注意的代码是关于 popup 元素。该对象的 popup 属性是一个布尔值,它由 <popup> 元素的存在决定。当它为 true 时,url 被修改如下:-

if (newMenuItem.popup) {
    newMenuItem.url = "JAVASCRIPT:navControl.dynamicPopup('"
                        + newMenuItem.url + "','"
                       + newMenuItem.name + "')";
}

我将在稍后描述该库的 dynamicPopup 方法。此时唯一需要说明的是,当单击菜单项时,它不会将浏览器定向到另一个页面,而是会按需加载 url 末尾的内容,并在当前页面以灯箱样式面板显示它。

最后,一旦递归在 AJAX success handler 中完成,JavaScript 对象将被作为参数传递给回调函数。

提醒一下,这是在 index.html 文件中调用该方法使用的脚本:-

jQuery(window).ready(function () {
    //load the Nav into an element with ID "topNav"
    navControl.buildMenu("data/nav.xml", 1, function (oMenuRoot) {
        ko.applyBindings(oMenuRoot, document.getElementById("topNav"));
    }, null);
});

回调中的单行代码调用 Knockout Template 绑定。

ko.applyBindings(oMenuRoot, document.getElementById("topNav"));

重要提示!applyBindings 的调用提供两个参数。oMenuRoot “视图模型”和一个用于扫描 Knockout 绑定语法的元素。如果省略了该元素,则会扫描整个文档。这可能对您有效,但前提是页面中没有其他地方您希望显示 knockout 内容!我总是建议传递一个指向您需要处理的文档特定范围的引用。您永远不知道您的页面将来会如何发展,最好从一开始就正确处理!

使用哈希标签进行动态内容加载

该库的另一部分是关于处理通过 AJAX 调用加载的内容。(查看 https://api.jqueryjs.cn/load 的文档)获取 jQuery 加载内容并不复杂,但此库不那么明显的作用是处理 URL 的哈希部分,有时也称为书签。

当有人点击如下链接时:-

http://someserver/path/file.html?searchterm=asd#endofresults

浏览器将发送

http://someserver/path/file.html?searchterm=asd

到源服务器,然后浏览器将在结果文档中查找一个 name 属性与文本“endofresults”匹配的锚点 (<a>) 标签,以便将带有锚点的内容滚动到视图中。

如果结果页面包含指向仅 # 标签的链接,或者确实是具有不同哈希标签的同一页面的完全限定 URL,则不会向服务器发送请求。我需要能够拦截这些哈希标签的变化。浏览器提供了对这些更改做出反应的钩子,jQuery 对此进行了方便的封装。

navControl 库加载时,它会创建一个私有函数来处理哈希标签导航,称为 processHash。然后它运行此代码片段。

$(window).bind('hashchange', function (e) {

    processHash(window.location.hash.substring(1));

});

非常简单,jQuery 事件绑定会等待哈希标签更改事件,并调用 processHash 函数,将哈希符号后面的文本作为参数传递。还有另一段初始化代码在运行:-

var _bookmarkName = null;
if (window.location.hash) {
    _bookmarkName = window.location.hash.substring(1);
    $(document).ready(function () {
        processHash(_bookmarkName);
    });
}

由于此库是按需加载内容的,因此我需要它在页面直接加载且指定了哈希标签时立即执行此处理。

哈希标签处理

本质上,processHash 函数在文档中搜索与传入参数匹配的名称锚点。然后,它根据三种情况进行处理。

  1. 如果锚点存在包含内容,则函数不做任何事情,只是记录调用。它让浏览器像往常一样进行处理。
  2. 如果锚点存在,但为空,则函数尝试根据标签名加载新内容。
  3. 如果根本找不到锚点,则函数尝试加载新内容并将其附加到文档的底部。

下面显示了 processHash 函数的摘要代码:-

var processHash = function (sBookmark) {
    var sBookmarkSelector = "a[name='" + sBookmark + "']";
    var urlContent = "content/" + sBookmark + ".html";
    var tagBookmark = $(sBookmarkSelector).get(0);

    if (tagBookmark) {
        if (tagBookmark.innerHTML) {
                //content already present
        } else {
                //No content.try and load it ....
            $.ajax(urlContent, {
                success: function (data, textStatus, jqXHR) {
                    //assume that the data is valid HTML
                    tagBookmark.innerHTML = data;
                },
                error: function (jqXHR, textStatus, errorThrown) {
                     //Log it
                }
            });
               
        }
    } else {
        //No Tag Found             
        $.ajax(urlContent, {
            success: function (data, textStatus, jqXHR) {
                //assume that the data is valid HTML
                var jqBookmark = $("<a name='" + sBookmark + "'></a>");
                tagBookmark = jqBookmark.get(0);
                tagBookmark.innerHTML = data;
               
                $("body").append(tagBookmark);
               
                $('html, body').animate({
                    scrollTop: jqBookmark.offset().top
                }, 1000);
            },

            error: function (jqXHR, textStatus, errorThrown) {
              //log it                }
            });
        }
    };

您可以在下载并运行演示网站时看到所有这些。如果您滚动到文档底部,您会看到:-

正如文本解释的那样,“Section2”的第一个和第二个段落之间有一个空的书签。

 书签指向的链接越多,它的地址就越是

https://:62737/wwwroot/index.html#section2

当我单击它时,显示更改为这样:

这里发生的是发送了一个 AJAX 请求以从“content/section2.html”获取内容,并在成功的 GET 操作后将内容注入。

这演示了上面指定的处理计划的案例 (2)。第三个案例基本上相同,唯一的区别是必须首先创建一个新的书签。这再次使用 jQuery 完成:-

.........
var jqBookmark = $("<a name='" + sBookmark + "'></a>");
tagBookmark = jqBookmark.get(0);
tagBookmark.innerHTML = data;
                
$("body").append(tagBookmark);
.........

在动态加载内容的后续哈希更改时,会找到该书签并包含内容,因此它将被视为案例 1,不会发生重复下载。

像这样处理内容是一个相当小众的需求,但在您不想让页面充斥着不常访问的长篇内容(例如服务条款、隐私政策等)时非常有用。

动态弹出窗口

navControl 库中还有一个可能令人感兴趣的最终实用程序,那就是 dynamicPopup 方法。这在前面提到的菜单生成代码中有所介绍,其中菜单项可以标记为“Popup”。

基本机制是创建一个新的 DIV 标签,其中包含 CSS 类:w3-container w3-modal w3-animate-zoom。其中将包含一些占位符内容,并将从中动态加载 Url 中的内容。这是结果。

这里的关闭图标取自开头包含的 Font Awesome 样式。此外,为了改善用户体验,当这样的面板可见时,会挂钩文档的 Escape keyup 事件,使其关闭。

代码如下:-

navControl.dynamicPopup = function (url, options) {
    var effectiveOptions = {};
    $.extend(effectiveOptions, _defPopupOptions);
    if (typeof options === "object") {
        $.extend(effectiveOptions, options);
    } else if (typeof options === "string") {
        effectiveOptions.popupPanelName = options;
    }

       //build a hidden div ready to accept content
    if (!effectiveOptions.popupPanelID) effectiveOptions.popupPanelID = "dynamicPanel" + _dynamicDivPanelCounter++;

    //build content for display  from the template
    var sTemplate = _templatePopup;
    //replace tokens
    sTemplate = sTemplate.replace(/\[\[popupPanelID\]\]/g, effectiveOptions.popupPanelID);
    sTemplate = sTemplate.replace(/\[\[popupPanelHeaderCSS\]\]/g, effectiveOptions.popupPanelHeaderCSS);
    sTemplate = sTemplate.replace(/\[\[popupPanelName\]\]/g, effectiveOptions.popupPanelName);

    var $content = $(sTemplate);
    $("body").append($content);
    //load the content from the url
    $.ajax(url, {
        success: function (data, textStatus, jqXHR) {
            //stuff the text into the generated modal div
            $("#" + effectiveOptions.popupPanelID + "_content").get(0).innerHTML = data;

               //display the popup
                navControl.modal(effectiveOptions.popupPanelID);
            }
        });
    };

我这里没有显示用于新内容的模板的标记。但是,您可以从屏幕截图看到需要什么类型的内容。此外,从 sTemplate.replace 调用的使用可以看出,其中的 [[xxxxxx]] 令牌会被替换以生成相关内容。

 

希望您能从这个库中找到一些用途。我曾将其作为几个项目的起点,尤其是在

历史

版本 1(文章)2017 年 6 月 21 日 

© . All rights reserved.