1.Linux下驱动安装指南linux下安装驱动
2.vue3ä¸çç¼è¯å¨åçåä¼åçç¥
3.element-tabs组件 源码阅读
4.squid 强制缓存动态页面
Linux下驱动安装指南linux下安装驱动
Linux中一般用于驱动安装的都是DKMS(Dynamic Kernel Module Support)动态内核模块支持机制。大部分发行版的补丁补丁安装介质都包含DKMS,从而使我们可以更容易地构建和安装设备驱动程序。源码源码本文将简要介绍如何在Linux下安装驱动程序。动态动态
1、补丁补丁检查内核。源码源码降重软件源码根据当前运行的动态动态内核,无论是补丁补丁下载公开可用的最新Linux内核,还是源码源码利用国内各种发行版,如CentOS和Ubuntu,动态动态通过它们提供的补丁补丁内核文件的方法,都可以安装最新的源码源码内核。可以用此处的动态动态代码查看内核信息:`uname –r`。
2、补丁补丁DKMS安装。源码源码从字面上可以看出,DKMS是用于管理动态内核模块,它能够自动匹配内核架构、重新安装内核时重新构建内核模块等。比起内核编译,使用DKMS构建设备驱动更为容易,也可以减轻Linux发行版的分发量。可以用以下代码安装DKMS:`sudo apt-get install dkms`
3、准备构建和安装模块补丁文件。服务预约系统源码系统准备好后,就可以准备构建模块文件和安装相关的补丁文件了。设备驱动的源码文件和补丁文件可以从设备制造商的官网上获得,我们可以下载安装。
4、编译模块文件。将模块文件解压至目标目录后,将它添加到DKMS的支持中:`sudo dkms add -m -v `。接下来就可以编译这一模块文件:`sudo dkms install -m -v `。
5、模块安装完成后,我们可以使用如下命令确认模块是否正确安装:`modprobe `,如果提示”module not found”,则表示构建失败。
以上步骤给出了Linux下安装驱动程序的指南。在执行安装之前,需要评估构建环境、模块版本和兼容性等,以确保所有操作都能成功执行。然而,由于已经完善的支持,只要采取合理的步骤,我们都可以轻松完成驱动的双龙出海源码安装。
vue3ä¸çç¼è¯å¨åçåä¼åçç¥
å¦ä¹ ç®æ
ç¼è¯å¨åç
vue3ç¼è¯è¿ç¨åæ
vue3ç¼è¯ä¼åçç¥
å¨åå§åä¹åå¯è½æç¼è¯çè¿ç¨ï¼æç»ç产ç©æ¯ä¸ªæ¸²æå½æ°ï¼æ们ç¥é渲æå½æ°è¿åçå¼æ¯ä¸ä¸ªèæDOM(vnode),é£ä¹è¿ä¸ªèæDOMå¨æ们åç»çæ´æ°è¿ç¨ä¸å°åºæä»ä¹ä½ç¨å¢ï¼æ们ä»å¤©å°±æ¥æ¢è®¨ä¸ä¸ã
ç¼è¯å¨åç1.æ¦å¿µå¹¿ä¹ä¸çç¼è¯åçï¼ç¼è¯å¨æ¯å°æºä»£ç 转åææºå¨ç ç软件ï¼æ以ç¼è¯çè¿ç¨åæ¯å°æºä»£ç 转åææºå¨ç çè¿ç¨ï¼ä¹å°±æ¯cpuå¯æ§è¡çäºè¿å¶ä»£ç ãä¾å¦ä½¿ç¨é«çº§è¯è¨javaç¼åçç¨åºéè¦ç¼è¯ææ们çä¸æä½è®¡ç®æºè½çæççåèç ã
å¦æäºè§£è¿ç¼è¯å¨çå·¥ä½æµç¨çåå¦åºè¯¥ç¥éï¼ä¸ä¸ªå®æ´çç¼è¯å¨çå·¥ä½æµç¨ä¼æ¯è¿æ ·ï¼
é¦å ï¼parse解æåå§ä»£ç å符串ï¼çææ½è±¡è¯æ³æ ASTã
å ¶æ¬¡ï¼transform转åæ½è±¡è¯æ³æ ï¼è®©å®åææ´è´´è¿ç®æ ãDSLãçç»æã
æåï¼codegenæ ¹æ®è½¬ååçæ½è±¡è¯æ³æ çæç®æ ãDSLãçå¯æ§è¡ä»£ç ã
2.vueä¸çç¼è¯å¨vueéä¹æç¼è¯çè¿ç¨ï¼æ们ç»å¸¸åçé£ä¸ªHTML模çï¼å¨çæ£å·¥ä½çæ¶åï¼å¹¶ä¸æ¯é£ä¸ªHTML模çï¼å®å®é ä¸æ¯ä¸ä¸ªæ¸²æå½æ°ï¼å¨è¿ä¸ªè¿ç¨ä¸å°±åçäºè½¬æ¢ï¼ä¹å°±æ¯ç¼è¯ï¼ä¹å°±æ¯é£ä¸ªå符串ç模çæç»ä¼åæä¸ä¸ªJSå½æ°ï¼å«renderå½æ°ãæ以å¨è¿ä¸ªè¿ç¨ä¸æ们就éè¦å¼å ¥ç¼è¯å¨çæ¦å¿µãå¨è®¡ç®æºä¸å½ä¸ç§ä¸è¥¿ä»ä¸ç§å½¢æå°å¦ä¸ç§å½¢æè¿è¡è½¬æ¢çæ¶åï¼å°±éè¦ç¼è¯ãç¼è¯å¨ï¼ç¨æ¥å°æ¨¡æ¿å符串ç¼è¯æ为JavaScript渲æå½æ°ç代ç
é£ä¹vueä¸çç¼è¯åçå¨ä»ä¹æ¶åå¢ï¼
è¿ä¸ªæ¶åæ们就éè¦è¿ä¸æ¥äºè§£vueå çä¸åçæ¬çä¸ååè½äºãvueææºå¸¦ç¼è¯å¨åä¸æºå¸¦ç¼è¯çå ï¼å¯¹ä¸åæ建çæ¬ç解éï¼ã
3.è¿è¡æ¶ç¼è¯å¨ä½¿ç¨æºå¸¦ç¼è¯å¨(compiler)çvueå çæ¶åï¼vueç¼è¯çæ¶å»æ¯åçå¨æè½½($mount)çæ¶åã
4.è¿è¡æ¶ä¸ç¼è¯å¦æ使ç¨æªæºå¸¦ç¼è¯å¨çvueå çæ¶åï¼vueå¨è¿è¡æ¶æ¯ä¸ä¼è¿è¡ç¼è¯çãé£ä¹å®çç¼è¯ååçå¨ä»ä¹æ¶åå¢ï¼ä½¿ç¨æªæºå¸¦ç¼è¯å¨çvueå çæ¶åï¼éè¦è¿è¡é¢ç¼è¯ï¼ä¹å°±æ¯åºäºæå»ºå·¥å ·ä½¿ç¨ï¼å°±æ¯æ们平æ¶ä½¿ç¨çvue-cliè¿è¡æ建ç项ç®ï¼å°±æ¯ä½¿ç¨webpackè°ç¨vue-loaderè¿è¡é¢ç¼è¯ï¼å°æævueæ件ï¼å°±æ¯SFCï¼å°éé¢çtemplate模çé¨å转æ¢ærenderå½æ°ãè¿æ ·åç好å¤å°±æ¯vueçå ä½ç§¯åå°äºï¼æ§è¡çæ¶åé度æ´å¿«äºï¼å 为ä¸éè¦è¿è¡ç¼è¯äºã
vueç¼è¯å¨åçç®åæ¥è¯´å°±æ¯ï¼å å°template模ç转æ¢æastæ½è±¡è¯æ³æ ï¼astå转æ¢æ渲æå½æ°renderã
é£ä¹ä»ä¹æ¯æ¯astæ½è±¡è¯æ³æ å¢ï¼
1.astæ½è±¡è¯æ³æ å¨template模çårenderå½æ°ä¹é´æä¸ä¸ªä¸é´äº§ç©å«åastæ½è±¡è¯æ³æ ãå®å°±æ¯ä¸ªjs对象ï¼å®è½å¤æè¿°å½å模ççç»æä¿¡æ¯ï¼è·vnodeå¾ç±»ä¼¼ã注æï¼aståªæ¯ç¨åºè¿è¡è¿ç¨ä¸ç¼è¯äº§ççï¼å®è·æ们æç»ç¨åºçè¿è¡æ¯æ²¡æä»»ä½å ³ç³»çãä¹å°±æ¯å½è¿ä¸ªæ¸²æå½æ°çæä¹åï¼astççå½å¨æå°±ç»æäºï¼ä¸åéè¦äºï¼èé£ä¸ªèæDOMåä¼´éæ´ä¸ªç¨åºççå½å¨æãè¿ä¸ªå°±æ¯aståèæDOMçæ¬è´¨åºå«ã
2.为ä»ä¹éè¦astå¢å¨ast转æ¢ærenderå½æ°çè¿ç¨ä¸ï¼éè¦è¿è¡ç¹å«çæä½ã第ä¸æ¬¡ï¼å°template转æçastæ¯ä¸ªé常ç²ç³çjs对象ï¼æ¯ä¸æ¬¡é常ç²ç³ç转æ¢ï¼ç±»ä¼¼æ£å表达å¼çå¹é ï¼ç¶åæ们çtemplate模çä¸è¿æå¾å¤è¡¨è¾¾å¼ï¼æ令ï¼äºä»¶éè¦éæ°è§£æï¼ç»è¿è¿äºå ·ä½çæ·±å å·¥ç解æ(transform)ä¹åä¼å¾å°ä¸ä¸ªç»æastï¼ç¶åè¿ä¸ªå¯¹è¿ä¸ªç»æastè¿è¡generateï¼çærenderå½æ°
template=>ast=>transform=>ast=>render3.miniçvueç¼è¯å¨ä¸é¢æ们æ¥çä¸ä¸ªminiççvueç¼è¯å¨ï¼å ·ä½ä»£ç å·²çç¥ï¼å ·ä½ä»£ç æå·²ç»æ¾å¨Githubä¸äºï¼mini-vue-compiler
functiontokenizer(input){ ...}functionparse(template){ consttokens=tokenizer(template)...}functiontransform(ast){ ...}functiontraverse(ast,context){ ...}functiongenerate(ast){ ...}functioncompile(template){ //1.解æconstast=parse(template)console.log(JSON.stringify(ast,null,2))//2.转æ¢transform(ast)//3.çæconstcode=generate(ast)console.log(code)//returnfunctionrender(ctx){ //returnh("h3",{ },//ctx.title//)}returnnewFunction(code)()}lettmpl=`<h3>{ { title}}</h3>`compile(tmpl)大æ¦æ以ä¸æä½ï¼å ¶ä¸parseå½æ°å°±æ¯åçå¨ætemplate转æ¢æastçè¿è¿ç¨ï¼å ·ä½æ¯éè¿ä¸äºæ£å表达å¼çå¹é templateä¸çå符串ãæ¯å¦å°
xxx转æast对象ï¼é£ä¹å°±æ¯éè¿æ£å表达å¼å¹é å¦ææ¯
é£ä¹å°±è®¾ç½®ä¸ä¸ªå¼å§æ è®°ï¼åå¾åé¢å¹é å°xxxå 容ï¼ç¶å就设置ä¸ä¸ªåå ç´ ï¼æåå¹é å°é£ä¹å°±è®¾ç½®ä¸ä¸ªç»ææ è®°ï¼ä»¥æ¤ç±»æ¨ãparse解æä¹åå¾å°çæ¯ä¸ä¸ªç²ç³çast对象ãç»è¿parse解æå¾å°ä¸ä¸ªç²ç³çast对象ä¹åï¼å°±ç¨transformè¿è¡æ·±å å·¥ï¼æåè¦ç»è¿generateçæ代ç ã
Vue3ç¼è¯è¿ç¨åææè½½çæ¶åå ætemplateç¼è¯ærenderå½æ°ï¼å¨å建å®ä¾ä¹åï¼ç´æ¥è°ç¨ç»ä»¶å®ä¾çrenderå½æ°å建è¿ä¸ªç»ä»¶ççå®DOMï¼ç¶å继ç»åä¸åéå½ã
1.vue2.xåvue3.xçç¼è¯å¯¹æ¯Vue2.xä¸çCompileè¿ç¨ä¼æ¯è¿æ ·ï¼
parseè¯æ³åæï¼ç¼è¯æ¨¡æ¿çæåå§ç²ç³çASTã
optimizeä¼ååå§ASTï¼æ è®°ASTElement为éææ ¹èç¹æéæèç¹ã
generateæ ¹æ®ä¼ååçASTï¼çæå¯æ§è¡ä»£ç ï¼ä¾å¦_cã_lä¹ç±»çã
å¨Vue3ä¸ï¼æ´ä½çCompileè¿ç¨ä»ç¶æ¯ä¸ä¸ªé¶æ®µï¼ä½æ¯ä¸åäºVue2.xçæ¯ï¼ç¬¬äºä¸ªé¶æ®µæ¢æäºæ£å¸¸ç¼è¯å¨é½ä¼åå¨çé¶æ®µtransformã
parseè¯æ³åæï¼ç¼è¯æ¨¡æ¿çæåå§ç²ç³çASTã
transforméåAST,对æ¯ä¸ä¸ªASTelementè¿è¡è½¬åï¼ä¾å¦ææ¬å ç´ ãæ令å ç´ ãå¨æå ç´ ççç转å
generateæ ¹æ®ä¼ååçASTï¼çæå¯æ§è¡ä»£ç å½æ°ã
2.æºç ç¼è¯å ¥å£æ们å ä»ä¸ä¸ªå ¥å£æ¥å¼å§æ们çæºç é 读ï¼packages/vue/index.tsã
//webå¹³å°ç¹æç¼è¯å½æ°functioncompileToFunction(template:string|HTMLElement,options?:CompilerOptions):RenderFunction{ //çç¥...if(template[0]==='#'){ //è·å模çå 容constel=document.querySelector(template)//çç¥...template=el?el.innerHTML:''}//ç¼è¯const{ code}=compile(template,extend({ //çç¥...},options))constrender=(__GLOBAL__?newFunction(code)():newFunction('Vue',code)(runtimeDom))asRenderFunction//çç¥...return(compileCache[key]=render)}//注åç¼è¯å½æ°registerRuntimeCompiler(compileToFunction)export{ compileToFunctionascompile}è¿ä¸ªå ¥å£æ件ç代ç æ¯è¾ç®åï¼åªæä¸ä¸ªcompileToFunctionå½æ°ï¼ä½å½æ°ä½å çå 容å´åæ¯è¾å ³é®ï¼ä¸»è¦æ¯ç»å以ä¸æ¥éª¤ï¼
ä¾èµæ³¨å ¥ç¼è¯å½æ°è³runtimeregisterRuntimeCompiler(compileToFunction)
runtimeè°ç¨ç¼è¯å½æ°compileToFunction
è°ç¨compileå½æ°
è¿åå å«codeçç¼è¯ç»æ
å°codeä½ä¸ºåæ°ä¼ å ¥Functionçæé å½æ°å°çæçå½æ°èµå¼ç»renderåé
å°renderå½æ°ä½ä¸ºç¼è¯ç»æè¿å
3.templateè·åapp.mount()è·åäºtemplatepackages/runtime-dom/src/index.ts
4.ç¼è¯templatecompileå°ä¼ ?templateç¼è¯ä¸ºrenderå½æ°ï¼packages/runtime-core/src/component.ts
å®é æ§?çæ¯baseCompileï¼packages/compiler-core/src/compile.ts
第?æ¥è§£æ-parseï¼è§£æå符串template为æ½è±¡è¯æ³æ ast
第?æ¥è½¬æ¢-transformï¼è§£æå±æ§ãæ ·å¼ãæ令ç
第ä¸æ¥?æ-generateï¼å°ast转æ¢ä¸ºæ¸²æå½æ°
Vue3ç¼è¯å¨ä¼åçç¥è¿æ¯ä¸ä¸ªéå¸¸å ¸åçç¨å åæ¢æ¶é´çæä½
1.éæèç¹æå<div><div>{ { msg}}</div><p>coboy</p><p>coboy</p><p>coboy</p></div>以ä¸è¿ä¸ªæ®µtemplateå¦æ没æå¼å¯éæèç¹æåå®ç¼è¯åæ¯è¿æ ·çï¼
import{ toDisplayStringas_toDisplayString,createVNodeas_createVNode,openBlockas_openBlock,createBlockas_createBlock}from"vue"exportfunctionrender(_ctx,_cache,$props,$setup,$data,$options){ return(_openBlock(),_createBlock("div",null,[_createVNode("div",null,_toDisplayString(_ctx.msg),1/*TEXT*/),_createVNode("p",null,"coboy"),_createVNode("p",null,"coboy"),_createVNode("p",null,"coboy")]))}å¦æå¼å¯äºéæèç¹æåä¹åå®ç¼è¯ååæ¯è¿æ ·çï¼
import{ toDisplayStringas_toDisplayString,createVNodeas_createVNode,openBlockas_openBlock,createBlockas_createBlock}from"vue"const_hoisted_1=/*#__PURE__*/_createVNode("p",null,"coboy",-1/*HOISTED*/)const_hoisted_2=/*#__PURE__*/_createVNode("p",null,"coboy",-1/*HOISTED*/)const_hoisted_3=/*#__PURE__*/_createVNode("p",null,"coboy",-1/*HOISTED*/)exportfunctionrender(_ctx,_cache,$props,$setup,$data,$options){ return(_openBlock(),_createBlock("div",null,[_createVNode("div",null,_toDisplayString(_ctx.msg),1/*TEXT*/),_hoisted_1,_hoisted_2,_hoisted_3]))}æ们å¯ä»¥çå°templateéåå¨å¤§éçä¸ä¼åçpæ ç¾ï¼æ以å½è¿ä¸ªç»ä»¶éæ°æ¸²æçæ¶åï¼è¿äºéæçä¸ä¼åçæ ç¾å°±ä¸åºè¯¥å次å建äºãæ以vue3å°±æè¿äºéæçä¸ä¼åçæ ç¾çVNodeæ¾å¨äºrenderå½æ°ä½ç¨åçå¤é¢ï¼å¨ä¸æ¬¡renderå½æ°å次æ§è¡çæ¶åï¼é£äºéææ ç¾çVNodeå·²ç»å¨å åéäºï¼ä¸éè¦éæ°å建äºãç¸å½äºå ç¨å½åæºå¨çå åï¼é¿å éå¤å建VNodeï¼ç¨å åæ¥æ¢æ¶é´ã大家ä»ç»æé ä¸çªéææåçåç¼ï¼éæäºåæ们å¯ä»¥ä¸çï¼ä½æ¯æåäºåï¼ç´ææ¬æå°è¡¨è¾¾åºå®ï¼éæèç¹ï¼è¢«æé«äºã
2.è¡¥ä¸æ è®°åå¨æå±æ§è®°å½<div><div:title="title">coboy</div></div>ææå°±æ¯å¨ç¼è¯çè¿ç¨ä¸ï¼å人ç¼ä¸æ ·å¯¹æ¨¡çè¿è¡æ«æçåªäºä¸è¥¿æ¯å¨æçï¼ç¶åæåæè¿äºå¨æçä¸è¥¿æåä¿åèµ·æ¥ï¼ä½ä¸ªæ è®°åè®°å½ï¼çä¸æ¬¡æ´æ°çæ¶åï¼åªæ´æ°è¿äºä¿åèµ·æ¥çå¨æçè®°å½ãæ¯å¦ä¸é¢æ¨¡ççtitleæ¯å¨æçï¼æåå个æ è®°åè®°å½ï¼æ´æ°çæ¶åå°±åªæ´æ°titleé¨åçå 容ã
import{ createVNodeas_createVNode,openBlockas_openBlock,createBlockas_createBlock}from"vue"exportfunctionrender(_ctx,_cache,$props,$setup,$data,$options){ return(_openBlock(),_createBlock("div",null,[_createVNode("div",{ title:_ctx.title},"coboy",8/*PROPS*/,["title"])]))}<div><div:title="title">{ { text}}</div></div>import{ toDisplayStringas_toDisplayString,createVNodeas_createVNode,openBlockas_openBlock,createBlockas_createBlock}from"vue"exportfunctionrender(_ctx,_cache,$props,$setup,$data,$options){ return(_openBlock(),_createBlock("div",null,[_createVNode("div",{ title:_ctx.title},_toDisplayString(_ctx.text),9/*TEXT,PROPS*/,["title"])]))}æ们å¯ä»¥è§å¯å°å¨_createVNodeå½æ°ç第å个åæ°æ¯ä¸ª9ï¼åé¢æ¯ä¸ä¸ªæ³¨éï¼/TEXT,PROPS/ï¼è¿ä¸ªæ¯è¡¨ç¤ºå¨å½åçèç¹éé¢æ两个ä¸è¥¿æ¯å¨æçï¼ä¸ä¸ªæ¯å é¨çææ¬ï¼ä¸ä¸ªæ¯å±æ§ï¼ç¶åå ·ä½æ¯åªä¸ªå±æ§ï¼å¨ç¬¬äºä¸ªåæ°çæ°ç»éé¢åè®°å½äºä¸æ¥["title"]ï¼æ个titleçå±æ§æ¯å¨æçã
å¨å°æ¥è¿è¡patchæ´æ°çæ¶åï¼å°±å¯ä»¥æ ¹æ®å½åè®°å½çä¿¡æ¯ï¼è¿è¡æ´æ°ï¼ç¼©åæ´æ°è¿ç¨åæä½ï¼å¯ä»¥é常精确å°åªè¿è¡titleåææ¬çæ´æ°ã
å¦ædivæ ç¾éæ¯éæææ¬çè¯ï¼_createVNodeå½æ°ç第å个åæ°ååæäº8ï¼åé¢ç注éåæäºï¼/PROPS/ï¼åé¢ç第äºä¸ªåæ°æ°æ®ä¸åã
_createVNodeå½æ°ç第å个åæ°çæ°åå ¶å®æ¯ä¸ä¸ªäºè¿å¶æ°å转æåè¿å¶çæ°åã
8çäºè¿å¶æ¯ï¼9çäºè¿å¶æ¯ï¼å¾å®¹æå¯ä»¥çåºäºè¿å¶çæ¯ä¸ä½çæ°åé½ä»£è¡¨çç¹æ®çå«ä¹ãè¿äºæ°åå°±æ¯patchFlagï¼é£ä¹ä»ä¹æ¯patchFlagå¢ï¼
ä»ä¹æ¯patchFlagpatchFlagæ¯complieræ¶çtransformé¶æ®µè§£æASTElementæä¸çè¡¥ä¸æ è®°ãå®ä¼ä¸ºruntimeæ¶çpatchVNodeæä¾ä¾æ®ï¼ä»èå®ç°é¶åæ´æ°VNodeåéææåçææã
patchFlag被å®ä¹ä¸ºä¸ä¸ªæ°åæ举类åï¼å®çæ¯ä¸ä¸ªæ举å¼å¯¹åºçæ è¯æä¹æ¯ï¼
TEXT=1å¨æææ¬çå ç´
CLASS=2å¨æç»å®classçå ç´
STYLE=4å¨æç»å®styleçå ç´
PROPS=8å¨æpropsçå ç´ ï¼ä¸ä¸å«æclassãstyleç»å®
FULL_PROPS=å¨æpropså带ækeyå¼ç»å®çå ç´
HYDRATE_EVENTS=äºä»¶çå¬çå ç´
STABLE_FRAGMENT=åå ç´ ç订é ä¸ä¼æ¹åçFragmentå ç´
KEYED_FRAGMENT=èªå·±æåå ç´ å¸¦ækeyå¼ç»å®çFragmentå ç´
UNKEYED_FRAGMENT=没ækeyå¼ç»å®çFragmentå ç´
NEED_PATCH=带ærefãæ令çå ç´
DYNAMIC_SLOTS=å¨æslotçç»ä»¶å ç´
HOISTED=-1éæçå ç´
BAIL=-2ä¸æ¯renderå½æ°çæçä¸äºå ç´ ï¼ä¾å¦renderSlot
æ´ä½ä¸patchFlagçå为两大类ï¼
å½patchFlagçå¼å¤§äº0æ¶ï¼ä»£è¡¨æ对åºçå ç´ å¨patchVNodeæ¶ærenderæ¶æ¯å¯ä»¥è¢«ä¼åçæææ´æ°ç
å½patchFlagçå¼å°äº0æ¶ï¼ä»£è¡¨æ对åºçå ç´ å¨patchVNodeæ¶ï¼æ¯éè¦è¢«fulldiffï¼å³è¿è¡éå½éåVNodetreeçæ¯è¾æ´æ°è¿ç¨ã
以ä¸å°±æ¯vue3çä¸ä¸ªé常é«æçä¼åçç¥å«è¡¥ä¸æ è®°åå¨æå±æ§è®°å½ã
3.ç¼åäºä»¶å¤çç¨åºfunctiontokenizer(input){ ...}functionparse(template){ consttokens=tokenizer(template)...}functiontransform(ast){ ...}functiontraverse(ast,context){ ...}functiongenerate(ast){ ...}functioncompile(template){ //1.解æconstast=parse(template)console.log(JSON.stringify(ast,null,2))//2.转æ¢transform(ast)//3.çæconstcode=generate(ast)console.log(code)//returnfunctionrender(ctx){ //returnh("h3",{ },//ctx.title//)}returnnewFunction(code)()}lettmpl=`<h3>{ { title}}</h3>`compile(tmpl)0å°æ¥æ¡æ¶ä¼åreacté£æ ·æ@click="onClick"åæ@click="()=>onClick()"ï¼æåå¯è½æ¯è¿æ ·çä¸ä¸ªç®å¤´å½æ°ãé£å°±æå³çæ¯æ¬¡onClickçå½æ°é½æ¯ä¸ä¸ªå ¨æ°çå½æ°ï¼é£å°±ä¼é æè¿ä¸ªåè°å½æ°ææ没æåï¼é½ä¼è¢«è®¤ä¸ºåäºï¼é£å°±å¿ é¡»è¿è¡ä¸ç³»åçæ´æ°ï¼é£ä¹å¦æè½æè¿ä¸ªåè°å½æ°ç¼åèµ·æ¥ï¼æ´æ°çæ¶åï¼å°±ä¸è¦åå建äºã
æªè¿è¡ç¼åäºä»¶å¤çç¨åºä¹åçç¼è¯
functiontokenizer(input){ ...}functionparse(template){ consttokens=tokenizer(template)...}functiontransform(ast){ ...}functiontraverse(ast,context){ ...}functiongenerate(ast){ ...}functioncompile(template){ //1.解æconstast=parse(template)console.log(JSON.stringify(ast,null,2))//2.转æ¢transform(ast)//3.çæconstcode=generate(ast)console.log(code)//returnfunctionrender(ctx){ //returnh("h3",{ },//ctx.title//)}returnnewFunction(code)()}lettmpl=`<h3>{ { title}}</h3>`compile(tmpl)1è¿è¡ç¼åäºä»¶å¤çç¨åºä¹åçç¼è¯
functiontokenizer(input){ ...}functionparse(template){ consttokens=tokenizer(template)...}functiontransform(ast){ ...}functiontraverse(ast,context){ ...}functiongenerate(ast){ ...}functioncompile(template){ //1.解æconstast=parse(template)console.log(JSON.stringify(ast,null,2))//2.转æ¢transform(ast)//3.çæconstcode=generate(ast)console.log(code)//returnfunctionrender(ctx){ //returnh("h3",{ },//ctx.title//)}returnnewFunction(code)()}lettmpl=`<h3>{ { title}}</h3>`compile(tmpl).åblockè¿æ¯ä»ä¹ææå¢ï¼æ ¹æ®å°¤é¨æºªæ¬äººç解æï¼ä»è¯´ï¼æ ¹æ®ä»çç»è®¡é£ä¸ªå¨æçé¨åæå¤åªæä¸åä¹ä¸ï¼åºæ¬ä¸é½æ¯éæé¨åï¼æ以å¨ç¼è¯çè¿ç¨ä¸ï¼è½ä¸è½åç°é£ä¸ªæ¯è¾å°çå¨æé¨åï¼æå®æ¾å°æ¯è¾é ä¸
element-tabs组件 源码阅读
在深入分析element-tabs组件源码的过程中,需要把握两个基本前提:首先,对API有着深入的理解;其次,带着具体问题进行阅读,以便更高效地获取所需信息。遵循两个基本原则:不要过于纠结于那些无关紧要的细节,而应首先明确自己的实现思路,然后再深入阅读源码。接下来,我们将针对几个关键点进行详细探讨。
首先,我们关注于元素切换时的滑动效果。通过观察源码,可以发现这种效果实现的关键在于tabs内部的计算逻辑。在`/tabs/src/tab-nav.vue`文件中,使用jsx语法实现的逻辑中,通过判断`type`的类型来决定是否调用`tab-bar`。`tab-bar`内部通过计算属性来计算`nav-bar`的宽度,这一计算依赖于`tabs.vue`通过`props`传入的`panes`数据。这表明`nav-bar`的宽度是由`panes`数组驱动的,从而实现了动态调整和滑动效果。
接下来,我们探讨`border-card`中的python游戏源码坦克边框显示机制。通过观察源码,发现`tabs.scss`中`nav-wrap`的样式设置为`overflow: hidden`。这个设置与边框显示之间的关系在于,通过改变当前选中的`tab`的`border-bottom-color`为`#fff`,来实现边框的动态显示效果。具体来说,当激活某个`tab`时,通过调整CSS样式使得边框底边颜色变白,从而达到视觉上的边框显现效果。实现的细节在于通过设置`nav`的盒子位置下移动1px,并且使激活的`tab`的`border-bottom`颜色为白色,以此达成效果。
再者,`tab-position`共有四个位置调节选项:`top`、`right`、`bottom`和`left`。通过分析源码可以发现,`top`是常规布局,而`left`与`right`是基于`BFC`的两侧布局,`bottom`则通过改变插槽子节点的位置来实现常规布局。具体实现细节在于`el-tabs__content`的代码中,针对`is-left`和`is-right`的SCSS代码,以及`is-top`和`is-bottom`的稀土可溯源码区别仅在于`tabs.vue`里的放置位置。这意味着`left`和`bottom`的布局是基于`BFC`的两侧等高布局,而`top`和`bottom`则只是常规流体布局,只是位置不同。
对于`stretch`功能的实现细节,通过分析源码可以得出当`stretch`设置为`false`时,`tab`的显示形式为`inline-block`;当设置为`true`时,父级变为`flex`布局,而子`tab`具有`flex:1`的属性。这表明`stretch`功能通过调整显示模式和布局方式,实现了`tab`的弹性扩展。
在业务逻辑方面,`tabs`组件的逻辑主要体现在计算`tabs`插槽里的`tab-pane`组件,并将其解析为对应的组件数组`panes`。渲染分为两部分:一方面,通过`tabs`组件将`panes`传给`tab-nav`渲染`tab-header`,另一方面,直接渲染`$slots.default`对应的`tab-pane`组件。`tabs`组件的选中状态由`currentName`控制。`tab-header`通过`inject`获取`tabs`实例的`setCurrentName`方法,从而操作选中的`tab`;而`tab-pane`则是通过`$parents.currentName`实时控制当前`pane`是否展示。
对于动态新增`tab`的细节,`tabs.vue`在`mounted`时会调用`calcPaneInstances`函数来获取对应的`panes`。`calcPaneInstances`的主要作用是通过`slots.default`获取对应的组件实例。`panes`在两个关键位置被使用:在`tab-nav`组件中构造`tab-header`,以及在不考虑切换影响的内容渲染中。当动态增加`tab-pane`时,虽然`panes`不会响应变化,但通过在`tabs.vue`的虚拟DOM补丁更新后执行`updated`钩子,可以自动更新`panes`。
此外,`tabs`插槽可以插入不受切换影响的内容,这一特性在`tabs.vue`中的渲染函数中体现。这里,全插槽内容都会被渲染,而`tab-pane`会根据`currentName`来决定是否展示。由此产生的效果是,插槽内容与`tab-pane`的选择逻辑完全分离,使得插槽内容不受切换状态影响。
当点击单个`tab`时,`tabs.vue`组件内部会通过`props`传递`handleTabClick`函数到`tabNav`组件。`nav`组件将该函数绑定到`click`事件上。当`click`事件触发时,如果不考虑`tab`是否为`disabled`状态,会触发`setCurrentName`函数。这个函数通过`beforeLeave`起到作用,以确保在切换到下一个`tab`之前进行适当的过渡。在`setCurrentName`中使用了两次`$nextTick`,其目的是确保在更新视图时子组件的`$nextTick`操作不会影响父组件的更新流程。
最后,源码中展示了`props`值`activeName`的使用,其功能与`value`类似,用于绑定选中的`tab`。源码中还提到了组件名称的获取方式,`props`值`vnode.tag`实际指向的是注册组件时返回的`vue-component+[name]`,而通过`vnode.componentOptions.Ctor.options.tag`可以获取正常组件名。如果在`options`中未声明`name`,那么组件名将基于注册组件时的名称。
通过这次深入阅读,我们不仅掌握了`element-tabs`组件的核心工作原理和实现细节,还学会了如何更有效地阅读和理解复杂的前端组件源码。在阅读过程中,耐心地记录问题、适时放松心情,都能帮助我们更好地理解代码,从而提升技术能力。
squid 强制缓存动态页面
其实我本不想写这个标题,我的本意是缓存yupoo api的查询数据,这个过程中找到了参考方法(Caching Google Earth with Squid)。呵呵,所以偶也来一回标题党。
这篇参考流传非常广,Digg上也被提过,我也不知道原出处是哪里了。
可是。。。。你按照它的指示设置,它并不能正确工作!!
话说回来,先说说我的需求。
最近yupoo的访问速度很慢,我有一堆api请求经常无法完成,猜测要么对方限制了同一ip的连接数,要么是yupoo又遇到了新一轮的流量瓶颈。跟Yupoo的zola联系后,确认是他们的负荷太高引起的,并没有限制连接数。所以我要想办法在我这边做一些缓存了。
因为我这边本身就是用squid代理来解决Ajax中调用API的跨域问题的,所以自然是目标瞄准了squid的配置文件。
yupoo api的请求地址是 www.yupoo.com/api/rest/?method=xxxxxxxxx...
大家都知道squid会自动缓存静态文件,可对于这种动态网页怎么让它也缓存起来呢,所以在google上找啊找,找到上面提得那片缓存Google Earth的博客文章。
他的方法是:
acl QUERY urlpath_regex cgi-bin /? intranet
acl forcecache url_regex -i kh.google keyhole.com
no_cache allow forcecache
no_cache deny QUERY
# ----
refresh_pattern -i kh.google % override-expire override-lastmod reload-into-ims ignore-reload
refresh_pattern -i keyhole.com % override-expire override-lastmod reload-into-ims ignore-reload
原理就是用 no_cache allow 和 refresh_pattern 来设定一些缓存规则,将google earth的请求强行缓存起来。
此文一出,自然早有人去验证,可是没人成功,原作者也音讯全无 ... squid的邮件列表里也提到。 ( 看标题进来的朋友,不要急,继续往下读,不会让你空手而回的 )
我也没在意,估计人家功力问题 。先试着用改写一下解决yupoo api的缓存问题。
acl QUERY urlpath_regex cgi-bin /?
acl forcecache url_regex -i yupoo/.com
no_cache allow forcecache
no_cache deny QUERY
refresh_pattern -i yupoo/.com % override-expire override-lastmod reload-into-ims ignore-reload
嘿,果然nnd毫无用处,访问记录里还是 一坨坨 TCP_MISS
于是翻来覆去看文档,找资料,发现是squid的bug惹得祸,不过早已经修正(严格来说是功能扩展补丁)。
我的squid是2.6.,翻了一下源代码,确实已经打好补丁了。
解决这个问题需要refresh_pattern的几个扩展参数(ignore-no-cache ignore-private),这几个参数在squid的文档和配置例子中均没有提到,看来squid还不够与时俱进。
下面讲一下问题所在。
先看看yupoo api返回的HTTP头部信息(cache 相关部分)
Cache-Control: no-cache, must-revalidate
Pragma: no-cache
这两行是控制浏览器的缓存行为的,指示浏览器不得缓存。squid也是遵循RFC的,正常情况下自然不会去缓存这些页面。override-expire override-lastmod reload-into-ims ignore-reload 统统不能对付它。
而那个补丁正是对付这两个Cache-Control:no-cache 和 Pragma: no-cache的。
因此把 refresh_pattern那句要改写成
refresh_pattern -i yupoo/.com % override-expire override-lastmod reload-into-ims ignore-reload ignore-no-cache ignore-private
这样就大功告成了, squid -k reconfigure 看看 access.log ,这回里面终于出现
TCP_HIT/ TCP_MEM_HIT/ 了,说明缓存规则确实起作用了,那个激动啊 ~~~~
====================
补充:
后来我看了一下google earth 服务器 hk1.google.com的HTTP头部,只有
Expires: Wed, Jul :: GMT
Last-Modified: Fri, Dec :: GMT
,这么看来照理不需ignore-no-cache ignore-private也能工作,可能是作者这里写错了
kh.google 应该是 kh./.google才对。
最后总结一下,缓存Google Earth/Map的正确的配置应该是
acl QUERY urlpath_regex cgi-bin /? intranet
acl forcecache url_regex -i kh./.google mt./.google mapgoogle/.mapabc keyhole.com
no_cache allow forcecache
no_cache deny QUERY
# ----
refresh_pattern -i kh./.google % override-expire override-lastmod reload-into-ims ignore-reload ignore-no-cache ignore-private
refresh_pattern -i mt./.google % override-expire override-lastmod reload-into-ims ignore-reload ignore-no-cache ignore-private
refresh_pattern -i mapgoogle/.mapabc % override-expire override-lastmod reload-into-ims ignore-reload ignore-no-cache ignore-private
refresh_pattern -i keyhole.com % override-expire override-lastmod reload-into-ims ignore-reload ignore-no-cache ignore-private
注:
khX.google.com 是google earth的服务器
mtX.google.com 是google map 的服务器
mapgoogle.mapabc.com 是google ditu的服务器
/archives/
2024-11-29 03:28
2024-11-29 03:23
2024-11-29 02:44
2024-11-29 02:37
2024-11-29 02:10
2024-11-29 01:30