项目演示地址

项目演示地址

项目源码

项目源码

其他版本教程

Vue版本

小程序版本

项目代码结构

前言

React 框架的优雅不言而喻,组件化的编程思想使得React框架开发的项目代码简洁,易懂,但早期 React 类组件的写法略显繁琐。React Hooks 是 React 16.8 发布以来最吸引人的特性之一,她简化了原有代码的编写,是未来 React 应用的主流写法。

本文通过一个实战小项目,手把手从零开始带领大家快速入门React Hooks。本项目线上演示地址:

在本项目中,会用到以下知识点:

  • React 组件化设计思想
  • React State 和 Props
  • React 函数式组件的使用
  • React Hooks useState 的使用
  • React Hooks useEffect 的使用
  • React 使用 Axios 请求远程接口获取问题及答案
  • React 使用Bootstrap美化界面

Hello React

(1)安装node.js 官网链接

(2)安装vscode 官网链接

(3)安装 creat-react-app 功能组件,该组件可以用来初始化一个项目, 即按照一定的目录结构,生成一个新项目。

打开cmd 窗口 输入:

  1. npm install --g create-react-app
  2. npm install --g yarn

(-g 代表全局安装)

如果安装失败或较慢。需要换源,可以使用淘宝NPM镜像,设置方法为:

  1. npm config set registry https://registry.npm.taobao.org

设置完成后,重新执行

  1. npm install --g create-react-app
  2. npm install --g yarn

(4)在你想创建项目的目录下 例如 D:/project/ 打开cmd命令 输入

  1. create-react-app react-exam

去使用creat-react-app命令创建名字是react-exam的项目

安装完成后,移至新创建的目录并启动项目

  1. cd react-exam
  2. yarn start

一旦运行此命令,localhost:3000新的React应用程序将弹出一个新窗口。

项目目录结构

右键react-exam目录,使用vscode打开该目录。

react-exam项目目录中有一个/public和/src目录,以及node_modules,.gitignore,README.md,和package.json。

在目录/public中,重要文件是index.html,其中一行代码最重要

  1. <div id="root"></div>

该div做为我们整个应用的挂载点

/src目录将包含我们所有的React代码。

要查看环境如何自动编译和更新您的React代码,请找到文件/src/App.js

将其中的

  1. <a
  2. className="App-link"
  3. href="https://reactjs.org"
  4. target="_blank"
  5. rel="noopener noreferrer"
  6. >
  7. Learn React
  8. </a>

修改为

  1. <a
  2. className="App-link"
  3. href="https://reactjs.org"
  4. target="_blank"
  5. rel="noopener noreferrer"
  6. >
  7. 和豆约翰 Learn React
  8. </a>

保存文件后,您会注意到localhost:3000编译并刷新了新数据。

React-Exam项目实战

1. 首页制作

1.安装项目依赖,在package.json中添加:

  1. "dependencies": {
  2. "@testing-library/jest-dom": "^4.2.4",
  3. "@testing-library/react": "^9.3.2",
  4. "@testing-library/user-event": "^7.1.2",
  5. "react": "^16.13.1",
  6. "react-dom": "^16.13.1",
  7. "react-scripts": "3.4.1",
  8. "axios": "^0.19.2",
  9. "bootstrap": "^4.5.0",
  10. "he": "^1.2.0",
  11. "react-loading": "^2.0.3",
  12. "reactstrap": "^8.4.1"
  13. },

执行命令:

  1. yarn install

修改index.js,导入bootstrap样式

  1. import "bootstrap/dist/css/bootstrap.min.css";

修改App.css代码

  1. html {
  2. width: 80%;
  3. margin-left: 10%;
  4. margin-top: 2%;
  5. }
  6. .ansButton {
  7. margin-right: 4%;
  8. margin-top: 4%;
  9. }

修改App.js,引入Quiz组件

  1. import React from 'react';
  2. import './App.css'
  3. import { Quiz } from './Exam/Quiz';
  4. function App() {
  5. return (
  6. <div className = 'layout'>
  7. <Quiz></Quiz>
  8. </div>
  9. );
  10. }
  11. export default App;

在项目src目录下新增Exam目录,Exam目录中新建Quiz.js

Quiz组件的定义如下:

Quiz.js,引入开始页面组件Toggle。

  1. import React, { useState } from "react";
  2. import { Toggle } from "./Toggle";
  3. export const Quiz = () => {
  4. const [questionData, setQuestionData] = useState([]);
  5. const questions = questionData.map(({ question }) => [question]);
  6. const answers = questionData.map(({ incorrect_answers, correct_answer }) =>
  7. [correct_answer, incorrect_answers].flat()
  8. );
  9. return (
  10. <>
  11. <Toggle
  12. setQuestionData={setQuestionData}
  13. />
  14. </>
  15. );
  16. };

Toggle.js,点击开始按钮,通过axios访问远程接口,获得题目及答案。

  1. import React from "react";
  2. import axios from "axios";
  3. import ToggleHeader from "./ToggleHeader";
  4. import {
  5. Button,
  6. Form,
  7. } from "reactstrap";
  8. export const Toggle = ({
  9. setQuestionData,
  10. }) => {
  11. const getData = async () => {
  12. try {
  13. const incomingData = await axios.get(
  14. `https://opentdb.com/api.php?amount=10&category=18&difficulty=easy&type=multiple`
  15. );
  16. setQuestionData(incomingData.data.results);
  17. } catch (err) {
  18. console.error(err);
  19. }
  20. };
  21. return (
  22. <>
  23. <ToggleHeader />
  24. <Form
  25. onSubmit={(e) => {
  26. e.preventDefault();
  27. getData();
  28. }}
  29. >
  30. <Button color="primary">开始</Button>
  31. </Form>
  32. </>
  33. );
  34. };

ToggleHeader.js

  1. import React from "react";
  2. import { Jumbotron, Container} from "reactstrap";
  3. export default function ToggleHeader() {
  4. return (
  5. <Jumbotron fluid>
  6. <Container fluid>
  7. <h1 className="display-4">计算机知识小测验</h1>
  8. </Container>
  9. </Jumbotron>
  10. );
  11. }

https://opentdb.com/api.php接口返回的json数据格式为

  1. {
  2. "response_code": 0,
  3. "results": [{
  4. "category": "Science: Computers",
  5. "type": "multiple",
  6. "difficulty": "easy",
  7. "question": "The numbering system with a radix of 16 is more commonly referred to as ",
  8. "correct_answer": "Hexidecimal",
  9. "incorrect_answers": ["Binary", "Duodecimal", "Octal"]
  10. }, {
  11. "category": "Science: Computers",
  12. "type": "multiple",
  13. "difficulty": "easy",
  14. "question": "This mobile OS held the largest market share in 2012.",
  15. "correct_answer": "iOS",
  16. "incorrect_answers": ["Android", "BlackBerry", "Symbian"]
  17. }, {
  18. "category": "Science: Computers",
  19. "type": "multiple",
  20. "difficulty": "easy",
  21. "question": "How many values can a single byte represent?",
  22. "correct_answer": "256",
  23. "incorrect_answers": ["8", "1", "1024"]
  24. }, {
  25. "category": "Science: Computers",
  26. "type": "multiple",
  27. "difficulty": "easy",
  28. "question": "In computing, what does MIDI stand for?",
  29. "correct_answer": "Musical Instrument Digital Interface",
  30. "incorrect_answers": ["Musical Interface of Digital Instruments", "Modular Interface of Digital Instruments", "Musical Instrument Data Interface"]
  31. }, {
  32. "category": "Science: Computers",
  33. "type": "multiple",
  34. "difficulty": "easy",
  35. "question": "In computing, what does LAN stand for?",
  36. "correct_answer": "Local Area Network",
  37. "incorrect_answers": ["Long Antenna Node", "Light Access Node", "Land Address Navigation"]
  38. }]
  39. }

程序运行效果:



当前项目目录结构为:

2. 问题展示页面

Quiz.js,新增toggleView变量用来切换视图。

  1. const [toggleView, setToggleView] = useState(true);

Quiz.js,其中Question和QuestionHeader 组件,参见后面。

  1. import { Question } from "./Question";
  2. import { Jumbotron } from "reactstrap";
  3. import QuestionHeader from "./QuestionHeader";
  4. ...
  5. export const Quiz = () => {
  6. var [index, setIndex] = useState(0);
  7. const [questionData, setQuestionData] = useState([]);
  8. ...
  9. return (
  10. <>
  11. {toggleView && (
  12. <Toggle
  13. setIndex={setIndex}
  14. setQuestionData={setQuestionData}
  15. setToggleView={setToggleView}
  16. />
  17. )}
  18. {!toggleView &&
  19. (
  20. <Jumbotron>
  21. <QuestionHeader
  22. setToggleView={setToggleView}
  23. />
  24. <Question question={questions[index]} />
  25. </Jumbotron>
  26. )}
  27. </>
  28. );

使用index控制题目索引

  1. var [index, setIndex] = useState(0);

修改Toggle.js

获取完远程数据,通过setToggleView(false);切换视图。

  1. export const Toggle = ({
  2. setQuestionData,
  3. setToggleView,
  4. setIndex,
  5. }) => {
  6. ...
  7. return (
  8. <>
  9. <ToggleHeader />
  10. <Form
  11. onSubmit={(e) => {
  12. e.preventDefault();
  13. getData();
  14. setToggleView(false);
  15. setIndex(0);
  16. }}
  17. >
  18. <Button color="primary">开始</Button>
  19. </Form>
  20. </>
  21. );
  22. };

QuestionHeader.js代码:

同样的,点击 返回首页按钮 setToggleView(true),切换视图。

  1. import React from "react";
  2. import { Button } from "reactstrap";
  3. export default function QuestionHeader({ setToggleView, category }) {
  4. return (
  5. <>
  6. <Button color="link" onClick={() => setToggleView(true)}>
  7. 返回首页
  8. </Button>
  9. </>
  10. );
  11. }

Question.js代码

接受父组件传过来的question对象,并显示。

其中he.decode是对字符串中的特殊字符进行转义。

  1. import React from "react";
  2. import he from "he";
  3. export const Question = ({ question }) => {
  4. // he is a oddly named library that decodes html into string values
  5. var decode = he.decode(String(question));
  6. return (
  7. <div>
  8. <hr className="my-2" />
  9. <h1 className="display-5">
  10. {decode}
  11. </h1>
  12. <hr className="my-2" />
  13. <br />
  14. </div>
  15. );
  16. };

程序运行效果:

首页



点击开始后,显示问题:

当前项目目录结构为:

3. 加载等待动画

新增LoadingSpin.js

  1. import React from "react";
  2. import { Spinner } from "reactstrap";
  3. export default function LoadingSpin() {
  4. return (
  5. <>
  6. <Spinner type="grow" color="primary" />
  7. <Spinner type="grow" color="secondary" />
  8. <Spinner type="grow" color="success" />
  9. <Spinner type="grow" color="danger" />
  10. </>
  11. );
  12. }

修改Quiz.js


  1. import LoadingSpin from "./LoadingSpin";
  2. export const Quiz = () => {
  3. const [isLoading, setLoading] = useState(false);
  4. return (
  5. <>
  6. {toggleView && (
  7. <Toggle
  8. ...
  9. setLoading={setLoading}
  10. />
  11. )}
  12. {!toggleView &&
  13. (isLoading ? (
  14. <LoadingSpin />
  15. ) :
  16. (
  17. ...
  18. ))}
  19. </>
  20. );
  21. };

修改Toggle.js

  1. export const Toggle = ({
  2. ...
  3. setLoading,
  4. }) => {
  5. const getData = async () => {
  6. try {
  7. setLoading(true);
  8. const incomingData = await axios.get(
  9. `https://opentdb.com/api.php?amount=10&category=18&difficulty=easy&type=multiple`
  10. );
  11. setQuestionData(incomingData.data.results);
  12. setLoading(false);
  13. } catch (err) {
  14. console.error(err);
  15. }
  16. };
  17. ...
  18. };

运行效果:



目前代码结构:

4. 实现下一题功能

新增Answer.js,用户点击下一题按钮,修改index,触发主界面刷新,显示下一题:

  1. import React from "react";
  2. import { Button } from "reactstrap";
  3. export const Answer = ({ setIndex, index }) => {
  4. function answerResult() {
  5. setIndex(index + 1);
  6. }
  7. return (
  8. <Button className="ansButton" onClick={answerResult}>
  9. 下一题
  10. </Button>
  11. );
  12. };

修改Quiz.js,添加Answer组件:

  1. import { Answer } from "./Answer";
  2. ...
  3. {!toggleView &&
  4. (isLoading ? (
  5. <LoadingSpin />
  6. ) :
  7. (
  8. <Jumbotron>
  9. ...
  10. <Answer
  11. setIndex={setIndex}
  12. index={index}
  13. />
  14. </Jumbotron>
  15. ))}

运行效果:



点击下一题:


5. 实现选项展示

新增AnswerList.js。

通过属性answers传进来的选项列表,需要被打乱顺序(shuffle )

  1. import React from "react";
  2. import { Answer } from "./Answer";
  3. export const AnswerList = ({ answers, index, setIndex }) => {
  4. if (answers) var correctAns = answers[0];
  5. const shuffle = (array) => {
  6. return array.sort(() => Math.random() - 0.5);
  7. };
  8. const arrayCheck = (arg) => {
  9. return Array.isArray(arg) ? arg : [];
  10. };
  11. return (
  12. <>
  13. {shuffle(arrayCheck(answers)).map((text,ind) => (
  14. <Answer
  15. text={text}
  16. correct={correctAns}
  17. setIndex={setIndex}
  18. index={index}
  19. key={ind}
  20. />
  21. ))}
  22. </>
  23. );
  24. };

修改Answer.js

  1. import React from "react";
  2. import he from "he";
  3. import { Button } from "reactstrap";
  4. export const Answer = ({ text, correct, setIndex, index }) => {
  5. function answerResult() {
  6. setIndex(index + 1);
  7. }
  8. var decode = he.decode(String(text));
  9. return (
  10. <Button className="ansButton" onClick={answerResult}>
  11. {decode}
  12. </Button>
  13. );
  14. };

修改Quiz.js

  1. // import { Answer } from "./Answer";
  2. import { AnswerList } from "./AnswerList";
  3. export const Quiz = () => {
  4. ...
  5. return (
  6. <>
  7. ...
  8. {!toggleView &&
  9. (isLoading ? (
  10. <LoadingSpin />
  11. ) :
  12. (
  13. ...
  14. <AnswerList
  15. answers={answers[index]}
  16. index={index}
  17. setIndex={setIndex}
  18. />
  19. </Jumbotron>
  20. ))}
  21. </>
  22. );
  23. };

运行效果:



项目结构:

6. 记录用户成绩

修改quiz.js,添加setResult,并传递给AnswerList


  1. export const Quiz = () => {
  2. var [result, setResult] = useState(null);
  3. ...
  4. return (
  5. <>
  6. ...
  7. {!toggleView &&
  8. (isLoading ? (
  9. <LoadingSpin />
  10. ) :
  11. (
  12. <Jumbotron>
  13. ...
  14. <AnswerList
  15. answers={answers[index]}
  16. index={index}
  17. setIndex={setIndex}
  18. setResult={setResult}
  19. />
  20. </Jumbotron>
  21. ))}
  22. </>
  23. );
  24. };

修改AnswerList.js,传递setResult

  1. import React from "react";
  2. import { Answer } from "./Answer";
  3. export const AnswerList = ({ answers, index,setResult, setIndex }) => {
  4. ...
  5. return (
  6. <>
  7. {shuffle(arrayCheck(answers)).map((text,ind) => (
  8. <Answer
  9. text={text}
  10. correct={correctAns}
  11. setIndex={setIndex}
  12. setResult={setResult}
  13. index={index}
  14. key={ind}
  15. />
  16. ))}
  17. </>
  18. );
  19. };

修改Answer.js,用户点击选项,回调setResult,通知Quiz组件,本次选择是对是错。

  1. import React from "react";
  2. import { Button } from "reactstrap";
  3. import he from 'he'
  4. export const Answer = ({ text, correct, setResult,setIndex, index }) => {
  5. function answerResult() {
  6. setIndex(index + 1);
  7. correct === text ? setResult(true) : setResult(false);
  8. }
  9. var decode = he.decode(String(text));
  10. return (
  11. <Button className="ansButton" onClick={answerResult}>
  12. {decode}
  13. </Button>
  14. );
  15. };

修改Quiz.js,放一个隐藏的GameOver组件,每当index发生变化的时候,触发GameOver中的useEffect代码,累计用户答对题目的数目(setRight)


  1. import GameOver from "./GameOver";
  2. export const Quiz = () => {
  3. const [right, setRight] = useState(0);
  4. const [gameIsOver, setGameOver] = useState(false);
  5. return (
  6. <>
  7. {toggleView && (
  8. <Toggle
  9. setIndex={setIndex}
  10. setQuestionData={setQuestionData}
  11. setToggleView={setToggleView}
  12. setLoading={setLoading}
  13. />
  14. )}
  15. {!toggleView &&
  16. (isLoading ? (
  17. <LoadingSpin />
  18. ) :
  19. (
  20. <Jumbotron>
  21. <QuestionHeader
  22. setToggleView={setToggleView}
  23. />
  24. <Question question={questions[index]} />
  25. <AnswerList
  26. answers={answers[index]}
  27. index={index}
  28. setIndex={setIndex}
  29. setResult={setResult}
  30. />
  31. </Jumbotron>
  32. ))}
  33. <GameOver
  34. right={right}
  35. setRight={setRight}
  36. quizLength={questions.length}
  37. setGameOver={setGameOver}
  38. result={result}
  39. index={index}
  40. />
  41. </>
  42. );
  43. };

新增GameOver.js组件,当index === quizLength && index时,setGameOver(true)设置游戏结束,显示用户得分。

  1. import React, { useEffect } from "react";
  2. export default function GameOver({
  3. right,
  4. setRight,
  5. setGameOver,
  6. index,
  7. quizLength,
  8. result,
  9. }) {
  10. useEffect(() => {
  11. if (result === true) {
  12. setRight(right + 1);
  13. }
  14. if (index === quizLength && index) {
  15. setGameOver(true);
  16. }
  17. }, [index]);
  18. return <div></div>;
  19. }

7. 游戏结束,展示用户得分

新增ScoreBoard.js

  1. import React from "react";
  2. export const ScoreBoard = ({ finalScore, right }) => {
  3. // if index === 0 then right === 0 --> this way when index is reset in toggle so is right answers
  4. const scoreFormatted = score => {
  5. if (score === 1) {
  6. return 100;
  7. } else if (score === 0) {
  8. return 0;
  9. } else {
  10. return score.toFixed(2) * 100;
  11. }
  12. }
  13. return (
  14. <>
  15. <>
  16. <h1 className="display-4">Correct Answers: {right}</h1>
  17. <hr className="my-2" />
  18. <h1 className="display-4">
  19. Final Score: %{scoreFormatted(finalScore)}
  20. </h1>
  21. <hr className="my-2" />
  22. </>
  23. <p>谢谢使用 </p>
  24. </>
  25. );
  26. };

ScoreHeader.js

  1. import React from "react";
  2. import { Button } from "reactstrap";
  3. export default function ScoreHeader({ setGameOver, setToggleView }) {
  4. return (
  5. <Button
  6. color="link"
  7. onClick={() => {
  8. setGameOver(false);
  9. setToggleView(true);
  10. }}
  11. >
  12. 返回首页
  13. </Button>
  14. );
  15. }

修改Quiz.js,当gameIsOver 变量为true时,显示得分页面。

  1. import { ScoreBoard } from "./ScoreBoard";
  2. import ScoreHeader from "./ScoreHeader";
  3. export const Quiz = () => {
  4. ...
  5. return (
  6. <>
  7. {!toggleView &&
  8. !gameIsOver &&
  9. (isLoading ? (
  10. <LoadingSpin />
  11. ) :
  12. (
  13. ...
  14. ))}
  15. {gameIsOver && (
  16. <Jumbotron>
  17. <ScoreHeader
  18. setToggleView={setToggleView}
  19. setGameOver={setGameOver}
  20. />
  21. <ScoreBoard right={right} finalScore={right / index} />
  22. </Jumbotron>
  23. )}
  24. ...
  25. </>
  26. );
  27. };

最后

从0开始,手把手教你使用React开发答题App的更多相关文章

  1. 手把手教你使用 Clion 开发 Linux C++ 项目

    手把手教你使用 Clion 开发 Linux C++ 项目 关于CLion CLion是一款专为开发C及C++所设计的跨平台IDE.它是以IntelliJ为基础设计的,包含了许多智能功能来提高开发人员 ...

  2. 手把手教你使用FineUI开发一个b/s结构的取送货管理信息系统系列博文索引

    近阶段接到一些b/s类型的软件项目,但是团队成员之前大部分没有这方面的开发经验,于是自己选择了一套目前网上比较容易上手的开发框架(FineUI),计划录制一套视频讲座,来讲解如何利用FineUI快速开 ...

  3. 手把手教你Chrome扩展开发:本地存储篇

    手把手教你开发chrome扩展一:开发Chrome Extenstion其实很简单 手把手教你开发Chrome扩展二:为html添加行为 手把手教你开发Chrome扩展三:关于本地存储数据 HTML5 ...

  4. 手把手教你搭建织女星开发板RISC-V开发环境

    前言 Windows环境下搭建基于Eclipse + RISC-V gcc编译器的RISC-V开发环境,配合openocd调试软件,可以实现RISC-V内核程序的编译.下载和调试. 准备工作 工欲善其 ...

  5. 0、手把手教React Native实战之开山篇

    ##作者简介 东方耀    Android开发   RN技术   facebook   github     android ios  原生开发   react reactjs nodejs 前端   ...

  6. React实战教程之从零开始手把手教你使用 React 最新特性Hooks API 打造一款计算机知识测验App

    项目演示地址 项目演示地址 项目代码结构 前言 React 框架的优雅不言而喻,组件化的编程思想使得React框架开发的项目代码简洁,易懂,但早期 React 类组件的写法略显繁琐.React Hoo ...

  7. 从0开始,手把手教你用Vue开发一个答题App01之项目创建及答题设置页面开发

    项目演示 项目演示 项目源码 项目源码 教程说明 本教程适合对Vue基础知识有一点了解,但不懂得综合运用,还未曾使用Vue从头开发过一个小型App的读者.本教程不对所有的Vue知识点进行讲解,而是手把 ...

  8. 从0开始,手把手教你用Vue开发一个答题App

    项目演示 项目演示 项目源码 项目源码 教程说明 本教程适合对Vue基础知识有一点了解,但不懂得综合运用,还未曾使用Vue从头开发过一个小型App的读者.本教程不对所有的Vue知识点进行讲解,而是手把 ...

  9. 倒计时0日!Apache DolphineScheduler4月 Meetup 大佬手把手教你大数据开发,离线调度

    随着互联网技术和信息技术的发展,信息的数据化产生了许多无法用常规工具量化.处理和捕捉的数字信息.面对多元的数据类型,海量的信息价值,如何有效地对大数据进行挖掘分析,对大数据工作流进行调度,是保障企业大 ...

随机推荐

  1. 需要加token验证的接口返回文件流下载

    没有加token之前,下载文件用的是a标签,直接下载. 现在要求是需要在header中加入token. getDownload(urls, fileName) { var url = urls; va ...

  2. Ubuntu安装protobuf步骤

    1.从谷歌官网获取源码 protobuf-2.4.1.tar.gz 2.解压 tar -zxvf protobuf-2.4.1.tar.gz 3.配置 ./configure 4.编译 make 5. ...

  3. Cypress系列(18)- 可操作类型的命令 之 点击命令

    如果想从头学起Cypress,可以看下面的系列文章哦 https://www.cnblogs.com/poloyy/category/1768839.html 前言 啥是可操作类型?就是可以和 DOM ...

  4. [转] linux操作系统下c语言编程入门--基础知识

    点击阅读原文 这篇文章介绍在LINUX下进行C语言编程所需要的基础知识.在这篇文章当中,我们将会学到以下内容: 1. 源程序编译        2. Makefile的编写        3. 程序库 ...

  5. @loj - 2106@ 「JLOI2015」有意义的字符串

    目录 @description@ @solution@ @accepted code@ @details@ @description@ B 君有两个好朋友,他们叫宁宁和冉冉.有一天,冉冉遇到了一个有趣 ...

  6. 拒绝降权!教你用 Python 确保制作的短视频独一无二

    1. 场景 前段时间有人私信我,说自己辛辛苦苦剪辑的短视频,上传到某平台后,由于播放量太大,收到 降权 的通知,直接导致这个账号废掉了! 其实,各大视频平台都有自己的一套鉴别算法,针对视频的二次创作, ...

  7. Windows 程序设计(3) 关于字符串

    1. 宽窄字节的区别及重要性 1.1 宽窄字节简介: C语言/C++语言,使用的字符串指针就是 char* 类型,C++中的字符串是 string,内部也是对 char* 的封装 窄字节 其实最早的系 ...

  8. ImportError: cannot import name _remove_dead_weakref

    出现这个错误, 和python环境有关. 电脑有多个版本造成的. python3 有这个_remove_dead_weakref python 2.7.10 并没有_remove_dead_weakr ...

  9. 重学 Java 设计模式:实战责任链模式「模拟618电商大促期间,项目上线流程多级负责人审批场景」

    作者:小傅哥 博客:https://bugstack.cn - 原创系列专题文章 沉淀.分享.成长,让自己和他人都能有所收获! 一.前言 场地和场景的重要性 射击

  10. SSL/TSL 原理( 握手原理和传输原理)

    本文参考<计算机网络 自顶向下方法> 目录 背景 通信的4要素 SSL/TLS in Detail 通讯保证 The Handshake Protocol 1. Initial Clien ...