[Project]JavaScriptを使用したルーティング
33633 ワード
開始します。🌈
ふーん!昨日と今日で10時間近くウロウロして、やっと実現!🖐🏻🖐🏻🖐🏻
実は原理はとっくに知っていましたが、私のすべてのコードを覆す必要があるので、
結果はもう一つの小細工(?)探している間に変わった
しかし、結局私は貴重なものを手に入れた.
ためらってもためらわないうちに直接叫んでください.👍👍
では、どうやって実現したのか見てみましょう?!
本題📖
私はまずApp
に以下のページを置きました!
ここで注意したいのは、SPA
の特徴です.
これにより、ページをルーティングとは別に、上記でインスタンスとして呼び出すことができ、後でルーティングの移動に応じてページを容易に貼り付けることができる.
そのため、初期ロードには時間がかかりますが、最終的には速度が速いという利点があります!👍👍
実際、私はこれを放棄したいと思っています.趣旨から、一貫性のために、私はもっと多くの時間を費やしました.😅
コードは次のとおりです.import router from './apis/router.js';
import MainPage from './pages/MainPage.js';
import PostEditPage from './pages/PostEditPage.js';
import { READ_POST_ROUTE } from '../src/utils/constants.js';
import removeAllChildNodes from './utils/removeAllChildNodes.js';
export default function App({ $target }) {
const postEditPage = new PostEditPage({
$target,
initialState: {
postId: 'new',
},
});
const mainPage = new MainPage({
$target,
initialState: {
username: 'jengyoung',
documents: [],
},
onClick: id => {
history.pushState(null, null, READ_POST_ROUTE + `/${id}`);
this.route();
},
});
this.route = () => {
removeAllChildNodes($target); // App 초기화
const { pathname } = window.location;
const splitedPath = pathname.split('/');
if (pathname === undefined || pathname === '/') {
mainPage.setState();
} else if (pathname.indexOf(READ_POST_ROUTE + '/') === 0) {
const postId = splitedPath[2];
postEditPage.setState({ postId });
}
};
this.route();
router(() => this.route());
}
もしここに何か特別な場所があったら.うーん、removeAllChildNodes
なので、すべてのノードを削除する関数を作成しました!特にありません.while
文を書いて削除しましたexport default function removeAllChildNodes(node) {
while (node.hasChildNodes()) {
node.removeChild(node.lastChild);
}
}
特に、ページに設定されたstate
は、更新されるたびにレンダリングされます(正確には、同じページコンポーネント(posts/1->posts/2)に移動するとします.
私は次のsetState
に従います.
ページを見てみましょうか?!
MainPage.js
昨日とずいぶん変わった
熟考の末、ノーソンのようにSideBar
に名前をつけることにしたが、個性的にタイトルに掲げた.これからはもう一つ作ります!import request from '../apis/request.js';
import Header from '../components/common/Header.js';
import SideBar from '../components/SideBar.js';
/*
{
username: string
documents: [<object>]
}
*/
export default function MainPage({
$target,
initialState = { username: '', documents: [] },
onClick,
}) {
this.state = initialState;
const $page = new DocumentFragment();
// const $page = document.createElement('div');
const sideBar = new SideBar({
$target: $page,
initialState,
onClick,
});
const header = new Header({
$target: $page,
headerSize: 'h5',
initialState: {
content: this.state.username,
},
});
this.setState = () => {
const posts = request();
this.state = {
...this.state,
documents: posts,
};
const { username, documents } = this.state;
header.setState({ content: username });
sideBar.setState({
username,
documents,
});
this.render();
};
this.render = () => {
$target.appendChild($page);
};
}
PostEditPage.js
ここでもずいぶん変わっていますが、考えてみると、レンダリングは次のように考えられます.
レンダーれんだりんぐ:画面にペイントします.
誰がこのレンダリングの主導権を持つべきですか?私があなたに聞いたとき、
結局、ページが持っているものがもっと確実だと思ったので、ページに描くことにしました.
したがって、setState
でレンダリングを再描画する場合、最終的にpostForm
によって独立して素子内部でレンダリングされると、render
は呼び出されなくなる.import PostForm from '../components/PostForm.js';
import debounce from '../utils/debounce.js';
import { getItem, setItem } from '../utils/storage.js';
/*
* this.state = {
* postId: string,
* }
*/
export default function PostEditPage({
$target,
initialState = { postId: 'new' },
}) {
const $page = document.createDocumentFragment();
this.state = initialState;
const { postId } = this.state;
const defaultValue = { title: '', content: '' };
const post = getItem(getLocalPostKey(postId), defaultValue);
const postForm = new PostForm({
$target: $page,
initialState: {
...post,
},
onEdit: post => {
debounce(setItem, 2000)(getLocalPostKey(this.state.postId), { ...post });
},
});
// postId가 바뀔 때 페이지의 상태가 변화합니다!
this.setState = nextState => {
this.state = nextState;
const post = getItem(getLocalPostKey(this.state.postId), defaultValue);
postForm.setState(post);
this.render();
};
this.render = () => {
if ($target.querySelector('form') === null) {
postForm.render(); // 에디터의 경우 여기서 렌더링을 해줘야, setState할 때 다시 렌더링되지 않습니다.
}
$target.appendChild($page);
};
}
const getLocalPostKey = postId => {
return `temp-save-${postId}`;
};
PostForm.js
逆に、PostForm構成部品については、既存のvalue
がレンダリング中に変更されたが、構成部品レンダリングの観点からは不適切であるように見えるため、setState
で行うことにした.
逆に、素子レンダリングの依存性がより明確に理解でき、満足しています.😄import Input from './common/Input.js';
export default function PostForm({
$target,
initialState = {
title: '',
content: '',
},
onEdit,
}) {
// 초기 컴포넌트를 DOM에 추가하고, 상태를 초기화합니다.
const $editor = document.createElement('form');
/*
* this.state = {
* title: string
* content: string
* }
*/
this.state = initialState;
/*************************************
* component *
*************************************/
const postTitle = new Input({
$target: $editor,
initialState: this.state.title,
onChange: title => {
const nextState = {
...this.state,
title,
};
this.setState(nextState);
postTitle.setState(title);
onEdit(this.state);
},
});
const $postContent = document.createElement('textarea');
this.setState = nextState => {
this.state = {
...this.state,
...nextState,
};
const { content } = this.state;
$postContent.value = content;
postTitle.setState(this.state.title);
};
this.render = () => {
$editor.appendChild($postContent);
$target.appendChild($editor);
};
$postContent.addEventListener('keyup', e => {
this.setState({
...this.state,
content: e.target.value,
});
onEdit({ ...this.state });
});
}
router
ああ、結果的に素子がこのように設定されています.どうやってルーティングしたのですか?!historyAPI
を使っています
一緒に勉強していたチョンヒョンの助けで、後ろを歩いても曖昧に表現された.
この時代最高の開発者であるジョンヒョンに大きな拍手を送った.👏👏👏
簡単に言えば、app
に設定されたthis.route
をパラメータとして受け取り、イベントに基づいて処理します.// route change라는 이벤트를 발생시킵니다.
const DISPATCH_ROUTE_CHANGE = 'route-change';
export default function router(onRoute) {
window.addEventListener(DISPATCH_ROUTE_CHANGE, e => {
const { nextUrl } = e.detail;
if (nextUrl) {
history.pushState(null, null, nextUrl);
console.log('nextUrl', nextUrl);
onRoute();
}
});
window.addEventListener('popstate', () => {
onRoute();
});
}
export const push = nextUrl => {
window.dispatchEvent(
new CustomEvent(DISPATCH_ROUTE_CHANGE, {
detail: {
nextUrl,
},
}),
);
};
結果を見てみましょう.
HTML開発者として、あなたのデザインはかなりきれいです!😅😅
の最後の部分👏
今はRouteまでやった!では、Defcosが提供するapi
と組み合わせて、本格的なタスクを作成しましょう.
皆さん、コードが楽しいことを祈っています.😃😄😝
Reference
この問題について([Project]JavaScriptを使用したルーティング), 我々は、より多くの情報をここで見つけました
https://velog.io/@young_pallete/프로젝트-JavaScript로-라우트-구현하기
テキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol
私はまず
App
に以下のページを置きました!ここで注意したいのは、
SPA
の特徴です.これにより、ページをルーティングとは別に、上記でインスタンスとして呼び出すことができ、後でルーティングの移動に応じてページを容易に貼り付けることができる.
そのため、初期ロードには時間がかかりますが、最終的には速度が速いという利点があります!👍👍
実際、私はこれを放棄したいと思っています.趣旨から、一貫性のために、私はもっと多くの時間を費やしました.😅
コードは次のとおりです.
import router from './apis/router.js';
import MainPage from './pages/MainPage.js';
import PostEditPage from './pages/PostEditPage.js';
import { READ_POST_ROUTE } from '../src/utils/constants.js';
import removeAllChildNodes from './utils/removeAllChildNodes.js';
export default function App({ $target }) {
const postEditPage = new PostEditPage({
$target,
initialState: {
postId: 'new',
},
});
const mainPage = new MainPage({
$target,
initialState: {
username: 'jengyoung',
documents: [],
},
onClick: id => {
history.pushState(null, null, READ_POST_ROUTE + `/${id}`);
this.route();
},
});
this.route = () => {
removeAllChildNodes($target); // App 초기화
const { pathname } = window.location;
const splitedPath = pathname.split('/');
if (pathname === undefined || pathname === '/') {
mainPage.setState();
} else if (pathname.indexOf(READ_POST_ROUTE + '/') === 0) {
const postId = splitedPath[2];
postEditPage.setState({ postId });
}
};
this.route();
router(() => this.route());
}
もしここに何か特別な場所があったら.うーん、removeAllChildNodes
なので、すべてのノードを削除する関数を作成しました!特にありません.while
文を書いて削除しましたexport default function removeAllChildNodes(node) {
while (node.hasChildNodes()) {
node.removeChild(node.lastChild);
}
}
特に、ページに設定されたstate
は、更新されるたびにレンダリングされます(正確には、同じページコンポーネント(posts/1->posts/2)に移動するとします.私は次の
setState
に従います.ページを見てみましょうか?!
MainPage.js
昨日とずいぶん変わった
熟考の末、ノーソンのように
SideBar
に名前をつけることにしたが、個性的にタイトルに掲げた.これからはもう一つ作ります!import request from '../apis/request.js';
import Header from '../components/common/Header.js';
import SideBar from '../components/SideBar.js';
/*
{
username: string
documents: [<object>]
}
*/
export default function MainPage({
$target,
initialState = { username: '', documents: [] },
onClick,
}) {
this.state = initialState;
const $page = new DocumentFragment();
// const $page = document.createElement('div');
const sideBar = new SideBar({
$target: $page,
initialState,
onClick,
});
const header = new Header({
$target: $page,
headerSize: 'h5',
initialState: {
content: this.state.username,
},
});
this.setState = () => {
const posts = request();
this.state = {
...this.state,
documents: posts,
};
const { username, documents } = this.state;
header.setState({ content: username });
sideBar.setState({
username,
documents,
});
this.render();
};
this.render = () => {
$target.appendChild($page);
};
}
PostEditPage.js
ここでもずいぶん変わっていますが、考えてみると、レンダリングは次のように考えられます.
レンダーれんだりんぐ:画面にペイントします.
誰がこのレンダリングの主導権を持つべきですか?私があなたに聞いたとき、
結局、ページが持っているものがもっと確実だと思ったので、ページに描くことにしました.
したがって、
setState
でレンダリングを再描画する場合、最終的にpostForm
によって独立して素子内部でレンダリングされると、render
は呼び出されなくなる.import PostForm from '../components/PostForm.js';
import debounce from '../utils/debounce.js';
import { getItem, setItem } from '../utils/storage.js';
/*
* this.state = {
* postId: string,
* }
*/
export default function PostEditPage({
$target,
initialState = { postId: 'new' },
}) {
const $page = document.createDocumentFragment();
this.state = initialState;
const { postId } = this.state;
const defaultValue = { title: '', content: '' };
const post = getItem(getLocalPostKey(postId), defaultValue);
const postForm = new PostForm({
$target: $page,
initialState: {
...post,
},
onEdit: post => {
debounce(setItem, 2000)(getLocalPostKey(this.state.postId), { ...post });
},
});
// postId가 바뀔 때 페이지의 상태가 변화합니다!
this.setState = nextState => {
this.state = nextState;
const post = getItem(getLocalPostKey(this.state.postId), defaultValue);
postForm.setState(post);
this.render();
};
this.render = () => {
if ($target.querySelector('form') === null) {
postForm.render(); // 에디터의 경우 여기서 렌더링을 해줘야, setState할 때 다시 렌더링되지 않습니다.
}
$target.appendChild($page);
};
}
const getLocalPostKey = postId => {
return `temp-save-${postId}`;
};
PostForm.js
逆に、PostForm構成部品については、既存の
value
がレンダリング中に変更されたが、構成部品レンダリングの観点からは不適切であるように見えるため、setState
で行うことにした.逆に、素子レンダリングの依存性がより明確に理解でき、満足しています.😄
import Input from './common/Input.js';
export default function PostForm({
$target,
initialState = {
title: '',
content: '',
},
onEdit,
}) {
// 초기 컴포넌트를 DOM에 추가하고, 상태를 초기화합니다.
const $editor = document.createElement('form');
/*
* this.state = {
* title: string
* content: string
* }
*/
this.state = initialState;
/*************************************
* component *
*************************************/
const postTitle = new Input({
$target: $editor,
initialState: this.state.title,
onChange: title => {
const nextState = {
...this.state,
title,
};
this.setState(nextState);
postTitle.setState(title);
onEdit(this.state);
},
});
const $postContent = document.createElement('textarea');
this.setState = nextState => {
this.state = {
...this.state,
...nextState,
};
const { content } = this.state;
$postContent.value = content;
postTitle.setState(this.state.title);
};
this.render = () => {
$editor.appendChild($postContent);
$target.appendChild($editor);
};
$postContent.addEventListener('keyup', e => {
this.setState({
...this.state,
content: e.target.value,
});
onEdit({ ...this.state });
});
}
router
ああ、結果的に素子がこのように設定されています.どうやってルーティングしたのですか?!
historyAPI
を使っています一緒に勉強していたチョンヒョンの助けで、後ろを歩いても曖昧に表現された.
この時代最高の開発者であるジョンヒョンに大きな拍手を送った.👏👏👏
簡単に言えば、
app
に設定されたthis.route
をパラメータとして受け取り、イベントに基づいて処理します.// route change라는 이벤트를 발생시킵니다.
const DISPATCH_ROUTE_CHANGE = 'route-change';
export default function router(onRoute) {
window.addEventListener(DISPATCH_ROUTE_CHANGE, e => {
const { nextUrl } = e.detail;
if (nextUrl) {
history.pushState(null, null, nextUrl);
console.log('nextUrl', nextUrl);
onRoute();
}
});
window.addEventListener('popstate', () => {
onRoute();
});
}
export const push = nextUrl => {
window.dispatchEvent(
new CustomEvent(DISPATCH_ROUTE_CHANGE, {
detail: {
nextUrl,
},
}),
);
};
結果を見てみましょう.HTML開発者として、あなたのデザインはかなりきれいです!😅😅
の最後の部分👏
今はRouteまでやった!では、Defcosが提供するapi
と組み合わせて、本格的なタスクを作成しましょう.
皆さん、コードが楽しいことを祈っています.😃😄😝
Reference
この問題について([Project]JavaScriptを使用したルーティング), 我々は、より多くの情報をここで見つけました
https://velog.io/@young_pallete/프로젝트-JavaScript로-라우트-구현하기
テキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol
Reference
この問題について([Project]JavaScriptを使用したルーティング), 我々は、より多くの情報をここで見つけました https://velog.io/@young_pallete/프로젝트-JavaScript로-라우트-구현하기テキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol