3줄의 코드로 가짜 UI 프레임워크를 작성했습니다.

나는 나의 새로운 개인 UI 프로젝트 중 하나가 기본으로 돌아가기를 원했습니다. 6년 동안 Angular/React를 사용한 후 나는 내 간단한 프로젝트를 단순하게 유지하고 예를 들어 순수 CSS에서 기본 메뉴 드롭다운을 만들 수 있는지 확인하기로 결정했습니다. 좋은 옛날과 같은 일을 하지만 CSS 그리드와 화살표 기능을 사용하십시오.

하루 만에 "추가 전용"CSS 괴물이 생겼습니다. 내 index.html은 같은 불안한 보라색 그늘에서 촉수를 싹트기까지 일주일이 걸릴 수 있다는 점에서 더 좋았습니다.

큰 파일을 작은 파일로 나누었을 때 웹 구성 요소를 밀접하게 미러링하는 구조를 사용하고 있음을 발견했습니다. 예를 들어, 멋진 팝오버에는 HTML과 JS를 약간 가미한 CSS가 많이 필요했습니다. 드롭다운 메뉴와 레이아웃 도우미 등은 모두 HTML, CSS 및 JS의 세 가지 모두는 아니더라도 가장 많이 필요했습니다. 폴더가 재정렬되었습니다. 파일 명명 규칙이 발생했습니다.

나는 또한 읽을 수 있는 DOM이 그리웠다. divspan 의 끝없는 퍼레이드 대신 유용한 HTML 태그를 보는 것을 놓쳤습니다. 나는 여전히 JS 모델 데이터의 자동 차이에 대한 응답으로 사용자 정의 태그를 즉석에서 다시 렌더링하는 반응 프레임워크가 필요하지 않았으며 .innerHTML 정적이 아닌 부분에 대해 잘 작동했지만 원했습니다. 에헴, 나쁜 옛날보다 더 나은 것. 이 대부분의 정적 사이트에서도 읽을 수 있는 HTML과 좋은 코드 구조를 원했습니다. 이것은 내가 쓴 것입니다.

 <script type="module">
      /* the "render once" UI framework */

      const loadHtmls = element =>
        Array.from(element.children)
          .map(child => (child.tagName.includes("-") ? loadHtml : loadHtmls)(child));

      const loadHtml = el =>
        fetch("html/" + el.tagName + ".html")
          .then(response => response.text())
          .then(html => {
            if (html.match(/{{innerHTML}}/)) html = html.replace(/{{innerHTML}}/g, el.innerHTML);
            Array.from(el.attributes).forEach(attr => (html = html.replace(new RegExp("{{" + attr.name + "}}", "g"), attr.value)));
            el.innerHTML = html;
          })
          .then(_ => loadHtmls(el))
          .then(_ =>
            Array.from(el.querySelectorAll("script")).forEach(old => {
              const replacement = document.createElement("script");
              replacement.setAttribute("type", "module");
              replacement.appendChild(document.createTextNode(old.innerHTML));
              old.replaceWith(replacement);
            })
          );

      loadHtmls(document.body);
    </script>
  </body>
</html>


마지막 줄은 이 스니펫이 있는 index.html의 표시 가능한 비트에서 첫 번째 줄을 호출합니다.

첫 번째 줄은 전달된 요소의 직계 자식을 살펴봅니다. 요소의 태그에 하이픈<like-this></like-this>이 포함된 경우 요소는 두 번째 줄로 전달됩니다. 그렇지 않으면 요소가 재귀를 위해 첫 번째 줄로 전달됩니다.

HTML5 사양에 따르면 하이픈이 포함된 태그는 항상 UnknownElement로 보장됩니다. 사용자 정의 foobar에서 내장 div를 말할 방법이 없으며 이 스니펫을 적은 노력으로 유지하기 위해 쉽게 제한할 수 있습니다.

이번에는 두 번째 줄에 대한 또 다른 제한 절충안은 모든 "구성 요소"가 구현하는 태그의 이름을 따서 명명된 동일한 폴더에 있어야 한다는 것입니다. 단일 폴더 규칙이 잘 확장되지 않더라도 파일 이름 규칙은 훌륭한 코드 구성 원칙으로 두 배가 됩니다. <some-component>some-component.html에 의해 구현되며, 차례로 <style>, <script> 또는 <link>를 사용하여 CSS 및 JS를 포함합니다. 쉬운.

두 번째 줄은 서버에서 구성 요소 파일을 가져오고 HTML에서 동일한 이름의 속성 값{{likeThis}}을 대체<some-component likeThis='42'>로 바꿉니다. 또한 {{innerHTML}}를 요소의 pre-render innerHTML로 대체합니다. 이는 flexbox에 들어가는 내용을 래핑하는 <flex-row>와 같은 구성 요소에 유용합니다.

    <flex-row wrap="nowrap">
      <named-panel name="Sidebar"></named-panel>
      <named-panel name="Main Content"></named-panel>
    </flex-row>


마지막으로 사용자 지정 구성 요소가 다른 사용자 지정 구성 요소를 호출할 수 있도록 새로 업데이트된 DOM으로 재귀합니다. DOM을 마친 후에야 스크립트를 실행하며, 이는 DOM 요소addEventListener가 될 수 있습니다. (HTML5는 스크립트 실행을 자동으로 금지하고, 타이핑이 현저히 적음에도 불구하고 eval 나쁜 점을 들었습니다.)

이 "프레임워크"는 분명히 프레임워크가 되기에는 너무 부족합니다. 바닐라 JS가 실제 런타임 변경을 수행하기 때문에 모든 것이 실행되고 서버 측에서 거의 완전히 정적 사이트로 렌더링될 수 있습니다. 그러나 대부분의 개인 프로젝트와 마찬가지로 저는 그것을 좋아합니다. 같은 방식으로 대부분의 사람들에게 추악할 수 있는 작은 애완견을 좋아할 수도 있습니다. 하지만 그는 내 애완견이고 우리가 촉수를 제거한 이후로 훨씬 좋아졌습니다.

좋은 웹페이지 즐겨찾기