コンポーネント化は、すべてのフロントエンドエンジニアにとって不可欠なスキルであり、それは要素、iview、vantと巧みに使用される他のUIコンポーネントライブラリは、実際の開発や多くの場合、より適切なビジネスコンポーネントをカプセル化する必要があるだけでなく、迅速な開発を支援するだけでなく、コードを簡潔にするだけでなく、コンポーネント化の能力を行使することは事実です。
アイデアの整理
node.jsの公式サイトにあるページングコンポーネントを例にして、以下のようなページングを実装したいとします:
製品視点でアイデアを整理した結果、実装するページングコンポーネントは以下のような機能を備えています:
1.現在のページの色の変更
2.ページ番号は5つまで、5つ未満は実際のページ数を表示
3.5ページ以上の総ページ数:総ページ数-現在のページ> 2、その後省略記号の表示の終わり;現在のページ> 2、その後省略記号の表示の始まり
4.総ページ数が5を超える場合:現在のページが最終ページの場合、合計3つのページ番号が表示され、現在のページが末尾ページの場合、合計4つのページ番号が表示され、残りの5つのページ番号が表示されます。
5.総ページ数が5ページ以上で、総ページ数-カレントページ>2、カレントページ>2を同時に満たす場合、カレントページは常に5つのページ番号の真ん中に表示されます。
6.左端と右端の矢印をクリックすると、それぞれ最初のページと最後のページにジャンプします。
基本構造
まず静的な構造を書きます:
<template>
<div class="page">
<span class="page-block center">{{'«'}}</span>
<span v-if="pageList[2]-2>1"
class="page-block center">...</span>
<span v-for="pageNum in pageList"
:key="pageNum"
class="page-block center"
:style="{color:pageNum===page?'#80bd01':'#778087'}">{{pageNum}}</span>
<span v-if="pageMax-pageList[2]>2"
class="page-block center">...</span>
<span class="page-block center">{{'»'}}</span>
</div>
</template>
<script>
export default {
data () {
return {
pageList: [1,2,3,4,5], // ページ番号のリスト
page: 1, // 現在のページ番号
pageMax: 7 // 最大ページ番号
};
}
};
</script>
<style rel="stylesheet/scss" lang="scss" scoped>
.page {
padding: 10px;
background-color: #fff;
&-block {
display: inline-block;
width: 30px;
height: 28px;
padding: 4px 8px;
font-size: 0.8em;
line-height: 18px;
border: 1px solid #ddd;
border-right: none;
box-sizing: border-box;
&:first-child {
width: 34px;
border-top-left-radius: 4px;
border-bottom-left-radius: 4px;
}
&:last-child {
width: 34px;
border-right: 1px solid #ddd;
border-top-right-radius: 4px;
border-bottom-right-radius: 4px;
}
}
}
</style>
親コンポーネントのコンポーネントを参照します:
<template>
<pagination></pagination>
</template>
<script>
import Pagination from "@/components/pagination";
export default {
components: { Pagination }
}
</script>
この時点での効果:5ページ以上の標準的な静的ページネーションが表示されます:
props
コンポーネントのいくつかの値は、親コンポーネントから渡され、次のように計算されてマウントされる必要があります。
props: {
// コンテンツ合計
total: {
type: Number,
default: 0
},
// ページ数
limit: {
type: Number,
default: 10
},
// 現在のページ番号
page: {
type: Number,
default: 1
},
},
data () {
return {
pageList: [] // ページ番号のリスト
};
},
computed: {
// 最大ページ番号
pageMax () {
return Math.ceil(this.total / this.limit);
},
},
onLoad () { // フレームワークはmpvueで、vueで作成された
this.initData();
},
methods: {
// ページリストを生成する
initData () {
this.pageList = []; // ページ番号をクリアする
var i = 1;
do {
this.pageList.push(i);
i++;
} while (i <= this.pageMax);
this.pageList.length > 5 && (this.pageList = this.pageList.slice(0, 5)); // 5ページまで表示する
}
}
親コンポーネントはこれらの値を渡します:
<pagination :total="dataList.length"
:limit="limit"
:page="page"></pagination>
data () {
return {
dataList: [], //
page: 1, // 現在のページ番号
limit: 20, // ページ数
};
},
onLoad () {
this.getData();
},
methods: {
getData () {
// 動的なリスト取得 - バックエンドのページングの例
this.dataList = (await getDataList(this.limit, this.page)).data;
}
}
この時点での効果:ページングコンポーネントは、親コンポーネントの実データ、つまりコンポーネントを使用しているページに従ってレンダリングされます。ページ数が5を超える場合と超えない場合コンポーネントの内容が異なり、最初のページの現在のページ番号
eventイベントコールバック
イベントはコンポーネントに追加され、親コンポーネントにコールバックされます:
<template>
<div class="page">
<span class="page-block center"
@click="pageChange(1)">{{'«'}}</span>
<span v-if="pageList[2]-2>1"
class="page-block center">...</span>
<span v-for="pageNum in pageList"
:key="pageNum"
class="page-block center"
:style="{color:pageNum===page?'#80bd01':'#778087'}"
@click="pageChange(pageNum)">{{pageNum}}</span>
<span v-if="pageMax-pageList[2]>2"
class="page-block center">...</span>
<span class="page-block center"
@click="pageChange(pageMax)">{{'»'}}</span>
</div>
</template>
methods: {
// サブコンポーネントイベントのコールバック: pagination
pageChange (page) {
this.$emit("page-change", page);
},
}
親コンポーネントは子コンポーネントからコールバックされたイベントを実行します:
<pagination :total="dataList.length"
:limit="limit"
:page="page"
@page-change="pageChange"></pagination>
methods: {
//
pageChange (page) {
this.page = page;
this.getData();
},
}
この時点で効果:ページの色が変更されますクリックして、親コンポーネントは、サブコンポーネントのコールバックイベントを受信し、値のページを返す - つまり、現在のページ番号は、サブページのレンダリングの内容のページ番号に応じて行うことができます。
watchページ変更
異なるページ番号は、異なるコンポーネントの内容をレンダリングするので、ページ番号の変更に耳を傾ける必要があり、コンポーネントの内容を更新し、同時に更新の合計数は、コンポーネントをリロードします。
watch: {
// ページ番号の変更をリスンする> ページ番号リストの更新
page (val) {
if (val <= 3) {
this.pageList = [];
var i = 1;
do {
this.pageList.push(i);
i++;
} while (i <= this.pageMax);
this.pageList.length > 5 && (this.pageList = this.pageList.slice(0, 5)); // 5ページまで表示する
} else if (val === this.pageMax) {
this.pageList = [val - 2, val - 1, val];
} else if (val === this.pageMax - 1) {
this.pageList = [val - 2, val - 1, val, val + 1];
} else {
this.pageList = [val - 2, val - 1, val, val + 1, val + 2];
}
},
// ページ番号の変更をリスンする> 更新された合計
total (val) {
this.initData();
}
}
この時の効果:ページングコンポーネントのすべてのコンテンツが完了するように、ページ番号の変更と変更の数に応じてコンポーネントは、異なるコンテンツをレンダリングします。
拡張機能
elementやiviewのように、現在のページ表示量のドロップダウンボックスをコンポーネントに追加することもできますし、親コンポーネントに子コンポーネントのスタイルレイアウトやページ数ボタンの数を決定させることもできます。一般的な考え方は変わりません:
1. 子コンポーネントは値を受け取り、その値に応じてレンダリングを変更します。
2.子コンポーネントはイベントを追加し、親コンポーネントにコールバックされます。
3.必要に応じてリスナーを追加します。
フルコード
<template>
<div class="page">
<span class="page-block center"
@click="pageChange(1)">{{'«'}}</span>
<span v-if="pageList[2]-2>1"
class="page-block center">...</span>
<span v-for="pageNum in pageList"
:key="pageNum"
class="page-block center"
:style="{color:pageNum===page?'#80bd01':'#778087'}"
@click="pageChange(pageNum)">{{pageNum}}</span>
<span v-if="pageMax-pageList[2]>2"
class="page-block center">...</span>
<span class="page-block center"
@click="pageChange(pageMax)">{{'»'}}</span>
</div>
</template>
<script>
export default {
props: {
// コンテンツ合計
total: {
type: Number,
default: 0
},
// ページ数
limit: {
type: Number,
default: 10
},
// 現在のページ番号
page: {
type: Number,
default: 1
},
},
data () {
return {
pageList: [] // ページ番号のリスト
};
},
computed: {
// 最大ページ番号
pageMax () {
return Math.ceil(this.total / this.limit);
},
},
onLoad () {
this.initData();
},
methods: {
initData () {
this.pageList = []; // ページ番号をクリアする
var i = 1;
do {
this.pageList.push(i);
i++;
} while (i <= this.pageMax);
this.pageList.length > 5 && // 5ページまで表示する
(this.pageList = this.pageList.slice(0, 5));
},
// サブコンポーネントイベントのコールバック: pagination
pageChange (pageCurrent) {
this.$emit("page-change", pageCurrent);
},
},
watch: {
// ページ番号の変更をリスンする> ページ番号リストの更新
page (val) {
if (val <= 3) {
this.pageList = [];
var i = 1;
do {
this.pageList.push(i);
i++;
} while (i <= this.pageMax);
this.pageList.length > 5 && // 5ページまで表示する
(this.pageList = this.pageList.slice(0, 5));
} else if (val === this.pageMax) {
this.pageList = [val - 2, val - 1, val];
} else if (val === this.pageMax - 1) {
this.pageList = [val - 2, val - 1, val, val + 1];
} else {
this.pageList = [val - 2, val - 1, val, val + 1, val + 2];
}
},
// ページ番号の変更をリスンする> 更新された合計
total (val) {
this.initData();
}
}
};
</script>
<style rel="stylesheet/scss" lang="scss" scoped>
.page {
padding: 10px;
background-color: #fff;
&-block {
display: inline-block;
width: 30px;
height: 28px;
padding: 4px 8px;
font-size: 0.8em;
line-height: 18px;
border: 1px solid #ddd;
border-right: none;
box-sizing: border-box;
&:first-child {
width: 34px;
border-top-left-radius: 4px;
border-bottom-left-radius: 4px;
}
&:last-child {
width: 34px;
border-right: 1px solid #ddd;
border-top-right-radius: 4px;
border-bottom-right-radius: 4px;
}
}
}
</style>
api
props:
| page-change | コンテンツ総数 | 番号 | 0 |
| 限界 | ページ数 | 番号 | 10 |
| ページ | 現在のページ番号 | 番号 | 1 |
events:
| ページ変更 | ページ番号変更のコールバック。 | 現在のページ番号 |





