Vue源码解析:模板字符串转AST语法树
时间:2023-04-02 15:19:27
HTML
鐪嬪畬Vue2.0婧愮爜鎯冲啓鍐欒嚜宸辩殑鐞嗚В锛屼絾鏄兘鍔涙湁闄愶紝鎵€浠ヤ粠绗竴娆℃姇绋垮紑濮嬬湅銆備綘2016骞?鏈?1鏃ワ紝鎴戞墦绠楅檰缁啓锛氭ā鏉垮瓧绗︿覆杞珹ST璇硶鏍慉ST璇硶鏍戣浆娓叉煋鍑芥暟Vue鍙屽悜缁戝畾鍘熺悊Vue铏氭嫙dom瀵规瘮鍘熺悊鍏朵腑鍖呮嫭鑷繁鐨勭悊瑙e拰婧愮爜鍒嗘瀽锛屽敖閲忓敖鍙兘瀹规槗鐞嗚В锛佺敱浜庢槸鏈€鏃╂彁浜ょ殑2.0锛屼笌鏈€鏂扮増鏈瓨鍦ㄨ澶氬樊寮傚拰bug锛屽悗缁細琛ュ厖锛屾暚璇疯皡瑙o紒甯︿腑鏂囨敞閲婄殑Vue婧愮爜宸蹭笂浼?..闂浠€涔堟槸AST锛烝ST锛坅bstractsyntaxtree锛夋剰涓烘娊璞¤娉曟爲锛屽叾瀹炴槸涓€绉嶆爲褰㈡暟鎹粨鏋勭殑琛ㄧず锛屾湁鐖惰妭鐐广€佸瓙鑺傜偣銆佸厔寮熻妭鐐圭瓑姒傚康鈥︹€TML涓轰粈涔堣杩欐牱锛屽畠鏈韩灏辨槸涓€妫垫爲缁撴瀯锛岃杞崲锛熷洜涓虹湡瀹炵殑DOM鍖呭惈浜嗗お澶氫笉闇€瑕佺殑灞炴€э紝濡傛灉鎴戜滑杩囨护鎺夋垜浠渶瑕佺殑灞炴€э紝鐒跺悗瀵瑰叾杩涜鎿嶄綔锛屾€ц兘浼氬緱鍒板緢澶х殑浼樺寲锛丄ST鍜岃櫄鎷熻妭鐐箆node鏄粈涔堝叧绯伙紵瀹冧滑鐨勭粨鏋勯潪甯哥浉浼笺€侫ST鍏跺疄灏辨槸vnode鐨勫墠韬€傜粡杩囦竴绯诲垪鐨勬寚浠よВ鏋愬拰鏁版嵁娓叉煋锛孉ST灏卞彉鎴愪簡vnode锛佽繖閲岀殑AST鍏跺疄鍙槸绠€鍗曠殑html瑙f瀽銆傚厛璇翠竴涓煂帮紝鍏堢湅鐪嬭緭鍏ヨ緭鍑猴紝{{msg}}
鏄剧劧锛岃緭鍑虹殑AST璇硶鏍戞槸涓€涓璞★紝瀹冨彧甯︽垜浠渶瑕佺殑鑺傜偣鏍囩锛坱ag锛夊拰灞炴€э紙attribute锛夛紝褰撶劧杩樻湁鏍戠粨鏋勪緷璧栵紙parent&children锛夈€傞毦鐐瑰湪浜庡瓧绗︿覆鐨勮В鏋愬拰鐖跺瓙鑺傜偣鍏崇郴鐨勬瀯寤恒€傞€氳繃闃呰婧愮爜锛宧tml瀛楃涓茬殑瑙f瀽涓昏浣跨敤浜咹TMLParser鍑芥暟锛屽惊鐜亶鍘嗭細绗竴姝ユ槸姝e垯琛ㄨ揪寮忕殑鍖归厤銆傛ā鏉垮瓧绗︿覆渚濇鏌ユ壘娉ㄩ噴銆両E鍒ゆ柇鏍囩銆乨octype鏍囩銆佺粨鏉熸爣绛俱€佸紑濮嬫爣绛俱€佹枃鏈瓑锛涚浜屾澶勭悊绗竴姝ヤ腑鎵惧埌鐨勭粨鏋溿€備粠妯℃澘瀛楃涓蹭腑鎴彇缁撴灉锛岀劧鍚庤繘涓€姝ュ鐞嗙粨鏉熸爣绛炬垨寮€濮嬫爣绛炬垨浠庢枃鏈腑寰楀埌鐨勫瓧绗︿覆锛涚涓夋锛氭埅鍙栫殑妯℃澘瀛楃涓查噸澶嶆楠?鍜?锛岀洿鍒颁负绌鸿烦鍑哄惊鐜€備互涓婇潰鐨勪緥瀛愪负渚嬶紝绗竴娆″惊鐜緱鍒板紑濮嬫爣绛?divclass="container">锛岀浜屾寰楀埌鏂囨湰鑺傜偣\n锛岀涓夋寰楀埌寮€濮嬫爣绛?span:class="{active:isActive}">锛岀鍥涙鑾峰彇鏂囨湰{{msg}}...褰撶劧姣忔fetch鍚庨兘浼氬瀛楃涓茶繘琛屽鐞嗭紝鍚庨潰浼氳缁嗚鏄庛€傚彟澶栵紝鐖跺瓙鑺傜偣鍏崇郴鐨勫缓绔嬶紝涓昏鏄埄鐢ㄤ簡鏍堢殑鍚庤繘鍏堝嚭鍘熷垯锛氭瘡娆″尮閰嶅埌璧峰鏍囩锛屽氨鍏ユ爤锛岀疆涓哄綋鍓嶅悓鏃朵负鐖惰妭鐐癸紱璇ュ厓绱犺璁剧疆涓哄綋鍓嶇埗鑺傜偣銆傛簮鐮佽В鏋怴ue2.0妯℃澘瀛楃涓茶浆AST璇硶鏍戠殑浠g爜閮藉湪html-parser.js涓紝鍥犱负鏈夊緢澶氬吋瀹圭殑杩囩▼锛堟祻瑙堝櫒鍏煎锛孹HTML鍏煎绛夛級锛屾墍浠ユ嬁涓€涓畝鍖栫増鐨刾arser銆俲s鏉ュ垎鏋愪竴涓嬶紝鍙互澶嶅埗浠g爜鍦ㄦ帶鍒跺彴鍥炶溅鐪嬬湅鏁堟灉銆俻arse()鍑芥暟鍏堢湅parse()鍑芥暟锛屽弬鏁癶tml鏄ā鏉垮瓧绗︿覆锛岃繑鍥炲€兼槸AST璇硶鏍戯細functionparse(html){letroot//AST鏍硅妭鐐筶etcurrentParent//current鐖惰妭鐐筶etstack=[]//鑺傜偣鏍圚TMLParser(html,{//杩涚▼寮€濮媡agstart(tag,attrs,unary){letelement={tag,attrs,//[{name:'class',value:'xx'},...]=>[{class:'xx'},...]attrsMap:attrs.reduce((cumulated,{name,value})=>{accumulated[name]=value||true;returnaccumulated;},{}),parent:currentParent,children:[]}//鍒濆鍖栨牴鑺傜偣if(!root){root=element}//濡傛灉鏈夌埗鑺傜偣锛屽垯灏嗗綋鍓嶈妭鐐瑰帇鍏hildren鏁扮粍if(currentParent){currentParent.children.push(element)}//涓嶆槸鑷棴鏍囩//杩涘叆褰撳墠鑺傜偣鐨勫唴閮ㄩ亶鍘嗭紝鎵€浠urrentParent璁剧疆涓鸿嚜韬玦f(!unary){currentParent=elementstack.push(element)}},//澶勭悊缁撴潫鏍囩end(){//寮瑰嚭鏍堝苟閲嶆柊鍒嗛厤鐖惰妭鐐箂tack.length-=1currentParent=stack[stack.length-1]},//澶勭悊鏂囨湰鑺傜偣chars(text){text=currentParent.tag==='pre'?鏂囨湰锛歵ext.trim()?text:''currentParent.children.push(text)}})returnroot}璇ユ柟娉曞唴閮ㄥ垱寤哄彉閲忓悗锛屼富瑕佽皟鐢℉TMLParser()鍑芥暟銆傚弬鏁版槸妯℃澘瀛楃涓插拰涓€涓璞★紙鍖呮嫭鐢ㄤ簬澶勭悊寮€濮嬫爣璁般€佺粨鏉熸爣璁板拰鏂囨湰鐨勫洖璋冿級銆傛垜浠厛鏉ョ湅鐪嬨€傚浣曞鐞嗘瘡娆″尮閰嶇殑寮€濮嬫爣绛撅紝start()鍑芥暟锛氭帴鏀朵笁涓弬鏁帮紝tag(鏍囩鍚嶇О)锛宎ttrs(鏍囩灞炴€э紝褰㈠紡涓篬{name:'class',value:'container'},...]),涓€鍏冿紙鏄惁涓鸿嚜闂悎鏍囩锛夛紱鍒涘缓涓€涓爲鑺傜偣瀵硅薄锛屽寘鎷睘鎬ag銆乤ttrs銆乤ttrsMap锛堝嵆灏哸ttrs杞崲鎴怺{class:'container'},...]锛夈€乸arent锛堟牴鑺傜偣搴旇灞炴€ф湭瀹氫箟锛夈€乧hildren锛涘垵濮嬪寲鏍硅妭鐐箁oot锛堝彧鏈夌涓€娆′細璧拌繖閲岋級锛涘鏋滄湁鐖惰妭鐐癸紝灏嗗綋鍓嶈妭鐐瑰帇鍏hildren鏁扮粍锛堝彧鏈夌涓€娆′笉浼氳蛋杩欓噷锛夛紱瀹冧笉鏄嚜闂爣绛撅紝鎶婂垰鍒氬垱寤虹殑鏍戣妭鐐瑰璞′綔涓虹埗鑺傜偣鍘嬪叆鏍堜腑銆傚尮閰嶇粨鏉熸爣绛剧殑澶勭悊姣旇緝绠€鍗曪紝鍑烘爤锛岃缃爤鐨勬渶鍚庝竴涓厓绱犱负鐖惰妭鐐癸紱鍖归厤鏂囨湰鑺傜偣鏃讹紝鍙渶瀵瑰叾杩涜澶勭悊骞跺皢鍏舵帹鍏hildren鏁扮粍鍗冲彲銆傝嚦姝わ紝鎴戝ぇ姒傛槑鐧戒簡HTMLParser鍑芥暟闇€瑕佸仛鐨勬槸锛氶亣鍒板紑濮嬫爣绛撅紝鑾峰彇鏍囩鍚嶇О銆佹爣绛惧睘鎬т互鍙婃槸鍚︿负鑷棴鍚堟爣绛撅紝鐒跺悗璋冪敤start()锛涢亣鍒扮粨鏉熸爣绛惧氨璋冪敤end()锛屼笉闇€瑕佷紶鍙傦紱閬囧埌鏂囨湰鑺傜偣锛屽氨浠ユ枃鏈妭鐐逛负鍙傛暟锛岃皟鐢╟hars()锛丠TMLParser()鍑芥暟鎺ヤ笅鏉ユ垜浠湅涓€涓婬TMLParser()鍑芥暟鏄浣曞疄鐜扮殑銆傛垜浠厛鏉ョ湅鐪嬫鍒欏寲銆傚畠宸茶鎴戞洿鏀逛负鏇寸畝鍗?..//寮€濮嬫爣璁板ごconststartTagOpen=/^<([\w\-]+)/,//寮€濮嬫爣璁板熬閮╯tartTagClose=/^\s*(\/?)>/,//鏍囩灞炴€ttribute=/^\s*([^\s"'<>\/=]+)(?:\s*((?:=))\s*(?:"([^"]*)"+|'([^']*)'+|([^\s"'=<>`]+)))?/,//缁撴潫鏍囩endTag=/^<\/([\w\-]+)>/;杩樻湁涓婇潰璇寸殑鑷棴鏍囩锛屾病鏈夌粨鏉熸爣绛剧殑閭g锛歷arempty=makeMap('area,base,basefont,br,col,embed,frame,hr,img,'+'input,isindex,keygen,link,meta,param,source,track,wbr');functionmakeMap(values){values=values.split(/,/);varmap={};values.forEach(function(value){map[value]=1;});returnfunction(value){returnmap[value.toLowerCase()]===1;};}//empty('input');=>true鍜屽父鐢ㄥ嚱鏁癮dvance()鎴彇html瀛楃涓诧紝鍙傛暟鏄埅鍙栫殑闀垮害锛歠unctionadvance(n){index+=n;//index鐢ㄦ潵璁板綍鍘熷鍗曡瘝涓殑鍓╀綑瀛楃涓插瓧绗︿覆涓殑浣嶇疆html=html.substring(n);}HTMLParser鍑芥暟涓細鐢ㄥ埌涓婇潰瀹氫箟鐨勫悇绉嶇被鍨嬨€傜湅涓€涓嬭繖涓嚱鏁扮殑缁撴瀯锛歠unctionHTMLParser(html,handler){vartagStack=[];//鏍囩鏍坴arindex=0;while(html){//html閫氳繃getOuterHTML浼犻€掞紝鍘绘帀鍓嶅悗绌烘牸锛屾墍浠ョ涓€涓猼extEnd蹇呴』涓?vartextEnd=html.indexOf('<');if(textEnd===0){//鍖归厤寮€濮嬫爣绛緑arstartTagMatch=parseStartTag();濡傛灉锛坰tartTagMatch锛墈handleStartTag锛坰tartTagMatch锛?缁х画;}//鍖归厤缁撴潫鏍囩varendTagMatch=html.match(endTag);濡傛灉锛坋ndTagMatch锛墈varcurIndex=index;鎻愬墠锛坋ndTagMatch[0].length锛夛紱parseEndTag(endTagMatch[1],curIndex,绱㈠紩);缁х画;}}//澶勭悊鏂囨湰鑺傜偣...}//杩欓噷鏈変竴浜涘嚱鏁板畾涔夈€?.}璁╂垜浠缁嗚皥璋堣繖涓柟娉曘€傛嬁鍒癶tml鍚庯紝杩涘叆while寰幆銆傝烦鍑哄惊鐜殑鏉′欢鏄惛骞瞙tml鍦ㄥ惊鐜殑寮€濮嬶紝鎵惧埌<鍦╤tml涓殑浣嶇疆銆傚鏋滀负0锛屽垯琛ㄧず鍖归厤寮€濮嬫爣绛炬垨缁撴潫鏍囩锛堣繖閲屾殏涓嶈€冭檻娉ㄩ噴銆丏octype鏍囩绛夛級锛屽鏋滀笉涓?锛屽垯琛ㄧず鏈夋枃鏈妭鐐广€傞鍏堢湅<涓嬫爣涓?鏃秔arseStartTag()鍑芥暟濡備綍瑙f瀽寮€濮嬫爣绛撅細functionparseStartTag(){varstart=html.match(startTagOpen);if(start){varmatch={tagName:start[1],attrs:[],start:index};鎻愬墠锛堝紑濮媅0].length锛夛紱鍙橀噺缁撴潫锛屽睘鎬э紱//鏈粨鏉熷苟涓庢爣绛惧睘鎬у尮閰峸hile(!(end=html.match(startTagClose))&&(attr=html.match(attribute))){advance(attr[0].length);鍖归厤.attrs.push(attr);//娣诲姞灞炴€if(end){advance(end[0].length);match.end=绱㈠紩锛涜繑鍥炲尮閰嶏紱}}}鐪嬪埌parseStartTag()鍑芥暟鍒氬垰鍚姩锛屼娇鐢╯tart鏍囩澶寸殑姝e垯琛ㄨ揪寮弒tartTagOpen杩涜鍖归厤锛屽尮閰嶆垚鍔熷垯鎷︽埅html銆傛瘮濡傪煂帮紝