React元件設計,仿米遊社首頁頻道設定頁面
theme: channing-cyan
持續創作,加速成長!這是我參與「掘金日新計劃 · 6 月更文挑戰」的第1天,點選檢視活動詳情
前言
作為一個剛接觸react 元件設計不久的新人,獨立完成一個元件的設計開發其中過程是十分卡手的,本篇詳盡的描述了米遊社首頁頻道選擇頁面元件開發的全過程,希望這個這個簡單元件的設計開發能對和我一樣接觸react元件開發不久的人有點幫助
準備階段
頁面分析
在正式開始仿頁面之前,先看下原頁面效果:
佈局十分常見,頭、身、尾,三部分,對應三個元件,點選推薦頻道元件中的新增符號,可以新增到我的頻道元件中,我的頻道中的列表資料可以長按進行拖拽排序,原頁面那個控制代碼符號好像就是提示用,沒有實際功能作用,整個列表長按都可以拖拽,當刪除到最後一個遊戲時會有一個小的模態框提示,原頁面資料發生改變右上角確定高亮,綜上我們需要完成:
- 監聽列表資料state 改變實現增加刪除
- 我的頻道列表長按拖拽排序
- 我的頻道列表只剩一個遊戲時,刪除彈出提示
- 資料發生改變,tab 中確定按鈕高亮顯示
根據需求我劃分元件檔案目錄如下:
SelectChannel
├─ Body
│ ├─ content
│ │ ├─ index.jsx
│ │ └─ style.js
│ ├─ index.jsx
│ └─ style.js
├─ Footer
│ ├─ content
│ │ ├─ index.jsx
│ │ └─ style.js
│ ├─ index.jsx
│ └─ style.js
├─ Header
│ ├─ index.jsx
│ └─ style.js
├─ index.jsx
└─ style.js
使用工具
vite: 腳手架,初始化react專案
dnd-kit: 拖拽排序功能就是靠他實現的,官方文件
styled-components: css in js,官方文件
classnames: 動態類名,官方文件
fastmock: 介面假資料
axios: 資料請求
開發階段
1. 初始化專案
- 終端npm init @vitejs/app 對專案進行初始化工作,根據提示輸入專案名,選react,順便開啟生成的vite配置檔案設定src目錄別名為@
- fastmock 準備好介面假資料,並在api 目錄中請求資料,元件中不做資料請求:資料
- iconfont 選擇需要的icon 相似即可,解壓放assets 目錄下
2. 移動端適配
-
移動端頁面開發當然少不了適配
- 在public 目錄下建立js 檔案adapter.js 內容如下: ```js var init = function () { var clientWidth = document.documentElement.clientWidth || document.body.clientWidth; if (clientWidth >= 640) { clientWidth = 640; } var fontSize = (20 / 375) * clientWidth; document.documentElement.style.fontSize = fontSize + 'px'; };
init();
window.addEventListener('resize', init);
- 在src 下建立目錄modules 建立rem.js如下:
js document.documentElement.style.fontSize = document.documentElement.clientWidth / 3.75 + 'px'; // 橫豎屏切換 window.onresize = function() { document.documentElement.style.fontSize = document.documentElement.clientWidth / 3.75 + 'px'; }- index.html中引用adapter.js ,main.jsx 中引用rem.js ## 3. 實現父元件 SelectChannel - 除了子元件獨有的部分,資料狀態改變和函式都在父元件裡進行,傳給子元件,完整檔案如下:
js export default function SelectChannel() {const [list, setList] = useState([ { id: 7, title: '大別野', img: 'http://bbs.mihoyo.com/_nuxt/img/game-dby.7b16fa8.jpg', checked: true, }, ]); const [loading,setLoading] = useState(false) const [change,setChange] = useState(false)
// 篩選出已選擇和未選擇項 const TrueCheck = list.filter(item => item.checked == true); const FalseCheck = list.filter(item => item.checked == false);
// 提示模態框 const modal=()=>{ return( loading &&
至少選擇一個遊戲哦~ ) } // 定時讓模態框消失 const setState = () =>{ setTimeout(()=>{ setLoading(false) },2000) }// 選擇 const choose = item => { // console.log('--------'); let idx = list.findIndex(data => item.id === data.id); // console.log(idx); list[idx].checked = !list[idx].checked; setList([...list]); setChange(true) };
// 刪除已選擇項 const deleteList = item => { let idx = list.findIndex(data => item.id === data.id); // 判斷已選擇項是否小於或等於兩個,若是,那麼不可刪除,彈出提示模態框,若大於兩個則執行刪除 if(TrueCheck.length <= 2){ setLoading(true); setState(); }else{ list[idx].checked = !list[idx].checked; setList([...list]); setChange(true) } };
// 拿取資料 useEffect(() => { (async () => { let { data } = await select(); // console.log(data); setList([...list, ...data]); })(); }, []);
// 拖拽後排序 const handleDragEnd = ({active, over}) => { if(active.id !== over.id){ setList((items) => { const oldIndex = items.findIndex(item => item.id === active.id) const newIndex = items.findIndex(item => item.id === over.id) return arrayMove(items, oldIndex, newIndex) }) } setChange(true) }
return ( <> {modal()}
最終目錄結構:
select-channel
├─ index.html
├─ package-lock.json
├─ package.json
├─ public
│ └─ js
│ └─ adapter.js
├─ src
│ ├─ api
│ │ └─ request.js
│ ├─ App.css
│ ├─ App.jsx
│ ├─ assets
│ │ ├─ font
│ │ └─ styles
│ │ └─ reset.css
│ ├─ components
│ │ └─ SelectChannel
│ │ ├─ Body
│ │ │ ├─ content
│ │ │ │ ├─ index.jsx
│ │ │ │ └─ style.js
│ │ │ ├─ index.jsx
│ │ │ └─ style.js
│ │ ├─ Footer
│ │ │ ├─ content
│ │ │ │ ├─ index.jsx
│ │ │ │ └─ style.js
│ │ │ ├─ index.jsx
│ │ │ └─ style.js
│ │ ├─ Header
│ │ │ ├─ index.jsx
│ │ │ └─ style.js
│ │ ├─ index.jsx
│ │ └─ style.js
│ ├─ index.css
│ ├─ main.jsx
│ └─ modules
│ └─ rem.js
└─ vite.config.js
最後
這就是這次元件實現的全過程,後續會繼續完善,程式碼在仿米遊社首頁頻道設定頁面
github page 直接檢視效果:實時演示