前言
今下午花了两三个小时,用最近一周学的东西做了一个很简单多选的答题程序,也算对前段时间学的一些的东西的总结,代码部分可能会多少有点冗余,毕竟是个粗工程,由于没有后端数据,我简单的用浏览器的l本地存储localStorage来实现数据的存取,代码编写用的是函数组件,UI框架简单用了一下Antd,css样式使用sass进行预处理。
一、简单概念
1.函数组件
React 的函数组件是 React 组件的另一种定义方式,两种方式都可以用于定义组件,但是相比于类组件,函数组件要更简单好用些函数组件的创建方式就是定义一个函数,这个函数返回一个React组件。 我们可以通过普通函数的方法和箭头函数的方法创建一个函数组件。
2.Hook
Hook 是一些可以让你在函数组件里“钩入” React state 及生命周期等特性的函数。Hook 不能在 class 组件中使用 —— 这使得我们不使用 class 也能使用 React。
import React, { useState } from 'react';
function Example() {
// 声明一个叫 "count" 的 state 变量
const [count, setCount] = useState(0);
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
useState(0)是一个可以返回一个数组的函数,该数组有两个参数,一个是我们创建的state变量,一个是该state变量的set方法,本身就是一个函数。
二、一个小项目
1.介绍
这个简单的项目是一个简单的答题程序,通过完成一些题目(多选题)来计算最后的得分,主要熟悉一下表单的操作,以及组件之前的传值操作。
2.Schema设计
const defalutschema = {
id: 1,
desc: '前端面试题',
outScore: 80,
totalScore: 0,
question: [
{
id: 1,
desc: 'let,const,var的区别?',
the_score: 0,
options: [
{
label: '变量提升:let,const定义的变量不会出现变量提升,而var会',
value: '变量提升:let,const定义的变量不会出现变量提升,而var会',
score: 10,
selected: false
},
{
label: '重复声明:同一作用域下let,const声明的变量不允许重复声明,而var可以',
value: '重复声明:同一作用域下let,const声明的变量不允许重复声明,而var可以',
score: 10,
selected: false
},
{
label: '暂时性死区:let,const声明的变量不能在声明之前使用,而var可以',
value: '暂时性死区:let,const声明的变量不能在声明之前使用,而var可以',
score: 20,
selected: false
},
{
label: '错误答案',
value: '错误答案',
score: 0,
selected: false
}
],
selected: [
]
}, {
id: 2,
desc: 'JS延迟加载的方式',
the_score: 0,
options: [
{
label: '把JS放在页面的最底部',
value: '把JS放在页面的最底部',
score: 10,
selected: false
},
{
label: 'script标签的defer属性:脚本会立即下载但延迟到整个页面加载完毕再执行。该属性对于内联脚本无作用 (即没有 「src」 属性的脚本)。',
value: 'script标签的defer属性:脚本会立即下载但延迟到整个页面加载完毕再执行。该属性对于内联脚本无作用 (即没有 「src」 属性的脚本)。',
score: 10,
selected: false
},
{
label: 'Async是在外部JS加载完成后,浏览器空闲时,Load事件触发前执行,标记为async的脚本并不保证按照指定他们的先后顺序执行,该属性对于内联脚本无作用 (即没有 「src」 属性的脚本)。',
value: 'Async是在外部JS加载完成后,浏览器空闲时,Load事件触发前执行,标记为async的脚本并不保证按照指定他们的先后顺序执行,该属性对于内联脚本无作用 (即没有 「src」 属性的脚本)。',
score: 10,
selected: false
},
{
label: '动态创建script标签,监听dom加载完毕再引入js文件',
value: '动态创建script标签,监听dom加载完毕再引入js文件',
score: 10,
selected: false
}
],
selected: [
]
}
]
}
3.App组件
App.js
import Question from "../Question/question";
import 'antd/dist/antd.css';
import { createRef, useMemo, useState } from "react";
import { Button } from "antd";
import styles from './Style.module.scss';
const defalutschema = {.......} //见上方schema的设计
window.localStorage.schema = JSON.stringify(defalutschema);
let a_schema;
try {
a_schema = JSON.parse(window.localStorage.schema);
console.log(1, a_schema);
} catch { };
let refs = [];
const App = (props) => {
const [schema, setSchema] = useState(a_schema);
const [finish, setFinish] = useState(false);
const [finishScore, setFinishScore] = useState(0);
const [disabled, setDisabled] = useState(false);
let { question, desc, outScore } = schema;
let totalScore;
let newSchema = {
id: 1,
totalScore: 0,
question: [],
};
const handleSave = () => {
setFinish(true);
totalScore = 0;
schema.question.forEach((item, index) => {
const { getSchema } = refs[index].current;
newSchema.question.push(getSchema());
if (getSchema().the_score) {
totalScore += getSchema().the_score;
}
});
newSchema.totalScore = totalScore;
window.localStorage.schema = JSON.stringify(newSchema);
setDisabled(true);
setFinishScore(newSchema.totalScore);
//alert(`你本次得分${newSchema.totalScore}!`)
}
useMemo(() => {
refs = question.map(item => createRef());
}, [question])
return (
<div className={styles.AppWrapper}>
<p className={styles.desc}>{desc} (满分{outScore})</p>
{finish ? <div className={styles.totalScore}>{finishScore}</div> : <div className={styles.totalScore}></div>}
{
schema.question.map((item, index) => {
return (
<div key={item.id} className={styles.question}>
<p className={styles.title}>{item.id}、 {item.desc}</p>
<Question finish={finish} item={item} ref={refs[index]}></Question>
</div>)
})
}
<Button type="primary" className={styles.Submitbtn} onClick={() => { handleSave() }} disabled={disabled}>交卷</Button>
</div>
)
}
export default App;
Style.module.scss
.AppWrapper{
background-color: aliceblue;
width: 400px;
margin: 20px;
padding: 10px;
position: relative;
.totalScore{
position: absolute;
right: -10px;
top: -30px;
font-size: 50px;
font-weight: bold;
color: red;
font-family: 'Times New Roman', Times, serif;
}
.desc{
font-size: 20px;
font-weight: bold;
}
.question{
width: 100%;
border: 1px solid #333;
padding: 10px;
font-size: 20px;
border-radius: 10px;
margin-top: 20px;
.title{
width: 100%;
height: 20px;
line-height: 20px;
}
}
.Submitbtn{
margin-top: 20px;
}
}
3.Question组件
question.js
import { Checkbox } from 'antd';
import React, { forwardRef, useImperativeHandle, useState } from 'react';
import styles from './style.module.scss';
let score = 0;
const char = ['A', 'B', 'C', 'D', 'E', 'F'];
const Question = (props, ref) => {
const { finish } = props;
const { id, desc, options } = props.item;
const [newSchema, setNewSchema] = useState({});
const [yanz, setYanz] = useState([0, 0, 0, 0]);
useImperativeHandle(ref, () => {
return {
getSchema: () => {
return newSchema
}
}
})
const getTag = (index, finish, yanz) => {
console.log(yanz);
if (yanz[index] === 1 && finish) {
return (<div className={styles.duicuo}>错</div>)
} else if (yanz[index] === 2 && finish) {
return (<div className={styles.duicuo}>对</div>)
} else {
return;
}
}
const onChange = (item) => {
item.selected = !item.selected;
let flag = 1;
score = 0;
let selectedArr = [];
setYanz([0, 0, 0, 0])
options.forEach((item, index) => {
if (item.selected && item.score !== 0) {
score += parseInt(item.score);
selectedArr.push(item);
const newYanz = yanz;
newYanz.splice(index, 1, 2);
setYanz(newYanz)
console.log(122, yanz);
} else if ((item.selected && item.score == 0)) {
flag = 0;
const cuoYanz = yanz;
cuoYanz.splice(index, 1, 1);
setYanz(cuoYanz)
}
})
if (!flag) {
score = 0;
}
const schema = {
id,
desc,
the_score: score,
options: options,
selected: selectedArr
}
setNewSchema(schema);
}
return (
<div className=''>
{
options.map((item, index) => (
<div className={styles.wrapper}>
{
getTag(index, finish, yanz)
}
<Checkbox key={index} defaultChecked={item.selected} onChange={() => { onChange(item) }}>{char[index]}、{item.label}</Checkbox>
<br />
</div>
))
}
</div>
)
};
export default forwardRef(Question);
style.module.scss
.wrapper{
position: relative;
.duicuo{
position: absolute;
top:14px;
left: 10px;
z-index: 9999;
color: red;
font-weight: bold;
}
}
3.最终效果
总结
最近还是学了一点东西,但是感觉熟练度还是欠佳,还在写一个个人博客的小网站,用的东西还是挺多的,这篇博客写完就得开始动手赶作业了,好久没写作业了。