React16源码: React.Children源码实现

React.Children


1 ) 概述

  • 这个API用的也比较的少,因为大部分情况下,我们不会单独去操作children
  • 我们在一个组件内部拿到 props 的时候,我们有props.children这么一个属性
  • 大部分情况下,直接把 props.children 把它渲染到我们的jsx 里面就可以了
  • 很少有情况需要去操作一下这个children,但是一旦需要去操作这个children呢
    • 直接使用react点children的API,而不是你直接去操作dom
    • 大部分时候拿到的 children,可能是一个合理的react element,或者是一个数组
  • React提供Children这个API去操作它,一定是有一个合理的原因的

2 )示例演示

import React from 'react'function ChildrenDemo(props) {console.log(props.children)console.log(React.Children.map(props.children, c => [c, c]))return props.children
}export default () => (<ChildrenDemo><span>1</span><span>2</span></ChildrenDemo>
)
  • 上面这个代码非常简单,创建了一个组件叫 ChildrenDemo
    • 里面有两个 span 作为children,在 props.children 里面,就可以拿到
  • 第一个打印出来的就是 props.children
    • 它就是两个 react element 节点
  • 第二个打印的是 map 的返回值
    • 我们通过react.children.map, 传入这个props.children 和一个callback
    • 这个callback,返回的是一个数组, 这个数组里面,包含两个相同的节点
      • 那这时候打印出来的是4个节点
      • 也就是每个span都被克隆成2份,2个span是4份
      • 前两个children 都是1,后两个都是2
    • 再来改一下 console.log(React.Children.map(props.children, c => [c, [c, c]]))
      • 它会输出六个节点
      • 0, 1, 2,的children是 1
      • 3, 4, 5 的 children 是2
      • 也就是说 react.children的map function返回的是一个数组,它会继续把它展开
      • 里面不管传了多少层嵌套的数组,最终都会展开成一层数组,即: 被拍平
    • 拍平后有几个元素,map中的当前child就会被克隆成几份
  • 这就是 React.Children.map,跟普通原生的数组.map 的一个本质区别

3 )源码分析

定位到 React.js 中

const React = {Children: {map,forEach,count,toArray,only,},// ... 省略其他
};
  • 这个对象里面有五个函数,跟原生数组操作非常的像
  • 前两个是最重要的,就是map 和 forEach, 它和数组的意义是一样的
  • 但它实际的操作可能跟数组的map和forEach会有一定的区别
  • map是这些方法所有逻辑里面最复杂的一个,而 map 和 forEach 是差不多的
    • 它们唯一的区别是一个有返回一个没有返回
    • map是通过我们传入的一个方法之后,返回的一个新的数组
    • 而forEach 中只在 null 的判断中返回,其实并非真实的返回值

再定位到 ReactChildren.js 中

/*** Copyright (c) Facebook, Inc. and its affiliates.** This source code is licensed under the MIT license found in the* LICENSE file in the root directory of this source tree.*/import invariant from 'shared/invariant';
import warning from 'shared/warning';
import {getIteratorFn,REACT_ELEMENT_TYPE,REACT_PORTAL_TYPE,
} from 'shared/ReactSymbols';import {isValidElement, cloneAndReplaceKey} from './ReactElement';
import ReactDebugCurrentFrame from './ReactDebugCurrentFrame';const SEPARATOR = '.';
const SUBSEPARATOR = ':';/*** Escape and wrap key so it is safe to use as a reactid** @param {string} key to be escaped.* @return {string} the escaped key.*/
function escape(key) {const escapeRegex = /[=:]/g;const escaperLookup = {'=': '=0',':': '=2',};const escapedString = ('' + key).replace(escapeRegex, function(match) {return escaperLookup[match];});return '$' + escapedString;
}/*** TODO: Test that a single child and an array with one item have the same key* pattern.*/let didWarnAboutMaps = false;const userProvidedKeyEscapeRegex = /\/+/g;
function escapeUserProvidedKey(text) {return ('' + text).replace(userProvidedKeyEscapeRegex, '$&/');
}const POOL_SIZE = 10;
const traverseContextPool = [];
function getPooledTraverseContext(mapResult,keyPrefix,mapFunction,mapContext,
) {if (traverseContextPool.length) {const traverseContext = traverseContextPool.pop();traverseContext.result = mapResult;traverseContext.keyPrefix = keyPrefix;traverseContext.func = mapFunction;traverseContext.context = mapContext;traverseContext.count = 0;return traverseContext;} else {return {result: mapResult,keyPrefix: keyPrefix,func: mapFunction,context: mapContext,count: 0,};}
}function releaseTraverseContext(traverseContext) {traverseContext.result = null;traverseContext.keyPrefix = null;traverseContext.func = null;traverseContext.context = null;traverseContext.count = 0;if (traverseContextPool.length < POOL_SIZE) {traverseContextPool.push(traverseContext);}
}/*** @param {?*} children Children tree container.* @param {!string} nameSoFar Name of the key path so far.* @param {!function} callback Callback to invoke with each child found.* @param {?*} traverseContext Used to pass information throughout the traversal* process.* @return {!number} The number of children in this subtree.*/
function traverseAllChildrenImpl(children,nameSoFar,callback,traverseContext,
) {const type = typeof children;if (type === 'undefined' || type === 'boolean') {// All of the above are perceived as null.children = null;}let invokeCallback = false;if (children === null) {invokeCallback = true;} else {switch (type) {case 'string':case 'number':invokeCallback = true;break;case 'object':switch (children.$$typeof) {case REACT_ELEMENT_TYPE:case REACT_PORTAL_TYPE:invokeCallback = true;}}}if (invokeCallback) {callback(traverseContext,children,// If it's the only child, treat the name as if it was wrapped in an array// so that it's consistent if the number of children grows.nameSoFar === '' ? SEPARATOR + getComponentKey(children, 0) : nameSoFar,);return 1;}let child;let nextName;let subtreeCount = 0; // Count of children found in the current subtree.const nextNamePrefix =nameSoFar === '' ? SEPARATOR : nameSoFar + SUBSEPARATOR;if (Array.isArray(children)) {for (let i = 0; i < children.length; i++) {child = children[i];nextName = nextNamePrefix + getComponentKey(child, i);subtreeCount += traverseAllChildrenImpl(child,nextName,callback,traverseContext,);}} else {const iteratorFn = getIteratorFn(children);if (typeof iteratorFn === 'function') {if (__DEV__) {// Warn about using Maps as childrenif (iteratorFn === children.entries) {warning(didWarnAboutMaps,'Using Maps as children is unsupported and will likely yield ' +'unexpected results. Convert it to a sequence/iterable of keyed ' +'ReactElements instead.',);didWarnAboutMaps = true;}}const iterator = iteratorFn.call(children);let step;let ii = 0;while (!(step = iterator.next()).done) {child = step.value;nextName = nextNamePrefix + getComponentKey(child, ii++);subtreeCount += traverseAllChildrenImpl(child,nextName,callback,traverseContext,);}} else if (type === 'object') {let addendum = '';if (__DEV__) {addendum =' If you meant to render a collection of children, use an array ' +'instead.' +ReactDebugCurrentFrame.getStackAddendum();}const childrenString = '' + children;invariant(false,'Objects are not valid as a React child (found: %s).%s',childrenString === '[object Object]'? 'object with keys {' + Object.keys(children).join(', ') + '}': childrenString,addendum,);}}return subtreeCount;
}/*** Traverses children that are typically specified as `props.children`, but* might also be specified through attributes:** - `traverseAllChildren(this.props.children, ...)`* - `traverseAllChildren(this.props.leftPanelChildren, ...)`** The `traverseContext` is an optional argument that is passed through the* entire traversal. It can be used to store accumulations or anything else that* the callback might find relevant.** @param {?*} children Children tree object.* @param {!function} callback To invoke upon traversing each child.* @param {?*} traverseContext Context for traversal.* @return {!number} The number of children in this subtree.*/
function traverseAllChildren(children, callback, traverseContext) {if (children == null) {return 0;}return traverseAllChildrenImpl(children, '', callback, traverseContext);
}/*** Generate a key string that identifies a component within a set.** @param {*} component A component that could contain a manual key.* @param {number} index Index that is used if a manual key is not provided.* @return {string}*/
function getComponentKey(component, index) {// Do some typechecking here since we call this blindly. We want to ensure// that we don't block potential future ES APIs.if (typeof component === 'object' &&component !== null &&component.key != null) {// Explicit keyreturn escape(component.key);}// Implicit key determined by the index in the setreturn index.toString(36);
}function forEachSingleChild(bookKeeping, child, name) {const {func, context} = bookKeeping;func.call(context, child, bookKeeping.count++);
}/*** Iterates through children that are typically specified as `props.children`.** See https://reactjs.org/docs/react-api.html#reactchildrenforeach** The provided forEachFunc(child, index) will be called for each* leaf child.** @param {?*} children Children tree container.* @param {function(*, int)} forEachFunc* @param {*} forEachContext Context for forEachContext.*/
function forEachChildren(children, forEachFunc, forEachContext) {if (children == null) {return children;}const traverseContext = getPooledTraverseContext(null,null,forEachFunc,forEachContext,);traverseAllChildren(children, forEachSingleChild, traverseContext);releaseTraverseContext(traverseContext);
}function mapSingleChildIntoContext(bookKeeping, child, childKey) {const {result, keyPrefix, func, context} = bookKeeping;let mappedChild = func.call(context, child, bookKeeping.count++);if (Array.isArray(mappedChild)) {mapIntoWithKeyPrefixInternal(mappedChild, result, childKey, c => c);} else if (mappedChild != null) {if (isValidElement(mappedChild)) {mappedChild = cloneAndReplaceKey(mappedChild,// Keep both the (mapped) and old keys if they differ, just as// traverseAllChildren used to do for objects as childrenkeyPrefix +(mappedChild.key && (!child || child.key !== mappedChild.key)? escapeUserProvidedKey(mappedChild.key) + '/': '') +childKey,);}result.push(mappedChild);}
}function mapIntoWithKeyPrefixInternal(children, array, prefix, func, context) {let escapedPrefix = '';if (prefix != null) {escapedPrefix = escapeUserProvidedKey(prefix) + '/';}const traverseContext = getPooledTraverseContext(array,escapedPrefix,func,context,);traverseAllChildren(children, mapSingleChildIntoContext, traverseContext);releaseTraverseContext(traverseContext);
}/*** Maps children that are typically specified as `props.children`.** See https://reactjs.org/docs/react-api.html#reactchildrenmap** The provided mapFunction(child, key, index) will be called for each* leaf child.** @param {?*} children Children tree container.* @param {function(*, int)} func The map function.* @param {*} context Context for mapFunction.* @return {object} Object containing the ordered map of results.*/
function mapChildren(children, func, context) {if (children == null) {return children;}const result = [];mapIntoWithKeyPrefixInternal(children, result, null, func, context);return result;
}/*** Count the number of children that are typically specified as* `props.children`.** See https://reactjs.org/docs/react-api.html#reactchildrencount** @param {?*} children Children tree container.* @return {number} The number of children.*/
function countChildren(children) {return traverseAllChildren(children, () => null, null);
}/*** Flatten a children object (typically specified as `props.children`) and* return an array with appropriately re-keyed children.** See https://reactjs.org/docs/react-api.html#reactchildrentoarray*/
function toArray(children) {const result = [];mapIntoWithKeyPrefixInternal(children, result, null, child => child);return result;
}/*** Returns the first child in a collection of children and verifies that there* is only one child in the collection.** See https://reactjs.org/docs/react-api.html#reactchildrenonly** The current implementation of this function assumes that a single child gets* passed without a wrapper, but the purpose of this helper function is to* abstract away the particular structure of children.** @param {?object} children Child collection structure.* @return {ReactElement} The first and only `ReactElement` contained in the* structure.*/
function onlyChild(children) {invariant(isValidElement(children),'React.Children.only expected to receive a single React element child.',);return children;
}export {forEachChildren as forEach,mapChildren as map,countChildren as count,onlyChild as only,toArray,
};
  • 翻到最下面,看到 mapChildren as map,这边 export 出去的是 map

  • 对应的,我们来看 mapchildren 这个方法

    /*** Maps children that are typically specified as `props.children`.** See https://reactjs.org/docs/react-api.html#reactchildrenmap** The provided mapFunction(child, key, index) will be called for each* leaf child.** @param {?*} children Children tree container.* @param {function(*, int)} func The map function.* @param {*} context Context for mapFunction.* @return {object} Object containing the ordered map of results.*/
    function mapChildren(children, func, context) {if (children == null) {return children;}const result = [];mapIntoWithKeyPrefixInternal(children, result, null, func, context);return result;
    }
    
    • 开始会调用一个方法叫 mapIntoWithKeyPrefixInternal

       function mapIntoWithKeyPrefixInternal(children, array, prefix, func, context) {let escapedPrefix = '';if (prefix != null) {escapedPrefix = escapeUserProvidedKey(prefix) + '/';}const traverseContext = getPooledTraverseContext(array,escapedPrefix,func,context,);traverseAllChildren(children, mapSingleChildIntoContext, traverseContext);releaseTraverseContext(traverseContext);
      }
      
    • 代码上是先处理了一下 escapedPrefix, 这个倒没什么,后面调用的方法和 forEachChildren 是差不多的

    • 进入这里的 getPooledTraverseContext 方法

    • 它先判断是否已有存在池中是否节点,如果有,则pop一个

    • 并将传入的内容都挂载到这个pop出来的对象上面,用于记录

    • 再经过一系列作用之后,执行到上面的 releaseTraverseContext 就是对对象进行清空

    • 上面的过程涉及到了一个对象池的概念,也就是缓存池,用于节省操作的性能

      • js是单线程语言,对大量对象进行操作,比如挂载和删除,可能会造成内存抖动的问题
      • 可能导致浏览器内的页面性能很差
      • 它设置Pool Size的大小是 10,是一个渐进的过程
      • 一开始是空的,随着对象的创建会进行缓存,接着复用
    • 总体来说,它会做一个非常重要的事情,就是到一个叫做 contextPool 的地方去获取一个 context

    • 接下去所有流程都是在这个函数里面调用了 traverseAllChildren 这个方法

    • 调用完所有的方法之后,它会把这个context再返回到这个 contextPool 里面

    • 调用的 traverseAllChildren 方法没有什么操作,本质上调了 traverseAllChildrenImpl 的方法

      /*** Traverses children that are typically specified as `props.children`, but* might also be specified through attributes:** - `traverseAllChildren(this.props.children, ...)`* - `traverseAllChildren(this.props.leftPanelChildren, ...)`** The `traverseContext` is an optional argument that is passed through the* entire traversal. It can be used to store accumulations or anything else that* the callback might find relevant.** @param {?*} children Children tree object.* @param {!function} callback To invoke upon traversing each child.* @param {?*} traverseContext Context for traversal.* @return {!number} The number of children in this subtree.*/
      function traverseAllChildren(children, callback, traverseContext) {if (children == null) {return 0;}return traverseAllChildrenImpl(children, '', callback, traverseContext);
      }
      
    • 进入 traverseAllChildrenImpl 这个方法会判断我们的children是否是一个数组或者是一个iterator对象

    • 这代表它们是多个节点是可以遍历的, 如果它是多个节点,它会去循环每一个节点

    • 然后对每一个节点再重新调用这个 traverseAllChildrenImpl 这个方法, 也就是递归实现

    • 最终要传入这个 traverseAllChildrenImpl 方法的children,是以单个节点的时候

    • 才会去执行真正的 mapSingleChildIntoContext 方法, 在这个方法里面会调用

    • React.Children.map 传入的第二个参数,也就是那个map function

    • 它会传入上面遍历出来的最终的单个节点,返回想要的map结果的一个数据

    • 拿到一个map数据之后,它会进行一个判断,是否是数组,如果不是数组

    • 它会在result中插入克隆节点,并替换key,防止有相同的key出现

    • 如果是数组的话,又会回过头来去调用这个 mapIntoWithKeyPrefixInternal,到这里完成了一个大的递归

    • 在这么一个递归的过程下去,最终是把里面返回的所有层级的数组都进行了一个展开

    • 展开之后就变成了一个一维数组, 这就是它的一个整体的流程

  • 然后再来对比一下 forEachChildren

    /**
    * Iterates through children that are typically specified as `props.children`.
    *
    * See https://reactjs.org/docs/react-api.html#reactchildrenforeach
    *
    * The provided forEachFunc(child, index) will be called for each
    * leaf child.
    *
    * @param {?*} children Children tree container.
    * @param {function(*, int)} forEachFunc
    * @param {*} forEachContext Context for forEachContext.
    */
    function forEachChildren(children, forEachFunc, forEachContext) {if (children == null) {return children;}const traverseContext = getPooledTraverseContext(null,null,forEachFunc,forEachContext,);traverseAllChildren(children, forEachSingleChild, traverseContext);releaseTraverseContext(traverseContext);
    }
    
    • 可以看到它最后没有 return,这就是 forEachChildrenmapChildren 的本质区别
  • 关于export 出去的 toArray

    function toArray(children) {const result = [];mapIntoWithKeyPrefixInternal(children, result, null, child => child);return result;
    }
    
    • toArraymapChildren 唯一的区别就是 map function
    • 换句话说,它的map function,其实就是 child => child
    • 它其实也会把数组展开,只是说没有map的过程
  • 还有 export 出去的 onlyChild

    function onlyChild(children) {invariant(isValidElement(children),'React.Children.only expected to receive a single React element child.',);return children;
    }
    
    • 其实就是判断一下这个children是否是单个的合理的 react element 节点
    • 如果是的话,就返回,不是的话,给出提醒
  • 最后 export 出去的 countChildren

    function countChildren(children) {return traverseAllChildren(children, () => null, null);
    }
    
    • 内部调用 traverseAllChildren, 本质上还是调用 traverseAllChildrenImpl
    • 最终返回的是统计后的值 subtreeCount
  • 最后还有一个 节点 key 相关的处理,主要核心实现是在 getComponentKey 也是个递归的处理

    • 打印出的每个节点上,都会有一个key,这个key的处理也是比较核心的
    • 参考 ChildrenDemo中的 React.Children.map 中的回调 c => [c, [c,c]] 这里会总计打印出6个节点
      • 可以看到第一个节点是 .0/.0
      • 然后第二个节点是 .0/.1:0
      • 然后第三个节点是 .0/.1:1
    • 可以按照上述函数和顶层声明的两个变量 SEPARATORSUBSEPARATOR
    • 理解下这个打印出的结果

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/592372.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

蓝牙物联网智能车用语音控制系统模块设计

随着信息产业的快速发展&#xff0c;简单的控制操作机器已经不能满足人类的欲望&#xff0c;利用语音识别技术让机器理解人类的语言&#xff0c;以及实现人机交互成为新的研究内容。对用户来说&#xff0c;这种人机交互的方式当是最自然的一种方式。同时&#xff0c;使人们在车…

塔夫特原则

塔夫特原则&#xff08;Tuftes Principles&#xff09;是由数据可视化专家爱德华塔夫特&#xff08;Edward Tufte&#xff09;提出的一组指导性原则&#xff0c;旨在帮助人们创建清晰、有效和有力的数据可视化图表。这些原则强调了以数据为核心&#xff0c;通过简洁、准确和易于…

【Java开发岗面试】八股文—Java虚拟机(JVM)

声明&#xff1a; 背景&#xff1a;本人为24届双非硕校招生&#xff0c;已经完整经历了一次秋招&#xff0c;拿到了三个offer。本专题旨在分享自己的一些Java开发岗面试经验&#xff08;主要是校招&#xff09;&#xff0c;包括我自己总结的八股文、算法、项目介绍、HR面和面试…

小球自由下落-第11届蓝桥杯选拔赛Python真题精选

[导读]&#xff1a;超平老师的Scratch蓝桥杯真题解读系列在推出之后&#xff0c;受到了广大老师和家长的好评&#xff0c;非常感谢各位的认可和厚爱。作为回馈&#xff0c;超平老师计划推出《Python蓝桥杯真题解析100讲》&#xff0c;这是解读系列的第23讲。 小球自由下落&…

python flask-wft

这个放在前面你个表单的博客内容 精髓放这 from flask import Flask from flask import render_template from flask_wtf import FlaskForm from wtforms.fields import (StringField, PasswordField, DateField, BooleanField,SelectField, SelectMultipleField, TextAreaFi…

第一个Qt程序----Hello word!

从今天起就开始我们的第一个Qt小程序&#xff0c;点击New Project后点击右侧的Application后点击Qt Widgets Application。Qt Widgets 模块提供了一组UI元素用于创建经典的桌面风格的用户界面&#xff0c;Widgets是小部件的意思&#xff0c;也可以称为控件&#xff0c;因此Qt …

粒子群优化pso结合bp神经网络优化对csv文件预测matlab(3)

1.csv数据为密西西比数据集&#xff0c;获取数据集可以管我要&#xff0c;数据集内容形式如下图&#xff1a; 2.代码 这里参考的是b站的一位博主。 数据集导入教程在我的另一篇文章bp写过&#xff0c;需要的话可以去看一下 psobp.m close all clc%读取数据 inputX; outputY;…

在 Android 上使用 MediaExtractor 和 MediaMuxer 提取视频\提取音频\转封装\添加音频等操作

文章目录 前言一、MediaExtractor 基本介绍与使用二、MediaMuxer 基本介绍与使用示例提取视频提取音频混合视频与音频文件 总结参考 前言 之前我们介绍了 FFmpeg 并利用它解封装、编解码的能力完成了一款简易的视频播放器。FFmpeg 是由 C 实现的&#xff0c;集成至 Android 等…

JVM中部分主要垃圾回收器的特点、使用的算法以及适用场景

JVM中部分主要垃圾回收器的特点、使用的算法以及适用场景&#xff1a; Serial GC&#xff08;串行收集器&#xff09; 特点&#xff1a;单线程执行&#xff0c;对新生代进行垃圾回收时采用复制算法&#xff08;Copying&#xff09;&#xff0c;在老年代可能使用标记-压缩或标记…

(学习打卡2)重学Java设计模式之六大设计原则

前言&#xff1a;听说有本很牛的关于Java设计模式的书——重学Java设计模式&#xff0c;然后买了(*^▽^*) 开始跟着小傅哥学Java设计模式吧&#xff0c;本文主要记录笔者的学习笔记和心得。 打卡&#xff01;打卡&#xff01; 六大设计原则 &#xff08;引读&#xff1a;这里…

K8S本地开发环境-minikube安装部署及实践

引言 在上一篇介绍了k8s的入门和实战&#xff0c;本章就来介绍一下在windows环境如何使用minikube搭建K8s集群&#xff0c;好了废话不多说&#xff0c;下面就和我一起了解Minikube吧。 什么是Minikube&#xff1f; Minikube 是一种轻量级的 Kubernetes 实现&#xff0c;可在本…

【docker】安装 Redis

查看可用的 redis版本 docker search redis拉取 redis最新镜像 docker pull redis:latest查看本地镜像 docker images创建挂在文件 mkdir -pv /test1/docker_volume/redis/datamkdir -pv /test1/docker_volume/redis/confcd /test1/docker_volume/redis/conf/touch redis.con…

IPC之十二:使用libdbus在D-Bus上异步发送/接收信号的实例

IPC 是 Linux 编程中一个重要的概念&#xff0c;IPC 有多种方式&#xff0c;本 IPC 系列文章的前十篇介绍了几乎所有的常用的 IPC 方法&#xff0c;每种方法都给出了具体实例&#xff0c;前面的文章里介绍了 D-Bus 的基本概念以及调用远程方法的实例&#xff0c;本文介绍 D-Bus…

[Angular] 笔记 23:Renderer2 - ElementRef 的生产版本

chatgpt: Renderer2 简介 在 Angular 中&#xff0c;Renderer2 是一个服务&#xff0c;用于处理 DOM 操作的抽象层。它提供了一种安全的方式来操作 DOM&#xff0c;同时与平台无关&#xff0c;有助于维护应用程序的跨浏览器兼容性和安全性。 Renderer2 的作用是在 Angular 组…

【C++】浅拷贝 / 深拷贝 / 写时拷贝

文章目录 1. 经典的string类问题2. 浅拷贝3. 深拷贝3.1 传统写法的String类3.2 现代写法的String类 4. 写时拷贝 1. 经典的string类问题 上一篇博客已经对string类进行了简单的介绍&#xff0c;大家只要能够正常使用即可。 链接&#xff1a;【C】string 在面试中&#xff0c;面…

20 太空漫游

效果演示 实现了一个太空漫游的动画效果&#xff0c;其中包括火箭、星星和月亮。当鼠标悬停在卡片上时&#xff0c;太阳和星星会变成黄色&#xff0c;火箭会变成飞机&#xff0c;月亮会变成小型的月亮。整个效果非常炫酷&#xff0c;可以让人想起科幻电影中的太空漫游。 Code &…

计算机网络(7):网络安全

网络安全问题 计算机网络上的通信面临以下的四种威胁: (1)截获(interception)攻击者从网络上窃听他人的通信内容。 (2)中断(interruption)攻击者有意中断他人在网络上的通信。 (3)篡改(modification)攻击者故意篡改网络上传送的报文。 (4)伪造(fabrication)攻击者伪造信息在网…

Python通过用户输入两个数字并计算两个

通过用户输入两个数字&#xff0c;并计算两个 以下实例为通过用户输入两个数字&#xff0c;并计算两个数字之和&#xff1a; 实例(Python 3.0) # -*- coding: UTF-8 -*-# Filename : test.py # author by : www.dida100.com# 用户输入数字 num1 input(输入第一个数字&#…

C# WinForm MessageBox自定义按键文本 COM组件版

c# 更改弹窗MessageBox按钮文字_c# messagebox.show 字体-CSDN博客 需要用到大佬上传到百度云盘的Hook类&#xff0c;在大佬给的例子的基础上改动了点。 加了ok按键&#xff0c;还原了最基础的messageBox。 为了适配多语言&#xff0c;增加ReadBtnLanguge方法。 应用时自己…

开发辅助三(缓存Redisson分布式锁+分页插件)

缓存 缓存穿透&#xff1a;查询一个不存在的数据&#xff0c;由于缓存不命中&#xff0c;将大量查询数据库&#xff0c;但是数据库也没有此记录。 没有将这次查询的null写入缓存&#xff0c;导致了这个不存在的数据每次请求都要到存储层查询&#xff0c;失去了缓存的意义。 解…