04 todoList案例
React全家桶
一、案例- TODO List 综合案例
功能描述
- 动态显示初始列表
- 添加一个 todo
- 删除一个 todo
- 反选一个 todo
- todo 的全部数量和完成数量
- 全选/全不选 todo
- 删除完成的 todo
1.1 静态组件构建
- 将资料包中的todos_page/index.html中核心代码添加到Todo.jsx文件中,并将class修改成className。
- 创建todo.css样式文件,并在将资料包中的css文件中内容copy到该文件中,并导入
import React from 'react'
import "./todo.css"
export default function Todo() {return (<div className="todo-container"><div className="todo-wrap"><div className="todo-header"><input type="text" placeholder="请输入你的任务名称,按回车键确认" /></div><ul className="todo-main"><li><label><input type="checkbox" /><span>xxxxx</span></label><button className="btn btn-danger">删除</button></li><li><label><input type="checkbox" checked /><span className="done">yyyy</span></label><button className="btn btn-danger">删除</button></li></ul><div className="todo-footer"><label><input type="checkbox" /></label><span><span>已完成0</span> / 全部2</span><button className="btn btn-danger">清除已完成任务</button></div></div></div>)
}
- 在将该组件导入到App.jsx中
import React from 'react'
import Todo from './TODO/Todo'
export default function App() {return <Todo />
}
1.2 静态组件拆分
当某一个组件功能复用性非常高的时候,咱们需要考虑将其进行拆分成具体的组件进行复用,
在本实例中只是本着模块化的思想进行拆分。
1.2.1 拆分头部
- 在TODO文件夹中创建一个TodoHeader文件夹,将关于头部的组件代码进行拆分
import React from 'react'
import "./TodoHeader.css"
export default function TodoHeader() {return (<div className="todo-header"><input type="text" placeholder="请输入你的任务名称,按回车键确认" /></div>)
}
- 将todo.css中关于header头部的样式也拆分出来,单独创建一个TodoHeader.css文件
/*header*/
.todo-header input {width: 560px;height: 28px;font-size: 14px;border: 1px solid #ccc;border-radius: 4px;padding: 4px 7px;
}.todo-header input:focus {outline: none;border-color: rgba(82, 168, 236, 0.8);box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6);
}
- 在Todo.jsx文件导入并调用组件
import React from 'react'
import "./todo.css"
import TodoHeader from './TodoHeader/TodoHeader'
export default function Todo() {return (<div className="todo-container"><div className="todo-wrap"><TodoHeader />...</div></div>)
}
1.2.2 拆分中间
- 在TODO文件夹中创建一个TodoMain文件夹,将关于中间的组件代码进行拆分
import React from 'react'
import './TodoMain.css'
export default function TodoMain() {return (<ul className="todo-main"><li><label><input type="checkbox" /><span>xxxxx</span></label><button className="btn btn-danger">删除</button></li><li><label><input type="checkbox" checked /><span className="done">yyyy</span></label><button className="btn btn-danger">删除</button></li></ul>)
}
- 将todo.css中关于Main中间的样式也拆分出来,单独创建一个TodoMain.css文件
/*main*/
.todo-main {margin-left: 0px;border: 1px solid #ddd;border-radius: 2px;padding: 0px;
}.todo-empty {height: 40px;line-height: 40px;border: 1px solid #ddd;border-radius: 2px;padding-left: 5px;margin-top: 10px;
}/*item*/
li {list-style: none;height: 36px;line-height: 36px;padding: 0 5px;border-bottom: 1px solid #ddd;
}li label {float: left;cursor: pointer;
}li label li input {vertical-align: middle;margin-right: 6px;position: relative;top: -1px;
}li button {float: right;display: none;margin-top: 3px;
}li:before {content: initial;
}li:last-child {border-bottom: none;
}li .done {color: #666;text-decoration: line-through;
}
- 在Todo.jsx文件导入并调用组件
import React from 'react'
import "./todo.css"
import TodoHeader from './TodoHeader/TodoHeader'
import TodoMain from './TodoMain/TodoMain'
export default function Todo() {return (<div className="todo-container"><div className="todo-wrap"><TodoHeader /><TodoMain />....</div></div>)
}
1.2.3 拆分底部
- 在TODO文件夹中创建一个TodoFooter文件夹,将关于底部的组件代码进行拆分
import React from 'react'
import "./TodoFooter.css"
export default function TodoFooter() {return (<div className="todo-footer"><label><input type="checkbox" /></label><span><span>已完成0</span> / 全部2</span><button className="btn btn-danger">清除已完成任务</button></div>)
}
- 将todo.css中关于Footer底部的样式也拆分出来,单独创建一个TodoFooter.css文件
/*footer*/
.todo-footer {height: 40px;line-height: 40px;padding-left: 6px;margin-top: 5px;
}.todo-footer label {display: inline-block;margin-right: 20px;cursor: pointer;
}.todo-footer label input {position: relative;top: -1px;vertical-align: middle;margin-right: 5px;
}.todo-footer button {float: right;margin-top: 5px;
}
- 在Todo.jsx文件导入并调用组件
import React from 'react'
import "./todo.css"
import TodoHeader from './TodoHeader/TodoHeader'
import TodoMain from './TodoMain/TodoMain'
import TodoFooter from './TodoFooter/TodoFooter'
export default function Todo() {return (<div className="todo-container"><div className="todo-wrap"><TodoHeader /><TodoMain /><TodoFooter /></div></div>)
}
1.3 关于数据与状态的分析
首先,TodoMain组件中的数据肯定是循环显示在组件中,
而且还可以通过文本框输入提交进行修改和删除按钮一系列操作,
不难分析数据是变化的,那么咱们可以将这个数据的初始记录在state状态
中。
其次,状态中记录的值是一个数组
,里面每一个任务是一个对象
,里面的done用来标识是否选中状态
[{id:1,title:'任务1',done:false},{id:2,title:'任务2',done:false}
]
1.4 任务列表的数据渲染展示
- 在Todo.jsx文件中创建初始化状态值,并将状态值通过组件标签属性的方式传递给相应的子组件
export default function Todo() {//记录状态let [todolists, changetodos] = useState([{ id: 1, title: '任务1', done: false },{ id: 2, title: '任务2', done: true }]);return (<div className="todo-container"><div className="todo-wrap"><TodoHeader /><TodoMain todolists={todolists} /><TodoFooter /></div></div>)
}
- 在TodoMain.jsx组件中接收父组件传递的属性属性,并进行循环渲染
import React from 'react'
import './TodoMain.css'
export default function TodoMain(props) {//函数式组件中子组件接收父组件中的属性//函数的参数名称自定义,只不过一般props含义为属性//对象解构赋值let { todolists } = props;return (<ul className="todo-main">{todolists.map(item => {return <li key={item.id}><label><input type="checkbox" checked={item.done} /><span className={item.done ? 'done' : ""}>{item.title}</span></label><button className="btn btn-danger">删除</button></li>})}</ul>)
}
1.5 新增任务功能
1.5.1 给Header子组件添加受控
- 在TodoHeader.jsx文件中添加受控组件,给文本框绑定onChange事件以及value属性
- 并添加onKeyDown事件,通过事件对象中的keyCode属性来判断用户按下的按键是什么
- 接收父组件传递的组件属性,用来修改父组件中的状态数据
import React, { useState } from 'react'
import "./TodoHeader.css"
export default function TodoHeader(props) {let { addTodo } = props;//声明状态let [title, setTitle] = useState('')let keyDown = (e) => {//通过事件对象中的keyCode属性来判断,用户敲下的是回车键if (e.keyCode === 13) {// 新增一个任务addTodo(e.target.value);//清空文本框中的value值setTitle('');}}let changeValue = (e) => {setTitle(e.target.value)}return (<div className="todo-header"><input type="text"placeholder="请输入你的任务名称,按回车键确认"onKeyDown={keyDown} value={title} onChange={changeValue} /></div>)
}
1.5.2 父组件传递属性到子组件
import React, { useState } from 'react'
import "./todo.css"
import TodoHeader from './TodoHeader/TodoHeader'
import TodoMain from './TodoMain/TodoMain'
import TodoFooter from './TodoFooter/TodoFooter'
export default function Todo() {//记录状态let [todolists, changetodos] = useState([{ id: 1, title: '任务1', done: false },{ id: 2, title: '任务2', done: true }]);let addTodo = (title) => {changetodos([...todolists,{id: todolists.length + 1,title,done: false}])}return (<div className="todo-container"><div className="todo-wrap"><TodoHeader addTodo={addTodo} /><TodoMain todolists={todolists} /><TodoFooter /></div></div>)
}
1.6 点击任务复选框修改任务状态功能
-
先在子组件中添加onChange事件,确保程序运行没有报错,但是子组件没办法直接修改父组件中的数据,
仍然需要父组件通过调用子组件时通过属性进行传递
import React from 'react'
import './TodoMain.css'
export default function TodoMain(props) {//函数式组件中子组件接收父组件中的属性//函数的参数名称自定义,只不过一般props含义为属性//对象解构赋值let { todolists } = props;let changeDone = () => {}return (<ul className="todo-main">{todolists.map(item => {return <li key={item.id}><label><input type="checkbox" checked={item.done}onChange={changeDone} /><span className={item.done ? 'done' : ""}>{item.title}</span></label><button className="btn btn-danger">删除</button></li>})}</ul>)
}
- 在父组件中添加一个修改状态的方法,并传递到子组件
import React, { useState } from 'react'
import "./todo.css"
import TodoHeader from './TodoHeader/TodoHeader'
import TodoMain from './TodoMain/TodoMain'
import TodoFooter from './TodoFooter/TodoFooter'
export default function Todo() {//前面代码省略...//定义一个可以修改状态的方法let modifyTodo = (id, done) => {//注意:在这里咱们要修改状态时,在changetodos()里面需要传入一个修改状态后的新数组//React会将原数组以及修改状态后的新数组进行比较let newtodo = todolists.map(item => {if (item.id === id) {item.done = done;}return item;})changetodos(newtodo)}return (<div className="todo-container"><div className="todo-wrap"><TodoHeader addTodo={addTodo} /><TodoMain todolists={todolists} modifyTodo={modifyTodo} /><TodoFooter /></div></div>)
}
- 子组件接收父组件传递的属性,并进行修改
import React from 'react'
import './TodoMain.css'
export default function TodoMain(props) {//函数式组件中子组件接收父组件中的属性//函数的参数名称自定义,只不过一般props含义为属性//对象解构赋值let { todolists, modifyTodo } = props;let changeDone = (id) => {return (e) => {modifyTodo(id, e.target.checked);}}return (<ul className="todo-main">{todolists.map(item => {return <li key={item.id}><label><input type="checkbox" checked={item.done}onChange={changeDone(item.id)} /><span className={item.done ? 'done' : ""}>{item.title}</span></label><button className="btn btn-danger">删除</button></li>})}</ul>)
}
1.7 删除任务以及空状态提示
- 在子组件中给删除按钮添加点击事件
import React from 'react'
import './TodoMain.css'
export default function TodoMain() {//省略前面代码...//声明删除功能函数let remove = () => {}return (<ul className="todo-main">{todolists.map(item => {return <li key={item.id}><label><input type="checkbox" checked={item.done}onChange={changeDone(item.id)} /><span className={item.done ? 'done' : ""}>{item.title}</span></label><button className="btn btn-danger" onClick={remove}>删除</button></li>})}</ul>)
}
- 在父组件中将需要删除的项通过属性传递到子组件中
import React, { useState } from 'react'
import "./todo.css"
import TodoHeader from './TodoHeader/TodoHeader'
import TodoMain from './TodoMain/TodoMain'
import TodoFooter from './TodoFooter/TodoFooter'
export default function Todo() {//省略前面代码...//声明要删除的函数let removeTodo = (id) => {//利用数组中的过滤方法,将不满足传递的要删除的id值以外的所有的项过滤出来let newtodo = todolists.filter(item => item.id !== id);changetodos(newtodo)}return (<div className="todo-container"><div className="todo-wrap"><TodoHeader addTodo={addTodo} /><TodoMain todolists={todolists} removeTodo={removeTodo} modifyTodo={modifyTodo} /><TodoFooter /></div></div>)
}
- 子组件根据父组件传递的属性进行接收,并执行
import React from 'react'
import './TodoMain.css'
export default function TodoMain(props) {//函数式组件中子组件接收父组件中的属性//函数的参数名称自定义,只不过一般props含义为属性//对象解构赋值let { todolists, modifyTodo, removeTodo } = props;let changeDone = (id) => {return (e) => {modifyTodo(id, e.target.checked);}}let remove = (id) => {return (e) => {removeTodo(id);}}return (<ul className="todo-main">{todolists.map(item => {return <li key={item.id}><label><input type="checkbox" checked={item.done}onChange={changeDone(item.id)} /><span className={item.done ? 'done' : ""}>{item.title}</span></label><button className="btn btn-danger" onClick={remove(item.id)}>删除</button></li>})}</ul>)
}
-
当将所有的任务全部删除后,页面没有任何数据,所以我们需要一个适当的提示
在子组件的虚拟DOM结构中添加一个li
return (<ul className="todo-main">{todolists.map(item => {return <li key={item.id}><label><input type="checkbox" checked={item.done}onChange={changeDone(item.id)} /><span className={item.done ? 'done' : ""}>{item.title}</span></label><button className="btn btn-danger" onClick={remove(item.id)}>删除</button></li>})}{todolists.length === 0 && <li className='empty'>暂无相关任务</li>}</ul>)
在TodoMain.css中设置empty的相关样式
/* 删除 */
li.empty {text-align: center;padding: 20px 0;
}
1.8 全选与全不选的效果
1.8.1 点击全选按钮
- 先给子组件中的复选框绑定一个 onChange事件
import React from 'react'
import "./TodoFooter.css"
export default function TodoFooter() {let changeAll = () => {}return (<div className="todo-footer"><label><input type="checkbox" onChange={changeAll} /></label><span><span>已完成0</span> / 全部2</span><button className="btn btn-danger">清除已完成任务</button></div>)
}
- 父组件声明函数,将其通过子组件属性进行传递
import React, { useState } from 'react'
import "./todo.css"
import TodoHeader from './TodoHeader/TodoHeader'
import TodoMain from './TodoMain/TodoMain'
import TodoFooter from './TodoFooter/TodoFooter'
export default function Todo() {//省略之前代码...//声明函数let checkAllTodo = (done) => {let newtodo = todolists.map(item => {item.done = done;return item;})changetodos(newtodo)}return (<div className="todo-container"><div className="todo-wrap"><TodoHeader addTodo={addTodo} /><TodoMain todolists={todolists} removeTodo={removeTodo} modifyTodo={modifyTodo} /><TodoFooter checkAllTodo={checkAllTodo} /></div></div>)
}
- 子组件接收属性并调用
import React from 'react'
import "./TodoFooter.css"
export default function TodoFooter(props) {let { checkAllTodo } = props;let changeAll = (e) => {checkAllTodo(e.target.checked);}return (<div className="todo-footer"><label><input type="checkbox" onChange={changeAll} /></label><span><span>已完成0</span> / 全部2</span><button className="btn btn-danger">清除已完成任务</button></div>)
}
1.8.2 点击每一项复选框选中全选框
- 父组件将状态数组传递到TodoFooter组件中
<TodoFooter checkAllTodo={checkAllTodo} todolists={todolists} />
-
子组件进行接收,当循环每一项中的复选框都选中了则全选框选中,反之不选中
并且考虑到当删除每一项之后,全选框也不应该选中,设定条件为数组长度不能为0
import React from 'react'
import "./TodoFooter.css"
export default function TodoFooter(props) {let { checkAllTodo, todolists } = props;let changeAll = (e) => {checkAllTodo(e.target.checked);}return (<div className="todo-footer"><label><input type="checkbox" onChange={changeAll}checked={todolists.every(item => item.done) && todolists.length > 0}/></label><span><span>已完成0</span> / 全部2</span><button className="btn btn-danger">清除已完成任务</button></div>)
}
- 实现底部任务统计效果
<span>已完成 {todolists.filter(item => item.done).length}</span> / 全部 {todolists.length}
1.9 移除已完成任务
- 给子组件中的按钮添加点击事件
import React from 'react'
import "./TodoFooter.css"
export default function TodoFooter() {//省略之前代码...let clear = () => {}return (<div className="todo-footer">//省略之前代码...<button className="btn btn-danger" onClick={clear}>清除已完成任务</button></div>)
}
- 父组件传递方法到子组件
import React, { useState } from 'react'
import "./todo.css"
import TodoHeader from './TodoHeader/TodoHeader'
import TodoMain from './TodoMain/TodoMain'
import TodoFooter from './TodoFooter/TodoFooter'
export default function Todo() {//省略之前代码....let removeAllTodo = () => {let newtodo = todolists.filter(item => !item.done);changetodos(newtodo)}return (<div className="todo-container"><div className="todo-wrap"><TodoHeader addTodo={addTodo} /><TodoMain todolists={todolists} removeTodo={removeTodo} modifyTodo={modifyTodo} /><TodoFootercheckAllTodo={checkAllTodo}todolists={todolists}removeAllTodo={removeAllTodo} /></div></div>)
}
- 子组件接收并执行
import React from 'react'
import "./TodoFooter.css"
export default function TodoFooter(props) {let { checkAllTodo, todolists, removeAllTodo } = props;let changeAll = (e) => {checkAllTodo(e.target.checked);}let clear = () => {removeAllTodo();}return (<div className="todo-footer"><label><input type="checkbox" onChange={changeAll}checked={todolists.every(item => item.done) && todolists.length > 0}/></label><span><span>已完成 {todolists.filter(item => item.done).length}</span> / 全部 {todolists.length}</span><button className="btn btn-danger" onClick={clear}>清除已完成任务</button></div>)
}
1.10 修复KEY重复的BUG
- npm i nanoid
- 在Todo.jsx文件中引入
import { nanoid } from 'nanoid'
- 修改添加任务时id的值,调用nanoid方法
{id: nanoid(),title,done: false
}
1.11 封装TodoItem组件
- 在Todo文件夹下创建TodoItem子文件夹,并在其中创建TodoItem.jsx文件,将TodoMain循环项代码拆分
import React from 'react'
export default function TodoItem() {return (<li key={item.id}><label><input type="checkbox" checked={item.done}onChange={changeDone(item.id)} /><span className={item.done ? 'done' : ""}>{item.title}</span></label><button className="btn btn-danger" onClick={remove(item.id)}>删除</button></li>)
}
- TodoMain父组件中导入TodoItem子组件,并将需要的数据传递
import React from 'react'
import './TodoMain.css'
import TodoItem from '../TodoItem/TodoItem';
export default function TodoMain(props) {//函数式组件中子组件接收父组件中的属性//函数的参数名称自定义,只不过一般props含义为属性//对象解构赋值let { todolists, modifyTodo, removeTodo } = props;return (<ul className="todo-main">{todolists.map(item => {return <TodoItem modifyTodo={modifyTodo} removeTodo={removeTodo} item={item} key={item.id} />})}{todolists.length === 0 && <li className='empty'>暂无相关任务</li>}</ul>)
}
- 子组件接收父组件传递的数据
import React from 'react'export default function TodoItem(props) {let { modifyTodo, removeTodo, item } = props;let changeDone = (id) => {return (e) => {modifyTodo(id, e.target.checked);}}let remove = (id) => {return (e) => {removeTodo(id);}}return (<li key={item.id}><label><input type="checkbox" checked={item.done}onChange={changeDone(item.id)} /><span className={item.done ? 'done' : ""}>{item.title}</span></label><button className="btn btn-danger" onClick={remove(item.id)}>删除</button></li>)
}
1.12 React中发送ajax请求
以英雄联盟数据列表为例
- 安装axios
npm i axios
- 创建一个Heros目录并添加Heros.jsx文件
import React from 'react'
import axios from 'axios'
import { useEffect } from 'react'
import { useState } from 'react'
export default function Hero() {let [heros, setHeros] = useState([]);//在组件挂载完成时执行useEffect(() => {/* axios.get('http://api.xiaohigh.com/heros').then(value => {console.log(value.data);}) */async function main() {let result = await axios.get('http://api.xiaohigh.com/heros');console.log(result)setHeros(result.data);}main()}, [])return (<div className='hero-container container'><h2 className='page-header'>英雄列表</h2><div className="row">{heros.map(item => {return <div className="col-xs-1" key={item.id}><img className='img-responsive' src={`http://cdn.xiaohigh.com${item.big_image}`} alt="" /><p className='text-center'>{item.name}</p></div>})}</div></div>)
}
1.13 json-server启动服务
- 在当前案例项目中根目录创建一个server文件夹,并添加一个db.json文件,将之前初始化状态数据copy进来
{"todos":[{ "id": 1, "title": "任务", "done": false },{ "id": 2, "title": "任务2", "done": true }]
}
- 在server文件夹下终端运行服务
json-server --watch db.json --port 3001 #可以利用json-server --help来查看参数
注:如果使用json-server时报错,有可能是没有安装json-server
使用全局安装:npm i json-server -g
- 运行服务
http://localhost:3001/todos
1.14 发送请求列表展示所有任务数据
- 在Todo.jsx文件中导入axios
import axios from 'axios'
- 在导入useEffect
import React, { useEffect } from 'react'
- 调用函数,其内部完成ajax请求
//模拟ComponentDidMount
useEffect(() => {async function main() {try {let result = await axios.get('http://127.0.0.1:3001/todos')changetodos(result.data)} catch (e) {console.log('请求失败' + e.message)}}main();
}, [])
1.15 新增任务并发送ajax请求
- 修改Todo.jsx中添加任务的方法代码为发送post请求
let addTodo = async (title) => {try {let result = await axios.post('http://127.0.0.1:3001/todos', {id: nanoid(),title,done: false})changetodos([...todolists,result.data])} catch (e) {console.warn('执行错误' + e.message)}
}
1.16 axios封装简化url-baseURL
- 在src目录下新创建一个utils文件夹,并创建一个http.js文件
import axios from 'axios'
let instance = axios.create({baseURL: 'http://127.0.0.1:3001'
})
export default instance;
- 修改Todo.jsx文件的导入以及请求的基础url
import axios from '../utils/http'
try {let result = await axios.post('/todos', {id: nanoid(),title,done: false})changetodos([...todolists,result.data])
} catch (e) {console.warn('执行错误' + e.message)
}
useEffect(() => {async function main() {try {let result = await axios.get('/todos')changetodos(result.data)} catch (e) {console.log('请求失败' + e.message)}}main();
}, [])
1.17 显示进度条效果
- 安装进度条包
npm i nprogress
- 考虑到每一个请求中都会用到进度条效果,所以我们可以给axios中添加拦截器,修改http.js代码
import axios from 'axios'
import NProgress from 'nprogress'
import "nprogress/nprogress.css"
let instance = axios.create({baseURL: 'http://127.0.0.1:3001'
})
instance.interceptors.request.use(config => {NProgress.start();return config;
})instance.interceptors.response.use(response => {NProgress.done();return response;
})
export default instance;
1.18 错误的统一处理-中断Promise链条
- 在axios的响应拦截器中添加失败响应回调
instance.interceptors.response.use(response => {NProgress.done();return response;
}, error => {console.log('请求响应失败')console.log(error)return new Promise(() => { });
})
- 在发送axios请求时,可以省去try…catch代码
1.19 发送请求修改复选框选中状态以及删除
let modifyTodo = async (id, done) => {//注意:在这里咱们要修改状态时,在changetodos()里面需要传入一个修改状态后的新数组//React会将原数组以及修改状态后的新数组进行比较await axios.patch(`/todos/${id}`, { done })let newtodo = todolists.map(item => {if (item.id === id) {item.done = done;}return item;})changetodos(newtodo)
}
let removeTodo = async (id) => {await axios.delete(`/todos/${id}`)let newtodo = todolists.filter(item => item.id !== id);changetodos(newtodo)
}
1.20 批量更新状态与清空已完成任务
1.20.1 批量更新
let checkAllTodo = async (done) => {//批量更新状态let promises = todolists.map(item => {//发送请求return axios.patch(`/todos/${item.id}`, { done });})try {await Promise.all(promises);let newtodo = todolists.map(item => {item.done = done;return item;})changetodos(newtodo)} catch (e) {console.log('更新失败' + e.message);}
}
1.20.2 清空已完成任务
let removeAllTodo = async () => {//发送请求let promises = todolists.filter(item => item.done).map(item => {return axios.delete(`/todos/${item.id}`)})try {await Promise.all(promises);let newtodo = todolists.filter(item => !item.done);changetodos(newtodo)} catch (e) {console.log('删除失败' + e.message)}}
1.21 toastify操作提醒
- 安装
npm i toastify
- 导入
import { ToastContainer, toast } from 'react-toastify';
import 'react-toastify/dist/ReactToastify.css';
- 在需要提示的位置添加
- 成功
toast.success('xxx');
- 失败
toast.error('xxx');
相关文章:

04 todoList案例
React全家桶 一、案例- TODO List 综合案例 功能描述 动态显示初始列表添加一个 todo删除一个 todo反选一个 todotodo 的全部数量和完成数量全选/全不选 todo删除完成的 todo 1.1 静态组件构建 将资料包中的todos_page/index.html中核心代码添加到Todo.jsx文件中,…...

海睿思分享 | 浅谈企业数据质量问题
一、数据质量问题场景 在日常工作中,业务领导经常通过BI系统来了解各项业务的业绩情况。倘若某天,他打开某张核心报表,发现当日某个区域的数据一直是空白的。BI开发人员经过几个小时的排查分析,发现是当日该区域的销售数据存在产…...

神经网络:激活函数
在计算机视觉中,激活函数是神经网络中的一种非线性函数,用于引入非线性变换和非线性特性到网络中。激活函数的作用、原理和意义如下: 1. 引入非线性变换: 神经网络的线性组合层(如卷积层和全连接层)只能表…...

图像色彩增强相关论文阅读-Representative Color Transform for Image Enhancement(ICCV2021)
文章目录 Representative Color Transform for Image EnhancementAbstractIntroductionRelated workMethod实验Conclusion Representative Color Transform for Image Enhancement 作者:Hanul Kim1, Su-Min Choi2, Chang-Su Kim3, Yeong Jun Koh 单位:S…...

Elasticsearch介绍与应用
Elasticsearch介绍与应用 Elasticsearch的官方文档。 Elasticsearch官网参考文档:https://www.elastic.co/guide/index.html Elasticsearch官方下载地址:https://www.elastic.co/cn/downloads/elasticsearch mvnrepository依赖库地址:http…...

JavaEE规范
Servlet:用于开发 Web 应用程序的 API,定义了处理 HTTP 请求和响应的方式。JSP(JavaServer Pages):一种在服务器端生成动态网页的技术,允许将 Java 代码嵌入到 HTML 页面中。(注意JSP本质就是一个Servlet)J…...

嵌入式实时操作系统的设计与开发New(八)
创建线程 用户在基于RTOS开发应用程序前,首先要创建线程。 用户创建一个线程时须指定用户希望采用的调度策略。 例如,用户想创建一个周期性执行的线程: acoral_period_policy_data_t* data; data acoral_malloc(sizeof(acoral_period_poli…...

MySQL事务相关笔记
杂项 InnoDB最大特点:支持事务和行锁; MyISAM不支持事务 介绍 一个事务是由一条或者多条对数据库操作的SQL语句所组成的一个不可分割的单元,只有当事务中的所有操作都正常执行完了,整个事务才会被提交给数据库。事务有如下特性…...

如何利用AI高效率快速调色
在设计行业中,时间是非常宝贵的资源,而设计师们常常需要应对繁忙的工作日程和紧迫的截止日期。为了提高工作效率和节省时间,越来越多的设计师开始利用人工智能(AI)技术中的高效调色功能。本文将介绍如何利用AI高效率快…...

数据结构--顺序表的基本操作--插入 and 删除
数据结构–顺序表的基本操作–插入 顺序表的插入操作 实现目标 ListInsert(&L,i,e):插入操作。在表L中的第i个位置上插入指定元素e。 typedef struct {int data[MaxSize];int len; }Sqlist;代码实现: #include <stdio.h> #include <stdlib.h> …...

BCSP-玄子Java开发之Java Web编程CH01_初识动态网页
BCSP-玄子Java开发之Java Web编程CH01_初识动态网页 1.1 B/S架构 B/S架构:浏览器/服务器 程序完全部署在服务器上使用浏览器访问服务器无需单独安装客户端软件 为什么要使用B/S架构 B/S与C/S比较B/S架构C/S架构软件安装浏览器需要专门的客户端应用升级维护客户…...

【软件教程】农林生环、水文、海洋、水环境、大气科学、人工智能、碳中和、碳排放、3S、R与统计等软件模型
本文涉及领域水文水资源、大气科学、农林生态、地信遥感、统计分析、编程语言等... 从软件基础到实践案例应用操作,手把手教学,提供永久回放观看和助学群长期辅助指导。适合课题组人员一站式学习,科研人员技术提升、企业单位工程项目、高校论…...

如何加入开源社
开源社成立于 2014 年,是由志愿贡献于开源事业的个人成员,依 “贡献、共识、共治” 原则所组成,始终维持厂商中立、公益、非营利的特点,是最早以 “开源治理、国际接轨、社区发展、项目孵化” 为使命的开源社区联合体。开源社积极…...

软件开发中的破窗效应
应该有很多人已经知道破窗效应【注1】这个社会学 (犯罪学)的词语,破窗效应最先由社会学家James Q. Wilson和George L. Kelling在一篇名为《Broken Windows》的文章中提出【注2】: “一个房子如果窗户破了,没有人去修补…...

机器视觉初步6-1:基于梯度的图像分割
把基于梯度的图像分割单独拿出来。 文章目录 一、图像梯度相关算子的原理1. Sobel算子2. Prewitt算子3. Roberts算子 二、python和halcon算子实现1.python实现2.halcon实现 基于梯度的图像分割方法利用像素之间的梯度信息来进行图像分割。 梯度 1是图像中像素灰度值变化最快的…...

从0开始,精通Go语言Rest微服务架构和开发
说在前面 现在拿到offer超级难,甚至连面试电话,一个都搞不到。 尼恩的技术社区中(50),很多小伙伴凭借 “左手云原生右手大数据”的绝活,拿到了offer,并且是非常优质的offer,据说年…...

Sui x KuCoin Labs夏季黑客松|本周Workshop预告
自Sui x KuCoin Labs夏季黑客松推出以来已有四周的时间,期间收获了众多开发者的积极报名和热情参与。随着黑客松报名即将进入尾声,同期举办的Workshop也迎来了本周的最后一波。本周的黑客松Workshop邀请到MoveEX和Mirror World的负责人作为嘉宾为大家带…...

从电源 LED 读取智能手机的秘密?
研究人员设计了一种新的攻击方法,通过记录读卡器或智能手机打开时的电源 LED,使用 iPhone 摄像头或商业监控系统恢复存储在智能卡和智能手机中的加密密钥。 众所周知,这是一种侧信道攻击。 通过密切监视功耗、声音、电磁辐射或执行操作所需…...

【Linux编辑器-vim使用】
目录 Linux编辑器-vim使用1.vim的基本概念2.vim的基本操作3.vim正常模式命令集4.vim末行模式命令集 Linux编辑器-vim使用 1.vim的基本概念 目前了解的vim有三种模式(其实有好多模式),分别是命令模式、插入模式和底行模式,各模式…...

安装Apache mysql php
目录 一.Apache网站服务 Apache——》静态页面处理——》将静态处理交给PHP Apache简介 安装Apache服务 编辑 安装软件思路 二.安装mysql数据库 1. 安装依赖包 2.创建程序用户管理 3.加压安装包 这边就安装完成了编辑 重点来了 报错了 没有空间 我最后的解决 方法…...

【人工智能】— 神经网络、前向传播、反向传播、梯度下降、局部最小值、多层前馈网络、缓解过拟合的策略
【人工智能】— 神经网络、前向传播、反向传播 前向传播反向传播梯度下降局部最小值多层前馈网络表示能力多层前馈网络局限缓解过拟合的策略 前向传播和反向传播都是神经网络训练中常用的重要算法。 前向传播是指将输入数据从输入层开始经过一系列的权重矩阵和激活函数的计算后…...

小文智能自定义变量详解
在小文交互场景设计时,有一个特殊功能,叫做自定义变量。有时,根据外呼对象的不同,需要对用户传达不同的内容,比如称呼、地址、公司名称等等。此时,就可以使用小文交互的自定义变量功能来实现对不同用户呼出…...
平面电磁波的反射与折射,极化滤波作用
目录 引言 反射定律和折射定律 反射系数和折射系数 平面电磁波在理想介质分界面上的全反射和全折射 全反射 全折射 极化滤波作用 平面电磁波在良导体上的反射与折射 引言 再复杂的电磁波我们都可以看作是很多平面电磁波的叠加 我们在前面介绍的时候,我们认…...

键盘当鼠标用
当鼠标坏掉又需要使用电脑时发现触控板也不能用这就很烦那么键盘当鼠标用教程来了 使用键盘当鼠标的步骤如下: 1. 按住“AltShiftNum Lock”快捷键,弹出鼠标键开启咨询框,点击“是”按钮。 小键盘的数字就是方向/和*就是左右键切换5是单击 …...

动态规划part9 | ● 198.打家劫舍 ● 213.打家劫舍II ● 337.打家劫舍III
文章目录 198.打家劫舍思路思路代码官方题解代码 213.打家劫舍II思路思路代码官方代码困难 337.打家劫舍III思路思路代码官方题解代码困难 今日收获 198.打家劫舍 198.打家劫舍 思路 dp含义,偷前i个房,切第i个房偷 dp[i]max(dp[i-2],dp[i-3])nums[i] …...

【k8s系列】一分钟搭建MicroK8s Dashboard
本文基于上一篇文章的内容进行Dashboard搭建,如果没有看过上一篇的同学请先查阅上一篇文章 k8s系列】使用MicroK8s 5分钟搭建k8s集群含踩坑经验 使用MicroK8s搭建Dashboard很简单,只需要在Master节点按照以下几步操作 1.启用Dashboard插件 microk8s en…...

ArcEngine二次开发0——入门(下载 部署 组件学习)
折腾一下ArcGIS Engine二次开发。 目录 1、开发环境配置2、部署一个ArcGIS Engine应用程序3、ArcObject组件学习4、报错及解决4、其他 1、开发环境配置 参考:https://blog.csdn.net/H48662654/article/details/113384150 (使用ArcEngine前,…...

人工智能---D分离
D分离(D-Separation)是一种用来判断变量是否条件独立的图形化方法。相比于非图形化方法,D-Separation更加直观,且计算简单。对于一个DAG(有向无环图)E,D-Separation方法可以快速的判断出两个节点…...

java spring cloud 企业工程项目管理系统源码-全面的工程项目管理
工程项目管理系统是指从事工程项目管理的企业(以下简称工程项目管理企业)受业主委托,按照合同约定,代表业主对工程项目的组织实施进行全过程或若干阶段的管理和服务。 如今建筑行业竞争激烈,内卷严重,…...

2023最新软件测试面试题【1000道题含答案】
1、自动化代码中,用到了哪些设计模式? 单例设计模式 工厂模式PO设计模式数据驱动模式面向接口编程设计模式 2、什么是断言( Assert) ? 断言Assert用于在代码中验证实际结果是不是符合预期结果,如果测试用例执行失败会抛出异常并提供断言日志 3、什么是web自动化测…...