网站店铺vr场景可以做吗网站的建设步骤

张小明 2026/1/5 18:28:57
网站店铺vr场景可以做吗,网站的建设步骤,宁波网站设计企业,天元建设集团有限公司法定代表人理解 Vue 2 中虚拟 DOM#xff08;VDOM#xff09;的实现原理和 Diff 算法的核心机制#xff0c;包括 VNode 的创建、patch 流程、以及双端 diff 算法的实现细节。 vue版本#xff1a;以 vue2.7.16 代码为参考#xff0c;可能会包含部分 vue3 polyfill 代码。 VDOM 存在的…理解 Vue 2 中虚拟 DOMVDOM的实现原理和 Diff 算法的核心机制包括 VNode 的创建、patch 流程、以及双端 diff 算法的实现细节。vue版本以vue2.7.16代码为参考可能会包含部分 vue3 polyfill 代码。VDOM 存在的原因DOM 性能开销过大直接操作 DOM 的性能开销比较大如果修改 DOM 树去执行更新可能会引起回流和重绘VDOM 通过维护一个 VDOM 树通过 diff 和 patch 优化更新流程计算出最小化更新操作再一次性同步到真实 DOM 状态减少 DOM 操作次数。开发人员关注如何编写代码VDOM 给开发者提供声明式的 UI 编程模型让开发人员可以把关注点从如何编写改变 UI 的代码转变为 “如何描述 UI 的最终状态”让框架本身去负责 DOM 的更新操作。跨平台VDOM 是平台无关的 JS 对象结构小程序、web、uniapp 都可以利用 VDOM 抽象结构来让渲染器消费。细粒度可控和优化空间key 可以帮助识别列表节点复用避免重建节点后续只需更新。vue3 中引入了静态节点优化同时引入了异步更新队列 nextTick 来支持批量更新操作。其中 diff 算法是 VDOM 中最核心的部分。h 函数/createElement 函数在 Vue 2 中用户编写 template 模板语法之后模板语法会被编译成 render 函数render 函数内部会调用createElement()去渲染节点。h()函数是在编写函数式组件时用到的渲染函数。// 创建带子元素的元素h(div,{class:container},[h(span,Child 1),h(span,Child 2)]);在 Vue 2 中h()是对createElement()的再封装// src/v3/h.tsexportfunctionh(type:any,props?:any,children?:any){if(!currentInstance){returncreateElement(currentInstance!,type,props,children,2,true)}}// src/shared/util.tsexportfunctionisPrimitive(value:any):boolean{return(typeofvaluestring||typeofvaluenumber||// $flow-disable-linetypeofvaluesymbol||typeofvalueboolean)}// src/core/vdom/create-element.tsexportfunctioncreateElement(context:Component,tag:any,data:any,children:any,normalizationType:any,alwaysNormalize:boolean):VNode|ArrayVNode{// 判断传入的 data 是否为数组还是原始值if(isArray(data)||isPrimitive(data)){normalizationTypechildren childrendata dataundefined}if(isTrue(alwaysNormalize)){normalizationTypeALWAYS_NORMALIZE}return_createElement(context,tag,data,children,normalizationType)}exportfunction_createElement(context:Component,tag?:string|Component|Function|Object,data?:VNodeData,children?:any,normalizationType?:number):VNode|ArrayVNode{// 1. 检查 data 是否为响应式对象是的话不应该作为 vnode 的data对象使用不应该使用if(isDef(data)isDef((dataasany).__ob__)){returncreateEmptyVNode()}// 2. 处理 :is 指令if(isDef(data)isDef(data.is)){tagdata.is}// 3. 处理 :is 为 falsy 值的情况if(!tag){returncreateEmptyVNode()}// 4. 处理 scoped slot单个函数作为 childrenif(isArray(children)isFunction(children[0])){datadata||{}data.scopedSlots{default:children[0]}children.length0}// 5. 规范化 childrenif(normalizationTypeALWAYS_NORMALIZE){childrennormalizeChildren(children)}elseif(normalizationTypeSIMPLE_NORMALIZE){childrensimpleNormalizeChildren(children)}// 6. 创建 VNodeletvnode,ns// 字符串标签if(typeoftagstring){letCtor ns(context.$vnodecontext.$vnode.ns)||config.getTagNamespace(tag)if(config.isReservedTag(tag)){// 平台内置元素div, span 等// platform built-in elementsvnodenewVNode(config.parsePlatformTagName(tag),data,children,undefined,undefined,context)}elseif((!data||!data.pre)isDef((CtorresolveAsset(context.$options,components,tag)))){// 组件// componentvnodecreateComponent(Ctor,data,context,children,tag)}else{// 未知元素或命名空间元素// unknown or unlisted namespaced elements// check at runtime because it may get assigned a namespace when its// parent normalizes childrenvnodenewVNode(tag,data,children,undefined,undefined,context)}}else{// 直接传入组件选项或构造函数// direct component options / constructorvnodecreateComponent(tagasany,data,context,children)}// 7. 应用命名空间if(isArray(vnode)){returnvnode}elseif(isDef(vnode)){if(isDef(ns))applyNS(vnode,ns)if(isDef(data))registerDeepBindings(data)returnvnode}else{returncreateEmptyVNode()}}VNodeVNodeVirtual Node是用于描述 DOM 节点的 JavaScript 对象。概念理解VNode虚拟节点是 Vue 用来描述真实 DOM 节点的轻量级 JavaScript 对象包含了节点的所有必要信息但不包含实际的 DOM 操作。VNode 通常包含以下属性当前 VNode 的标签名或者组件属性和事件子 vnode 数组文本内容对应的真实 DOM 节点key唯一标识context组件实例constvnode{tag:div,// 标签名或组件data:{// 属性、事件等attrs:{id:app},on:{click:handler},},children:[],// 子 VNodetext:undefined,// 文本内容elm:undefined,// 对应的真实 DOMkey:unique-key,// 唯一标识context:vm,// 组件实例// ... 其他属性};Vue 2 的 VDOM 和 Diff 算法当数据发生改变时响应式属性的setter方法会调用Dep.notify通知所有订阅者Watcher订阅者就会调用patch给真实的DOM打补丁更新相应的视图。进入 patch 步骤的流程在 Vue 中会有两个步骤会走到 patch首次渲染mountComponent() → Watcher → updateComponent() → patch()。数据更新setter → Watcher → updateComponent() → patch()。mountComponent()中会执行new Watcher()操作。Watcher 将updateComponent()作为回调函数传入可以看到是调用 。_update(vm._render())获取新的 VNode 后执行更新操作。// src/core/instance/lifecycle.tsexportfunctionmountComponent(vm:Component,el:Element|null|undefined,hydrating?:boolean):Component{vm.$elel;if(!vm.$options.render){// ts-expect-error invalid typevm.$options.rendercreateEmptyVNode;}callHook(vm,beforeMount);letupdateComponent;// 核心关键当组件更新时会触发该方法updateComponent(){vm._update(vm._render(),hydrating);};constwatcherOptions:WatcherOptions{before(){if(vm._isMounted!vm._isDestroyed){callHook(vm,beforeUpdate);}},};// watcher 初始化newWatcher(vm,updateComponent,noop,watcherOptions,true/* isRenderWatcher */);hydratingfalse;// flush buffer for flush: pre watchers queued in setup()constpreWatchersvm._preWatchers;if(preWatchers){for(leti0;ipreWatchers.length;i){preWatchers[i].run();}}// 挂载相关if(vm.$vnodenull){vm._isMountedtrue;callHook(vm,mounted);}returnvm;}在_update()的内部就调用了__patch__()比对节点去完成更新。// src/core/instance/lifecycle.tsVue.prototype._updatefunction(vnode){constprevVNodethis._vnode;this._vnodevnode;if(!prevVNode){// 初次渲染this.$elthis.__patch__(this.$el,vnode);}else{// 更新this.$elthis.__patch__(prevVNode,vnode);}};__patch__()来源于//src/platforms/web/runtime/index.ts// 在 web 平台创建 patch 函数Vue.prototype.__patch__inBrowser?patch:noop;// src/platforms/web/runtime/patch.tsimport*asnodeOpsfromweb/runtime/node-ops;import{createPatchFunction}fromcore/vdom/patch;importbaseModulesfromcore/vdom/modules/index;importplatformModulesfromweb/runtime/modules/index;// the directive module should be applied last, after all// built-in modules have been applied.constmodulesplatformModules.concat(baseModules);// 最终返回了 patch 函数exportconstpatch:FunctioncreatePatchFunction({nodeOps,modules});patchvnode 新旧节点更新的入口patch 函数是 VNode 更新的入口主要处理以下四种情况无新节点旧节点销毁没有新节点直接触发旧节点的destroy()钩子销毁 vnode。无旧节点新节点创建没有旧节点说明是页面刚开始初始化的时候此时根本不需要比较了直接全是新建所以只调用createElm()。新旧节点一致执行 patchVnode 更新 VNode旧节点和新节点自身一样通过sameVnode()判断节点是否一样一样时直接调用patchVnode()去处理这两个节点。新旧节点不一致销毁旧 VNode插入新 VNode旧节点和新节点自身不一样当两个节点不一样的时候直接创建新节点删除旧节点。//src/core/vdom/patch.tsfunctionpatch(oldVnode,vnode,hydrating,removeOnly){if(isUndef(vnode)){// 没有新节点直接执行 destroy 钩子函数if(isDef(oldVnode))invokeDestroyHook(oldVnode);return;}letisInitialPatchfalse;constinsertedVnodeQueue[];if(isUndef(oldVnode)){isInitialPatchtrue;createElm(vnode,insertedVnodeQueue);// 没有旧节点直接用新节点生成 DOM 元素}else{constisRealElementisDef(oldVnode.nodeType);if(!isRealElementsameVnode(oldVnode,vnode)){// 判断旧节点和新节点自身一样一致执行 patchVnodepatchVnode(oldVnode,vnode,insertedVnodeQueue,null,null,removeOnly);}else{// 否则直接销毁旧节点根据新节点生成 DOM 元素if(isRealElement){if(oldVnode.nodeType1oldVnode.hasAttribute(SSR_ATTR)){oldVnode.removeAttribute(SSR_ATTR);hydratingtrue;}if(isTrue(hydrating)){if(hydrate(oldVnode,vnode,insertedVnodeQueue)){invokeInsertHook(vnode,insertedVnodeQueue,true);returnoldVnode;}}oldVnodeemptyNodeAt(oldVnode);}returnvnode.elm;}}}patchVnode新旧同节点的内容更新过程patchVnode主要做了几个判断新节点是否是文本节点如果是则直接更新 DOM 的文本内容为新节点的文本内容。新节点和旧节点如果都有子节点则处理比较更新子节点进入双端 diff 流程。只有新节点有子节点旧节点没有那么不用比较了所有节点都是全新的所以直接全部新建就好了新建是指创建出所有新 DOM并且添加进父节点。只有旧节点有子节点而新节点没有说明更新后的页面旧节点全部都不见了那么要做的就是把所有的旧节点删除也就是直接把 DOM 删除。functionpatchVnode(oldVnode,vnode,insertedVnodeQueue,removeOnly){// 如果新旧节点一致什么都不做if(oldVnodevnode){return;}// 假如已创建,克隆复用VNodeif(isDef(vnode.elm)isDef(ownerArray)){// clone reused vnodevnodeownerArray[index]cloneVNode(vnode)}// 让 vnode.elm 引用到现在的真实 DOM当 elm 修改时vnode.elm 会同步变化constelm(vnode.elmoldVnode.elm);// 异步占位符if(isTrue(oldVnode.isAsyncPlaceholder)){if(isDef(vnode.asyncFactory.resolved)){hydrate(oldVnode.elm,vnode,insertedVnodeQueue);}else{vnode.isAsyncPlaceholdertrue;}return;}// 如果新旧都是静态节点并且具有相同的 key// 当 vnode 是克隆节点或是 v-once 指令控制的节点时只需要把 oldVnode.elm 和 oldVnode.child 都复制到 vnode 上// 也不用再有其他操作if(isTrue(vnode.isStatic)isTrue(oldVnode.isStatic)vnode.keyoldVnode.key(isTrue(vnode.isCloned)||isTrue(vnode.isOnce))){vnode.componentInstanceoldVnode.componentInstance;return;}leti;constdatavnode.data;if(isDef(data)isDef((idata.hook))isDef((ii.prepatch))){i(oldVnode,vnode);}constoldCholdVnode.children;constchvnode.children;if(isDef(data)isPatchable(vnode)){for(i0;icbs.update.length;i)cbs.update[i](oldVnode,vnode);if(isDef((idata.hook))isDef((ii.update)))i(oldVnode,vnode);}// 如果 vnode 不是文本节点或者注释节点if(isUndef(vnode.text)){// 并且都有子节点if(isDef(oldCh)isDef(ch)){// 并且子节点不完全一致则调用 updateChildrenif(oldCh!ch)updateChildren(elm,oldCh,ch,insertedVnodeQueue,removeOnly);// 如果只有新的 vnode 有子节点}elseif(isDef(ch)){if(isDef(oldVnode.text))nodeOps.setTextContent(elm,);// elm 已经引用了老的 DOM 节点在老的 DOM 节点上添加子节点addVnodes(elm,null,ch,0,ch.length-1,insertedVnodeQueue);// 如果新 vnode 没有子节点而旧 vnode 有子节点直接删除老的 oldCh}elseif(isDef(oldCh)){removeVnodes(elm,oldCh,0,oldCh.length-1);// 如果老节点是文本节点}elseif(isDef(oldVnode.text)){nodeOps.setTextContent(elm,);}// 如果新 vnode 和老 vnode 是文本节点或注释节点// 但是 vnode.text ! oldVnode.text 时只需要更新 vnode.elm 的文本内容就可以}elseif(oldVnode.text!vnode.text){nodeOps.setTextContent(elm,vnode.text);}if(isDef(data)){if(isDef((idata.hook))isDef((ii.postpatch)))i(oldVnode,vnode);}}updateChildren新旧 vnode 子节点的 diff 算法比较流程通过比较新旧 vnode 子节点就会通过双端 diff 来比较同层节点。当节点一致时就会递归调用patchVnode()进行更新。Vue 2 通过四个指针新旧节点的起始和结束位置进行比较尽可能复用节点当新老VNode节点的start相同时直接patchVnode()同时新老VNode节点的开始索引都加 1。当新老VNode节点的end相同时同样直接patchVnode()同时新老VNode节点的结束索引都减 1。当老VNode节点的start和新VNode节点的end相同时这时候在patchVnode()后还需要将当前真实 DOM 节点移动到oldEndVnode的后面同时老VNode节点开始索引加 1新VNode节点的结束索引减 1。当老VNode节点的end和新VNode节点的start相同时这时候在patchVnode()后还需要将当前真实 DOM 节点移动到oldStartVnode的前面同时老VNode节点结束索引减 1新VNode节点的开始索引加 1。如果都不满足以上四种情形那说明没有相同的节点可以复用则会分为以下两种情况从旧的VNode为key值对应index序列为value值的哈希表中找到与newStartVnode一致key的旧的VNode节点再进行patchVnode()同时将这个真实 DOM 移动到oldStartVnode对应的真实 DOM 的前面。调用createElm()创建一个新的 DOM 节点放到当前newStartIdx的位置。functionupdateChildren(parentElm,oldCh,newCh,insertedVnodeQueue,removeOnly){letoldStartIdx0// 旧头索引letnewStartIdx0// 新头索引letoldEndIdxoldCh.length-1// 旧尾索引letnewEndIdxnewCh.length-1// 新尾索引letoldStartVnodeoldCh[0]// oldVnode的第一个childletoldEndVnodeoldCh[oldEndIdx]// oldVnode的最后一个childletnewStartVnodenewCh[0]// newVnode的第一个childletnewEndVnodenewCh[newEndIdx]// newVnode的最后一个childletoldKeyToIdx,idxInOld,vnodeToMove,refElm// removeOnly is a special flag used only by transition-group// to ensure removed elements stay in correct relative positions// during leaving transitionsconstcanMove!removeOnly// 如果oldStartVnode和oldEndVnode重合并且新的也都重合了证明diff完了循环结束while(oldStartIdxoldEndIdxnewStartIdxnewEndIdx){// 如果oldVnode的第一个child不存在if(isUndef(oldStartVnode)){// oldStart索引右移oldStartVnodeoldCh[oldStartIdx]// Vnode has been moved left// 如果oldVnode的最后一个child不存在}elseif(isUndef(oldEndVnode)){// oldEnd索引左移oldEndVnodeoldCh[--oldEndIdx]// oldStartVnode 和 newStartVnode 是同一个节点}elseif(sameVnode(oldStartVnode,newStartVnode)){// patch oldStartVnode 和 newStartVnode索引左移继续循环patchVnode(oldStartVnode,newStartVnode,insertedVnodeQueue)oldStartVnodeoldCh[oldStartIdx]newStartVnodenewCh[newStartIdx]// oldEndVnode 和 newEndVnode 是同一个节点}elseif(sameVnode(oldEndVnode,newEndVnode)){// patch oldEndVnode 和 newEndVnode索引右移继续循环patchVnode(oldEndVnode,newEndVnode,insertedVnodeQueue)oldEndVnodeoldCh[--oldEndIdx]newEndVnodenewCh[--newEndIdx]// oldStartVnode 和 newEndVnode 是同一个节点}elseif(sameVnode(oldStartVnode,newEndVnode)){// Vnode moved right// patch oldStartVnode 和 newEndVnodepatchVnode(oldStartVnode,newEndVnode,insertedVnodeQueue)// 如果 removeOnly 是 false则将 oldStartVnode.elm 移动到 oldEndVnode.elm 之后canMovenodeOps.insertBefore(parentElm,oldStartVnode.elm,nodeOps.nextSibling(oldEndVnode.elm))// oldStart 索引右移newEnd 索引左移oldStartVnodeoldCh[oldStartIdx]newEndVnodenewCh[--newEndIdx]// 如果 oldEndVnode 和 newStartVnode 是同一个节点}elseif(sameVnode(oldEndVnode,newStartVnode)){// Vnode moved left// patch oldEndVnode 和 newStartVnodepatchVnode(oldEndVnode,newStartVnode,insertedVnodeQueue)// 如果 removeOnly 是 false则将 oldEndVnode.elm 移动到 oldStartVnode.elm 之前canMovenodeOps.insertBefore(parentElm,oldEndVnode.elm,oldStartVnode.elm)// oldEnd 索引左移newStart 索引右移oldEndVnodeoldCh[--oldEndIdx]newStartVnodenewCh[newStartIdx]// 如果都不匹配}else{if(isUndef(oldKeyToIdx))oldKeyToIdxcreateKeyToOldIdx(oldCh,oldStartIdx,oldEndIdx)// 尝试在 oldChildren 中寻找和 newStartVnode 的具有相同的 key 的 VnodeidxInOldisDef(newStartVnode.key)?oldKeyToIdx[newStartVnode.key]:findIdxInOld(newStartVnode,oldCh,oldStartIdx,oldEndIdx)// 如果未找到说明 newStartVnode 是一个新的节点if(isUndef(idxInOld)){// New element// 创建一个新 VnodecreateElm(newStartVnode,insertedVnodeQueue,parentElm,oldStartVnode.elm)// 如果找到了和 newStartVnode 具有相同的 key 的 Vnode叫 vnodeToMove}else{vnodeToMoveoldCh[idxInOld]/* istanbul ignore if */if(process.env.NODE_ENV!production!vnodeToMove){warn(It seems there are duplicate keys that is causing an update error. Make sure each v-for item has a unique key.)}// 比较两个具有相同的 key 的新节点是否是同一个节点// 不设 keynewCh 和 oldCh 只会进行头尾两端的相互比较设 key 后除了头尾两端的比较外还会从用 key 生成的对象 oldKeyToIdx 中查找匹配的节点所以为节点设置 key 可以更高效的利用 DOMif(sameVnode(vnodeToMove,newStartVnode)){// patch vnodeToMove 和 newStartVnodepatchVnode(vnodeToMove,newStartVnode,insertedVnodeQueue)// 清除oldCh[idxInOld]undefined// 如果 removeOnly 是 false则将找到的和 newStartVnode 具有相同的 key 的 Vnode叫 vnodeToMove.elm// 移动到 oldStartVnode.elm 之前canMovenodeOps.insertBefore(parentElm,vnodeToMove.elm,oldStartVnode.elm)// 如果 key 相同但是节点不相同则创建一个新的节点}else{// same key but different element. treat as new elementcreateElm(newStartVnode,insertedVnodeQueue,parentElm,oldStartVnode.elm)}}// 右移newStartVnodenewCh[newStartIdx]}}四种规则的具体原因和作用假设旧列表oldVnodes指针oldStartIdx开始索引、oldEndIdx结束索引。新列表newVnodes指针newStartIdx开始索引、newEndIdx结束索引。节点复用的判断key相同且标签名等基础属性一致。1. 当oldStartVnode.key newStartVnode.key新旧开始节点相同操作直接patchVnode()复用节点更新内容然后oldStartIdx、newStartIdx。原因这是最理想的情况 —— 新旧列表头部节点完全一致无需移动 DOM直接更新内容即可。例如旧列表[A, B, C]新列表[A, B, D]首节点A相同直接复用并后移指针。2. 当oldEndVnode.key newEndVnode.key新旧结束节点相同操作直接patchVnode()然后oldEndIdx--、newEndIdx--原因与规则 1 对称尾部节点相同无需移动直接更新内容。例如旧列表[A, B, C]新列表[D, B, C]尾节点C相同复用并前移指针3. 当oldStartVnode.key newEndVnode.key旧开始节点 新结束节点操作patchVnode()后将旧开始节点对应的真实 DOM移动到旧结束节点的后面然后oldStartIdx、newEndIdx--。原因这种情况说明该节点在新列表中被 “移到了尾部”。通过一次移动操作而非删除再新增复用节点减少 DOM 操作成本。例如旧列表[A, B, C]新列表[B, C, A]旧首A与新尾A匹配此时只需把A移动到C后面即可符合新列表结构。4. 当oldEndVnode.key newStartVnode.key旧结束节点 新开始节点操作patchVnode()后将旧结束节点对应的真实 DOM移动到旧开始节点的前面然后oldEndIdx--、newStartIdx。原因与规则 3 对称该节点在新列表中被 “移到了头部”通过一次移动操作复用节点。例如旧列表[A, B, C]新列表[C, A, B]旧尾C与新首C匹配把C移动到A前面即可。双端 diff 算法的优势优先处理 “无需移动” 的节点规则 1 和 2 直接复用头部 / 尾部相同的节点避免无效操作。用最少移动解决 “顺序调整”规则 3 和 4 针对节点位置互换的场景通过一次移动即可完成位置修正比 “删除 新增” 高效得多DOM 移动的成本远低于删除和创建。减少遍历范围每处理完一个节点指针就向中间收缩逐步缩小对比范围避免全量遍历时间复杂度从 O(n²) 优化为 O(n)。思考1. Vue2 中所指的同层节点比较是指哪一块同层节点比较发生在同个新旧 vnode 节点的子节点children比较阶段即双端 diff 阶段不会发生跨层级节点的比较。2. 为何要采用双端 diff如果是正常的子节点 diff我们需要遍历新节点然后再嵌套遍历旧节点即 Vue 设计与实现中讲到的简单 diff 流程时间复杂度是 O(n²)使用双端 diff首尾指针比对可以把实现复杂度压缩到 O(n)。总结VDOM 存在的价值通过维护虚拟 DOM 树减少直接操作真实 DOM 的性能开销提供声明式编程模型支持跨平台渲染。Diff 算法流程数据变化触发setter → Watcher → updateComponent() → patch() → patchVnode() → updateChildren()通过双端 diff 算法高效比较和更新节点。双端 diff 算法使用四个指针新旧节点的起始和结束位置进行比较通过四种匹配规则优先处理无需移动的节点用最少移动解决顺序调整时间复杂度从 O(n²) 优化为 O(n)。key 复用节点key 属性帮助识别相同节点并复用避免不必要的重建。参考内容vuejs/vue at v2.7.16深入理解 Vue.js 的虚拟 DOM 和 Diff 算法Vue 设计与实现 - 第 10 章 双端 diff 算法
版权声明:本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!

制作app免费网站模板长春火车站高清图片

免费咖啡烘焙软件终极指南:Artisan让你成为专业烘焙师 【免费下载链接】artisan artisan: visual scope for coffee roasters 项目地址: https://gitcode.com/gh_mirrors/ar/artisan 你是否曾经梦想过成为一名专业的咖啡烘焙师?现在,这…

张小明 2026/1/2 21:18:17 网站建设

外贸原单童装哪个网站做西地那非片的功能主治服用方式

用8位定时器玩转LED调光:从原理到实战的嵌入式手记你有没有遇到过这样的场景?手上的MCU资源紧张,没有专用PWM模块,却要实现一个呼吸灯效果;或者产品要求超低功耗,不能靠软件延时“死等”来控制亮度。这时候…

张小明 2026/1/2 14:13:28 网站建设

蓝奏云注册网站wordpress 4.7.3

DeepSeek-Coder-V2本地部署完整指南 【免费下载链接】DeepSeek-Coder-V2 项目地址: https://gitcode.com/GitHub_Trending/de/DeepSeek-Coder-V2 DeepSeek-Coder-V2是当前性能最强大的开源代码智能模型之一,在多项基准测试中表现出色,特别适合需…

张小明 2026/1/2 16:15:22 网站建设

互动科技 网站建设海南最近三天的新闻大事

量子计算:原理、算法与独特特性 1. 独特设置门 在量子计算中,单量子比特转换或受控非门可用于实现任何酉变换。为了便于处理,使用较小的门集合往往更好。虽然无法通过有限的门集合组合来执行所有酉变换,但可以证明,任何有限的门集合都能以任意精度近似任何酉转换。而且,…

张小明 2026/1/3 16:42:18 网站建设

廊坊网站排名优化价格网站的配色技巧

Qwen3-VL思维版:终极视觉语言AI来了! 【免费下载链接】Qwen3-VL-235B-A22B-Thinking 项目地址: https://ai.gitcode.com/hf_mirrors/Qwen/Qwen3-VL-235B-A22B-Thinking Qwen3-VL-235B-A22B-Thinking正式发布,标志着视觉语言模型进入&…

张小明 2026/1/4 2:37:01 网站建设