[Project]モードでの作成/削除機能


開始します。🔥


はい.今は12時間のプロジェクトで、同じ部分に3時間も割り込んでました…!
私の忍耐力が最后の瞬间まで坚持する时、私は误解の部分があると思って、だから修正した后の结果、私は正常な动作をしました!!👏👏👏
だから本当に...走ることが大切だと改めて感じた
では、それがどのように実現されているかを見てみましょう.

本題📃


モダルになりたいいずれにしても、作成や削除時に十分な情報を簡単に伝えることができ、apiを勝手に使用することを避けることができます.
だから.以下のモデルを作成しました.

Modal.js


この毛は、inputの毛を入れることができ、そうでない毛と統合して使用することができます.したがって、isInput、すなわちpropsを受け取りました.それは変わらないので、initialStateに入れませんでした.
import names from '../../utils/classNames.js';
import {
  _appendChilds,
  _createElemWithAttr,
} from '../../utils/customDOMMethods.js';
import Input from './Input.js';

export default function Modal({
  $target = document.querySelector('#app'),
  head = '내용을 입력해주세요!',
  isInput = false,
  initialState = { title: '' },
  onConform,
}) {
  const {
    modalBlock,
    container,
    modalConformButton,
    modalCancelButton,
    modalHead,
    modalInput,
    modalButtonBox,
  } = names;

  const $fragment = new DocumentFragment();
  this.$container = _createElemWithAttr('div', [container]);

  const $modal = _createElemWithAttr('div', [modalBlock]);
  const $modalHead = _createElemWithAttr('h3', [modalHead], head);
  const $modalButtonBox = _createElemWithAttr('div', [modalButtonBox]);
  const $conformButton = _createElemWithAttr('button', [modalConformButton]);
  const $cancelButton = _createElemWithAttr('button', [modalCancelButton]);

  $conformButton.textContent = '확인';
  $cancelButton.textContent = '취소';
  $fragment.appendChild(this.$container);
  this.$container.appendChild($modal);
  $modal.appendChild($modalHead);

  if (isInput) {
    this.state = initialState;
    const input = new Input({
      $target: $modal,
      placeholder: '제목을 입력해주세요!',
      initialState: this.state,
      onChange: title => {
        this.setState({ title });
      },
    });
    input.$input.classList.add(modalInput);
    this.setState = nextState => {
      this.state = nextState;
      if (isInput) {
        input.setState({
          title: this.state.title,
        });
      }
    };
  }
  _appendChilds($modalButtonBox, $conformButton, $cancelButton);
  _appendChilds($modal, $modalButtonBox);

  this.render = () => {
    $target.appendChild($fragment);
  };

  const onCancel = () => {
    $target.removeChild(this.$container);
  };

  $conformButton.addEventListener(
    'click',
    async () => await onConform(isInput ? this.state.title : undefined),
  );
  $cancelButton.addEventListener('click', () => onCancel());
}
また、onCancelもどうせキャンセルなので、パラメータは別途受け付けていません!
では、どのように呼び出されたのか見てみましょう.

sideBar.js

import classNames from '../utils/classNames.js';
import {
  _removeAllChildNodes,
  _createElemWithAttr,
} from '../utils/customDOMMethods.js';
import renderPosts from '../utils/renderPosts.js';
import names from '../utils/classNames.js';
import createPost from '../apis/route/post/createPost.js';
import Modal from './common/Modal.js';
import { push } from '../apis/router.js';
import { ERROR_STATUS } from '../utils/constants.js';
import deletePost from '../apis/route/post/deletePost.js';
import getPostList from '../apis/route/post/getPostList.js';

/*
  {
    documents: []
  }
*/

export default function SideBar({ $target, initialState, onClick }) {
  const {
    postsItem,
    postsBlock,
    sideBarItem,
    postBlock,
    postToggleBtn,
    postNext,
    postNextNew,
    postRemoveBtn,
  } = names;

  const $sideBar = document.createElement('nav');
  $sideBar.className = classNames.sideBarContainer;

  const $posts = _createElemWithAttr('section', [sideBarItem, postsBlock]);
  this.state = initialState;

  this.setState = nextState => {
    if (JSON.stringify(this.state) !== JSON.stringify(nextState)) {
      _removeAllChildNodes($posts);
      this.state = nextState;
      const { documents } = this.state;
      const $fragment = new DocumentFragment();
      renderPosts($fragment, documents);
      $posts.appendChild($fragment);
      $sideBar.appendChild($posts);
    }
    this.render();
  };

  this.render = () => {
    $target.appendChild($sideBar);
  };

  $sideBar.addEventListener('click', e => {
    if (!e.target.classList.contains(postsItem)) return;
    const postId = e.target.getAttribute(['data-id']);
    onClick(postId);
  });

  $posts.addEventListener('click', e => {
    const { target } = e;
    if (!target.classList.contains(postToggleBtn)) return;
    const closestPostId = target.closest(`.${postBlock}`).dataset.id;
    const $nextItem = $posts.querySelector(
      `.${postNext}[data-id="${closestPostId}"]`,
    );
    $nextItem.classList.toggle('invisible');
    target.classList.toggle('toggle');
  });

  $sideBar.addEventListener('click', e => {
    const closestPostNextNew = e.target.closest(`.${postNextNew}`);
    if (!closestPostNextNew) return;
    const $app = document.querySelector('#app');
    const closestPostNext = e.target.closest(`.${postNext}`);
    const modal = new Modal({
      $target: $app,
      head: '생성할 페이지의 제목을 입력해주세요!',
      isInput: true,
      onConform: async title => {
        try {
          const result = await createPost(this.state.username, {
            title,
            parent: closestPostNext.dataset.id,
          });
          push(`/posts/${result.id}`);
        } catch (e) {
          console.error(e);
          alert(ERROR_STATUS, e);
        }
      },
    });
    modal.render();
  });

  $sideBar.addEventListener('click', e => {
    if (!e.target.classList.contains(postRemoveBtn)) return;
    const $app = document.querySelector('#app');
    const closestPostNext = e.target.closest(`.${postsItem}`);
    const modal = new Modal({
      $target: document.querySelector('#app'),
      head: '정말로 삭제하시겠어요?',
      isInput: false,
      onConform: async () => {
        try {
          await deletePost(this.state.username, closestPostNext.dataset.id);
          const posts = await getPostList(this.state.username);
          this.setState({
            documents: posts,
          });
        } catch (e) {
          console.error(e);
          alert(ERROR_STATUS, e);
        } finally {
          $app.removeChild(modal.$container);
        }
      },
    });
    modal.render();
  });
}

では、どこが塞がれていますか?!


レンダリング時に、既存のデータ+削除されたデータをsideBarにマージしてレンダリングします.
ここで本当に~たくさんの悩みを言って、本当に怒って、もとは私はこれを無視しました.
_removeAllChildNodes($posts);
$sideBarを対象に書かれていましたこのとき、現在のデータは$postですが、単純に$sideBarから外すだけでは消えないでしょう?!いいえ、彼はまだ生きていると思います.😂😂😂createElementは生命力がありますね.本当に怖い子なので気をつけて!
またDocumentFragmentも無視した.この友達はcreateElementと反対に私の役は終わりました?!そして行ってしまった.
だからページを作るときに使ったことがあって、レンダリングすると逃げるこいつ...道徳書...📖📖🔥🔥🔥
とりあえずこの2つの問題を解決したのは5時半でしたがとても気持ちが良かったです
君が知らないことを調べるほどいいことはないからだ.😄 ずっと忘れない

sidebar.scss


今から子供たちに服を着せに行きます(?)行きましょう.
@import "../color";

.sidebar-container {
  position: fixed;
  top: 0;
  width: 300px;
  height: 100vh;
  overflow-y: scroll;
  padding: 1rem;
  background: $mint100;
  .sidebar__item.posts {
    width: 100%;
    .post {
      display: flex;
      align-items: center;
      width: 100%;
      margin: {
        right: auto;
        bottom: 0.5rem;
      }
      &:hover {
        cursor: pointer;
      }
      &__link {
        text-decoration: none;
        color: black;
        text-overflow: ellipsis;
        white-space: nowrap;
        overflow: hidden;
      }
      &__toggle-btn {
        transition: all 0.3s;
        &:hover {
          color: rgb(255, 145, 0);
        }
      }
      &__remove-btn {
        margin-left: auto;
      }
      &__new-button {
        display: flex;
        align-items: center;
      }
    }
    .post-next {
      padding-left: 1.375rem;
      &__new {
        display: flex;
        align-items: center;
        transition: all 0.3s;
        margin-bottom: 1rem;
        &:hover {
          cursor: pointer;
          color: rgb(255, 145, 0);
        }
      }
      &__new-icon {
        margin-right: 0.25rem;
      }
    }
  }
}
cssがこんなに面白いとは知らなかった!これは苦痛の後の新しい発見です!
そして、fetchからrequestに発展しました(…)createPostdeletePostの方法を作りました!

createPost.js

import request from '../../request.js';

const createPost = async (username, body) => {
  return await request(`/documents`, {
    options: { body: JSON.stringify(body), method: 'POST' },
    header: {
      'x-username': username,
    },
  });
};

export default createPost;

deletePost.js

import request from '../../request.js';

const deletePost = async (username, id) => {
  return await request(`/documents/${id}`, {
    options: {
      method: 'DELETE',
    },
    header: {
      'x-username': username,
    },
  });
};

export default deletePost;
では、結果を見てみましょう?!

使いやすい😄

終了時🔥


14時間も勉強して、眠くて気が狂った時...!
しかし、私は今晩徹夜することにしました.(副題:あなたの実力で眠れるの?!
40時間、耐えられるだろう…?!
働きましょう青春!!😂😂😂