See the Pen 
  Vue3前端分頁  by 喇賽人 (@weber87na )
  on CodePen . 
功能分析 & 實作 分頁應該是個每隔一兩年就會跑出來的問題 , 懶一點就用套件 , 不然自幹還是要想一陣子
主要資料源 => 反正就某個地方的 json array閹割過的主要資料源 => 實際上看到 table or list 的應該是他每頁裡面顯示的資料筆數 => 通常就是 5 or 10總頁數 => ceil(主要資料源的數量 / 每頁裡面顯示的資料筆數)總頁碼的 array => 大概長這樣 [1 , 2 , 3 , 4 , 5 , 6 , 7 , 8]顯示的頁碼 array => 預期 5 頁的話大概長這樣 [1 , 2 , 3 , 4 , 5]目前選到的頁碼跳任意頁第一頁上一頁下一頁最後一頁
html & css 我這裡有套 bootstrap 5 , 大致上分為兩個部分 , table 裡面擺閹割過的主要資料源顯示資料 , nav 裡則是分頁的頁碼
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 <div  id ="app" >     <table  class ="table table-striped table-hover" >          <thead >              <tr >                  <th  scope ="col" > id</th >                  <th  scope ="col" > name</th >                  <th  scope ="col" > color</th >              </tr >          </thead >          <tbody >              <tr  v-for ="flower in displayFlowers" >                  <td > {{ flower.id }}</td >                  <td > {{ flower.name }}</td >                  <td > {{ flower.color }}</td >              </tr >          </tbody >      </table >      <nav  aria-label ="..." >          <ul  class ="pagination" >              <li  class ="page-item"                   @click ="gotoFirstPage()" >                 <a  class ="page-link"                       href ="javascript:;" > First</a >             </li >              <li  class ="page-item"                   @click ="gotoPrevPage()" >                 <a  class ="page-link"                       href ="javascript:;" > Previous</a >             </li >              <li  class ="page-item"                   :class ="{active:isActive(page)}"                  v-for ="page in displayPageArray"                  @click ="gotoPage(page)" >                 <a  class ="page-link"                       href ="javascript:;" >  {{ page }}</a >             </li >              <li  class ="page-item"                   @click ="gotoNextPage()" >                 <a  class ="page-link"                       href ="javascript:;" > Next</a >             </li >              <li  class ="page-item"                   @click ="gotoLastPage()" >                 <a  class ="page-link"                       href ="javascript:;" > Last</a >             </li >          </ul >      </nav >  </div > 
css 我只擺個居中沒啥好講的
1 2 3 4 5 6 body { 	display: flex; 	justify-content: center; 	align-items: center; } 
js 首先用 ref 定義一個 flowers 的主要資料源
1 2 3 4 5 6 7 let  flowers = ref([	{ id : 1 , name : '玫瑰' , color : 'red'  }, 	{ id : 2 , name : '太陽花' , color : 'yellow'  }, 	{ id : 3 , name : '向日葵' , color : 'yellow'  }, 	{ id : 4 , name : '薰衣草' , color : 'purple'  }, 	{ id : 5 , name : '鬱金香' , color : 'pink'  }, 	... 
接著算出總頁數
1 let  totalPageSize = Math .ceil(flowers.value.length / pageRows)
然後用 slice 函數 , 類似 linq 裡面的 skip + take 功能[1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10]slice(0 , 5) => [1 , 2 , 3 , 4 , 5]slice(5 , 10) => [6 , 7 , 8 , 9 , 10]
pageRows 表示 每頁裡面顯示的資料筆數currentPage 目前選到第幾頁 , 起始為 1slice 則由 0 開始計算
假設第一頁取 5 * 1 - 5 及 5 * 15 * 2 - 5 及 5 * 2
所以可以快速得出分頁結果
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 let  displayFlowers = computed(	() => { 		if  (flowers.value.length > 5 ) { 			return  normalSize(); 		} else  { 			return  flowers.value 		} 	} ) function  normalSize (	return  flowers.value.slice( 		pageRows * currentPage.value - pageRows, 		pageRows * currentPage.value 	) } 
接著定義出 目前選到的頁碼 跳任意頁 等函數 , 另外還有個 isActive 這個是拿來套用目前選到頁碼樣式的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 let currentPage = ref(1) function gotoPage(page) { 	currentPage.value = page } function gotoLastPage() { 	currentPage.value = totalPageSize } function gotoFirstPage() { 	currentPage.value = 1 } function gotoPrevPage() { 	if (currentPage.value > 1) 		currentPage.value = currentPage.value - 1 } function gotoNextPage() { 	if (currentPage.value < totalPageSize) 		currentPage.value = currentPage.value + 1 } function isActive(page) { 	return currentPage.value === page } 
接著就是最核心的地方 , 計算頁碼
如果分頁數量大於 5 的話 , 先看看目前選到的頁碼是否小於 3 , 是的話直接傳 [1, 2, 3, 4, 5][4 , 5 , 6 , 7 , 8]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 function  getPages (	let  result = [] 	for  (let  i = 1 ; i <= totalPageSize; i++) { 		result.push(i) 	} 	return  result } let  displayPageSize = 5 function  getDisplayPages (	let  pages = getPages() 	let  result = []; 	 	if  (pages.length <= 5 ) { 		return  pages 	} 	 	 	if  (currentPage.value < 3 ) { 		result = [1 , 2 , 3 , 4 , 5 ] 		return  result 	} 	 	if  (currentPage.value >= pages.length - 2 ) { 		result.push(pages.length - 4 ) 		result.push(pages.length - 3 ) 		result.push(pages.length - 2 ) 		result.push(pages.length - 1 ) 		result.push(pages.length) 		return  result 	} 	 	if  (currentPage.value >= 3 ) { 		result.push(currentPage.value - 2 ) 		result.push(currentPage.value - 1 ) 		result.push(currentPage.value) 		result.push(currentPage.value + 1 ) 		result.push(currentPage.value + 2 ) 		return  result; 	} } 
貓毛 bug 修復 不過做到這裡如果遇到很 貓毛 的人會認為是 bug 有一點點不完美 , 因為我的算法讓 active & focus 有可能是不一致的情形active 第 4 頁 , 但是會 focus 在第 5 頁mousedown mouseup click 這三個事件搭配mouseDown => mouseUp => mouseClick 不過在此 mouseUp 用不到
先宣告一個 ref=pageItems 特別注意因為是 loop 蓋出的 element 所以這裡會是一個 arraymouseDown 時先用 event.preventDefault() 消除 focus , 呼叫 gotoPage(page) 接著切換頁碼mouseClick 這時候取得 ref array 裡面的 active elementli 粗暴的用 querySelector('a') 直接得到 a 並且 focuslet activeEle = pageItems.value.find(x => x.classList.contains('active')) 插在 mouseClick 的話active 元素
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 const  pageItems = ref(null );function  mouseDown (page ) 	console .log('mouseDown' ) 	event.preventDefault() 	gotoPage(page) } function  mouseUp (event ) 	console .log('mouseUp' ) } const  pageItems = ref(null );function  mouseClick (event, page ) 	 	let  activeEle = pageItems.value.find(x  =>'active' )) 	 	 	let  tag = activeEle.querySelector('a' ) 	tag.focus() } function  gotoPage (page )	currentPage.value = page } 
html 調整如下
1 2 3 4 5 6 7 8 9 10 <li  class ="page-item"  	:class ="{active:isActive(page)}"  	@mousedown ="mouseDown(page)"  	@mouseup ="mouseUp($event)"  	@click ="mouseClick($event , page)"  	ref ="pageItems"  	v-for ="page in displayPageArray" > 	<a  class ="page-link"   		href ="javascript:;" >  {{ page }}</a > </li > 
drag & drop 順便玩玩 drag & drop 功能 , 因為寫過 N 次了所以也不難 XD這裡 就是用這種方法
html
1 2 3 4 5 6 7 8 9 10 <tr v-for="flower in displayFlowers" 	draggable="true" 	@dragstart="onDrag($event, flower)" 	@drop="onDrop($event, flower)" 	@dragover.prevent 	@dragenter.preven> 	<td>{{ flower.id }}</td> 	<td>{{ flower.name }}</td> 	<td>{{ flower.color }}</td> </tr> 
js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 function onDrag(event, flower) { 	event.dataTransfer.dropEffect = 'move' 	event.dataTransfer.effectAllowed = 'move' 	event.dataTransfer.setData('id', flower.id) } // 交換式 // function onDrop(event, flower) { //     let dragId = parseInt(event.dataTransfer.getData('id')) //     let dropId = flower.id //     let dragIndex = flowers.value.findIndex(x => x.id === dragId) //     let dropIndex = flowers.value.findIndex(x => x.id === dropId) //     let temp = flowers.value[dragIndex] //     flowers.value[dragIndex] = flowers.value[dropIndex] //     flowers.value[dropIndex] = temp // } //drag 之後的元素往前推 function onDrop(event, flower) { 	let dragId = parseInt(event.dataTransfer.getData('id')) 	let dropId = flower.id 	let dragFlower = flowers.value.find(x => x.id === dragId) 	let dragIndex = flowers.value.findIndex(x => x.id === dragId) 	let dropIndex = flowers.value.findIndex(x => x.id === dropId) 	flowers.value.splice(dragIndex, 1); 	flowers.value.splice(dropIndex, 0, dragFlower); }