重複コードの再パッケージ(VanillaJS)
開始します.🌈
私のコードを見たとき、私はいつも心配していました.というコードは、これからも使えますか? は繰り返す感じ?! は性能面で悪いのではないでしょうか?! ということで、今回も私のコードを見て、イベント面で何度か重複している部分を見ました.
そして始まります.ボタンコードを再包装!
本題📖
私が再包装することにしたコードは
私の場合、ボタンがクリックされると、モードを実行させる一連のステップもフォーマットできると思います.
第一に、共通の部分を選ぶ.
そこで、私たちはまず共通の部分を選びました.
その結果、ある月の活動を実行する部分で、次のような結論が得られました.活動は多くの場所で使用でき、関数形式より の場合、まずmodalを実行します.必要なパラメータは、modalのタイトルと そこで、この3つをパラメータの関数として、以降の重複コードで再使用しましょう.したがって、これらのモデルを作成するコードについては、
renderComponentMethods.js
こんなに早く一つ一つのコードを省略しようとすると興奮しますか?!
では、
sidebar.js
ここで私は彼に関数を作った.
これは、いずれにしても、ボタンをクリックしたときに現れる
そこで,
sidebar.js/openCreatePageModal
したがって、check->openCreatePageModelを実行する関数も作成されます.
sidebar.js/renderModal
最後にどれだけ減らせるか見てみましょう.
改造後再構成関数を除いて、コードは約20%短縮され、 モードの関数イベントを生成するコードがより直感的になりました! 終了時👏
カバーした瞬间に悩みがいっぱい
でも終わってから.以降は突然何か変化がありますか? 再製作が必要な場合は便利に再利用できるので心配なし! 皆さん、きれいなコードと一緒にプロジェクトを頑張りましょう.🖐
あまり良いコードではありませんが、この文章が誰かに参考になることを望んでいます.😆 以上
💡 より簡潔な再構築スキームがある場合は、フィードバックを惜しまないでください:)
私のコードを見たとき、私はいつも心配していました.
そして始まります.ボタンコードを再包装!
本題📖
私が再包装することにしたコードは
sidebar
部分です.import {
_removeAllChildNodes,
_createElemWithAttr,
_renderPosts,
} from '@/utils/customDOMMethods';
import names from '@/utils/classNames';
import createPost from '@/apis/route/post/createPost';
import Modal from '@/components/common/Modal';
import { push } from '@/apis/router';
import { ERROR_STATUS } from '@/utils/constants';
import deletePost from '@/apis/route/post/deletePost';
import getPostList from '@/apis/route/post/getPostList';
import Button from '@/components/common/Button';
import checkState from '@/utils/checkState';
/*
{
username,
documents: []
}
*/
export default function SideBar({ $target, initialState, onClick }) {
const {
postsItem,
postsBlock,
sideBarItem,
sideBarContainer,
sideBarButtonBox,
sideBarCreatePostBtn,
postBlock,
postToggleBtn,
postNext,
postLink,
postNextNew,
postRemoveBtn,
} = names;
this.state = initialState;
const $sideBar = _createElemWithAttr('nav', [sideBarContainer]);
const $posts = _createElemWithAttr('section', [sideBarItem, postsBlock]);
const $sideBarButtonBox = _createElemWithAttr('div', [sideBarButtonBox]);
new Button({
$target: $sideBarButtonBox,
attributes: { classNames: [sideBarCreatePostBtn], text: '페이지 생성' },
onClick: () => {
const $app = document.querySelector('#app');
const modal = new Modal({
$target: $app,
head: '생성할 페이지의 제목을 입력해주세요!',
isInput: true,
onConform: async title => {
try {
const result = await createPost(this.state.username, {
title,
parent: null,
});
push(`/posts/${result.id}`);
} catch (e) {
console.error(e);
alert(ERROR_STATUS, e);
}
},
});
modal.render();
},
});
$sideBar.appendChild($sideBarButtonBox);
this.setState = nextState => {
if (!checkState(this.state, 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 = () => {
console.log($sideBar, $target);
if (!$target.querySelector(`.${sideBarContainer}`))
$target.append($sideBar);
};
$sideBar.addEventListener('click', e => {
if (
!e.target.classList.contains(postsItem) &&
!e.target.classList.contains(postLink)
) {
return;
}
const postId = e.target.closest(`.${postsItem}`).getAttribute(['data-id']);
onClick(postId);
});
$posts.addEventListener('click', e => {
const { target } = e;
if (!target.classList.contains(postToggleBtn, 'post__link')) 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 closestPostNext = e.target.closest(`.${postsItem}`);
const modal = new Modal({
$target: document.querySelector('#app'),
head: '정말로 삭제하시겠어요?',
isInput: false,
onConform: async () => {
try {
const { id } = closestPostNext.dataset;
await deletePost(this.state.username, id);
const posts = await getPostList(this.state.username);
this.setState({
documents: posts,
});
if (id === window.location.pathname.split('/')[2]) {
push('/');
}
} catch (e) {
console.error(e);
alert(ERROR_STATUS, e);
}
},
});
modal.render();
});
}
どうですか.繰り返したような気がしますか?!私の場合、ボタンがクリックされると、モードを実行させる一連のステップもフォーマットできると思います.
第一に、共通の部分を選ぶ.
そこで、私たちはまず共通の部分を選びました.
その結果、ある月の活動を実行する部分で、次のような結論が得られました.
addEventListener
形式で残るほうが説得力があるので触らないでください.input
があるかどうか、およびtry
があるかどうかです.utils
というディレクトリに配置し、後でコンポーネントレンダリングで役立つ関数を収集します.renderComponentMethods.js
というモジュールが作成されました.renderComponentMethods.js
import Modal from '@/components/common/Modal';
import names from '@/utils/classNames';
import { ERROR_STATUS } from '@/utils/constants';
export const renderModalByEvent = ({ head, isInput, tryFunc }) => {
const { container } = names;
const $app = document.querySelector('#app');
const modal = new Modal({
$target: document.querySelector('#app'),
head,
isInput,
onConform: async content => {
try {
await tryFunc(isInput && content);
} catch (e) {
console.error(e);
alert(ERROR_STATUS, e);
} finally {
if ($app.querySelector(`.${container}`)) {
$app.removeChild(modal.$container);
}
}
},
});
modal.render();
};
たくさん摘んだみたい!こんなに早く一つ一つのコードを省略しようとすると興奮しますか?!
では、
sidebar
に移動して適用します.sidebar.js
ここで私は彼に関数を作った.
これは、いずれにしても、ボタンをクリックしたときに現れる
tryFunc
が、この素子の中でほとんど似ているからである.そこで,
openCreatePageModal
というアプリケーション関数を作成した.sidebar.js/openCreatePageModal
const openCreatePageModal = async $elem => {
renderModalByEvent({
head: INPUT_TITLE_MESSAGE,
isInput: true,
tryFunc: async title => {
const result = await createPost(this.state.username, {
title,
parent: $elem?.dataset.id ?? null,
});
push(`/posts/${result.id}`);
},
});
};
でも本当は不満もあるcheck
以降->作成モードの過程でも、この過程は強い繰返し感があります.したがって、check->openCreatePageModelを実行する関数も作成されます.
sidebar.js/renderModal
const renderModal = async ({ eventTarget, isValid, closestSelectorName }) => {
if (!isValid) return;
const $elem = eventTarget.closest(`.${closestSelectorName}`);
await openCreatePageModal($elem);
};
どのように簡単ですか.最後にどれだけ減らせるか見てみましょう.
new Button({
$target: $sideBarButtonBox,
attributes: { classNames: [sideBarCreatePostBtn], text: '페이지 생성' },
onClick: () => {
const $app = document.querySelector('#app');
const modal = new Modal({
$target: $app,
head: '생성할 페이지의 제목을 입력해주세요!',
isInput: true,
onConform: async title => {
try {
const result = await createPost(this.state.username, {
title,
parent: null,
});
push(`/posts/${result.id}`);
} catch (e) {
console.error(e);
alert(ERROR_STATUS, e);
}
},
});
modal.render();
},
});
こんなハーモニー! new Button({
$target: $sideBarButtonBox,
attributes: {
classNames: [sideBarCreatePostBtn],
text: BUTTON_COMPONENT_TEXT,
},
onClick: () => openCreatePageModal(),
});
本当にやり終えて、ずいぶん簡略化しましたね.改造後
export default function SideBar({ $target, initialState, onClick }) {
const {
sideBarContainer,
postsItem,
postsBlock,
sideBarItem,
sideBarButtonBox,
sideBarCreatePostBtn,
postBlock,
postToggleBtn,
postNext,
postLink,
postNextNew,
postCreateBtn,
postRemoveBtn,
} = names;
const $sideBar = _createElemWithAttr('nav', [sideBarContainer]);
const $posts = _createElemWithAttr('section', [sideBarItem, postsBlock]);
this.state = initialState;
const $sideBarButtonBox = _createElemWithAttr('div', [sideBarButtonBox]);
new Button({
$target: $sideBarButtonBox,
attributes: {
classNames: [sideBarCreatePostBtn],
text: BUTTON_COMPONENT_TEXT,
},
onClick: () => openCreatePageModal(),
});
$sideBar.appendChild($sideBarButtonBox);
this.setState = nextState => {
if (!checkState(this.state, 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 = () => {
if (!$target.querySelector(`${sideBarContainer}`)) {
$target.appendChild($sideBar);
}
};
$sideBar.addEventListener('click', e => {
const { classList } = e.target;
if (!classList.contains(postsItem) && !classList.contains(postLink)) return;
const postId = e.target.closest(`.${postsItem}`).getAttribute(['data-id']);
onClick(postId);
});
$posts.addEventListener('click', e => {
const { target } = e;
if (!target.classList.contains(postToggleBtn, 'post__link')) 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 => {
renderModal({
eventTarget: e.target,
isValid: e.target.closest(`.${postNextNew}`),
closestSelectorName: postNext,
});
});
$sideBar.addEventListener('click', e => {
renderModal({
eventTarget: e.target,
isValid: e.target.classList.contains(postCreateBtn),
closestSelectorName: postsItem,
});
});
$sideBar.addEventListener('click', e => {
if (!e.target.classList.contains(postRemoveBtn)) return;
const closestPostsItem = e.target.closest(`.${postsItem}`);
renderModalByEvent({
head: MODAL_DELETE_QUESTION,
isInput: false,
tryFunc: async () => {
await deletePost(this.state.username, closestPostsItem.dataset.id);
const posts = await getPostList(this.state.username);
this.setState({
documents: posts,
});
},
});
});
const renderModal = async ({ eventTarget, isValid, closestSelectorName }) => {
if (!isValid) return;
const $elem = eventTarget.closest(`.${closestSelectorName}`);
await openCreatePageModal($elem);
};
const openCreatePageModal = async $elem => {
renderModalByEvent({
head: INPUT_TITLE_MESSAGE,
isInput: true,
tryFunc: async title => {
const result = await createPost(this.state.username, {
title,
parent: $elem?.dataset.id ?? null,
});
push(`/posts/${result.id}`);
},
});
};
}
結局こうして、カバーした瞬间に悩みがいっぱい
でも終わってから.
あまり良いコードではありませんが、この文章が誰かに参考になることを望んでいます.😆 以上
💡 より簡潔な再構築スキームがある場合は、フィードバックを惜しまないでください:)
Reference
この問題について(重複コードの再パッケージ(VanillaJS)), 我々は、より多くの情報をここで見つけました https://velog.io/@young_pallete/Project-중복되는-코드-리팩토링하기-VanillaJSテキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol