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下安装驱动程序的指南。在执行安装之前,需要评估构建环境、模块版本和兼容性等,以确保所有操作都能成功执行。然而,由于已经完善的支持,只要采取合理的步骤,我们都可以轻松完成驱动的ybatis源码教学安装。
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`中的网页源码突破边框显示机制。通过观察源码,发现`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:36183人浏览
2024-11-29 02:55737人浏览
2024-11-29 02:451411人浏览
2024-11-29 01:312518人浏览
2024-11-29 01:231152人浏览
2024-11-29 01:102798人浏览
「合理的股價」是多少?投資人該怎麼做資產分配?專業投資人整理四個個股投資的經驗法則:少量的投資頻率才是適合大部分投資人長期操作的方式!您的閱讀篇數已達上限立刻訂閱全閱讀,即可享全站不限篇數閱讀
文:田習如中央社特派員)當飛機即將降落時,不少靠窗的乘客開始拿起手機拍攝跑道旁陸續映入眼簾的愛國者飛彈、凱撒自走砲等,原來,這場立陶宛主辦的歷來最大型國際會議,來的不只近40國領袖,還有他們國家的先進