并不是最好的写法,只是前段时间学习,尝试写的demo,如有误请指正

Vue3

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
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>vue3 todo list</title>
<script src="https://unpkg.com/vue@next"></script>
<!-- element plus 组件库 -->
<!-- 引入样式 -->
<link rel="stylesheet" href="https://unpkg.com/element-plus/lib/theme-chalk/index.css">
<!-- 引入组件库 -->
<script src="https://unpkg.com/element-plus/lib/index.full.js"></script>
<!-- reset css -->
<link href="https://cdn.bootcdn.net/ajax/libs/reseter.css/1.2.0/reseter.min.css" rel="stylesheet">
<style>
.container {
width: 500px;
margin: 50px auto;
}

.head {
display: flex;
justify-content: space-between;
}

.task-list {
margin-top: 20px;
}

.task {
display: flex;
margin: 10px 0;
justify-content: space-between;
align-items: center;
}
</style>
</head>

<body>
<div id="app">
<div class="container">
<div class="head">
<el-input v-model="inputVal" placeholder="请输入任务" style="margin-right: 20px;"></el-input>
<el-button type="primary" @click="addList">Add</el-button>
</div>
<div class="task-list">
<el-card class="box-card">
<template #header>
<div class="card-header">
<span>任务列表</span>
</div>
</template>
<div v-for="(item,index) in unCompletedTasks" :key="item.id" class="task">
{{item.content}}
<div class="btn-group">
<el-button size='small' type="success" @click='toggleTask(item.id)'>完成</el-button>
<el-popconfirm title="确定要删除吗?" @confirm="deleteTask(item.id)">
<template #reference>
<el-button size='small' type="danger">删除</el-button>
</template>
</el-popconfirm>

</div>
</div>
</el-card>
</div>
<div class="task-list">
<el-card class="box-card">
<template #header>
<div class="card-header">
<span>已完成任务</span>
</div>
</template>
<div v-for="item in completedTasks" :key="item.id" class="task">
{{item.content}}
<div class="btn-group">
<el-popconfirm title="确定要删除吗?" @confirm="deleteTask(item.id)">
<template #reference>
<el-button size='small' type="danger">删除</el-button>
</template>
</el-popconfirm>
</div>
</div>
</el-card>
</div>
</div>
</div>
<script>
const { ref, computed } = Vue
const app = Vue.createApp({
setup() {
const list = ref([])
const inputVal = ref('')
let id = 0

// 新增任务
function addList() {
// id 自增 保证唯一
id++
// 任务的数据格式 {id,content,completed}
list.value.unshift({ id, content: inputVal.value, completed: false })
}

function toggleTask(id) {
const index = list.value.findIndex(v => v.id === id)
list.value[index].completed = !list.value[index].completed
}

function deleteTask(id) {
const index = list.value.findIndex(v => v.id === id)
list.value.splice(index, 1)
}

// 已完成 任务
const completedTasks = computed(() => list.value.filter(v => v.completed))
// 未完成 任务
const unCompletedTasks = computed(() => list.value.filter(v => !v.completed))

return { inputVal, list, addList, completedTasks, unCompletedTasks, toggleTask, deleteTask }
}
})

app.use(ElementPlus);
app.mount('#app')
</script>
</body>

</html>

React-Hooks

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
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>react-hooks todolist</title>
<script src="https://cdn.bootcdn.net/ajax/libs/react/16.13.1/umd/react.production.min.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/react-dom/16.13.1/umd/react-dom.production.min.js"></script>
<!-- babel -->
<script src="https://cdn.bootcdn.net/ajax/libs/babel-standalone/7.0.0-beta.3/babel.min.js"></script>
<!-- bootstrap -->
<link href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.4.0/css/bootstrap.min.css" rel="stylesheet">
<style>
.container {
width: 500px;
margin: 50px auto;
}
</style>
</head>

<body>
<!-- 根节点 -->
<div id="root"></div>
<script type="text/babel">
const App = React.createElement(() => {
const { useEffect, useState, useCallback, useMemo } = window.React;
// 任务列表
const [list, setList] = useState([])
// 输入框内容
const [inputVal, setInputVal] = useState('')

// 唯一id
let id = 0;

// 添加任务
const addList = useCallback(() => {
if (!inputVal) return
id++
setList(x => {
return [...x, { id, compluted: false, content: inputVal }]
})
}, [inputVal])

// 切换任务状态
const toggleTask = useCallback((id)=>{
setList(x=>{
const index = x.findIndex(v=> v.id === id)
x[index].compluted = !x[index].compluted
return [...x]
})
},[])

// 删除任务状态
const deleteTask = useCallback((id)=>{
setList(x=>{
const index = x.findIndex(v=> v.id === id)
x.splice(index,1)
return [...x]
})
},[])

// 输入框组件 JSX
const Input = (<div class="input-group">
<input type="text" class="form-control" placeholder="输入任务" value={inputVal} onChange={(e) => setInputVal(e.target.value)} aria-describedby="输入任务" />
<span class="input-group-addon" id="basic-addon2" onClick={addList}>添加任务</span>
</div>)

// 已完成的任务列表
const computedList = useMemo(() => {
if (!list || !list.length) return <ul></ul>
return <ul class='list-group'>
{list.filter(v => v.compluted).map(v => {
return <a class="list-group-item" style={{display:'flex',justifyContent:'space-between',alignItems:'center'}} key={v.id}>
<div>{v.content}</div>
<div class="btn-group" role="group" aria-label="...">
<button type="button" class="btn btn-danger" onClick={()=>deleteTask(v.id)}>删除</button>
</div>
</a>
})}
</ul>
}, [list])
// 未完成的任务列表
const unComputedList = useMemo(() => {
if (!list || !list.length) return <ul></ul>
return <ul class='list-group'>
{list.filter(v => !v.compluted).map(v => {
return <a class="list-group-item" style={{display:'flex',justifyContent:'space-between',alignItems:'center'}} key={v.contnet}>
<div>{v.content}</div>
<div class="btn-group" role="group" aria-label="...">
<button type="button" class="btn btn-success" onClick={()=>toggleTask(v.id)}>完成</button>
<button type="button" class="btn btn-danger" onClick={()=>deleteTask(v.id)}>删除</button>
</div>
</a>
})}
</ul>
}, [list])



// 最终返回的元素节点
return <div class="container">
{Input}
<div class="panel panel-default" style={{ marginTop: '1rem' }}>
<div class="panel-heading">
<h3 class="panel-title">未完成的任务</h3>
</div>
<div class="panel-body">
{unComputedList}
</div>
</div>
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">已完成的任务</h3>
</div>
<div class="panel-body">
{computedList}
</div>
</div>
</div>
})

// 将创建的元素渲染到指定元素内
ReactDOM.render(App, document.getElementById("root"));
</script>
</body>

</html>