ページネーション(Pagination)— 省略・ドロップダウン・テキスト入力 3パターン比較
このコンポーネントについて
ページ数が多くなると、全ページ番号をボタンで並べる方式ではUIが横に溢れてしまいます。 この事例では「省略(...)型」「ドロップダウン型」「テキスト入力型」の3パターンを同じデータで並べて比較し、それぞれの特徴と使い分けを確認できます。
省略(...)型は全体のページ数の把握に優れますが、中間ページへの直接ジャンプが難しいという課題があります。 ドロップダウン型はセレクトボックスで任意のページへ即移動でき、テキスト入力型は入力欄が1つだけで非常にコンパクトです。 リスト — ページネーション や テーブル — ページネーション+フィルター で紹介している基本的なボタン型ページングの発展パターンとして参照してください。
- 3パターン比較 — 省略(...)型・ドロップダウン型・テキスト入力型を同一データで並べて表示。特徴の違いをすぐ体感できる
- 共通JSONデータ — 食べ物60件を4件/ページ表示 → 15ページ。3パターンで同じ
data.jsonを共有する - 省略ロジック(パターン1) — 現在ページ±1のウィンドウ・先頭・末尾を常に表示し、ギャップに
…を挟む。…はクリック不可のセパレーター - ドロップダウン選択(パターン2) —
<select>に全ページ一覧を生成。選択変更で即ジャンプ。前後ボタンとセットで操作しやすい - テキスト入力ジャンプ(パターン3) —
<input type="number">でページ番号を直接入力。Enter またはフォーカスアウトで移動。範囲外の値は自動クランプ - XSS対策 — すべてのDOM操作は
createElement/textContentを使用。innerHTMLに変数を渡さない
実装のポイント・注意点
省略ロジックは「表示するページ番号のセット」を計算してから描画する。
{1, current-1, current, current+1, total} の5つの候補から範囲外(0以下・total超)を除き昇順ソートし、連続しない番号の間に '...' を挿入します。
「currentが1のとき current-1=0 が除外されて 1, 2, ..., total になる」など、端ページでも自動で正しく機能します。
… は <button> ではなく <span> で実装する。
ボタンにするとフォーカスが当たり誤クリックも発生します。pointer-events: none; user-select: none; をセットで指定し、完全にインタラクション不可にしましょう。
ドロップダウン型の select はデータ取得後に生成する。
総ページ数がデータ件数から確定するため、HTMLに option を静的に書けません。fetch の .then() 内で createElement('option') を繰り返して生成します。
ページ移動後は select.value = currentPage で表示を同期させることも忘れずに。
テキスト入力型は keydown(Enter)と blur の両方でジャンプ処理を呼ぶ。
Enter だけだとスマートフォン等でソフトキーボードを閉じた際にジャンプされないケースがあります。
入力値は Math.min(Math.max(1, n), totalPages) でクランプし、範囲外・空欄・NaN はすべて現在ページに戻します。
HTML・CSS・バニラJavaScriptのみで実装しており、フレームワーク不要でコピペすぐに動きます。
デモ
3パターンは同じJSONデータを共有しています。それぞれ独立して操作できます。
Pattern 1 — 省略(...)型
Pattern 2 — ドロップダウン型
Pattern 3 — テキスト入力型
サンプルソース
4つのファイルを同じフォルダに保存し、ローカルサーバー(VS Code Live Server等)経由で
index.html を開くと動作確認できます。
ファイル名:index.html / style.css / script.js
+ data/ フォルダに data.json
— fetch を使用しているため file:// での直接表示は動作しません(CORSエラー)。
保存時の文字コードは UTF-8 を指定してください。
3パターンはまとめて1セットになっています。不要なパターンのHTMLブロック・CSSセクション・JS関数を削除して使ってください。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>ページネーション比較サンプル</title>
<link rel="stylesheet" href="./style.css">
</head>
<body>
<!-- ============================
Pattern 1 — 省略(...)型
全ページボタンを並べず先頭・末尾・現在ページ周辺のみ表示
ページ数が多い場合に横幅を節約できる
============================= -->
<div class="pg-wrap">
<h2 class="pg-label">Pattern 1 — 省略(...)型</h2>
<p class="pg-count" id="js-p1-count"></p>
<ul class="pg-list" id="js-p1-list"></ul>
<nav class="pg-pager" id="js-p1-pager" aria-label="ページ移動(省略型)"></nav>
</div>
<!-- ============================
Pattern 2 — ドロップダウン型
select で全ページ一覧→任意ページへ即ジャンプ
ページ数が多くても UI がコンパクト
============================= -->
<div class="pg-wrap">
<h2 class="pg-label">Pattern 2 — ドロップダウン型</h2>
<p class="pg-count" id="js-p2-count"></p>
<ul class="pg-list" id="js-p2-list"></ul>
<nav class="pg-pager pg-pager--dropdown" aria-label="ページ移動(ドロップダウン型)">
<button class="pg-btn" id="js-p2-prev" disabled>◀</button>
<select class="pg-select" id="js-p2-select" aria-label="ページ選択"></select>
<button class="pg-btn" id="js-p2-next">▶</button>
</nav>
</div>
<!-- ============================
Pattern 3 — テキスト入力型
数値入力で任意ページへジャンプ
入力欄1つで最もコンパクト。ページ数が非常に多い場合に特に有効
============================= -->
<div class="pg-wrap">
<h2 class="pg-label">Pattern 3 — テキスト入力型</h2>
<p class="pg-count" id="js-p3-count"></p>
<ul class="pg-list" id="js-p3-list"></ul>
<nav class="pg-pager pg-pager--input" aria-label="ページ移動(テキスト入力型)">
<button class="pg-btn" id="js-p3-prev" disabled>◀</button>
<input class="pg-input" id="js-p3-input" type="number" min="1" value="1" aria-label="ページ番号入力">
<span class="pg-total" id="js-p3-total">/ —</span>
<button class="pg-btn" id="js-p3-next">▶</button>
</nav>
</div>
<script src="./script.js"></script>
</body>
</html>
/* ページネーション 3パターン比較 — style.css */
*, *::before, *::after { box-sizing: border-box; }
:root {
--color-primary: #2B7FE8;
--color-border: #D0D7E0;
--color-text: #1A2332;
--color-muted: #5A6A7A;
--color-light: #9AA5B4;
}
body {
font-family: sans-serif;
max-width: 520px;
margin: 32px auto;
padding: 0 16px;
color: var(--color-text);
}
/* --- 各パターンのラッパー --- */
.pg-wrap {
margin-bottom: 40px;
padding-bottom: 32px;
border-bottom: 1px solid #E8ECF0;
}
.pg-wrap:last-child { border-bottom: none; }
/* --- パターンラベル --- */
.pg-label {
font-size: 13px;
font-weight: 700;
color: var(--color-primary);
margin: 0 0 12px;
}
/* --- 件数・ページ数 --- */
.pg-count {
font-size: 12px;
color: var(--color-muted);
margin: 0 0 8px;
}
/* --- リスト --- */
.pg-list {
list-style: none;
padding: 0;
margin: 0 0 12px;
}
.pg-list li {
display: flex;
align-items: center;
gap: 12px;
padding: 9px 0;
border-bottom: 1px solid #EEF0F3;
}
.pg-list li:last-child { border-bottom: none; }
.pg-id { font-size: 12px; color: var(--color-light); min-width: 28px; }
.pg-name { font-size: 15px; }
/* --- ページャー共通 --- */
.pg-pager {
display: flex;
align-items: center;
gap: 4px;
flex-wrap: wrap;
}
/* ============================
Pattern 1 — 省略(...)型
============================= */
.pg-btn {
min-width: 36px;
height: 36px;
padding: 0 8px;
border: 1.5px solid var(--color-border);
border-radius: 6px;
background: #fff;
color: var(--color-text);
font-size: 13px;
cursor: pointer;
transition: background 0.15s, border-color 0.15s;
}
.pg-btn:hover:not(:disabled):not(.is-active) { background: #F1F5F9; }
.pg-btn.is-active {
background: var(--color-primary);
color: #fff;
border-color: var(--color-primary);
font-weight: 700;
}
.pg-btn:disabled { color: #CBD5E1; cursor: not-allowed; }
/* 省略記号(クリック不可) */
.pg-ellipsis {
min-width: 36px;
height: 36px;
display: inline-flex;
align-items: center;
justify-content: center;
color: var(--color-light);
font-size: 13px;
cursor: default;
pointer-events: none;
user-select: none;
}
/* ============================
Pattern 2 — ドロップダウン型
============================= */
.pg-select {
height: 36px;
padding: 0 28px 0 10px;
border: 1.5px solid var(--color-border);
border-radius: 6px;
background: #fff url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath d='M1 1l5 5 5-5' stroke='%235A6A7A' stroke-width='1.5' fill='none' stroke-linecap='round'/%3E%3C/svg%3E") no-repeat right 8px center;
font-size: 14px;
color: var(--color-text);
cursor: pointer;
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
}
/* ============================
Pattern 3 — テキスト入力型
============================= */
.pg-input {
width: 52px;
height: 36px;
text-align: center;
border: 1.5px solid var(--color-border);
border-radius: 6px;
font-size: 14px;
/* スピナー非表示 */
-webkit-appearance: none;
-moz-appearance: textfield;
}
.pg-input::-webkit-inner-spin-button,
.pg-input::-webkit-outer-spin-button { -webkit-appearance: none; margin: 0; }
.pg-total {
font-size: 14px;
color: var(--color-muted);
white-space: nowrap;
}
// ============================================================
// ページネーション 3パターン比較 — script.js
// ============================================================
// fetch('./data/data.json') でJSONを1回取得し3パターンで共有する
// 各パターンはそれぞれ独立した currentPage 変数を持つ
var PAGE_SIZE = 4; // 1ページあたりの表示件数
var allItems = []; // 読み込んだ全件データ(3パターン共用)
// --- 各パターンの現在ページ ---
var currentPage1 = 1;
var currentPage2 = 1;
var currentPage3 = 1;
// --- DOM要素 ---
var p1CountEl = document.getElementById('js-p1-count');
var p1ListEl = document.getElementById('js-p1-list');
var p1PagerEl = document.getElementById('js-p1-pager');
var p2CountEl = document.getElementById('js-p2-count');
var p2ListEl = document.getElementById('js-p2-list');
var p2PrevBtn = document.getElementById('js-p2-prev');
var p2SelectEl = document.getElementById('js-p2-select');
var p2NextBtn = document.getElementById('js-p2-next');
var p3CountEl = document.getElementById('js-p3-count');
var p3ListEl = document.getElementById('js-p3-list');
var p3PrevBtn = document.getElementById('js-p3-prev');
var p3InputEl = document.getElementById('js-p3-input');
var p3TotalEl = document.getElementById('js-p3-total');
var p3NextBtn = document.getElementById('js-p3-next');
// --- JSONを読み込んで初期化(1回だけ) ---
fetch('./data/data.json')
.then(function(res) { return res.json(); })
.then(function(data) {
allItems = data;
var totalPages = Math.ceil(allItems.length / PAGE_SIZE);
buildP2Select(totalPages); // Pattern 2: select の選択肢を生成
p3InputEl.max = totalPages; // Pattern 3: input の max を設定
p3TotalEl.textContent = '/ ' + totalPages;
renderP1();
renderP2();
renderP3();
})
.catch(function() {
p1CountEl.textContent = 'データの読み込みに失敗しました。';
});
// ============================================================
// Pattern 1 — 省略(...)型
// ============================================================
// 省略記号を含むページリストを生成する
// {1, current-1, current, current+1, total} の有効値を昇順ソートし
// 連続しない番号の間に '...' を挿入する
function getPageList(current, total) {
var set = {};
[1, current - 1, current, current + 1, total].forEach(function(p) {
if (p >= 1 && p <= total) { set[p] = true; }
});
var nums = Object.keys(set).map(Number).sort(function(a, b) { return a - b; });
var result = [];
for (var i = 0; i < nums.length; i++) {
if (i > 0 && nums[i] - nums[i - 1] > 1) { result.push('...'); }
result.push(nums[i]);
}
return result;
}
function renderP1() {
var totalPages = Math.ceil(allItems.length / PAGE_SIZE);
renderList(p1ListEl, currentPage1);
p1CountEl.textContent = allItems.length + '件 / ' + totalPages + 'ページ';
p1PagerEl.textContent = ''; // 前回のボタンをクリア
var prevBtn = makeBtn('前へ', 'pg-btn');
prevBtn.disabled = (currentPage1 === 1);
prevBtn.addEventListener('click', function() { currentPage1--; renderP1(); });
p1PagerEl.appendChild(prevBtn);
// 省略ロジックで生成した配列をボタン・省略記号に変換
getPageList(currentPage1, totalPages).forEach(function(item) {
if (item === '...') {
var span = document.createElement('span');
span.className = 'pg-ellipsis';
span.textContent = '…';
p1PagerEl.appendChild(span);
} else {
var isActive = item === currentPage1;
var btn = makeBtn(String(item), 'pg-btn' + (isActive ? ' is-active' : ''));
btn.dataset.page = item; // data-page 属性でクロージャ問題を回避
btn.addEventListener('click', function() {
currentPage1 = parseInt(this.dataset.page, 10);
renderP1();
});
p1PagerEl.appendChild(btn);
}
});
var nextBtn = makeBtn('次へ', 'pg-btn');
nextBtn.disabled = (currentPage1 === totalPages);
nextBtn.addEventListener('click', function() { currentPage1++; renderP1(); });
p1PagerEl.appendChild(nextBtn);
}
// ============================================================
// Pattern 2 — ドロップダウン型
// ============================================================
// select の選択肢を生成(fetch 後に1回だけ呼ぶ)
function buildP2Select(totalPages) {
p2SelectEl.textContent = '';
for (var i = 1; i <= totalPages; i++) {
var opt = document.createElement('option');
opt.value = i;
opt.textContent = i + ' / ' + totalPages;
p2SelectEl.appendChild(opt);
}
}
p2SelectEl.addEventListener('change', function() {
currentPage2 = parseInt(this.value, 10);
renderP2();
});
p2PrevBtn.addEventListener('click', function() { currentPage2--; renderP2(); });
p2NextBtn.addEventListener('click', function() { currentPage2++; renderP2(); });
function renderP2() {
var totalPages = Math.ceil(allItems.length / PAGE_SIZE);
renderList(p2ListEl, currentPage2);
p2CountEl.textContent = allItems.length + '件 / ' + totalPages + 'ページ';
p2SelectEl.value = currentPage2; // select を現在ページに合わせる
p2PrevBtn.disabled = (currentPage2 === 1);
p2NextBtn.disabled = (currentPage2 === totalPages);
}
// ============================================================
// Pattern 3 — テキスト入力型
// ============================================================
// Enter キーでジャンプ
p3InputEl.addEventListener('keydown', function(e) {
if (e.key === 'Enter') { jumpP3(); }
});
// フォーカスアウトでもジャンプ(誤入力を自動補正)
p3InputEl.addEventListener('blur', jumpP3);
p3PrevBtn.addEventListener('click', function() { currentPage3--; renderP3(); });
p3NextBtn.addEventListener('click', function() { currentPage3++; renderP3(); });
function jumpP3() {
var totalPages = Math.ceil(allItems.length / PAGE_SIZE);
var n = parseInt(p3InputEl.value, 10);
// NaN・空欄は現在ページを維持。範囲外は 1〜totalPages にクランプ
if (isNaN(n)) { n = currentPage3; }
currentPage3 = Math.min(Math.max(1, n), totalPages);
renderP3();
}
function renderP3() {
var totalPages = Math.ceil(allItems.length / PAGE_SIZE);
renderList(p3ListEl, currentPage3);
p3CountEl.textContent = allItems.length + '件 / ' + totalPages + 'ページ';
p3InputEl.value = currentPage3; // input を現在ページに合わせる
p3PrevBtn.disabled = (currentPage3 === 1);
p3NextBtn.disabled = (currentPage3 === totalPages);
}
// ============================================================
// 共通:リスト描画
// ============================================================
function renderList(listEl, currentPage) {
var start = (currentPage - 1) * PAGE_SIZE;
var pageItems = allItems.slice(start, start + PAGE_SIZE);
listEl.textContent = ''; // 前回のアイテムを一括クリア
pageItems.forEach(function(item) {
var li = document.createElement('li');
var idEl = document.createElement('span');
var nmEl = document.createElement('span');
idEl.className = 'pg-id';
nmEl.className = 'pg-name';
idEl.textContent = '#' + item.id;
nmEl.textContent = item.name;
li.appendChild(idEl);
li.appendChild(nmEl);
listEl.appendChild(li);
});
}
// button 要素を生成するヘルパー
function makeBtn(text, className) {
var btn = document.createElement('button');
btn.textContent = text;
btn.className = className;
return btn;
}
[
{"id": 1, "name": "りんご"},
{"id": 2, "name": "バナナ"},
{"id": 3, "name": "みかん"},
{"id": 4, "name": "ぶどう"},
{"id": 5, "name": "いちご"},
{"id": 6, "name": "メロン"},
{"id": 7, "name": "すいか"},
{"id": 8, "name": "もも"},
{"id": 9, "name": "なし"},
{"id": 10, "name": "かき"},
{"id": 11, "name": "キウイ"},
{"id": 12, "name": "マンゴー"},
{"id": 13, "name": "パイナップル"},
{"id": 14, "name": "ライチ"},
{"id": 15, "name": "スターフルーツ"},
{"id": 16, "name": "にんじん"},
{"id": 17, "name": "たまねぎ"},
{"id": 18, "name": "じゃがいも"},
{"id": 19, "name": "キャベツ"},
{"id": 20, "name": "ほうれんそう"},
{"id": 21, "name": "ブロッコリー"},
{"id": 22, "name": "トマト"},
{"id": 23, "name": "なす"},
{"id": 24, "name": "ピーマン"},
{"id": 25, "name": "きゅうり"},
{"id": 26, "name": "レタス"},
{"id": 27, "name": "セロリ"},
{"id": 28, "name": "ごぼう"},
{"id": 29, "name": "だいこん"},
{"id": 30, "name": "かぼちゃ"},
{"id": 31, "name": "とうもろこし"},
{"id": 32, "name": "えだまめ"},
{"id": 33, "name": "アスパラガス"},
{"id": 34, "name": "さつまいも"},
{"id": 35, "name": "パプリカ"},
{"id": 36, "name": "しいたけ"},
{"id": 37, "name": "えのき"},
{"id": 38, "name": "まいたけ"},
{"id": 39, "name": "なめこ"},
{"id": 40, "name": "エリンギ"},
{"id": 41, "name": "くり"},
{"id": 42, "name": "くるみ"},
{"id": 43, "name": "アーモンド"},
{"id": 44, "name": "ピスタチオ"},
{"id": 45, "name": "カシューナッツ"},
{"id": 46, "name": "ピーナッツ"},
{"id": 47, "name": "マカダミアナッツ"},
{"id": 48, "name": "ヘーゼルナッツ"},
{"id": 49, "name": "かぼちゃの種"},
{"id": 50, "name": "ひまわりの種"},
{"id": 51, "name": "大豆"},
{"id": 52, "name": "小豆"},
{"id": 53, "name": "ひよこ豆"},
{"id": 54, "name": "レンズ豆"},
{"id": 55, "name": "玄米"},
{"id": 56, "name": "もち米"},
{"id": 57, "name": "そば"},
{"id": 58, "name": "小麦"},
{"id": 59, "name": "オーツ麦"},
{"id": 60, "name": "ライ麦"}
]
AI用プロンプト
各パターンのプロンプトをコピーしてAIに渡すと、同様のコンポーネントを生成できます。
ChatGPTやClaudeにこのプロンプトを渡すと、同様のコンポーネントをゼロから生成・カスタマイズできます。要件を追記して使うのがおすすめです。
※ このプロンプトを使ってもデモとまったく同じ動作にならない場合があります。AIの解釈や生成タイミングによって差が出ることをご了承ください。
💡 jQuery・Vue・React など特定のライブラリで実装したい場合は、プロンプトの末尾に「〇〇を使って実装してください」と追記してください。
Pattern 1 — 省略(...)型
# ページネーション(省略・...型)作成依頼
## 概要
JSONから取得したデータを4件ずつページ表示するシンプルなリストを実装してください。
ページネーションは省略(...)型で、ページ数が多い場合に全ボタンを並べず先頭・末尾・現在ページ周辺のみ表示します。
## 要件
- fetch() でJSONファイル(配列: id / name)を取得する
- 4件/ページで表示。ページ数はデータ件数から Math.ceil(件数 / 4) で動的計算する
- ページネーションは「前へ」「ページ番号ボタン(省略付き)」「次へ」構成
- 常に先頭ページ・最終ページ・現在ページ±1 のボタンを表示し、間にギャップがあれば「...」を挿入する
- 「...」はクリック不可のセパレーターとして表示する(ボタンではなく span で実装)
- 「前へ」は1ページ目、「次へ」は最終ページで disabled にする
- 件数と総ページ数をリアルタイム表示する
## 技術仕様
- HTML / CSS / バニラJavaScript で実装
- 外部ライブラリ:なし
- レスポンシブ対応:必要(ボタンが折り返しても崩れないこと)
## 動作詳細
表示ページセット = {1, current-1, current, current+1, total} から範囲外を除去し昇順ソート。
連続しない番号の間に '...' を挿入してボタン列を生成する。
ページ移動のたびにボタン列を再生成する。
DOM操作は createElement / textContent を使い、innerHTML に変数を渡さない。
## 出力形式
HTML・CSS・JavaScriptを分けて出力してください。
各ファイルは単独でコピー&ペーストして使えるよう記述してください。
Pattern 2 — ドロップダウン型
# ページネーション(ドロップダウン型)作成依頼
## 概要
JSONから取得したデータを4件ずつページ表示するシンプルなリストを実装してください。
ページネーションは「◀ [n / N ▼] ▶」のドロップダウン型で、selectボックスから任意のページへ直接ジャンプできます。
## 要件
- fetch() でJSONファイル(配列: id / name)を取得する
- 4件/ページで表示。ページ数はデータ件数から Math.ceil(件数 / 4) で動的計算する
- ページネーションは「◀」ボタン+ select +「▶」ボタンの3要素構成
- select の option は「1 / 15」「2 / 15」…のように全ページぶん動的生成する
- select の値変更で即そのページに移動し、移動後に select.value を現在ページで更新する
- 「◀」は1ページ目、「▶」は最終ページで disabled にする
- 件数と総ページ数をリアルタイム表示する
## 技術仕様
- HTML / CSS / バニラJavaScript で実装
- 外部ライブラリ:なし
- レスポンシブ対応:必要
## 動作詳細
fetch 後に select の option を totalPages 個ぶん生成する。
前後ボタンと select 変更はどちらも同一の goToPage(n) 関数を呼び出す。
DOM操作は createElement / textContent を使い、innerHTML に変数を渡さない。
## 出力形式
HTML・CSS・JavaScriptを分けて出力してください。
各ファイルは単独でコピー&ペーストして使えるよう記述してください。
Pattern 3 — テキスト入力型
# ページネーション(テキスト入力型)作成依頼
## 概要
JSONから取得したデータを4件ずつページ表示するシンプルなリストを実装してください。
ページネーションは「◀ [入力欄] / N ▶」のテキスト入力型で、ページ番号を直接入力してジャンプできます。
## 要件
- fetch() でJSONファイル(配列: id / name)を取得する
- 4件/ページで表示。ページ数はデータ件数から Math.ceil(件数 / 4) で動的計算する
- ページネーションは「◀」ボタン+ number input +「/ N」テキスト+「▶」ボタン構成
- input に数値を入力し Enter キーまたはフォーカスアウト(blur)でそのページに移動する
- 入力値は Math.min(Math.max(1, n), totalPages) でクランプし範囲外・NaN は現在ページに戻す
- ページ移動のたびに input.value を現在ページに更新する
- 「◀」は1ページ目、「▶」は最終ページで disabled にする
- 件数と総ページ数をリアルタイム表示する
## 技術仕様
- HTML / CSS / バニラJavaScript で実装
- 外部ライブラリ:なし
- レスポンシブ対応:必要
## 動作詳細
input[type="number"] のスピナーは CSS で非表示にする(-webkit-appearance: none; -moz-appearance: textfield;)。
keydown で Enter(key === 'Enter')と blur の両方でジャンプ処理を呼ぶ。
前後ボタン・input 移動はすべて goToPage(n) 関数を通す。
DOM操作は createElement / textContent を使い、innerHTML に変数を渡さない。
## 出力形式
HTML・CSS・JavaScriptを分けて出力してください。
各ファイルは単独でコピー&ペーストして使えるよう記述してください。