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,这就是
forEachChildren
跟mapChildren
的本质区别
- 可以看到它最后没有 return,这就是
-
关于export 出去的
toArray
function toArray(children) {const result = [];mapIntoWithKeyPrefixInternal(children, result, null, child => child);return result; }
toArray
和mapChildren
唯一的区别就是 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
- …
- 可以按照上述函数和顶层声明的两个变量
SEPARATOR
和SUBSEPARATOR
- 理解下这个打印出的结果
相关文章:
React16源码: React.Children源码实现
React.Children 1 ) 概述 这个API用的也比较的少,因为大部分情况下,我们不会单独去操作children我们在一个组件内部拿到 props 的时候,我们有props.children这么一个属性大部分情况下,直接把 props.children 把它渲染到我们的jsx…...
深度学习|4.1 深L层神经网络 4.2 深层网络的正向传播
4.1 深L层神经网络 对于某些问题来说,深层神经网络相对于浅层神经网络解决该问题的效果会较好。所以问题就变成了神经网络层数的设置。 其中 n [ i ] n^{[i]} n[i]表示第i层神经节点的个数, w [ l ] w^{[l]} w[l]代表计算第l层所采用的权重系数ÿ…...
印象笔记03 衍生软件使用
印象笔记03 衍生软件使用 Verse 以下内容来源于官方介绍 VERSE是一款面向未来的智能化生产力工具,由印象笔记团队诚意推出。 你可以用VERSE: 管理数字内容,让信息有序高效运转;搭建知识体系,构建你的强大知识库&am…...
R语言【CoordinateCleaner】——cc_gbif(): 根据通过 method 参数定义的方法,删除或标记地理空间中异常值的记录。
cc_gbif()是R语言包coordinatecleaner中的一个函数,用于清理GBIF(全球生物多样性信息设施)数据集的地理坐标。该函数可以识别潜在的坐标错误,并对其进行修正或删除。 以下是cc_gbifl()函数的一般用法和主要参数: cc_…...
模式识别与机器学习-集成学习
集成学习 集成学习思想过拟合与欠拟合判断方法 K折交叉验证BootstrapBagging随机森林的特点和工作原理: BoostingAdaBoost工作原理:AdaBoost的特点和优点:AdaBoost的缺点: Gradient Boosting工作原理:Gradient Boostin…...
vue简单实现滚动条
背景:产品提了一个需求在一个详情页,一个form表单元素太多了,需要滚动到最下面才能点击提交按钮,很不方便。他的方案是,加一个滚动条,这样可以直接拉到最下面。 优化:1、支持滚动条,…...
计算机网络第一课
先了解层级: 传输的信息称为协议数据单元(PDU),PDU在每个层次的称呼都不同,见下图:...
初识大数据,一文掌握大数据必备知识文集(12)
🏆作者简介,普修罗双战士,一直追求不断学习和成长,在技术的道路上持续探索和实践。 🏆多年互联网行业从业经验,历任核心研发工程师,项目技术负责人。 🎉欢迎 👍点赞✍评论…...
安全防御之授权和访问控制技术
授权和访问控制技术是安全防御中的重要组成部分,主要用于管理和限制对系统资源(如数据、应用程序等)的访问。授权控制用户可访问和操作的系统资源,而访问控制技术则负责在授权的基础上,确保只有经过授权的用户才能访问…...
Iceberg从入门到精通系列之二十:Iceberg支持的字段类型
Iceberg从入门到精通系列之二十:Iceberg支持的字段类型 Iceberg 表支持以下类型: 字段类型描述注释booleanTrue or falseint32 位有符号整数可以提升到longlong64 位有符号整数float32 位 IEEE 754 浮点可以提升到doubledouble64 位 IEEE 754 浮点decim…...
Unity坦克大战开发全流程——结束场景——通关界面
结束场景——通关界面 就照着这样来拼 写代码 hideme不要忘了 修改上一节课中的代码...
K8S三种发布方式和声明式资源管理
蓝绿发布 把应用服务集群标记位两个组,蓝组和绿组,先升级蓝组,先要把蓝组从负载均衡当中移除,绿组继续提供服务,蓝组升级完毕,再把绿组从负载均衡当中移除,绿组升级,然后都加入回负载…...
从千问Agent看AI Agent——我们很强,但还有很长的路要走
前言 最近双十一做活动买了台新电脑,显卡好起来了自然也开始大模型的学习工作了,这篇文章可能是该系列的第一弹,本地私有化部署千问agent,后面还会尝试一些其他的大模型结合本地知识库或者做行业垂直模型训练的,一步…...
Word2Vector介绍
Word2Vector 2013 word2vec也叫word embeddings,中文名“词向量”,google开源的一款用于词向量计算的工具,作用就是将自然语言中的字词转为计算机可以理解的稠密向量。在word2vec出现之前,自然语言处理经常把字词转为离散的单独的…...
书生·浦语大模型全链路开源体系----(1)
书生浦语大模型全链路开源体系 什么是大语言模型? 大语言模型是指具有大规模参数和强大语言理解能力的机器学习模型。这些模型通常使用深度学习技术,特别是递归神经网络(RNN)或变换器(Transformer)等架构…...
第四篇 行为型设计模式 - 灵活定义对象间交互
第四篇:行为型设计模式 - 灵活定义对象间交互 行为型设计模式关注对象之间的交互和职责分配,旨在定义对象间的高效、灵活的通信机制。以下是十一种常见行为型设计模式的详解及其应用场景。 1. 策略模式详解及其应用场景 详解: 策略模式定义…...
2023最新租号平台系统源码支持单独租用或合租使用
这是一款租号平台源码,采用常见的租号模式。目前网络上还很少见到此类类型的源码。 平台的主要功能如下: 支持单独租用或采用合租模式; 采用易支付通用接口进行支付; 添加邀请返利功能,以便站长更好地推广…...
数据库的连接
连接数据库 我们使用WinR输入cmd打开运行窗口 输入:sqlplus并回车 输入用户名和密码,我用的是Scott,密码我自己设置的123456,Scott默认的密码是tiger,回车 这种情况表示登录成功 在连接Scott成功的情况下创建一些数据,在我的资源里面有个Oracle数据基础可以下载,直接复制粘…...
第14课 利用openCV快速数豆豆
除了检测运动,openCV还能做许多有趣且实用的事情。其实openCV和FFmpeg一样都是宝藏开源项目,貌似简单的几行代码功能实现背后其实是复杂的算法在支撑。有志于深入学习的同学可以在入门后进一步研究算法的实现,一定会受益匪浅。 这节课&#…...
在前端利用Broadcast Channel实现浏览器跨 Tab 窗口通信的方法
Broadcast Channel 在前端,我们经常会用postMessage来实现页面间的通信,但这种方式更像是点对点的通信。对于一些需要广播(让所有页面知道)的消息,用postMessage不是非常自然。Broadcast Channel 就是用来弥补这个缺陷…...
【Apache Doris】自定义函数之 JAVA UDF 详解
【Apache Doris】自定义函数之 JAVA UDF 详解 一、背景说明二、原理简介三、环境信息3.1 硬件信息3.2 软件信息 四、IDE准备五、JAVA UDF开发流程5.1 源码准备5.1.1 pom.xml5.1.2 JAVA代码 5.2 mvn打包5.2.1 clean5.2.2 package 5.3 函数使用5.3.1 upload5.3.2 使用 六、注意事…...
BMS电池管理系统带充放电控制过流过压保护
2.4G无线采集BMS开发板(主从一体) 全新升级 (赠送上位机源码TTL 上位机,可以改成自己想要的界面) 12串电池TTL上位机 CAN通信上位机源码有偿开源,供项目二次开发。 增加STM32平台 USB转TTL通信 CAN通信 增加…...
在Linux中以后台静默运行Java应用程序
在Linux系统上运行Java应用程序时,有时我们希望将其设置为后台运行,而关闭终端窗口时不会影响进程的执行。在本文中,我们将介绍几种实现这一目标的方法。 1. 使用nohup命令 nohup是一个用于在后台运行进程的命令,而且关闭终端窗…...
k8s---Pod的生命周期
Pod是什么? pod是k8s中最小的资源管理组件。 pod也是最小化运行容器化应用的资源管理对象。 pod是一个抽象的概念,可以理解为一个或者多个容器化应用的集合 在一个pod当中运行一个容器是最常用的方式 在一个pod当中可以同时运行多个容器,…...
CSS animation动画和关键帧实现轮播图效果HTML
CSS animation动画和关键帧实现轮播图效果HTML 这轮播图效果使用h5和css3实现效果,不需要js控制,但是其中的缺点就是不能使用鼠标进行切换效果。 具有代码如下 <!DOCTYPE html> <html lang"en"><head><meta charset&quo…...
Unity之键盘鼠标的监控
小编最近在玩大表哥2,通过 W、A、S、D 来移动亚瑟,鼠标左键来不吃牛肉 我们都知道玩家通过按键鼠标来控制游戏人物做出相应的行为动作,那在Unity引擎里是怎么知道玩家是如何操作的呢?本篇来介绍Unity是怎样监控键盘和鼠标的。 首先…...
C# windows服务程序开机自启动exe程序
我们使用传统的Process.Start(".exe")启动进程会遇到无法打开UI界面的问题,尤其是我们需要进行开启自启动程序设置时出现诸多问题,于是我们就想到采用windows服务开机自启动来创建启动一个新的exe程序,并且是显式运行。 首先是打开…...
【SpringMVC】常用注解
什么是MVC? MVC是一种程序分层开发模式,分别是Model(模型),View(视图)以及Controller(控制器)。这样做可以将程序的用户界面和业务逻辑分离,使得代码具有良好…...
关于曲率、曲率半径和曲率圆,看这几篇文章就够啦
关于曲率、曲率半径和曲率圆的内容,是考研数学数学一和数学二大纲中明确要求掌握的内容,但这部分内容在很多教材教辅以及练习题中较少涉及。在本文中,荒原之梦考研数学网就为大家整理了曲率、曲率半径和曲率圆方程相关的概念、基础知识以及练…...
java面试题-Spring常见的异常类有哪些?
远离八股文,面试大白话,通俗且易懂 看完后试着用自己的话复述出来。有问题请指出,有需要帮助理解的或者遇到的真实面试题不知道怎么总结的也请评论中写出来,大家一起解决。 java面试题汇总-目录-持续更新中 NullPointerException&…...
床上做受网站/网站设计方案
MUI: http://dev.dcloud.net.cn/mui/snippet/ html5plus: http://www.html5plus.org/doc/h5p.html转载于:https://www.cnblogs.com/haitaoli/p/10520749.html...
网站不提交表单/互动营销成功案例
React入门React中的 jsx 的使用 模块 一般就是一个js文件 模块化指项目是按照一个模块一个模块写的,也就是一个js一个js方式写的 组件 实现局部功能的html/css/js 文件 组件化指项目是按照组件的方式编写的...
经营性网站备案怎么备案/店铺推广渠道有哪些方式
MetersPhere自动化解决用户登录问题添加钉钉机器人 现在遇到的问题,做自动化的时候几乎每个接口都需要token,这个token是登录获取的,那我有很多个自动化的场景,如果我每一个场景都加入登录接口,同时执行很多场景的时候…...
淘宝网站建设不允许/私域流量运营管理
1.MyBatis中设置或获取插入的自增主键 http://my.oschina.net/kolbe/blog/512904 2.MySql性能调优与架构设计系列 http://www.cnblogs.com/jesselzj/p/5584245.html 3.Mysql Mac 安装:https://segmentfault.com/a/1190000004061246 4. 数据库备份与恢复:…...
什么是网络开发/苏州关键词优化软件
IDC评述网(idcps.com)02月19日报道:根据市场研究公司Net Applications最新数据显示,在2月全球搜索引擎市场份额大战中,Google-Global以58.44%的份额稳坐冠军宝座,环比上月,份额下降了4.30%。而亚…...
做变态的视频网站/官方网站百度一下
1 前言设计师交付给前端开发一张宽度为750px的视觉稿,设计稿上元素的尺寸、颜色、位置等已做过标注,要求工程师工在适配不同屏幕尺寸的设备时采用等比缩放的方案。前面我们讲过可以使用viewport缩放方案实现页面级的缩放适配。但该方案有个问题ÿ…...