React16源码: React中的updateClassComponent的源码实现

本文主要是介绍React16源码: React中的updateClassComponent的源码实现,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

ClassComponent 的更新


1 ) 概述

  • 在 react 中 class component,是一个非常重要的角色
  • 它承担了 react 中 更新整个应用的API
    • setState
    • forceUpdate
  • 在react当中,只有更新了state之后,整个应用才会重新进行渲染
  • 在 class component 中, 它的逻辑相对复杂

2 )源码

在 packages/react-reconciler/src/ReactFiberBeginWork.js

// 这个方法就是更新 ClassComponent 组件的一个过程
function updateClassComponent(current: Fiber | null,workInProgress: Fiber,Component: any,nextProps,renderExpirationTime: ExpirationTime,
) {// Push context providers early to prevent context stack mismatches.// During mounting we don't know the child context yet as the instance doesn't exist.// We will invalidate the child context in finishClassComponent() right after rendering.// 先跳过 context 相关的逻辑let hasContext;if (isLegacyContextProvider(Component)) {hasContext = true;pushLegacyContextProvider(workInProgress);} else {hasContext = false;}prepareToReadContext(workInProgress, renderExpirationTime);// instance 就是我们 class component,通过new这个class获取的一个对象const instance = workInProgress.stateNode;// 在这里面,它声明了一个 shouldUpdate 的一个属性let shouldUpdate; // 先判断instance是否存在, 比如说我们第一次通过 ReactDOM.render 进行渲染的过程当中// 在从上往下第一次渲染的过程当中,第一次更新到 class component 的时候// 它的instance肯定是不存在的,因为它还没有被更新过,所以它的节点肯定是没有被创建的if (instance === null) {// 接下去, 判断一下current是否等于null// current等于null的情况是代表在进入第一次渲染,因为current它还不存在// 如果current不等于null, 代表我们至少已经经历过一次渲染了// 这时候 instance 不存在,而 current 存在,说明第一次渲染的时候没有创建这个instance// 同样说明这个组件是被 suspended 的,一个组件处于suspended的状态// 在这里react认为它相当于是第一次被渲染, 在初次渲染的时候,只是抛出了一个promise// 并没有真正的渲染出它的子节点, 抛出了一个promise之后,接下去的渲染就结束了if (current !== null) {// An class component without an instance only mounts if it suspended// inside a non- concurrent tree, in an inconsistent state. We want to// tree it like a new mount, even though an empty version of it already// committed. Disconnect the alternate pointers.current.alternate = null;workInProgress.alternate = null;// Since this is conceptually a new fiber, schedule a Placement effectworkInProgress.effectTag |= Placement;}// In the initial pass we might need to construct the instance.// 对于没有instance的一个情况,需要去创建 class instanceconstructClassInstance(workInProgress,Component,nextProps,renderExpirationTime,);// 并且要mount这个 class instancemountClassInstance(workInProgress,Component,nextProps,renderExpirationTime,);// 在第一次渲染的时候,会执行上述两个方法,并且 shouldUpdate = true;shouldUpdate = true;} else if (current === null) {// In a resume, we'll already have an instance we can reuse.// 在 有instance 和 没有 current 的情况下,这种是之前被中断的// 在执行 class component 的 render 方法的时候 报错,但 instance 已被创建// 代表着可以复用 instanceshouldUpdate = resumeMountClassInstance(workInProgress,Component,nextProps,renderExpirationTime,);} else {// 对于又有 current 又有 instance的情况,说明组件已经被重新渲染了// 这个 updateClassInstance 方法和 上述 resumeMountClassInstance 类似// 最大的区别是 内部判断 comonentDidUpdate shouldUpdate = updateClassInstance(current,workInProgress,Component,nextProps,renderExpirationTime,);}// 这里最终调用 finishClassComponentreturn finishClassComponent(current,workInProgress,Component,shouldUpdate,hasContext,renderExpirationTime,);
}
  • 进入 constructClassInstance

    function constructClassInstance(workInProgress: Fiber,ctor: any,props: any,renderExpirationTime: ExpirationTime,
    ): any {// 先跳过 context 相关let isLegacyContextConsumer = false;let unmaskedContext = emptyContextObject;let context = null;const contextType = ctor.contextType;// if (typeof contextType === 'object' && contextType !== null) {// 跳过 DEVif (__DEV__) {if (contextType.$$typeof !== REACT_CONTEXT_TYPE &&!didWarnAboutInvalidateContextType.has(ctor)) {didWarnAboutInvalidateContextType.add(ctor);warningWithoutStack(false,'%s defines an invalid contextType. ' +'contextType should point to the Context object returned by React.createContext(). ' +'Did you accidentally pass the Context.Provider instead?',getComponentName(ctor) || 'Component',);}}context = readContext((contextType: any));} else {unmaskedContext = getUnmaskedContext(workInProgress, ctor, true);const contextTypes = ctor.contextTypes;isLegacyContextConsumer =contextTypes !== null && contextTypes !== undefined;context = isLegacyContextConsumer? getMaskedContext(workInProgress, unmaskedContext): emptyContextObject;}// Instantiate twice to help detect side-effects.if (__DEV__) {if (debugRenderPhaseSideEffects ||(debugRenderPhaseSideEffectsForStrictMode &&workInProgress.mode & StrictMode)) {new ctor(props, context); // eslint-disable-line no-new}}// ctor 是 construct 的一个缩写 这个 ctor 就是在 ReactElement当中// 存在的那个type,也就是 class component 定义的那个class// 传入 props和context,对应于 ReactBaseClasses.js 里面,Component 函数 接收的这两个参数// 第三个参数 updater 后面在 adoptClassInstance 里面设置const instance = new ctor(props, context);// 获取 stateconst state = (workInProgress.memoizedState =instance.state !== null && instance.state !== undefined? instance.state: null);adoptClassInstance(workInProgress, instance);if (__DEV__) {if (typeof ctor.getDerivedStateFromProps === 'function' && state === null) {const componentName = getComponentName(ctor) || 'Component';if (!didWarnAboutUninitializedState.has(componentName)) {didWarnAboutUninitializedState.add(componentName);warningWithoutStack(false,'`%s` uses `getDerivedStateFromProps` but its initial state is ' +'%s. This is not recommended. Instead, define the initial state by ' +'assigning an object to `this.state` in the constructor of `%s`. ' +'This ensures that `getDerivedStateFromProps` arguments have a consistent shape.',componentName,instance.state === null ? 'null' : 'undefined',componentName,);}}// If new component APIs are defined, "unsafe" lifecycles won't be called.// Warn about these lifecycles if they are present.// Don't warn about react-lifecycles-compat polyfilled methods though.if (typeof ctor.getDerivedStateFromProps === 'function' ||typeof instance.getSnapshotBeforeUpdate === 'function') {let foundWillMountName = null;let foundWillReceivePropsName = null;let foundWillUpdateName = null;if (typeof instance.componentWillMount === 'function' &&instance.componentWillMount.__suppressDeprecationWarning !== true) {foundWillMountName = 'componentWillMount';} else if (typeof instance.UNSAFE_componentWillMount === 'function') {foundWillMountName = 'UNSAFE_componentWillMount';}if (typeof instance.componentWillReceiveProps === 'function' &&instance.componentWillReceiveProps.__suppressDeprecationWarning !== true) {foundWillReceivePropsName = 'componentWillReceiveProps';} else if (typeof instance.UNSAFE_componentWillReceiveProps === 'function') {foundWillReceivePropsName = 'UNSAFE_componentWillReceiveProps';}if (typeof instance.componentWillUpdate === 'function' &&instance.componentWillUpdate.__suppressDeprecationWarning !== true) {foundWillUpdateName = 'componentWillUpdate';} else if (typeof instance.UNSAFE_componentWillUpdate === 'function') {foundWillUpdateName = 'UNSAFE_componentWillUpdate';}if (foundWillMountName !== null ||foundWillReceivePropsName !== null ||foundWillUpdateName !== null) {const componentName = getComponentName(ctor) || 'Component';const newApiName =typeof ctor.getDerivedStateFromProps === 'function'? 'getDerivedStateFromProps()': 'getSnapshotBeforeUpdate()';if (!didWarnAboutLegacyLifecyclesAndDerivedState.has(componentName)) {didWarnAboutLegacyLifecyclesAndDerivedState.add(componentName);warningWithoutStack(false,'Unsafe legacy lifecycles will not be called for components using new component APIs.\n\n' +'%s uses %s but also contains the following legacy lifecycles:%s%s%s\n\n' +'The above lifecycles should be removed. Learn more about this warning here:\n' +'https://fb.me/react-async-component-lifecycle-hooks',componentName,newApiName,foundWillMountName !== null ? `\n  ${foundWillMountName}` : '',foundWillReceivePropsName !== null? `\n  ${foundWillReceivePropsName}`: '',foundWillUpdateName !== null ? `\n  ${foundWillUpdateName}` : '',);}}}}// Cache unmasked context so we can avoid recreating masked context unless necessary.// ReactFiberContext usually updates this cache but can't for newly-created instances.if (isLegacyContextConsumer) {cacheContext(workInProgress, unmaskedContext, context);}return instance;
    }
    
    • 进入 adoptClassInstance
      function adoptClassInstance(workInProgress: Fiber, instance: any): void {instance.updater = classComponentUpdater; // 挂载 update 方法workInProgress.stateNode = instance; // instance 挂载到 stateNode 以供下次进来时使用,下次进来就会存在了// The instance needs access to the fiber so that it can schedule updatesReactInstanceMap.set(instance, workInProgress);if (__DEV__) {instance._reactInternalInstance = fakeInternalInstance;}
      }
      
    • 进入 ReactInstanceMap 这个就是对 instance 上 _reactInternalFiber 属性的设置
      export function remove(key) {key._reactInternalFiber = undefined;
      }export function get(key) {return key._reactInternalFiber;
      }export function has(key) {return key._reactInternalFiber !== undefined;
      }export function set(key, value) {key._reactInternalFiber = value;
      }
      
      • 这也意味着,通过 this._reactInternalFiber 就可以拿到当前 fiber 对象
  • 进入 mountClassInstance

    // Invokes the mount life-cycles on a previously never rendered instance.
    function mountClassInstance(workInProgress: Fiber,ctor: any,newProps: any,renderExpirationTime: ExpirationTime,
    ): void {if (__DEV__) {checkClassInstance(workInProgress, ctor, newProps);}const instance = workInProgress.stateNode;instance.props = newProps;instance.state = workInProgress.memoizedState;instance.refs = emptyRefsObject;const contextType = ctor.contextType;if (typeof contextType === 'object' && contextType !== null) {instance.context = readContext(contextType);} else {const unmaskedContext = getUnmaskedContext(workInProgress, ctor, true);instance.context = getMaskedContext(workInProgress, unmaskedContext);}if (__DEV__) {if (instance.state === newProps) {const componentName = getComponentName(ctor) || 'Component';if (!didWarnAboutDirectlyAssigningPropsToState.has(componentName)) {didWarnAboutDirectlyAssigningPropsToState.add(componentName);warningWithoutStack(false,'%s: It is not recommended to assign props directly to state ' +"because updates to props won't be reflected in state. " +'In most cases, it is better to use props directly.',componentName,);}}if (workInProgress.mode & StrictMode) {ReactStrictModeWarnings.recordUnsafeLifecycleWarnings(workInProgress,instance,);ReactStrictModeWarnings.recordLegacyContextWarning(workInProgress,instance,);}if (warnAboutDeprecatedLifecycles) {ReactStrictModeWarnings.recordDeprecationWarnings(workInProgress,instance,);}}// 获取 updateQueue,初次渲染这个 updateQueue 是空的// 对于有 setState 的情况,它的 updateQueen 里面可能有多个update// 这个时候, 需要调用这个 updateQueen 来去得到一个新的statelet updateQueue = workInProgress.updateQueue;if (updateQueue !== null) {// 这里 计算出新的state 并赋值给 workInProgress.memoizedStateprocessUpdateQueue(workInProgress,updateQueue,newProps,instance,renderExpirationTime,);// 同时更新 instance.stateinstance.state = workInProgress.memoizedState;}// 判断是否有这个生命周期方法const getDerivedStateFromProps = ctor.getDerivedStateFromProps;if (typeof getDerivedStateFromProps === 'function') {// 如果存在该生命周期方法,则计算新的state// 这个生命周期会在组件更新的过程中被调用applyDerivedStateFromProps(workInProgress,ctor,getDerivedStateFromProps,newProps,);instance.state = workInProgress.memoizedState;}// In order to support react-lifecycles-compat polyfilled components,// Unsafe lifecycles should not be invoked for components using the new APIs.// 判断是否有 componentWillMount 生命周期方法// 在这个生命周期方法中,会执行 setState 方法if (typeof ctor.getDerivedStateFromProps !== 'function' &&typeof instance.getSnapshotBeforeUpdate !== 'function' &&(typeof instance.UNSAFE_componentWillMount === 'function' ||typeof instance.componentWillMount === 'function')) {// callComponentWillMount(workInProgress, instance);// If we had additional state updates during this life-cycle, let's// process them now.// 执行了 这个生命周期方法,就需要重新执行 updateQueue// 如果在这时执行了 setState, 立马被反映到组件上面updateQueue = workInProgress.updateQueue;if (updateQueue !== null) {processUpdateQueue(workInProgress,updateQueue,newProps,instance,renderExpirationTime,);instance.state = workInProgress.memoizedState;}}if (typeof instance.componentDidMount === 'function') {workInProgress.effectTag |= Update;}
    }
    
    • 进入 processUpdateQueue
      export function processUpdateQueue<State>(workInProgress: Fiber,queue: UpdateQueue<State>,props: any,instance: any,renderExpirationTime: ExpirationTime,
      ): void {hasForceUpdate = false;// 克隆 updateQueuequeue = ensureWorkInProgressQueueIsAClone(workInProgress, queue);if (__DEV__) {currentlyProcessingQueue = queue;}// These values may change as we process the queue.let newBaseState = queue.baseState;let newFirstUpdate = null;let newExpirationTime = NoWork;// Iterate through the list of updates to compute the result.let update = queue.firstUpdate; let resultState = newBaseState;while (update !== null) {const updateExpirationTime = update.expirationTime;if (updateExpirationTime < renderExpirationTime) {// This update does not have sufficient priority. Skip it.if (newFirstUpdate === null) {// This is the first skipped update. It will be the first update in// the new list.newFirstUpdate = update;// Since this is the first update that was skipped, the current result// is the new base state.newBaseState = resultState;}// Since this update will remain in the list, update the remaining// expiration time.if (newExpirationTime < updateExpirationTime) {newExpirationTime = updateExpirationTime;}} else {// This update does have sufficient priority. Process it and compute// a new result.resultState = getStateFromUpdate(workInProgress,queue,update,resultState,props,instance,);const callback = update.callback;// 判断是否有 callbackif (callback !== null) {workInProgress.effectTag |= Callback; // 加上 Callback 这块// Set this to null, in case it was mutated during an aborted render.update.nextEffect = null; // 防止在中断的渲染中被修改if (queue.lastEffect === null) {queue.firstEffect = queue.lastEffect = update; // 链表操作} else {queue.lastEffect.nextEffect = update;queue.lastEffect = update;}}}// Continue to the next update.update = update.next;}// Separately, iterate though the list of captured updates.let newFirstCapturedUpdate = null;update = queue.firstCapturedUpdate;while (update !== null) {const updateExpirationTime = update.expirationTime;if (updateExpirationTime < renderExpirationTime) {// This update does not have sufficient priority. Skip it.if (newFirstCapturedUpdate === null) {// This is the first skipped captured update. It will be the first// update in the new list.newFirstCapturedUpdate = update;// If this is the first update that was skipped, the current result is// the new base state.if (newFirstUpdate === null) {newBaseState = resultState;}}// Since this update will remain in the list, update the remaining// expiration time.if (newExpirationTime < updateExpirationTime) {newExpirationTime = updateExpirationTime;}} else {// This update does have sufficient priority. Process it and compute// a new result.resultState = getStateFromUpdate(workInProgress,queue,update,resultState,props,instance,);const callback = update.callback;if (callback !== null) {workInProgress.effectTag |= Callback;// Set this to null, in case it was mutated during an aborted render.update.nextEffect = null;if (queue.lastCapturedEffect === null) {queue.firstCapturedEffect = queue.lastCapturedEffect = update;} else {queue.lastCapturedEffect.nextEffect = update;queue.lastCapturedEffect = update;}}}update = update.next;}if (newFirstUpdate === null) {queue.lastUpdate = null;}if (newFirstCapturedUpdate === null) {queue.lastCapturedUpdate = null;} else {workInProgress.effectTag |= Callback;}if (newFirstUpdate === null && newFirstCapturedUpdate === null) {// We processed every update, without skipping. That means the new base// state is the same as the result state.newBaseState = resultState;}queue.baseState = newBaseState;queue.firstUpdate = newFirstUpdate;queue.firstCapturedUpdate = newFirstCapturedUpdate;// Set the remaining expiration time to be whatever is remaining in the queue.// This should be fine because the only two other things that contribute to// expiration time are props and context. We're already in the middle of the// begin phase by the time we start processing the queue, so we've already// dealt with the props. Context in components that specify// shouldComponentUpdate is tricky; but we'll have to account for// that regardless.workInProgress.expirationTime = newExpirationTime;workInProgress.memoizedState = resultState;if (__DEV__) {currentlyProcessingQueue = null;}
      }
      
      • 进入 ensureWorkInProgressQueueIsAClone
      function ensureWorkInProgressQueueIsAClone<State>(workInProgress: Fiber,queue: UpdateQueue<State>,
      ): UpdateQueue<State> {const current = workInProgress.alternate;if (current !== null) {// If the work-in-progress queue is equal to the current queue,// we need to clone it first.if (queue === current.updateQueue) {// 要保证 workInProgress.updateQueue 是一个克隆的queue, 而非直接进行修改queue = workInProgress.updateQueue = cloneUpdateQueue(queue); // 拷贝 queue}}return queue;
      }
      
    • 进入 getStateFromUpdate
      function getStateFromUpdate<State>(workInProgress: Fiber,queue: UpdateQueue<State>,update: Update<State>,prevState: State,nextProps: any,instance: any,
      ): any {switch (update.tag) {case ReplaceState: {const payload = update.payload;if (typeof payload === 'function') {// Updater functionif (__DEV__) {if (debugRenderPhaseSideEffects ||(debugRenderPhaseSideEffectsForStrictMode &&workInProgress.mode & StrictMode)) {payload.call(instance, prevState, nextProps);}}return payload.call(instance, prevState, nextProps);}// State objectreturn payload;}// 这里 a & ~b 表示: a & 除了b之外的所有属性case CaptureUpdate: {workInProgress.effectTag =(workInProgress.effectTag & ~ShouldCapture) | DidCapture; // 这里最终剩下的 只有 DidCapture}// Intentional fallthroughcase UpdateState: {const payload = update.payload;let partialState;if (typeof payload === 'function') {// Updater functionif (__DEV__) {if (debugRenderPhaseSideEffects ||(debugRenderPhaseSideEffectsForStrictMode &&workInProgress.mode & StrictMode)) {payload.call(instance, prevState, nextProps);}}// 如果是 function 则调用 payload 传入之前的参数 计算出 statepartialState = payload.call(instance, prevState, nextProps);} else {// Partial state objectpartialState = payload;}// 处理特殊情况if (partialState === null || partialState === undefined) {// Null and undefined are treated as no-ops.return prevState;}// Merge the partial state and the previous state.// 合并return Object.assign({}, prevState, partialState);}case ForceUpdate: {hasForceUpdate = true;return prevState;}}return prevState;
      }
      
  • 进入 finishClassComponent

    function finishClassComponent(current: Fiber | null,workInProgress: Fiber,Component: any,shouldUpdate: boolean,hasContext: boolean,renderExpirationTime: ExpirationTime,
    ) {// Refs should update even if shouldComponentUpdate returns false// 这个先跳过markRef(current, workInProgress);// 判断 workInProgress.effectTag 上是否有 DidCaptureconst didCaptureError = (workInProgress.effectTag & DidCapture) !== NoEffect;// 在没有更新也没有错误捕获的情况下if (!shouldUpdate && !didCaptureError) {// Context providers should defer to sCU for renderingif (hasContext) {invalidateContextProvider(workInProgress, Component, false);}// 跳过更新return bailoutOnAlreadyFinishedWork(current,workInProgress,renderExpirationTime,);}const instance = workInProgress.stateNode;// RerenderReactCurrentOwner.current = workInProgress;let nextChildren;// 有任何错误捕获, 但没有配置这个api的时候// 这个 getDerivedStateFromError 生命周期的api和 componentDidCatch 有区别, 后者在下次更新的时候处理,中间可能instance不存在(因为出错了)// 就继续可能引发在这个class component上面设置的 ref拿到一个null, 操作ref的时候就会出现错误// 在前者这个新的生命周期的api中, 在本次渲染中,生成 state, 渲染出属性, 这样对于 instance 对象依然存在 对应 ref 就可以拿到实际的对象if (didCaptureError &&typeof Component.getDerivedStateFromError !== 'function') {// If we captured an error, but getDerivedStateFrom catch is not defined,// unmount all the children. componentDidCatch will schedule an update to// re-render a fallback. This is temporary until we migrate everyone to// the new API.// TODO: Warn in a future release.nextChildren = null;if (enableProfilerTimer) {stopProfilerTimerIfRunning(workInProgress);}} else {if (__DEV__) {ReactCurrentFiber.setCurrentPhase('render');nextChildren = instance.render();if (debugRenderPhaseSideEffects ||(debugRenderPhaseSideEffectsForStrictMode &&workInProgress.mode & StrictMode)) {instance.render();}ReactCurrentFiber.setCurrentPhase(null);} else {// 调用 render 方法,计算出新的 childrennextChildren = instance.render();}}// React DevTools reads this flag.workInProgress.effectTag |= PerformedWork; // 增加 PerformedWork// 不是第一次渲染,并且有错误捕获if (current !== null && didCaptureError) {// If we're recovering from an error, reconcile without reusing any of// the existing children. Conceptually, the normal children and the children// that are shown on error are two different sets, so we shouldn't reuse// normal children even if their identities match.forceUnmountCurrentAndReconcile(current,workInProgress,nextChildren,renderExpirationTime,);} else {// 正常情况调用 调和 childrenreconcileChildren(current,workInProgress,nextChildren,renderExpirationTime,);}// Memoize state using the values we just used to render.// TODO: Restructure so we never read values from the instance.workInProgress.memoizedState = instance.state;// The context might have changed so we need to recalculate it.if (hasContext) {invalidateContextProvider(workInProgress, Component, true);}return workInProgress.child; // 把 render 方法渲染出来的第一个子节点 返回给 nextUnitOfWork, 就可以在 workLoop 中继续进行更新的流程
    }
    
  • 简单总结

    • 以上是更新 class component 的整体流程
    • 一开始要使用 constructClassInstance 创建 class instance
    • 内部会根据不同情况调用不同方法
    • 并且要调用 mountClassInstance 来挂载
    • 如果是第一次渲染被中断的情况
      • 如果存在 instance 则重复使用 instance
      • 它调用的生命周期方法仍然是 第一次渲染的生命周期方法
      • 也就是 componentDidMount
    • 如果不是第一次渲染的情况
      • 调用 updateClassInstance 方法
      • 这种会最终调用 componentDidUpdate 方法
    • 它们中间的流程类似
      • 判断各种情况,创建新的 instance 或 复用之前的
      • 通过 processUpdateQueue 来获取新的 state
      • 会把它赋值到 instance 和 fiber 上面进行记录
      • 最终都会调用 finishClassComponent
        • 这里面做一些错误判断的处理
        • 以及是否可以跳过更新的过程
        • 还有重新调和子节点 (通用流程)

这篇关于React16源码: React中的updateClassComponent的源码实现的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/629482

相关文章

Vue3 的 shallowRef 和 shallowReactive:优化性能

大家对 Vue3 的 ref 和 reactive 都很熟悉,那么对 shallowRef 和 shallowReactive 是否了解呢? 在编程和数据结构中,“shallow”(浅层)通常指对数据结构的最外层进行操作,而不递归地处理其内部或嵌套的数据。这种处理方式关注的是数据结构的第一层属性或元素,而忽略更深层次的嵌套内容。 1. 浅层与深层的对比 1.1 浅层(Shallow) 定义

这15个Vue指令,让你的项目开发爽到爆

1. V-Hotkey 仓库地址: github.com/Dafrok/v-ho… Demo: 戳这里 https://dafrok.github.io/v-hotkey 安装: npm install --save v-hotkey 这个指令可以给组件绑定一个或多个快捷键。你想要通过按下 Escape 键后隐藏某个组件,按住 Control 和回车键再显示它吗?小菜一碟: <template

【 html+css 绚丽Loading 】000046 三才归元阵

前言:哈喽,大家好,今天给大家分享html+css 绚丽Loading!并提供具体代码帮助大家深入理解,彻底掌握!创作不易,如果能帮助到大家或者给大家一些灵感和启发,欢迎收藏+关注哦 💕 目录 📚一、效果📚二、信息💡1.简介:💡2.外观描述:💡3.使用方式:💡4.战斗方式:💡5.提升:💡6.传说: 📚三、源代码,上代码,可以直接复制使用🎥效果🗂️目录✍️

【前端学习】AntV G6-08 深入图形与图形分组、自定义节点、节点动画(下)

【课程链接】 AntV G6:深入图形与图形分组、自定义节点、节点动画(下)_哔哩哔哩_bilibili 本章十吾老师讲解了一个复杂的自定义节点中,应该怎样去计算和绘制图形,如何给一个图形制作不间断的动画,以及在鼠标事件之后产生动画。(有点难,需要好好理解) <!DOCTYPE html><html><head><meta charset="UTF-8"><title>06

hdu1043(八数码问题,广搜 + hash(实现状态压缩) )

利用康拓展开将一个排列映射成一个自然数,然后就变成了普通的广搜题。 #include<iostream>#include<algorithm>#include<string>#include<stack>#include<queue>#include<map>#include<stdio.h>#include<stdlib.h>#include<ctype.h>#inclu

JAVA智听未来一站式有声阅读平台听书系统小程序源码

智听未来,一站式有声阅读平台听书系统 🌟&nbsp;开篇:遇见未来,从“智听”开始 在这个快节奏的时代,你是否渴望在忙碌的间隙,找到一片属于自己的宁静角落?是否梦想着能随时随地,沉浸在知识的海洋,或是故事的奇幻世界里?今天,就让我带你一起探索“智听未来”——这一站式有声阅读平台听书系统,它正悄悄改变着我们的阅读方式,让未来触手可及! 📚&nbsp;第一站:海量资源,应有尽有 走进“智听

【C++】_list常用方法解析及模拟实现

相信自己的力量,只要对自己始终保持信心,尽自己最大努力去完成任何事,就算事情最终结果是失败了,努力了也不留遗憾。💓💓💓 目录   ✨说在前面 🍋知识点一:什么是list? •🌰1.list的定义 •🌰2.list的基本特性 •🌰3.常用接口介绍 🍋知识点二:list常用接口 •🌰1.默认成员函数 🔥构造函数(⭐) 🔥析构函数 •🌰2.list对象

【Prometheus】PromQL向量匹配实现不同标签的向量数据进行运算

✨✨ 欢迎大家来到景天科技苑✨✨ 🎈🎈 养成好习惯,先赞后看哦~🎈🎈 🏆 作者简介:景天科技苑 🏆《头衔》:大厂架构师,华为云开发者社区专家博主,阿里云开发者社区专家博主,CSDN全栈领域优质创作者,掘金优秀博主,51CTO博客专家等。 🏆《博客》:Python全栈,前后端开发,小程序开发,人工智能,js逆向,App逆向,网络系统安全,数据分析,Django,fastapi

让树莓派智能语音助手实现定时提醒功能

最初的时候是想直接在rasa 的chatbot上实现,因为rasa本身是带有remindschedule模块的。不过经过一番折腾后,忽然发现,chatbot上实现的定时,语音助手不一定会有响应。因为,我目前语音助手的代码设置了长时间无应答会结束对话,这样一来,chatbot定时提醒的触发就不会被语音助手获悉。那怎么让语音助手也具有定时提醒功能呢? 我最后选择的方法是用threading.Time

Android实现任意版本设置默认的锁屏壁纸和桌面壁纸(两张壁纸可不一致)

客户有些需求需要设置默认壁纸和锁屏壁纸  在默认情况下 这两个壁纸是相同的  如果需要默认的锁屏壁纸和桌面壁纸不一样 需要额外修改 Android13实现 替换默认桌面壁纸: 将图片文件替换frameworks/base/core/res/res/drawable-nodpi/default_wallpaper.*  (注意不能是bmp格式) 替换默认锁屏壁纸: 将图片资源放入vendo