[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
に発展しました(…)createPost
とdeletePost
の方法を作りました!
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時間、耐えられるだろう…?!
働きましょう青春!!😂😂😂
Reference
この問題について([Project]モードでの作成/削除機能), 我々は、より多くの情報をここで見つけました
https://velog.io/@young_pallete/Project-모달을-통한-생성삭제-기능-구현
テキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol
モダルになりたいいずれにしても、作成や削除時に十分な情報を簡単に伝えることができ、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
に発展しました(…)createPost
とdeletePost
の方法を作りました!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時間、耐えられるだろう…?!
働きましょう青春!!😂😂😂
Reference
この問題について([Project]モードでの作成/削除機能), 我々は、より多くの情報をここで見つけました https://velog.io/@young_pallete/Project-모달을-통한-생성삭제-기능-구현テキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol