【react小项目】bmi-calculator
bmi-calculator
目录
- bmi-calculator
- 初始化项目
- 01大致布局
- 01代码
- 02完善样式
- 02代码
- 03输入信息模块
- 03代码
- 04 使用图表
- 04代码
- 05详细记录信息渲染
- 05代码
- 06 让数据变成响应式的
- 06-1输入框的数据处理
- 06-2图表,和记录信息的区域数据处理
- 07 删除功能,撤销功能
- 删除功能完成
- 撤销功能
- 08 数据持久化、组件化、模块化
- 08-1数据持久化
- 存数据
- 取数据
- Undo 使用本地化数据,不使用useRef()缓存了
- 08-2组件化、模块化
- 08-2-1输入添加模块
- 08-2-2图表模块
- 08-2-3七天数据模块
- 09 修一些bug
学习地址:https://gitee.com/cheng_yong_xu/bmi-calculator-my
源码地址:https://github.com/GermaVinsmoke/bmi-calculator
对于学习react的同学,这是个不错的学习项目,循序渐进, 很多注释
可以学到什么
函数组件
useState, useEffect,useRef
prop-types
materialize-css
react-chartjs-2(折线图)
数据本地存储
模块化,组件化
成品效果
初始化项目
第一次提交
App组件
启动
01大致布局
【分支01】
使用了Materialize CSS框架的网格系统(Grid System)来布局页面内容。
01代码
import React, { useState, useEffect } from 'react';
import 'materialize-css/dist/css/materialize.min.css';
import './App.css'
const App = () => {return (<div className='container'>{/* 标题 */}<div className='row center'><h1 className='white-text'>BMI Tracker</h1></div>{/* 输入框 */}<div className='row'><div className='col m12 s12'><div className='row'><div className='col m6 s12'><label htmlFor="weight">Weight (in kg)</label><inputtype="number"id="weight"name="weight"min="1"max="999"placeholder="50"/></div><div className='col m6 s12'><label htmlFor="height">Height (in cm)</label><inputtype="number"id="height"name="height"min="1"max="999"placeholder="175"/></div></div><div className='center'><buttonid="bmi-btn"className="calculate-btn"type="button">Calculate BMI</button></div>{ }</div>
//</div>{/* 统计图 */}<div className='row center white-text'>统计图</div>{/* 详细记录信息 */}<div><div className='row center'><h2 className='white-text'>7 Day Data</h2></div><div me='data-container row'><div className="col m6 s12"><div className="card"><div className="card-content"><span className="card-title" data-test="bmi">BMI: 20.1</span><div className="card-data"><span data-test="weight">Weight: 70 kg</span><span data-test="height">Height: 180 cm</span><span data-test="date">Date: 2022/12/12</span></div><button className="delete-btn">X</button></div></div></div></div></div><div className='center'><button className='calculate-btn'>Undo</button></div></div>)
}export default App;
02完善样式
【分支02】
02代码
body{background-color: #172B4D;
}
/* .center h1 {color: #fff;
} */input {background-color: #fff !important;border-radius: 44px !important;width: 90% !important;padding: 0px 15px !important;
}input:focus {border-bottom: none !important;box-shadow: none !important;
}label {display: block;color: #fff !important;font-size: 1rem !important;
}.calculate-btn{background-color: #3f51b5;padding: 15px 50px;color: white;font-size: 16px;border-radius: 44px;cursor: pointer;border: 1px solid #3f51b5;margin-bottom: 40px;transform: translate3d(0, 0, 0);transition: all 0.2s ease;
}.calculate-btn:hover {background-color: #fff;transform: translate(0px, -2px);color: #5364c3;box-shadow: 0px 15px 30px -12px rgba(255, 255, 255, 0.2);
}.calculate-btn:focus {background-color: #32408f;
}.calculate-btn:focus:hover {color: white;
}.calculate-btn:disabled {border: 1px solid #999999;background-color: #cccccc;color: #666666;cursor: default;
}.calculate-btn:disabled:hover {box-shadow: none;transform: translate(0, 0);
}.data-container {background-color: #1f3a67;border-radius: 11px;margin-top: 40px;padding-top: 40px;padding-bottom: 40px;
}.card{background-color: #274881 !important;color: white;
}.card-title {font-weight: 500 !important;text-align: center;
}.card-data {display: flex;justify-content: space-around;
}.delete-btn {background-color: #e74c3c;color: white;border: none;border-radius: 50%;font-weight: 700;padding: 5px 9px;cursor: pointer;position: absolute;top: 0;right: 0;}
.delete-btn:focus {background-color: #e74c3c;
}
03输入信息模块
【分支03】
1.定义数据
2.定义,初始化数据状态
3.input 改变时,更新数据(受控组件)
4.提交数据
03代码
// src\components\App\App.jsx
import React, { useState, useEffect } from 'react';
import 'materialize-css/dist/css/materialize.min.css';
import './App.css'// 定义数据
const initialValues = {weight: '100',height: '180',data: ''
}const App = () => {// 定义,初始化数据状态const [state, setState] = useState(initialValues)// input 改变时,更新数据const handleChange = e => {let { value, name } = e.target;setState({...state,[name]: value,})}// 提交数据const handleSubmit = e => {setState(initialValues)console.log('已提交', state)}return (<div className='container'>{/* 标题 */}<div className='row center'><h1 className='white-text'>BMI Tracker</h1></div>{/* 输入框 */}<div className='row'><div className='col m12 s12'><div className='row'><div className='col m6 s12'><label htmlFor="weight">Weight (in kg)</label><inputtype="number"id="weight"name="weight"min="1"max="999"placeholder="50"value={state.weight}onChange={handleChange}/></div><div className='col m6 s12'><label htmlFor="height">Height (in cm)</label><inputtype="number"id="height"name="height"min="1"max="999"placeholder="175"value={state.height}onChange={handleChange}/></div></div><div className='center'><buttonid="bmi-btn"className="calculate-btn"type="button"disabled={!state.weight || !state.height}onClick={handleSubmit}>Calculate BMI</button></div>{ }</div></div>{/* 统计图 */}<div className='row center white-text'>统计图</div>{/* 详细记录信息 */}<div><div className='row center'><h2 className='white-text'>7 Day Data</h2></div><div className='data-container row'><div className="col m6 s12"><div className="card"><div className="card-content"><span className="card-title" data-test="bmi">BMI: 20.1</span><div className="card-data"><span data-test="weight">Weight: 70 kg</span><span data-test="height">Height: 180 cm</span><span data-test="date">Date: 2022/12/12</span></div><button className="delete-btn">X</button></div></div></div></div></div><div className='center'><button className='calculate-btn'>Undo</button></div></div>)
}export default App;
04 使用图表
chartjs:https://www.chartjs.org/docs/latest/
react-chartjs-2:https://react-chartjs-2.js.org/
主要知道react-chartjs-2
怎么使用
【04分支】
04代码
// src\components\App\App.jsx
import React, { useState, useEffect } from 'react';
import { Line } from 'react-chartjs-2';
import 'materialize-css/dist/css/materialize.min.css';
import './App.css'// 定义数据
const initialValues = {weight: '100',height: '180',data: ''
}const App = () => {// 定义,初始化数据状态const [state, setState] = useState(initialValues)// input 改变时,更新数据const handleChange = e => {let { value, name } = e.target;setState({...state,[name]: value,})}// 提交数据const handleSubmit = e => {setState(initialValues)console.log('已提交', state)}const labelData = [2021,2022,2023]const bmiData = [100,200,300]// 定义图标数据const data = canvas => {// 从传入的canvas元素中获取2D绘图上下文,这是在canvas上绘制图形的基础。// 这段代码创建了一个线性渐变对象,起始于坐标(63, 81),结束于(181, 700),颜色从#929dd9渐变到#172b4d。这常用于为图表的填充色提供动态效果。const ctx = canvas.getContext("2d");const gradient = ctx.createLinearGradient(63, 81, 181, 700);gradient.addColorStop(0, '#929dd9');gradient.addColorStop(1, '#172b4d');return{labels: labelData, // 图表的标签数组,通常对应X轴的各个分类datasets: [ // 一个数据集对象{label: 'BMI', // 数据集的标签,通常用于图例data: bmiData, // 数据集的实际数值数组,对应Y轴的值。backgroundColor: gradient, // 使用之前创建的gradient作为填充色。borderColor: '#3F51B5', // 数据点的边框颜色为#3F51B5。pointRadius: 6, // 数据点的半径为6。pointHoverRadius: 8, // 鼠标悬停时数据点的半径增大到8。pointHoverBorderColor: 'white', // 鼠标悬停时数据点边框颜色变为白色。pointHoverBorderWidth: 2 // 鼠标悬停时数据点边框宽度为2。}]}
}// options 该对象包含了配置信息,主要用来定制基于Chart.js库的图表外观和行为const options = {responsive: true, // 设置图表是否应响应式scales: { //定义图表的坐标轴配置,包括x轴(xAxes)和y轴(yAxes)的样式和行为xAxes: [{scaleLabel: {display: true,labelString: 'Date',fontSize: 18,fontColor: 'white'},gridLines: {display: false,color: 'white'},ticks: {fontColor: 'white',fontSize: 16}}],yAxes: [{scaleLabel: { // x轴标题的配置。display: true, // 是否显示x轴标题labelString: 'BMI', // x轴标题的文本内容fontSize: 18, // 标题的字体大小和颜色fontColor: 'white'},gridLines: { // 网格线的配置display: false, // 不显示x轴的网格线color: 'white' // 格线的颜色,即使不显示也定义了颜色},ticks: { // 刻度线的配置fontColor: 'white', // 刻度线标签的字体颜色和大小。fontSize: 16,beginAtZero: true // 图表的y轴刻度从0开始}}]},tooltips: { // 定义图表提示框(tooltip)的样式。// 分别设置提示框标题和内容的字体大小。titleFontSize: 13,bodyFontSize: 13}}return (<div className='container'>{/* 标题 */}<div className='row center'><h1 className='white-text'>BMI Tracker</h1></div>{/* 输入框 */}<div className='row'><div className='col m12 s12'><div className='row'><div className='col m6 s12'><label htmlFor="weight">Weight (in kg)</label><inputtype="number"id="weight"name="weight"min="1"max="999"placeholder="50"value={state.weight}onChange={handleChange}/></div><div className='col m6 s12'><label htmlFor="height">Height (in cm)</label><inputtype="number"id="height"name="height"min="1"max="999"placeholder="175"value={state.height}onChange={handleChange}/></div></div><div className='center'><buttonid="bmi-btn"className="calculate-btn"type="button"disabled={!state.weight || !state.height}onClick={handleSubmit}>Calculate BMI</button></div>{ }</div></div>{/* 统计图 */}<div className='row center white-text'>{/* 使用折线图 */}<Line data={data} options={options}/></div>{/* 详细记录信息 */}<div><div className='row center'><h2 className='white-text'>7 Day Data</h2></div><div className='data-container row'><div className="col m6 s12"><div className="card"><div className="card-content"><span className="card-title" data-test="bmi">BMI: 20.1</span><div className="card-data"><span data-test="weight">Weight: 70 kg</span><span data-test="height">Height: 180 cm</span><span data-test="date">Date: 2022/12/12</span></div><button className="delete-btn">X</button></div></div></div></div></div><div className='center'><button className='calculate-btn'>Undo</button></div></div>)
};
export default App;
解释
const data = canvas => {const ctx = canvas.getContext('2d');const gradient = ctx.createLinearGradient(63, 81, 181, 700);gradient.addColorStop(0, '#929dd9');gradient.addColorStop(1, '#172b4d');return {labels: labelData,datasets: [{label: 'BMI',data: bmiData,backgroundColor: gradient,borderColor: '#3F51B5',pointRadius: 6,pointHoverRadius: 8,pointHoverBorderColor: 'white',pointHoverBorderWidth: 2}]};};
这段JavaScript代码定义了一个名为data的函数,它接收一个canvas元素作为参数,并返回一个配置对象,该对象常用于初始化或更新基于Chart.js(或其他类似图表库)的图表数据和样式。下面是代码的详细解释:
- 获取2D渲染上下文:
javascriptconst ctx = canvas.getContext('2d');
这行代码从传入的canvas
元素中获取2D绘图上下文,这是在canvas上绘制图形的基础。
- 创建线性渐变:
javascript const gradient = ctx.createLinearGradient(63, 81, 181, 700);gradient.addColorStop(0, '#929dd9');gradient.addColorStop(1, '#172b4d');
这段代码创建了一个线性渐变对象,起始于坐标(63, 81)
,结束于(181, 700)
,颜色从#929dd9
渐变到#172b4d
。这常用于为图表的填充色提供动态效果。
-
- 返回图表配置对象
- 返回的对象结构定义了图表的数据和样式,主要包括:
-
labels:
labelData
,图表的标签数组,通常对应X轴的各个分类。 -
- datasets
- 包含一个数据集对象,具体定义为:
- label:
'BMI'
,数据集的标签,通常用于图例。 - data:
bmiData
,数据集的实际数值数组,对应Y轴的值。 - backgroundColor: 使用之前创建的
gradient
作为填充色。 - borderColor: 数据点的边框颜色为
#3F51B5
。 - pointRadius: 数据点的半径为6。
- pointHoverRadius: 鼠标悬停时数据点的半径增大到8。
- pointHoverBorderColor: 鼠标悬停时数据点边框颜色变为白色。
- pointHoverBorderWidth: 鼠标悬停时数据点边框宽度为2。
综上所述,这个函数用于生成一个配置对象,配置了一种特定样式的图表,其中数据填充色为线性渐变,适合于展示BMI(身体质量指数)等相关数据的图表展示。
options
的对象,该对象包含了配置信息,主要用来定制基于Chart.js库的图表外观和行为。具体配置项解释如下:
-
responsive: true: 设置图表是否应响应式,即图表是否会根据其容器的大小自动调整。
-
scales: 定义图表的坐标轴配置,包括x轴(xAxes)和y轴(yAxes)的样式和行为。
-
xAxes: 配置x轴的设置。
-
- scaleLabel
- x轴标题的配置。
- display: true: 是否显示x轴标题。
- labelString: ‘Date’: x轴标题的文本内容。
- fontSize: 18 和 fontColor: ‘white’: 标题的字体大小和颜色。
-
- gridLines
- 网格线的配置。
- display: false: 不显示x轴的网格线。
- color: ‘white’: 网格线的颜色,即使不显示也定义了颜色。
-
- ticks
- 刻度线的配置。
- fontColor: ‘white’ 和 fontSize: 16: 刻度线标签的字体颜色和大小。
-
-
yAxes: 配置y轴的设置,结构和配置项含义与x轴相似,但多了beginAtZero: true,表示y轴的刻度应该从0开始。
-
-
tooltips: 定义图表提示框(tooltip)的样式。
- titleFontSize: 13 和 bodyFontSize: 13: 分别设置提示框标题和内容的字体大小。
整体而言,这段代码详细地定制了一个图表的外观,包括坐标轴的标题、网格线、刻度线的样式,以及提示框的字体大小,使得图表更加符合特定的视觉需求,比如使用白色字体适应深色背景等。
05详细记录信息渲染
【05分支】
1.完整信息数据列表
硬编码,编写两组数据
2.完整信息数据列表渲染到图表
3.详细记录信息渲染
现在和设计稿已经一样了,
05代码
// src\components\App\App.jsx
import React, { useState, useEffect } from 'react';
import { Line } from 'react-chartjs-2';
import 'materialize-css/dist/css/materialize.min.css';
import './App.css'// 定义数据
const initialValues = {weight: '100',height: '180',data: ''
}// 完整信息数据列表
const stateS = [{ "weight": "50", "height": "170", "date": "2024/6/11 20:05:16", "bmi": "17.30", "id": "e4d54aef-0e89-4e7e-a887-9d7a289da5de" },{ "weight": "51", "height": "170", "date": "2024/6/11 20:05:32", "bmi": "17.65", "id": "a79a7b3c-c1e6-48b3-a2ff-f331db09fa72" }
]const App = () => {// 定义,初始化数据状态const [state, setState] = useState(initialValues)// input 改变时,更新数据const handleChange = e => {let { value, name } = e.target;setState({...state,[name]: value,})}// 提交数据const handleSubmit = e => {setState(initialValues)console.log('已提交', state)}// 交给图表 显示数据const labelData = stateS.map(item => item.date)const bmiData = stateS.map(item => item.bmi)// 定义图标数据const data = canvas => {// 从传入的canvas元素中获取2D绘图上下文,这是在canvas上绘制图形的基础。// 这段代码创建了一个线性渐变对象,起始于坐标(63, 81),结束于(181, 700),颜色从#929dd9渐变到#172b4d。这常用于为图表的填充色提供动态效果。const ctx = canvas.getContext("2d");const gradient = ctx.createLinearGradient(63, 81, 181, 700);gradient.addColorStop(0, '#929dd9');gradient.addColorStop(1, '#172b4d');return {labels: labelData, // 图表的标签数组,通常对应X轴的各个分类datasets: [ // 一个数据集对象{label: 'BMI', // 数据集的标签,通常用于图例data: bmiData, // 数据集的实际数值数组,对应Y轴的值。backgroundColor: gradient, // 使用之前创建的gradient作为填充色。borderColor: '#3F51B5', // 数据点的边框颜色为#3F51B5。pointRadius: 6, // 数据点的半径为6。pointHoverRadius: 8, // 鼠标悬停时数据点的半径增大到8。pointHoverBorderColor: 'white', // 鼠标悬停时数据点边框颜色变为白色。pointHoverBorderWidth: 2 // 鼠标悬停时数据点边框宽度为2。}]}}// options 该对象包含了配置信息,主要用来定制基于Chart.js库的图表外观和行为const options = {responsive: true, // 设置图表是否应响应式scales: { //定义图表的坐标轴配置,包括x轴(xAxes)和y轴(yAxes)的样式和行为xAxes: [{scaleLabel: {display: true,labelString: 'Date',fontSize: 18,fontColor: 'white'},gridLines: {display: false,color: 'white'},ticks: {fontColor: 'white',fontSize: 16}}],yAxes: [{scaleLabel: { // x轴标题的配置。display: true, // 是否显示x轴标题labelString: 'BMI', // x轴标题的文本内容fontSize: 18, // 标题的字体大小和颜色fontColor: 'white'},gridLines: { // 网格线的配置display: false, // 不显示x轴的网格线color: 'white' // 格线的颜色,即使不显示也定义了颜色},ticks: { // 刻度线的配置fontColor: 'white', // 刻度线标签的字体颜色和大小。fontSize: 16,beginAtZero: true // 图表的y轴刻度从0开始}}]},tooltips: { // 定义图表提示框(tooltip)的样式。// 分别设置提示框标题和内容的字体大小。titleFontSize: 13,bodyFontSize: 13}}return (<div className='container'>{/* 标题 */}<div className='row center'><h1 className='white-text'>BMI Tracker</h1></div>{/* 输入框 */}<div className='row'><div className='col m12 s12'><div className='row'><div className='col m6 s12'><label htmlFor="weight">Weight (in kg)</label><inputtype="number"id="weight"name="weight"min="1"max="999"placeholder="50"value={state.weight}onChange={handleChange}/></div><div className='col m6 s12'><label htmlFor="height">Height (in cm)</label><inputtype="number"id="height"name="height"min="1"max="999"placeholder="175"value={state.height}onChange={handleChange}/></div></div><div className='center'><buttonid="bmi-btn"className="calculate-btn"type="button"disabled={!state.weight || !state.height}onClick={handleSubmit}>Calculate BMI</button></div>{ }</div></div>{/* 统计图 */}<div className='row center white-text'>{/* 使用折线图 */}<Line data={data} options={options} /></div>{/* 详细记录信息 */}<div><div className='row center'><h2 className='white-text'>7 Day Data</h2></div><div className='data-container row'>{stateS.length > 0 ? (<>{stateS.map(info => (<div className="col m6 s12"><div className="card"><div className="card-content"><span className="card-title" data-test="bmi">BMI: {info.bmi}</span><div className="card-data"><span data-test="weight">Weight: {info.weight} kg</span><span data-test="height">Height: {info.height} cm</span><span data-test="date">Date: {info.date}</span></div><button className="delete-btn">X</button></div></div></div>))}</>) : (<div className='center white-text'>No log found</div>)}</div></div><div className='center'><button className='calculate-btn'>Undo</button></div></div>)
};
export default App;
06 让数据变成响应式的
06-1输入框的数据处理
【06-1分支】
问题
问题代码
解决
每次state变化,都会触发更新
我们在体重,身高输入框,输入
53,175
会往state状态里插入,如下的的一条数据
{weight: '53', height: '175', date: '2024/6/15 21:40:24', bmi: '17.31', id: 'f83452b5-a7b5-4a57-beb1-ea552bf432cb'}
接在下来,我们的图表,和记录信息的区域,都显示这些数据
06-2图表,和记录信息的区域数据处理
state有几条数据就显示几条
07 删除功能,撤销功能
点击x删除对应数据
点击Undo撤销上一步操作(如果上一步是点击x删除对应数据,那么Undo就是回复上一步;如果上一步是添加里一条数据,那么Undo就是删除新添加的这条数据 )
删除功能完成
撤销功能
思路就是所在点击删除后,第一件事就是先保存一份最新的state
// let lastState // 注意这个地方,如只是一般的变量,那么每次setState(lastState),渲染的时候handleUndo函数都会从新执行,一直在初始化lastState,所以需要使用useReflet lastState = useRef([])const deleteCard = (id) => {lastState.current = state.slice();let newState = state.filter(item => item.id !== id)setState(newState)// console.log(id,state)// console.log(lastState.current)}const handleUndo = () => {// setState(lastState);setState(lastState.current);// console.log(lastState.current , state)}
到目前位置,我们所有的功能都已完成
08 数据持久化、组件化、模块化
目前我们我们把这个小应用全部写在了一个文件里,这样文件会显得臃肿,庞大,混乱难以维护。当等功能增多的时候就会,更加庞大,混乱。
所以我们接下来要拆分这个组件,分成一个个小的组件。
现在我们的数据在缓存里,刷新就会丢失。所以我们将数据持久化到本地,关闭浏览器也不会丢失。
08-1数据持久化
【分支08-1】
写一个将数据存储到本地,从本地获取的数据的模块
// src\helpers\localStorage.js
export const getData = (key) => {if (!localStorage) return;try {return JSON.parse(localStorage.getItem(key));} catch (err) {console.error(`Error getting item ${key} from localStorage`, err);}
};export const storeData = (key, item) => {if (!localStorage) return;try {return localStorage.setItem(key, JSON.stringify(item));} catch (err) {console.error(`Error storing item ${key} to localStorage`, err);}
};
存数据
useEffect(() => {storeData('data', state); // 初始化组件和每次更新state时,都会触发storeData保存数据console.log('App_state', state)}, [state]);
取数据
const App = () => {// ,initialState 被定义为一个箭头函数,然后作为 useState 的参数使用。这里有一个常见的误解:通常我们不希望将 useState 的初始化函数定义为箭头函数,因为这样会导致每次组件渲染时都会创建一个新的函数实例,可能会引发不必要的组件重新渲染。// initialState是一个箭头函数,这种方式适用于当你想延迟执行 getData('data') 或者在未来的某个时间点决定是否执行这个操作时const initialState = () => getData('data') || []; const [state, setState] = useState(initialState)
Undo 使用本地化数据,不使用useRef()缓存了
// let lastState // 注意这个地方,如只是一般的变量,那么每次setState(lastState),渲染的时候handleUndo函数都会从新执行,一直在初始化lastState,所以需要使用useRef// let lastState = useRef([])const deleteCard = (id) => {storeData('lastState', state); // 不使用useRef([])缓存了,直接本地化保存数据let newState = state.filter(item => item.id !== id)setState(newState)// console.log(id,state)// console.log(lastState.current)}const handleUndo = () => {// setState(lastState);setState(getData('lastState'));// console.log(lastState.current , state)}
08-2组件化、模块化
将输入添加,图表模块,七天数据模块,做成单独的模块
输入添加模块
图表模块
七天数据模块
08-2-1输入添加模块
【分支08-2-1】
直接将我写好的都拿过来
将 Input_handleChange
, 从App模块传递到 BmiForm 模块
import React, { useState } from 'react';
import PropTypes from 'prop-types';
import '../App/App.css'const Input_initialValues = {weight: '',height: '',date: ''
}const BmiForm = ({ Input_handleChange }) => {// 定义,初始化数据状态const [Input_state, setState_Input] = useState(Input_initialValues)// input 改变时,更新数据const handleChange = e => {let { value, name } = e.target;// 输入的数字不能大于999if (value > 999) {value = 999}const date = new Date().toLocaleString().split(',')[0]// console.log(date)// 更新输入框的值setState_Input({...Input_state,[name]: value,date})}// 提交数据const handleSubmit = () => {Input_handleChange(Input_state)setState_Input(Input_initialValues)// console.log('已提交', Input_state)// console.log('已提交', Input_initialValues)}return (<>{/* 输入框 */}< div className='row' ><div className='col m12 s12'><div className='row'><div className='col m6 s12'><label htmlFor="weight">Weight (in kg)</label><inputtype="number"id="weight"name="weight"min="1"max="999"placeholder="50"value={Input_state.weight}onChange={handleChange}/></div><div className='col m6 s12'><label htmlFor="height">Height (in cm)</label><inputtype="number"id="height"name="height"min="1"max="999"placeholder="175"value={Input_state.height}onChange={handleChange}/></div></div><div className='center'><buttonid="bmi-btn"className="calculate-btn"type="button"disabled={!Input_state.weight || !Input_state.height}onClick={handleSubmit}>Calculate BMI</button></div>{ }</div></div ></>)
}BmiForm.propTypes ={change: PropTypes.func.isRequired
}export default BmiForm;
08-2-2图表模块
【分支08-2-2】
直接将我写好的都拿过来
08-2-3七天数据模块
【分支08-2-3】
直接将我写好的都拿过来
09 修一些bug
【分支09】
相关文章:
【react小项目】bmi-calculator
bmi-calculator 目录 bmi-calculator初始化项目01大致布局01代码 02完善样式02代码 03输入信息模块03代码 04 使用图表04代码 05详细记录信息渲染05代码 06 让数据变成响应式的06-1输入框的数据处理06-2图表,和记录信息的区域数据处理 07 删除功能,撤销功…...
python判断一个数是不是偶数
在Python中,你可以使用模运算符 % 来判断一个数是否为偶数。模运算符会返回两个数相除的余数。如果一个数除以2的余数为0,那么这个数就是偶数。 以下是一个简单的Python函数,用于判断一个数是否为偶数: def is_even(n):return n…...
Apipost模拟HTTP客户端
模拟HTTP客户端的软件有很多,其中比较著名的就有API-FOX、POSTMAN。 相信很多小伙伴都使用POSTMAN。这篇博客主要介绍Apipost的原因是,Apipost无需下载,具有网页版。 APIFOX的站内下载: Api-Fox,类似于PostMan的软件…...
uniapp 调用手机上安装的app (高德地图 百度地图 Apple地图 谷歌地图)
uniapp 调用手机上安装的app (高德地图 百度地图 Apple地图 谷歌地图) 效果 思路 获取手机类型(安卓/iOS)let platform uni.getSystemInfoSync().platform判断手机有没有安装需要的应用plus.runtime.isApplicationExist({action: ""}))打开应用 跳转过去plus.runt…...
如果供应商不能按时交货怎么办?
虽然说我们在采购的时候,我们会和供应商签订合同,合同上也会注明交期时间等一些必需的条件。 但是当供货商真的没有如期交货,或者交货拖延的时候,我们第一时间选择的是拿起法律武器来让对方承担违约责任吗? 显然,这选…...
【Linux应用】Linux系统的设备管理——Udev
1.udev概述 udev是 Linux2.6内核里的一个功能,它替代了原来的 devfs,成为当前 Linux 默认的设备管理工具,能够根据系统中的硬件设备的状态动态更新设备文件,包括设备文件的创建,删除等。 udev以守护进程的形式运行&am…...
超实用!给独立开发者福音的一站式应用开发工具!
各位开发者们,是否曾经为了搭建服务、开发接口API而头痛不已?是否曾因为需要集成各种第三方认证服务而感到心力交瘁?别担心,今天我要向大家介绍的是一款专为“懒人”开发者准备的神器——MemFire Cloud。这款一站式应用开发工具不…...
华为 HarmonyOS 中国市场份额一季度超越苹果 iOS
华为 HarmonyOS 中国市场份额一季度超越苹果 iOS 根据最新发布的数据,研究机构Counterpoint Research指出,在2024年第一季度,华为的操作系统HarmonyOS在中国市场超越了苹果的iOS,成为中国市场上的第二大操作系统。 ![在这里插入…...
【乐吾乐2D可视化组态编辑器】导航
支持点击图元,切换画面或跳转链接。 乐吾乐2D可视化组态编辑器地址:https://2d.le5le.com/ 切换画面 1. 添加事件 2. 设置事件行为 事件行为"发送消息",消息名选择"导航"。 3. 配置消息参数 消息参数,…...
vue 之 vuex
目录 vuex 是什么 Vuex管理哪些状态呢? Vuex 页面刷新数据丢失怎么解决 1. 使用浏览器的本地存储 2. 使用 Vuex 持久化插件 3. 使用后端存储 注意事项 Vuex 为什么要分模块并且加命名空间 vuex 是什么 vuex 是专门为 vue 提供的全局状态管理系统,…...
【代码随想录】【算法训练营】【第36天】[452]用最少数量的箭引爆气球 [435]无重叠区间 [763]划分字母区间
前言 思路及算法思维,指路 代码随想录。 题目来自 LeetCode。 day 36,周三,最难坚持的一天~ 题目详情 [452] 用最少数量的箭引爆气球 题目描述 452 用最少数量的箭引爆气球 解题思路 前提:区间可能重叠 思路:…...
【ElasticSearch】windows server 2019安装ES8.9.1 + kibana8.9.1 + IK分词器
目录 准备工作 ES Kibana IK 安装 es es访问测试 将es安装为系统服务 Kibana 配置es 运行kibana 访问测试 IK 补充 准备工作 ES8.9.1 kibana8.9.1 IK的版本最好要对应上!!! ES es8.9.1: https://artifa…...
前端面试题(一)答案版
面试形式:线下面试:时长60分钟 面试过程:填写个人信息->笔记题->HR根据前面2份资料提问->技术面试(见如下面试题) 面试官:项目负责人 公司背景:教育培训公司,项目给本公…...
qt c++ 子界面调用主窗口函数
方法:使用单例模式 将主窗口设计为单例模式。在子界面中通过单例访问主窗口实例,并调用公共函数。 // mainwindow.h #include <QMainWindow>class MainWindow : public QMainWindow {Q_OBJECTpublic:static MainWindow& instance() {static …...
Excel中多条件判断公式怎么写?
在Excel里,这种情况下的公式怎么写呢? 本题有两个判断条件,按照题设,用IF函数就可以了,这样查看公式时逻辑比较直观: IF(A2>80%, 4, IF(A2>30%, 8*(A2-30%),0)) 用IF函数写公式,特别是当…...
从申请到放款,外汇贷款软件的全流程测试解析
一、业务概述 外汇贷款是商业银行经营的一项重要资产业务。它是指银行运用外汇资金,向借款人提供短期或长期的外汇资金融通。这种贷款业务不仅能帮助银行获取经济效益,还是银行联系客户的主要途径。外汇贷款对于利用外资、引进先进技术设备,以…...
数据分析之数据预处理、分析建模、可视化
1、数据分析概述 数据分析:对大量有序或无序的数据进行信息的集中整合、运算提取、展示等操作,通过这些操作找出研究对象的内在规律。 目的:揭示事物运动、变化、发展的规律。 意义:提高系统运行效率、优化系统作业流程、预测未…...
计算机网络:1概述
概述 因特网 网络、互连网(互联网)与因特网的区别与关系 若干节点和链路互连形成网络,若干网络通过路由器互连形成互连网,世界上最大的互连网是互联网(因特网Internet)。 因特网发展的三个阶段 因特网…...
Mybatis工作流程和插件开发
在了解插件开发之前,我们先总体的来梳理一下Mybatis的大致执行流程: 1.new SqlSessionFactoryBuilder().build(inputStream):先根据配置文件(包含了全局配置文件和映射配置文件)初始化一个对象Configuration(这里对象里…...
部署大模型LLM
在autodl上部署大模型 windows运行太麻烦,环境是最大问题。 选择云上服务器【西北B区 / 514机】 cpp (c c plus plus) 纯 C/C 实现,无需外部依赖。针对使用 ARM NEON、Accelerate 和 Metal 框架的 Apple 芯片进行了优化。支持适用于 x86 架构的 AVX、…...
【CT】LeetCode手撕—88. 合并两个有序数组
目录 题目1- 思路2- 实现⭐88. 合并两个有序数组——题解思路 2- ACM实现 题目 原题连接:88. 合并两个有序数组 1- 思路 模式识别 模式1:两个有序数组合并 ——> 双指针模式2:返回结果填充到 nums1[mn] ——> 需要开辟新的数组空间 …...
深入分析 Android BroadcastReceiver (二)
文章目录 深入分析 Android BroadcastReceiver (二)1. 深入理解 BroadcastReceiver 的高级使用和优化2. 有序广播(Ordered Broadcasts)2.1 实现有序广播 3. 粘性广播(Sticky Broadcasts)3.1 使用粘性广播 4. 本地广播(…...
Linux常⽤服务器构建-ssh和scp
目录 1.ssh <1>ssh介绍 <2>安装ssh A.安装ssh服务器 B.远程登陆 <3>使⽤ssh连接服务器 2.scp 本地⽂件复制到远程: 本地⽬录复制到远程: 远程⽂件复制到本地: 远程⽬录复制到本地: 1.ssh <1>…...
《QT实用小工具·七十》openssl+qt开发的P2P文件加密传输工具
1、概述 源码放在文章末尾 该项目实现了P2P的文件加密传输功能,具体包含如下功能: 1、 多文件多线程传输 2、rsaaes文件传输加密 3、秘钥随机生成 4、断点续传 5、跨域传输引导服务器 项目界面如下所示: 接收界面 发送界面 RSA秘钥生成…...
短链接生成器排名前三!长链接转化成短链接工具有哪些?
在现今的网络营销环境中,短链接的应用越来越广泛。它不仅能简化长链接,提高分享效果,还能提升企业品牌形象和用户体验。于是,市场上涌现出众多短链接生成工具。本文将为您揭秘短链接生成器排名前三的产品,帮您找到最适…...
Vue50-mixin混入
一、为什么要使用 mixin混入 两个组件共享一个配置。 二、使用 mixin混入 2-1、创建一个混合js文件 2-2、引入混合js文件 1、局部混合 在每个组件中都引入混合js文件 注意: 混合就是复用配置,vm实例中的所有的配置项,都能在混合.js文件中写…...
Java创建线程的方式
继承Thread类 这是创建线程的基本方式之一。你需要创建一个新的类,该类继承自Thread类,并重写run()方法。然后,你可以创建这个类的一个实例并调用它的start()方法来启动新线程。 public class MyThread extends Thread { Override public vo…...
C# 程序结构
C# 程序结构 C#(读作“C-sharp”)是一种由微软开发的高级编程语言,它是.NET框架的一部分。C# 设计用于现代软件开发,具有强大的类型系统、丰富的库支持和面向对象的特性。本文将详细介绍C#程序的基本结构,包括其语法、类型系统、控制结构、类和对象等。 C# 程序的基本结…...
【Linux】使用 iptables 验证访问HDFS 所使用到的端口
目录 编辑 一、实操背景 二、iptables 简介 三、模拟操作 一、实操背景 背景: 在客户有外网的服务器需要访问内网大数据集群HDFS,使用iptable模拟测试需要开放的端口。 二、iptables 简介 具体介绍看文章: 【Linux】Iptables 详解与实战…...
工程设计问题---多盘离合器制动器设计问题
这个问题的主要目的是使多片式离合器制动器的质量最小化。在这个问题中,使用了五个整数决策变量,它们是内半径(x1)、外半径(x2)、盘厚度(x3)、致动器的力(x4)…...
独家提供实用网站线路大全/如何申请网站域名流程
关于网页打印,window.print()提供的功能离远离一般的需求,很多情况下需要编程扩展 目前网上有很多关于网页打印的,但大多采用了ActiveX控件或IE内置的一些Object,由于ActiveX的安全性因素,实用性大打折扣 关于网页的横…...
vs可以做网站吗/十大中文网站排名
在真实部署环境中,很难将dist生成的内容直接部署到服务器根目录。直接按默认配置build的项目无法在子文件夹中正常运行,需要进行如下配置: 例如: 将项目部署到服务器根目录下的project文件夹下: 修改Router index.js…...
网站建设需要些什么东西/seo工具在线访问
javascript浏览器Ajax请求在现代网站中大量使用。 除了使用执行Ajax请求的内置方法之外,还使用XMLHttpRequest实例,许多开发人员还使用jQuery的方法来执行相同的任务。 在本文中,我们将介绍两个替代库,它们使您可以实现相同的目标…...
什么叫做门户网站/网络科技
1、按顺序安装如下包:中文支持fonts-chinese-3.02-12.el5.noarch.rpmm17n-db-common-cjk-1.3.3-46.el5.noarch.rpmm17n-db-chinese-1.3.3-46.el5.noarch.rpm中文输入法scim-libs-1.4.4-39.el5.i386.rpmscim-1.4.4-39.el5.i386.rpmscim-chinese-standard-0.0.2-1.el5…...
佛山网站建设专家/seo代码优化工具
答案:请安装以下步骤在Windws XP进行释放并重新获得一个ID地址的操作:1。点击“开始”按钮,然后点击“附件”选项再点击“命令提示符”。2。在DOS命令行模式输入以下命令“ipconfig /release”然后按回车键,使用此命令可以释放IP地…...
免费用的云服务器/seo网站排名软件
在这里插入代码片45个Vue开源项目汇总在过去的一年里,我们比较了将近 12,000 个 Vue.js 开源项目和库,从中挑选了最好的 45 个 这些项目和库可以分为 3 类:1.用户界面(1~19)2.Vue.js 工具(20~36)3.项目(37~45)这是一个非常好的清单,精心挑选了 2018 年 1 月至 12 月期…...