coldfusion
Static content is so yesterday. Websites, whether internal or external, are all about staying current.
昨天的静态内容是如此 。 内部或外部网站都是与时俱进的。
To that end, on a recent internal project I created a new intranet site and opted to develop a dynamically populated menu in ColdFusion. I went this route so that managing the links didn’t require us to open up the HTML files each time new content was added. This made updating the menu much less trouble for me as well as the content owners.
为此,在最近的内部项目中,我创建了一个新的Intranet站点,并选择在ColdFusion中开发一个动态填充的菜单。 我走了这条路,以便管理链接不需要每次添加新内容时都打开HTML文件。 这使得更新菜单对我和内容所有者而言都没有那么麻烦。
Why go through the trouble of building a dynamic menu in ColdFusion when an HTML/JavaScript menu could be written and maintained with relative ease? Sure, we could have built the menu in HTML and JavaScript and just modified the code as needed, but where’s the fun in that? More importantly, project maintenance wasn’t what I was looking for. I didn’t want to be tied to the project in perpetuity; the team I was on was too small and had too many new projects to be spending time on the maintenance of old projects.
当可以相对轻松地编写和维护HTML / JavaScript菜单时,为什么还要在ColdFusion中构建动态菜单呢? 当然,我们可以用HTML和JavaScript构建菜单,然后根据需要修改代码,但是这样做的乐趣何在? 更重要的是,项目维护不是我想要的。 我不想永远被这个项目所束缚; 我所在的团队规模太小,有太多新项目,无法花时间维护旧项目。
The end users and I came up with a menu that could be managed easily, and took up very little space on the site. The reason why space was an issue was that the site had several embedded sections, each of which had several embedded sections, which had… you see where I’m going.
最终用户和我想出了一个易于管理的菜单,并且只占用了很少的网站空间。 空间之所以成为问题,是因为该站点有几个嵌入式部分,每个部分都有几个嵌入式部分,这些部分有……您知道我要去的地方。
We’ll start by designing the database — we can’t write code to access a database until we know how the database is designed. The database for our dynamic menu is straightforward. To accomplish our menu we only need two tables — no stored procedures or anything else (though a stored procedure would be the easiest way to manage the data in the menu), so you can use any database system you’d like.
我们将从设计数据库开始-在知道数据库的设计方式之前,我们无法编写代码来访问数据库。 动态菜单的数据库非常简单。 要完成菜单,我们只需要两个表-不需要存储过程或其他任何表(尽管存储过程是管理菜单中数据的最简单方法),因此您可以使用任何数据库系统。
Image 1
图片1
Image 1 shows the database tables we’ll use for our menu. The MENU_ITEMS table is where all the actual menu tree items will live. Name (menu_item_name) and HREF (menu_item_url) are stored along with the primary key (menu_item_id). The table MENU_ITEMS_XREF holds the structure of the tree itself. Both menu_item_id and child_id refer to the menu_item_id from the MENU_ITEMS table. IDs that appear in the child_id column indicate that that ID will be nested under the item in the menu_item_id column. Image 2 illustrates this concept.
图1显示了我们将用于菜单的数据库表。 MENU_ITEMS表是所有实际菜单树项所在的位置。 Name ( menu_item_name )和HREF ( menu_item_url )与主键( menu_item_id )一起存储。 表MENU_ITEMS_XREF包含树本身的结构。 无论menu_item_id和child_id指menu_item_id从MENU_ITEMS表。 出现在的ID child_id列指示该ID将项目下嵌套在menu_item_id柱。 图2说明了此概念。
Image 2
图片2
The last column in the MENU_ITEMS_XREF table is the sort_order field. Initially, I just let the menu query that generates the menu handle the sorting (alphabetically). Wouldn’t you know it, though — the business unit had other ideas. So now there is a sort_order field, which allows the content owner to place more important or popular topics closer to the top of the page.
MENU_ITEMS_XREF表的最后一列是sort_order字段。 最初,我只是让生成菜单的菜单查询处理排序(按字母顺序)。 但是,您不知道吗–业务部门有其他想法。 因此,现在有一个sort_order字段,该字段使内容所有者可以将更重要或受欢迎的主题放在页面顶部附近。
That’s it for the database. Let’s code!
数据库就是这样。 让我们编码吧!
The code we use to create the menu is pretty easy to follow. Basically, we’ll create a custom ColdFusion tag that recurses over a database structure and builds the appropriate menu structure as it goes. We’ll break down the pieces of create_menu.cfm, which you can download here, and discuss each section. The end result will be a completely de-mystified, dynamically built tree menu.
我们用来创建菜单的代码非常容易遵循。 基本上,我们将创建一个自定义ColdFusion标记,该标记在数据库结构上递归并随其构建适当的菜单结构。 我们将分解create_menu.cfm的片段,您可以在此处下载这些片段,并讨论每个部分。 最终结果将是一个完全不神秘的,动态构建的树菜单。
The code in Section A defines some initial parameters we’ll need as default. You may or may not need these, depending on whether your site has pages in sub folders and such. Our site did, so we needed a way to get up the folder tree to the images directory.
A节中的代码定义了一些默认需要的初始参数。 您可能需要也可能不需要这些,这取决于您的站点是否在子文件夹等中有页面。 我们的网站做了,所以我们需要一种将文件夹树移到images目录的方法。
Section A
A节
<CFPARAM DEFAULT="1" NAME="ATTRIBUTES.Level"> <CFPARAM DEFAULT="" NAME="ATTRIBUTES.divID"> <CFIF ATTRIBUTES.Level EQ 1> <CFSET VARIABLES.RootLevel = ""> <CFELSEIF ATTRIBUTES.Level EQ 2> <CFSET VARIABLES.RootLevel = "../"> <CFELSEIF ATTRIBUTES.Level EQ 3> <CFSET VARIABLES.RootLevel = "../../"> </CFIF>The following sections of code all combine into a single JavaScript block, but for the sake of making it easier to explain, I’ve broken it into smaller, more digestible pieces. This is the JavaScript that will handle the menu, collapsing and expanding the appropriate branches, and changing the image states of those branches as required.
以下各节代码全部合并为一个JavaScript块,但是为了使解释更容易,我将其分为更小,更易理解的部分。 这是JavaScript,它将处理菜单,折叠和展开适当的分支,并根据需要更改这些分支的图像状态。
Section B
B区
<CFOUTPUT> <script type="text/javascript"> function ShowMenu(n) { var menu, arrowImg; menu = document.getElementById("d" + n);Section C
C区
// Determine if the menu is currently showing. if (menu.style.display == 'block') { // If it is showing, hide the menu and update the twisty image. menu.style.display = 'none'; arrowImg = document.images['i' + n]; arrowImg.src = "#VARIABLES.RootLevel#images/right_arrow.gif"; }Section C handles the event of clicking on an already-expanded menu branch. Doing this triggers the branch to collapse. The menu doesn’t have to function this way, but why require your users to select a different level just to collapse a section? Instead, we simply take the section the user clicked on and see if it’s expanded; if it is, we collapse it. If it is not expanded, move right along to Section D.
C节处理单击已展开的菜单分支的事件。 这样做会触发分支崩溃。 菜单不必以这种方式运行,但是为什么要让用户选择其他级别只是为了折叠部分? 取而代之的是,我们只需要查看用户单击的部分,看看它是否已展开; 如果是,我们将其折叠。 如果未展开,请向右移至D节。
Section D
D区
else { // Hide all layers first. var divs = document.getElementsByTagName("div"); for (var i = 0; i < divs.length; i++) if (divs[i].id.indexOf("d0") >= 0) divs[i].style.display = 'none'; // Reset the images. for (var j = 0; j < document.images.length; j++) if (document.images[j].src.indexOf("down_arrow") > 0) document.images[j].src = "#VARIABLES.RootLevel#images/right_arrow.gif"; // Show the menus and update their twisty images. i = 2; while (n.length >= i) { menu = document.getElementById("d" + n.substring(0, i)); arrowImg = document.images["i" + n.substring(0, i)]; menu.style.display = "block"; arrowImg.src = "#VARIABLES.RootLevel#images/down_arrow.gif"; i += 2; } } } </script> </CFOUTPUT>Section D is pretty long — it’s the remainder of the JavaScript function ShowMenu(). If the branch that the user selected was not already expanded, the first order of business is to collapse all branches. We essentially want to start with a fresh menu each time. To accomplish this, we loop over the structure of the image tags (all named in series), resetting each image. We repeat the process on the menu structure itself (each <div> tag that makes up the menu is named in series like the images, so looping over the entire menu is very easy).
D部分相当长-这是JavaScript函数ShowMenu()的其余部分。 如果用户选择的分支尚未扩展,则首要任务是折叠所有分支。 我们本质上希望每次都从一个新菜单开始。 为此,我们遍历了图像标签的结构(全部序列化),重置每个图像。 我们在菜单结构本身上重复此过程(组成菜单的每个<div>标签像图像一样依次命名,因此遍历整个菜单非常容易)。
Once the entire menu has been collapsed, we have to expand the chosen menu branch. Since each branch can have its own sub-branches, the JavaScript has to not only expand the main branch, but, if the user clicks a sub-branch, that branch must be expanded also (see Image 3). Once the appropriate branches are expanded, the corresponding images need to be changed. Our menu uses two images: a blue arrow pointing to the right and a gold arrow that points down. These serve as an additional visual cue for the user.
折叠完整个菜单后,我们必须展开所选菜单分支。 由于每个分支都可以有自己的子分支,因此JavaScript不仅必须扩展主分支,而且,如果用户单击一个子分支,则还必须扩展该分支(参见图3)。 适当的分支一旦展开,就需要更改相应的图像。 我们的菜单使用两张图片:指向右边的蓝色箭头和指向下方的金色箭头。 这些为用户提供了额外的视觉提示。
Image 3
图片3
Once the images are adjusted, we’re done – in terms of the JavaScript, that is. We covered the JavaScript first, even though the ColdFusion part of our custom tag will execute first, because I wanted to establish the flow of the code and how it should work before we cover the set up. The JavaScript is the work horse of this menu, so it’s important to know what’s going on there and how everything works. Now, time to face the CF!
调整图像后,就完成了JavaScript。 尽管自定义标签的ColdFusion部分将首先执行,但我们还是先介绍了JavaScript,因为在我们进行介绍之前,我想确定代码流程以及代码的工作方式。 JavaScript是此菜单的主力军,因此了解发生的事情以及一切工作原理非常重要。 现在,该面对CF!
This menu is the product of a ColdFusion custom tag. Wherever you need the menu to appear (keeping in mind that this menu is vertical), you simply include the tag. To set up the menu on a page, you’ll require two lines of code. Sample 1 shows the <body> tag as well as the actual custom tag call. The ColdFusion code in the body tag expands the menu to reflect the user’s location within the site. Without this logic the menu collapses on load by default.
此菜单是ColdFusion自定义标签的产品。 无论您需要菜单出现在何处(请记住该菜单是垂直菜单),只需添加标签即可。 要在页面上设置菜单,您需要两行代码。 示例1显示了<body>标签以及实际的自定义标签调用。 body标签中的ColdFusion代码可展开菜单以反映用户在站点中的位置。 没有这种逻辑,默认情况下菜单会在加载时折叠。
Sample 1
样品1
<body <CFIF IsDefined('URL.Div')> onload="ShowMenu('<CFOUTPUT>#URL.Div#</CFOUTPUT>')"</CFIF>> <CFINCLUDE TEMPLATE="modules/menu/create_menu.cfm">We don’t call the custom tag in the standard <CF_> syntax; instead we call it using <CFINCLUDE>. The tag’s designed to call itself as it builds the tree, so we just need to include the code.
我们不会以标准<CF_>语法调用自定义标签; 相反,我们使用<CFINCLUDE>来称呼它。 标签的设计目的是在构建树时调用自身,因此我们只需要包含代码即可。
Now, back to the custom tag — we’ll continue with the ColdFusion code. Section E establishes our variables and queries the database. You’ll notice the query is actually a query of a variable. You can execute this section in whichever way you are most comfortable. I chose to store my initial query as an APPLICATION scoped variable, as the menu data doesn’t change very frequently. Also, because the menu is located on each page of the site, I wanted to spare my database the extra traffic. The last query in Section E creates the application variable.
现在,回到自定义标签-我们将继续使用ColdFusion代码。 E节建立我们的变量并查询数据库。 您会注意到查询实际上是一个变量查询。 您可以按照自己喜欢的任何方式执行此部分。 我选择将初始查询存储为APPLICATION范围的变量,因为菜单数据不会经常更改。 另外,因为菜单位于站点的每个页面上,所以我想为数据库节省额外的流量。 E节中的最后一个查询创建应用程序变量。
Section E
E节
<CFPARAM DEFAULT="0" NAME="ATTRIBUTES.MenuID"> <CFPARAM DEFAULT="" NAME="ATTRIBUTES.DivID"> <CFPARAM DEFAULT="0" NAME="VARIABLES.LoopCount"> <CFPARAM DEFAULT="0" NAME="VARIABLES.IncreNum"> <CFLOCK SCOPE="APPLICATION" TIMEOUT="10" TYPE="READONLY"> <CFSET VARIABLES.qGrabMenu = APPLICATION.qGrabMenu> <CFSET VARIABLES.DataSource = APPLICATION.DataSource> </CFLOCK> <CFQUERY DBTYPE="query" NAME="qGetMenuElement"> SELECT * FROM VARIABLES.qGrabMenu WHERE Menu_item_ID = #ATTRIBUTES.MenuID# ORDER BY sort_order </CFQUERY> <CFQUERY DATASOURCE="#APPLICATION.DataSource#" NAME="APPLICATION.qGrabMenu" CACHEDWITHIN="#APPLICATION.QueryTimeOut#"> SELECT menu_item_id, (SELECT menu_item_name FROM MENU_ITEMS WHERE MENU_ITEMS.menu_item_id = menu_items_xref.menu_item_id) AS Parent, (SELECT menu_item_url FROM MENU_ITEMS WHERE MENU_ITEMS.menu_item_id = menu_items_xref.menu_item_id) AS Parentlink, child_id, (SELECT menu_item_name FROM MENU_ITEMS WHERE MENU_ITEMS.menu_item_id = menu_items_xref.child_id) AS Child, (SELECT menu_item_url FROM MENU_ITEMS WHERE MENU_ITEMS.menu_item_id = menu_items_xref.child_id) AS Childlink, sort_order FROM menu_items_xref </CFQUERY>Section F rounds out our code; it’s the final piece of our create_menu.cfm custom tag. Using recursion, we’re able to build and populate the menu tree with a single custom tag. Create_menu.cfm uses recursion to call itself as a custom tag in order to build sub-branches off the main root menu as needed. When a sub-branch is required, the code calls <CF_create_menu>, which processes the data for the new branch. Should additional sub-branches be needed for an existing sub-branch, the code is called again and recurses another level (or as many levels as required) to create the branch(es). As each level completes, the one above continues on. After all the recursions have run, we’re left with the menu tree.
F节完善了我们的代码; 这是我们的create_menu.cfm自定义标记的最后一部分。 使用递归,我们可以使用单个自定义标签构建并填充菜单树。 Create_menu.cfm使用递归将其称为自定义标签,以便根据需要在主根菜单上构建子分支。 当需要一个子分支时,代码调用<CF_create_menu> ,它处理新分支的数据。 如果现有子分支需要其他子分支,则再次调用该代码并递归另一个级别(或所需的多个级别)以创建分支。 完成每个级别后,上面的一个继续。 运行完所有递归后,我们将剩下菜单树。
Section F
F节
<!--- Build menu ---> <CFLOOP QUERY="qGetMenuElement"> <!--- Increment the loop counter ---> <CFSET VARIABLES.LoopCount = VARIABLES.LoopCount + 1> <CFIF (qGetMenuElement.childlink NEQ '')> <!--- Last element on a branch ---> <CFOUTPUT> <a href="#VARIABLES.RootLevel##childlink#" class="menu"><img src="#VARIABLES.RootLevel#images/transparent.gif" width="9" height="9" border="0" hspace="4">#child#<!--- -#ATTRIBUTES.divID# ---></a><CFIF ATTRIBUTES.divID NEQ ""><CFIF FindNoCase(qGetMenuElement.ChildLink, CGI.PATH_INFO)><script type="text/javascript">ShowMenu('#ATTRIBUTES.divID#');</script></CFIF></CFIF> </CFOUTPUT> <!--- build out branches ---> <CFELSE> <CFOUTPUT> <CFSET VARIABLES.IncreNum = "0" & VARIABLES.LoopCount> <CFSET VARIABLES.Num = ATTRIBUTES.DivID & VARIABLES.IncreNum> <a href="##" class="menu" onclick="ShowMenu('#VARIABLES.Num#'); this.blur(); return false"><img src="#VARIABLES.RootLevel#images/right_arrow.gif" name="i#VARIABLES.Num#" width="9" height="9" border="0" hspace="4 /">#child#<!--- -#ATTRIBUTES.divID# ---></a> <div id="d#VARIABLES.Num#" class="expand"> <CF_create_menu menuID = "#child_id#" divID = "#VARIABLES.Num#" level = "#ATTRIBUTES.Level#"> </div> </CFOUTPUT> </CFIF> </CFLOOP> <!--- Reset the loop counter ---> <CFSET VARIABLES.LoopCount = 0>That’s all there is to it! We’ve created a dynamic collapsible tree menu using a database and ColdFusion.
这里的所有都是它的! 我们使用数据库和ColdFusion创建了动态可折叠树菜单。
翻译自: https://www.sitepoint.com/dynamic-menu-coldfusion/
coldfusion
相关资源:jdk-8u281-windows-x64.exe