我有一個平面陣列,我正在嘗試從它們創建一個分層站點地圖。到目前為止我所擁有的非常混亂,所以我想要一種更好的方法。
這是我擁有的頁面陣列
const pages = [
{
"name": "Page 1",
"url": "/page-1/",
},
{
"name": "Page 2",
"url": "/page-2/",
},
{
"name": "Child 1",
"url": "/page-1/child-1/",
},
{
"name": "Child 2",
"url": "/page-1/child-1/child-2/",
},
{
"name": "Child 3",
"url": "/page-1/child-1/child-2/child-3/",
}
]
這就是我想要輸出的結果
<ul>
<li>
<a href="/page-1/">Page 1</a>
<ul>
<li>
<a href="/page-1/child-1/">Child 1</a>
<ul>
<li>
<a href="/page-1/child-1/child-2/">Child 2</a>
<ul>
<li>
<a href="/page-1/child-1/child-2/child-3/">Child 3</a>
</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
<li><a href="/page-2/">Page 2</a></li>
</ul>
這就是我目前所擁有的,它有效,但想找到一種更好的方法來做到這一點
const generateSitemap = function(pages) => {
let sitemap = "";
let organisedPages = [];
const sortPages = function (runs) {
if (pages.length === 0) return;
pages.forEach((page) => {
const title = page.name;
const url = page.url;
// Get homepage and content pages only
let pageObj = {
title: title,
url: url,
children: [],
};
// Handle top level pages first then build up children as you go deeper
if (pageLevel(url) === 1) {
organisedPages.push(pageObj);
pages = pages.filter((page1) => page !== page1);
} else if (runs === 2) {
organisedPages.forEach((oPage, i) => {
// Check to see if url is in segments and matches
let parseUrl = url.substring(1).slice(0, -1);
const urlParts = parseUrl.split("/");
const parentUrl = `/${urlParts.slice(0, -1).join("/")}/`;
if (oPage.url === parentUrl) {
organisedPages[i].children.push(pageObj);
pages = pages.filter(
(page1) => pageObj.url !== page1.systemProperties.url
);
return;
}
});
} else if (runs === 3) {
organisedPages.forEach((oPage, i) => {
// Check to see if url is in segments and matches
let parseUrl = url.substring(1).slice(0, -1);
const urlParts = parseUrl.split("/");
const parentUrl = urlParts.slice(0, -1);
const parentUrlComp = `/${parentUrl.join("/")}/`;
const parentUrl2 = parentUrl.slice(0, -1);
const parentUrl2Comp = `/${parentUrl2.join("/")}/`;
if (oPage.url === parentUrl2Comp) {
organisedPages[i].children.forEach((child, j) => {
if (child.url === parentUrlComp) {
organisedPages[i].children[j].children.push(pageObj);
pages = pages.filter(
(page1) => pageObj.url !== page1.systemProperties.url
);
return;
}
});
}
});
} else if (runs === 4) {
organisedPages.forEach((oPage, i) => {
// Check to see if url is in segments and matches
let parseUrl = url.substring(1).slice(0, -1);
const urlParts = parseUrl.split("/");
const parentUrl = urlParts.slice(0, -1);
const parentUrlComp = `/${parentUrl.join("/")}/`;
const parentUrl2 = parentUrl.slice(0, -1);
const parentUrl2Comp = `/${parentUrl2.join("/")}/`;
const parentUrl3 = parentUrl2.slice(0, -1);
const parentUrl3Comp = `/${parentUrl3.join("/")}/`;
if (oPage.url === parentUrl3Comp) {
organisedPages[i].children.forEach((child, j) => {
if (child.url === parentUrl2Comp) {
organisedPages[i].children[j].children.forEach((child1, k) => {
if (child1.url === parentUrlComp) {
organisedPages[i].children[j].children[k].children.push(
pageObj
);
pages = pages.filter(
(page1) => pageObj.url !== page1.systemProperties.url
);
return;
}
});
}
});
}
});
}
});
runs ;
if (runs < 5) {
sortPages(runs);
}
};
sortPages(1);
/**
* Check if page is a parent
*
* @param {string} url page url
* @returns {number} length of segments
*/
function pageLevel(url) {
// Remove first and last forward slash that is provided
let parseUrl = url.substring(1).slice(0, -1);
// Split parsed url by forward slash
const urlParts = parseUrl.split("/");
// Check segment length
return urlParts.length;
}
/**
* Loop through organised pages and set listing.
*/
organisedPages.forEach((page) => {
sitemap = `<li>`;
sitemap = `<a href="${page.url}">${page.title}</a>`;
// Check if we need children loop for each parent page
if (page.children.length) {
sitemap = `<ul>`;
page.children.forEach((page) => {
sitemap = `<li>`;
sitemap = `<a href="${page.url}">${page.title}</a>`;
// Check if we need children loop for each sub-child page
if (page.children.length) {
sitemap = `<ul>`;
page.children.forEach((page) => {
sitemap = `<li>`;
sitemap = `<a href="${page.url}">${page.title}</a>`;
if (page.children.length) {
sitemap = `<ul>`;
page.children.forEach((page) => {
sitemap = `<li>`;
sitemap = `<a href="${page.url}">${page.title}</a>`;
sitemap = `</li>`;
});
sitemap = `</ul>`;
}
sitemap = `</li>`;
});
sitemap = `</ul>`;
}
sitemap = `</li>`;
});
sitemap = `</ul>`;
}
sitemap = `</li>`;
});
return sitemap;
};
generateSitemap(pages)
uj5u.com熱心網友回復:
我會選擇從 HTML 格式中打破物件的邏輯嵌套,因為我認為它使所有的功能都更簡單。為了方便地進行嵌套,我還將添加一個輔助函式來從 url 獲取父 id,例如,
getParentId ("/page-1/") //=> ""
getParentId ("/page-1/child-1/") //=> "/page-1"
getParentId ("/page-1/child-1/child-2/") //=> "/page1/child-1"
// ... etc
我們可以輕松地將這個函式行內到 中nest,但我認為它作為助手更干凈。這有點奇怪的復雜性,因為在某處有一個額外的斜線,開始或結束。/在搜索我們的串列以找到孩子時,我們選擇切掉決賽。
代碼如下所示:
const getParentId = (url) => url .slice (0, url .slice (0, -1) .lastIndexOf ('/'))
const nest = (pages, parentId = "", id = parentId .slice (0, -1)) => pages
.filter (({url}) => getParentId (url) == id)
.map (({url, ...rest}) => ({...rest, url, children: nest (pages, url)}))
const format = (nodes) => `<ul>${nodes .map (({name, url, children}) =>
`<li><a href="${url}">${name}</a>${children .length ? format (children) : ''}</li>`
).join('')}</ul>`
const pages2html = (pages) => format (nest (pages))
const pages = [{name: "Page 1", url: "/page-1/"}, {name: "Page 2", url: "/page-2/"}, {name: "Child 1", url: "/page-1/child-1/"}, {name: "Child 2", url: "/page-1/child-1/child-2/"}, {name: "Child 3", url: "/page-1/child-1/child-2/child-3/"}]
console .log (pages2html (pages))
.as-console-wrapper {max-height: 100% !important; top: 0}
這里nest將你的節點變成這樣的格式:
[
{
name: "Page 1",
url: "/page-1/",
children: [
{
name: "Child 1",
url: "/page-1/child-1/",
children: [
{
name: "Child 2",
url: "/page-1/child-1/child-2/",
children: [
{
name: "Child 3",
url: "/page-1/child-1/child-2/child-3/",
children: []
}
]
}
]
}
]
},
{
name: "Page 2",
url: "/page-2/",
children: []
}
]
然后format將其轉換為您的 HTML。我們將它們包裝在一起,pages2html以便呼叫一個函式,但作業是在這兩個至少可能重用的函式中完成的。
請注意,我們不會嘗試以您請求的格式保留空白。我們可以這樣做,但代價是變得format更丑陋。這是一個快速嘗試,我認為這是正確的。但我不會發誓:
const format = (nodes, depth = 0) => `${depth > 0 ? '\n' : ''
}${' '.repeat (2 * depth) }<ul>${nodes .map (({name, url, children}) => `
${' ' .repeat (2 * depth 1) }<li>
${' ' .repeat (2 * depth 2) }<a href="${url}">${name}</a>${
children .length ? `` format (children, depth 1) : ''
}
${' ' .repeat (2 * depth 1) }</li>`
).join('')}
${' '.repeat (2 * depth)}</ul>`
我們只需使用一個depth引數來記錄嵌套級別,并使用它來確定在行首使用多少空格。
總的來說,我發現這種風格作為一系列轉換作業,使用起來要簡單得多。是的,我們可以在一個函式中完成所有這些。它的代碼行數甚至可能比我的四個獨立函式少。但是這些中的每一個都更易于理解,并且在需要時更易于更改。
并且遞回將比您的多級分支更靈活、更簡單,正如您從next.
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/494492.html
標籤:javascript html 递归 网站地图
