update todolistdemo
This commit is contained in:
parent
01f0316675
commit
8268a8f242
@ -10,4 +10,11 @@ cd my-project
|
|||||||
npm install
|
npm install
|
||||||
npm run dev
|
npm run dev
|
||||||
```
|
```
|
||||||
![image](assets/startReact.png)
|
![image](assets/startReact.png)
|
||||||
|
|
||||||
|
#執行demo專案
|
||||||
|
開vscode到該專案資料夾(例如todolist_demo)
|
||||||
|
開啟終端機
|
||||||
|
```
|
||||||
|
npm run dev
|
||||||
|
```
|
24
進階_React框架/demo/todolist_demo/.gitignore
vendored
Normal file
24
進階_React框架/demo/todolist_demo/.gitignore
vendored
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
# Logs
|
||||||
|
logs
|
||||||
|
*.log
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
pnpm-debug.log*
|
||||||
|
lerna-debug.log*
|
||||||
|
|
||||||
|
node_modules
|
||||||
|
dist
|
||||||
|
dist-ssr
|
||||||
|
*.local
|
||||||
|
|
||||||
|
# Editor directories and files
|
||||||
|
.vscode/*
|
||||||
|
!.vscode/extensions.json
|
||||||
|
.idea
|
||||||
|
.DS_Store
|
||||||
|
*.suo
|
||||||
|
*.ntvs*
|
||||||
|
*.njsproj
|
||||||
|
*.sln
|
||||||
|
*.sw?
|
50
進階_React框架/demo/todolist_demo/README.md
Normal file
50
進階_React框架/demo/todolist_demo/README.md
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
# React + TypeScript + Vite
|
||||||
|
|
||||||
|
This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.
|
||||||
|
|
||||||
|
Currently, two official plugins are available:
|
||||||
|
|
||||||
|
- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md) uses [Babel](https://babeljs.io/) for Fast Refresh
|
||||||
|
- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh
|
||||||
|
|
||||||
|
## Expanding the ESLint configuration
|
||||||
|
|
||||||
|
If you are developing a production application, we recommend updating the configuration to enable type aware lint rules:
|
||||||
|
|
||||||
|
- Configure the top-level `parserOptions` property like this:
|
||||||
|
|
||||||
|
```js
|
||||||
|
export default tseslint.config({
|
||||||
|
languageOptions: {
|
||||||
|
// other options...
|
||||||
|
parserOptions: {
|
||||||
|
project: ['./tsconfig.node.json', './tsconfig.app.json'],
|
||||||
|
tsconfigRootDir: import.meta.dirname,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
- Replace `tseslint.configs.recommended` to `tseslint.configs.recommendedTypeChecked` or `tseslint.configs.strictTypeChecked`
|
||||||
|
- Optionally add `...tseslint.configs.stylisticTypeChecked`
|
||||||
|
- Install [eslint-plugin-react](https://github.com/jsx-eslint/eslint-plugin-react) and update the config:
|
||||||
|
|
||||||
|
```js
|
||||||
|
// eslint.config.js
|
||||||
|
import react from 'eslint-plugin-react'
|
||||||
|
|
||||||
|
export default tseslint.config({
|
||||||
|
// Set the react version
|
||||||
|
settings: { react: { version: '18.3' } },
|
||||||
|
plugins: {
|
||||||
|
// Add the react plugin
|
||||||
|
react,
|
||||||
|
},
|
||||||
|
rules: {
|
||||||
|
// other rules...
|
||||||
|
// Enable its recommended rules
|
||||||
|
...react.configs.recommended.rules,
|
||||||
|
...react.configs['jsx-runtime'].rules,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
```
|
28
進階_React框架/demo/todolist_demo/eslint.config.js
Normal file
28
進階_React框架/demo/todolist_demo/eslint.config.js
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
import js from '@eslint/js'
|
||||||
|
import globals from 'globals'
|
||||||
|
import reactHooks from 'eslint-plugin-react-hooks'
|
||||||
|
import reactRefresh from 'eslint-plugin-react-refresh'
|
||||||
|
import tseslint from 'typescript-eslint'
|
||||||
|
|
||||||
|
export default tseslint.config(
|
||||||
|
{ ignores: ['dist'] },
|
||||||
|
{
|
||||||
|
extends: [js.configs.recommended, ...tseslint.configs.recommended],
|
||||||
|
files: ['**/*.{ts,tsx}'],
|
||||||
|
languageOptions: {
|
||||||
|
ecmaVersion: 2020,
|
||||||
|
globals: globals.browser,
|
||||||
|
},
|
||||||
|
plugins: {
|
||||||
|
'react-hooks': reactHooks,
|
||||||
|
'react-refresh': reactRefresh,
|
||||||
|
},
|
||||||
|
rules: {
|
||||||
|
...reactHooks.configs.recommended.rules,
|
||||||
|
'react-refresh/only-export-components': [
|
||||||
|
'warn',
|
||||||
|
{ allowConstantExport: true },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)
|
13
進階_React框架/demo/todolist_demo/index.html
Normal file
13
進階_React框架/demo/todolist_demo/index.html
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<title>Vite + React + TS</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="root"></div>
|
||||||
|
<script type="module" src="/src/main.tsx"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
3226
進階_React框架/demo/todolist_demo/package-lock.json
generated
Normal file
3226
進階_React框架/demo/todolist_demo/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
29
進階_React框架/demo/todolist_demo/package.json
Normal file
29
進階_React框架/demo/todolist_demo/package.json
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
{
|
||||||
|
"name": "my-react-app",
|
||||||
|
"private": true,
|
||||||
|
"version": "0.0.0",
|
||||||
|
"type": "module",
|
||||||
|
"scripts": {
|
||||||
|
"dev": "vite",
|
||||||
|
"build": "tsc -b && vite build",
|
||||||
|
"lint": "eslint .",
|
||||||
|
"preview": "vite preview"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"react": "^19.0.0",
|
||||||
|
"react-dom": "^19.0.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@eslint/js": "^9.19.0",
|
||||||
|
"@types/react": "^19.0.8",
|
||||||
|
"@types/react-dom": "^19.0.3",
|
||||||
|
"@vitejs/plugin-react": "^4.3.4",
|
||||||
|
"eslint": "^9.19.0",
|
||||||
|
"eslint-plugin-react-hooks": "^5.0.0",
|
||||||
|
"eslint-plugin-react-refresh": "^0.4.18",
|
||||||
|
"globals": "^15.14.0",
|
||||||
|
"typescript": "~5.7.2",
|
||||||
|
"typescript-eslint": "^8.22.0",
|
||||||
|
"vite": "^6.1.0"
|
||||||
|
}
|
||||||
|
}
|
1
進階_React框架/demo/todolist_demo/public/vite.svg
Normal file
1
進階_React框架/demo/todolist_demo/public/vite.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>
|
After Width: | Height: | Size: 1.5 KiB |
111
進階_React框架/demo/todolist_demo/src/App.tsx
Normal file
111
進階_React框架/demo/todolist_demo/src/App.tsx
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
import { useState } from "react";
|
||||||
|
|
||||||
|
function App() {
|
||||||
|
const [_input, setInput] = useState<string>("");
|
||||||
|
const [_task, setTask] = useState<string[]>([]);
|
||||||
|
const [_editTask , setEditTask] = useState<string>();
|
||||||
|
const [_editIndex , setEditIndex] = useState<number>();
|
||||||
|
|
||||||
|
// ✅ 新增任務
|
||||||
|
const addfun = () => {
|
||||||
|
if (_input.trim() === "") return; // 避免空輸入
|
||||||
|
setTask([..._task, _input]); // 新增到陣列
|
||||||
|
setInput(""); // 清空輸入框
|
||||||
|
};
|
||||||
|
|
||||||
|
// ✅ 刪除指定任務(透過 index)
|
||||||
|
const deletefun = (index: number) => {
|
||||||
|
setTask(_task.filter((_, i) => i !== index)); // 只保留不是該 index 的項目
|
||||||
|
};
|
||||||
|
|
||||||
|
const editfun = (index:number) =>{
|
||||||
|
setEditTask(_task[index])
|
||||||
|
setEditIndex(index)
|
||||||
|
}
|
||||||
|
|
||||||
|
const savefun = (index:number) =>{
|
||||||
|
if (_editIndex === undefined || _editTask === undefined) return;
|
||||||
|
const updatedTask = [..._task]
|
||||||
|
updatedTask[_editIndex] = _editTask
|
||||||
|
setTask(updatedTask);
|
||||||
|
setEditTask(undefined)
|
||||||
|
setEditIndex(undefined)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<h2>代辦事項</h2>
|
||||||
|
<input
|
||||||
|
value={_input}
|
||||||
|
onChange={(e) => setInput(e.target.value)}
|
||||||
|
placeholder="輸入代辦事項..."
|
||||||
|
/>
|
||||||
|
<button onClick={addfun}>加入</button>
|
||||||
|
<TableComponent
|
||||||
|
_task={_task}
|
||||||
|
_editIndex={_editIndex}
|
||||||
|
_editTask={_editTask}
|
||||||
|
deletefun={deletefun}
|
||||||
|
editfun={editfun}
|
||||||
|
setEditTask={setEditTask}
|
||||||
|
savefun = {savefun}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function TableComponent(
|
||||||
|
{
|
||||||
|
_task,
|
||||||
|
_editIndex,
|
||||||
|
_editTask,
|
||||||
|
deletefun,
|
||||||
|
editfun,
|
||||||
|
savefun,
|
||||||
|
setEditTask
|
||||||
|
}:{
|
||||||
|
_task: string[];
|
||||||
|
_editIndex : number | undefined;
|
||||||
|
_editTask :string | undefined;
|
||||||
|
deletefun: (index: number) => void;
|
||||||
|
editfun:(index:number) => void;
|
||||||
|
setEditTask:(value:string) => void;
|
||||||
|
savefun:(index:number) =>void ;
|
||||||
|
}) {
|
||||||
|
return (
|
||||||
|
<table >
|
||||||
|
<tbody>
|
||||||
|
{_task.map((aa, index) => (
|
||||||
|
<tr key={index}>
|
||||||
|
<td>
|
||||||
|
{_editIndex == index?(
|
||||||
|
<>
|
||||||
|
<input value={_editTask} onChange={(e)=>setEditTask(e.target.value)}/>
|
||||||
|
<button onClick={() =>savefun(_editIndex)}>儲存</button>
|
||||||
|
</>
|
||||||
|
):(
|
||||||
|
aa
|
||||||
|
)}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{_editIndex !== index?(
|
||||||
|
<button onClick={() => editfun(index)}>編輯</button> ):null}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{_editIndex != index?(
|
||||||
|
<>
|
||||||
|
<button onClick={() => deletefun(index)}>刪除</button> {/* ✅ 點擊刪除該行 */}
|
||||||
|
</>):(null)}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
))}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default App;
|
9
進階_React框架/demo/todolist_demo/src/main.tsx
Normal file
9
進階_React框架/demo/todolist_demo/src/main.tsx
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
import { StrictMode } from 'react'
|
||||||
|
import { createRoot } from 'react-dom/client'
|
||||||
|
import App from './App.tsx'
|
||||||
|
|
||||||
|
createRoot(document.getElementById('root')!).render(
|
||||||
|
<StrictMode>
|
||||||
|
<App />
|
||||||
|
</StrictMode>,
|
||||||
|
)
|
1
進階_React框架/demo/todolist_demo/src/vite-env.d.ts
vendored
Normal file
1
進階_React框架/demo/todolist_demo/src/vite-env.d.ts
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
/// <reference types="vite/client" />
|
26
進階_React框架/demo/todolist_demo/tsconfig.app.json
Normal file
26
進階_React框架/demo/todolist_demo/tsconfig.app.json
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
|
||||||
|
"target": "ES2020",
|
||||||
|
"useDefineForClassFields": true,
|
||||||
|
"lib": ["ES2020", "DOM", "DOM.Iterable"],
|
||||||
|
"module": "ESNext",
|
||||||
|
"skipLibCheck": true,
|
||||||
|
|
||||||
|
/* Bundler mode */
|
||||||
|
"moduleResolution": "bundler",
|
||||||
|
"allowImportingTsExtensions": true,
|
||||||
|
"isolatedModules": true,
|
||||||
|
"moduleDetection": "force",
|
||||||
|
"noEmit": true,
|
||||||
|
"jsx": "react-jsx",
|
||||||
|
|
||||||
|
/* Linting */
|
||||||
|
"strict": true,
|
||||||
|
"noUnusedLocals": true,
|
||||||
|
"noUnusedParameters": true,
|
||||||
|
"noFallthroughCasesInSwitch": true,
|
||||||
|
"noUncheckedSideEffectImports": true
|
||||||
|
},
|
||||||
|
"include": ["src"]
|
||||||
|
}
|
7
進階_React框架/demo/todolist_demo/tsconfig.json
Normal file
7
進階_React框架/demo/todolist_demo/tsconfig.json
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"files": [],
|
||||||
|
"references": [
|
||||||
|
{ "path": "./tsconfig.app.json" },
|
||||||
|
{ "path": "./tsconfig.node.json" }
|
||||||
|
]
|
||||||
|
}
|
24
進階_React框架/demo/todolist_demo/tsconfig.node.json
Normal file
24
進階_React框架/demo/todolist_demo/tsconfig.node.json
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
|
||||||
|
"target": "ES2022",
|
||||||
|
"lib": ["ES2023"],
|
||||||
|
"module": "ESNext",
|
||||||
|
"skipLibCheck": true,
|
||||||
|
|
||||||
|
/* Bundler mode */
|
||||||
|
"moduleResolution": "bundler",
|
||||||
|
"allowImportingTsExtensions": true,
|
||||||
|
"isolatedModules": true,
|
||||||
|
"moduleDetection": "force",
|
||||||
|
"noEmit": true,
|
||||||
|
|
||||||
|
/* Linting */
|
||||||
|
"strict": true,
|
||||||
|
"noUnusedLocals": true,
|
||||||
|
"noUnusedParameters": true,
|
||||||
|
"noFallthroughCasesInSwitch": true,
|
||||||
|
"noUncheckedSideEffectImports": true
|
||||||
|
},
|
||||||
|
"include": ["vite.config.ts"]
|
||||||
|
}
|
7
進階_React框架/demo/todolist_demo/vite.config.ts
Normal file
7
進階_React框架/demo/todolist_demo/vite.config.ts
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
import { defineConfig } from 'vite'
|
||||||
|
import react from '@vitejs/plugin-react'
|
||||||
|
|
||||||
|
// https://vite.dev/config/
|
||||||
|
export default defineConfig({
|
||||||
|
plugins: [react()],
|
||||||
|
})
|
@ -22,5 +22,5 @@ index.css主要用來改全域的css
|
|||||||
![image](../assets/2-1.jpg)
|
![image](../assets/2-1.jpg)
|
||||||
|
|
||||||
## Package.json
|
## Package.json
|
||||||
安裝套件資訊都在這
|
安裝套件資訊都在這
|
||||||
![image](../assets/2-3.jpg)
|
![image](../assets/2-3.jpg)
|
Loading…
Reference in New Issue
Block a user