代码无法正常工作,如原始网站所示

问题描述 投票:0回答:1

我从codepen.io复制了这个树查看器,试图在我的静态网站上使用它。奇怪的是,它不能像 codepen.io 上显示的那样工作。理想情况下,我们应该能够展开和折叠子目录,但是当我将代码复制到自己的网页中后,所有子目录都仅与父文件夹一起列出。

这就是展开之前的样子:

enter image description here

但这就是我在自己的网站上实际得到的:

enter image description here

下面是从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。

我做错了什么?如何使此代码片段如图所示工作?

javascript html css
1个回答
0
投票

您没有包含他们在 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>

© www.soinside.com 2019 - 2024. All rights reserved.