我从codepen.io复制了这个树查看器,试图在我的静态网站上使用它。奇怪的是,它不能像 codepen.io 上显示的那样工作。理想情况下,我们应该能够展开和折叠子目录,但是当我将代码复制到自己的网页中后,所有子目录都仅与父文件夹一起列出。
这就是展开之前的样子:
但这就是我在自己的网站上实际得到的:
下面是从codepen.io复制的代码片段,你可以尝试一下开头的链接,看看它在codepen.io上是如何工作的。
/* shorthand functions (createElement is defined at bottom)*/
const div = (props, ...children) => createElement("div", props, ...children);
const ul = (props, ...children) => createElement("ul", props, ...children);
const li = (props, ...children) => createElement("li", props, ...children);
const i = (props, ...children) => createElement("i", props, ...children);
const span = (props, ...children) => createElement("span", props, ...children);
const header = (props, ...children) =>
createElement("header", props, ...children);
const p = (props, ...children) => createElement("p", props, ...children);
const section = (props, ...children) =>
createElement("section", props, ...children);
const button = (props, ...children) =>
createElement("button", props, ...children);
/* File */
const File = ({ name }) => {
return div(
{ className: "file" },
i({ className: "material-icons", style: "opacity: 0;" }, "arrow_right"),
i({ className: "material-icons" }, "insert_drive_file"),
span(null, name)
);
};
/* Folder */
const openedFolderIcon = "folder_open";
const closedFolderIcon = "folder";
const openedArrowIcon = "arrow_drop_down";
const closedArrowIcon = "arrow_right";
function changeOpened(event) {
const folderHeader = event.target.classList.contains("folder-header")
? event.target
: event.target.parentElement;
const opened = folderHeader.getAttribute("opened") == "true";
const newOpened = !opened;
let icons = folderHeader.querySelectorAll(".material-icons");
icons.forEach(icon => {
if (/arrow/i.test(icon.textContent)) {
icon.textContent = newOpened ? openedArrowIcon : closedArrowIcon;
} else {
icon.textContent = newOpened ? openedFolderIcon : closedFolderIcon;
}
});
try {
const sibling = folderHeader.nextElementSibling;
if (newOpened) {
sibling.classList.remove("hide");
} else {
sibling.classList.add("hide");
}
} catch (e) {
console.warn(`No sibling of elem ${folderHeader} found ...`);
}
folderHeader.setAttribute("opened", newOpened);
}
const Folder = (props, ...children) => {
const opened = props.opened || false;
const arrowIcon = opened ? openedArrowIcon : closedArrowIcon;
const folderIcon = opened ? openedFolderIcon : closedFolderIcon;
const folderName = props.name || "unknown";
return div(
{ className: "folder" },
header(
{
onClick: changeOpened,
className: "folder-header",
opened: opened
},
i({ className: "material-icons" }, arrowIcon),
i({ className: "material-icons" }, folderIcon),
span(null, folderName)
),
ul({ className: opened ? "" : "hide" }, ...children)
);
};
/* TreeView */
const TreeView = () => {
return section(
{ className: "container" },
Folder(
{ name: "src" },
Folder({ name: "myTest.js" }, File({ name: "whatup.js" })),
File({ name: "justASimpleFile.css" })
),
File({ name: "project.json" })
);
};
const app = document.querySelector("#treeView");
app.appendChild(createElement(TreeView));
/* My react-clone mini library */
function appendChildren(parent, children) {
for (let child of children) {
if (!child) continue;
switch (typeof child) {
case "string":
const el = document.createTextNode(child);
parent.appendChild(el);
break;
default:
parent.appendChild(child);
break;
}
}
}
function setStyle(el, style) {
if (typeof style == "string") {
el.setAttribute("style", style);
} else {
Object.assign(el.style, style);
}
}
function setClass(el, className) {
className.split(/\s/).forEach(element => {
if (element) {
el.classList.add(element);
}
});
}
function setProps(el, props) {
const eventRegex = /^on([a-z]+)$/i;
for (let propName in props) {
if (!propName) continue;
if (propName === "style") {
setStyle(el, props[propName]);
} else if (propName === "className") {
setClass(el, props[propName]);
} else if (eventRegex.test(propName)) {
const eventToListen = propName.replace(eventRegex, "$1").toLowerCase();
el.addEventListener(eventToListen, props[propName]);
} else {
el.setAttribute(propName, props[propName]);
}
}
}
//type, [props], [...children]
function createElement(type, props, ...children) {
if (typeof type === "function") {
return type(props);
} else {
const el = document.createElement(type);
if (props && typeof props === "object") {
setProps(el, props);
}
if (children) {
appendChildren(el, children);
}
return el;
}
}
/* Tree View */
#treeView {
padding-top: 2em;
padding-right: 0.1em;
padding-bottom: 3em;
overflow: auto;
white-space: nowrap;
}
#treeView span {
display: inline-flex;
vertical-align: middle;
padding-left: 0.3em;
font-size: 1.1rem;
}
#treeView i {
display: inline-flex;
vertical-align: middle;
}
/* File */
.file {
position: relative;
display: block;
cursor: pointer;
}
.file:hover {
background-color: #ccc;
}
/* Folder */
.folder {
display: block;
}
.folder-header {
position: relative;
cursor: pointer;
/* z-index: 999; */
}
.folder-header:hover {
background-color: #ccc;
}
.folder > ul {
padding-left: 0;
margin: 0;
}
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
<div class="row">
<div class="col s12 m4" id="treeView">
</div>
</div>
如您所见,此代码也不适用于 SO。
我做错了什么?如何使此代码片段如图所示工作?
您没有包含他们在 codepen 上使用的库
/* shorthand functions (createElement is defined at bottom)*/
const div = (props, ...children) => createElement("div", props, ...children);
const ul = (props, ...children) => createElement("ul", props, ...children);
const li = (props, ...children) => createElement("li", props, ...children);
const i = (props, ...children) => createElement("i", props, ...children);
const span = (props, ...children) => createElement("span", props, ...children);
const header = (props, ...children) =>
createElement("header", props, ...children);
const p = (props, ...children) => createElement("p", props, ...children);
const section = (props, ...children) =>
createElement("section", props, ...children);
const button = (props, ...children) =>
createElement("button", props, ...children);
/* File */
const File = ({ name }) => {
return div(
{ className: "file" },
i({ className: "material-icons", style: "opacity: 0;" }, "arrow_right"),
i({ className: "material-icons" }, "insert_drive_file"),
span(null, name)
);
};
/* Folder */
const openedFolderIcon = "folder_open";
const closedFolderIcon = "folder";
const openedArrowIcon = "arrow_drop_down";
const closedArrowIcon = "arrow_right";
function changeOpened(event) {
const folderHeader = event.target.classList.contains("folder-header")
? event.target
: event.target.parentElement;
const opened = folderHeader.getAttribute("opened") == "true";
const newOpened = !opened;
let icons = folderHeader.querySelectorAll(".material-icons");
icons.forEach(icon => {
if (/arrow/i.test(icon.textContent)) {
icon.textContent = newOpened ? openedArrowIcon : closedArrowIcon;
} else {
icon.textContent = newOpened ? openedFolderIcon : closedFolderIcon;
}
});
try {
const sibling = folderHeader.nextElementSibling;
if (newOpened) {
sibling.classList.remove("hide");
} else {
sibling.classList.add("hide");
}
} catch (e) {
console.warn(`No sibling of elem ${folderHeader} found ...`);
}
folderHeader.setAttribute("opened", newOpened);
}
const Folder = (props, ...children) => {
const opened = props.opened || false;
const arrowIcon = opened ? openedArrowIcon : closedArrowIcon;
const folderIcon = opened ? openedFolderIcon : closedFolderIcon;
const folderName = props.name || "unknown";
return div(
{ className: "folder" },
header(
{
onClick: changeOpened,
className: "folder-header",
opened: opened
},
i({ className: "material-icons" }, arrowIcon),
i({ className: "material-icons" }, folderIcon),
span(null, folderName)
),
ul({ className: opened ? "" : "hide" }, ...children)
);
};
/* TreeView */
const TreeView = () => {
return section(
{ className: "container" },
Folder(
{ name: "src" },
Folder({ name: "myTest.js" }, File({ name: "whatup.js" })),
File({ name: "justASimpleFile.css" })
),
File({ name: "project.json" })
);
};
const app = document.querySelector("#treeView");
app.appendChild(createElement(TreeView));
/* My react-clone mini library */
function appendChildren(parent, children) {
for (let child of children) {
if (!child) continue;
switch (typeof child) {
case "string":
const el = document.createTextNode(child);
parent.appendChild(el);
break;
default:
parent.appendChild(child);
break;
}
}
}
function setStyle(el, style) {
if (typeof style == "string") {
el.setAttribute("style", style);
} else {
Object.assign(el.style, style);
}
}
function setClass(el, className) {
className.split(/\s/).forEach(element => {
if (element) {
el.classList.add(element);
}
});
}
function setProps(el, props) {
const eventRegex = /^on([a-z]+)$/i;
for (let propName in props) {
if (!propName) continue;
if (propName === "style") {
setStyle(el, props[propName]);
} else if (propName === "className") {
setClass(el, props[propName]);
} else if (eventRegex.test(propName)) {
const eventToListen = propName.replace(eventRegex, "$1").toLowerCase();
el.addEventListener(eventToListen, props[propName]);
} else {
el.setAttribute(propName, props[propName]);
}
}
}
//type, [props], [...children]
function createElement(type, props, ...children) {
if (typeof type === "function") {
return type(props);
} else {
const el = document.createElement(type);
if (props && typeof props === "object") {
setProps(el, props);
}
if (children) {
appendChildren(el, children);
}
return el;
}
}
/* Tree View */
#treeView {
padding-top: 2em;
padding-right: 0.1em;
padding-bottom: 3em;
overflow: auto;
white-space: nowrap;
}
#treeView span {
display: inline-flex;
vertical-align: middle;
padding-left: 0.3em;
font-size: 1.1rem;
}
#treeView i {
display: inline-flex;
vertical-align: middle;
}
/* File */
.file {
position: relative;
display: block;
cursor: pointer;
}
.file:hover {
background-color: #ccc;
}
/* Folder */
.folder {
display: block;
}
.folder-header {
position: relative;
cursor: pointer;
/* z-index: 999; */
}
.folder-header:hover {
background-color: #ccc;
}
.folder > ul {
padding-left: 0;
margin: 0;
}
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
<link href="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/css/materialize.min.css" rel="stylesheet">
<link href="https://cdnjs.cloudflare.com/ajax/libs/material-design-iconic-font/2.2.0/css/material-design-iconic-font.min.css" rel="stylesheet">
<div class="row">
<div class="col s12 m4" id="treeView">
</div>
</div>