当前位置: 首页 > Web前端 > HTML

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}}

    {{item+$index}}
changemsg
鏄剧劧锛岃緭鍑虹殑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銆傛瘮濡傪煂帮紝
锛屽尮閰嶆垚鍔熸嫤鎴悗锛屽墿涓嬬殑class="container">
銆傜劧鍚庡彇鍖归厤鏍囩灞炴€х殑姝e垯琛ㄨ揪寮忓睘鎬э紝涓€涓竴涓殑鍙栧嚭鏉ワ紝灏嗗尮閰嶇粨鏋滄斁鍏ttrs鏁扮粍锛岀洿鍒板尮閰嶅埌寮€濮嬫爣绛剧殑缁撳熬锛坰tartTagClose锛夈€傜户缁笂闈㈢殑馃尠锛岀粡杩囪繖涓€姝ワ紝鍙墿涓?/div>锛屾渶缁堜細杩斿洖鍖归厤瀵硅薄銆傜湅鐪嬮暱鍟ユ牱锛氳嚦姝ゅぇ閮ㄥ垎鏍囩鍖归厤宸ヤ綔宸茬粡瀹屾垚锛屾爣绛惧悕绉板拰鏍囩灞炴€ч兘寰楀埌浜嗭紝浣嗘槸鏍囩灞炴€т粛鐒舵槸姝e垯鍖归厤缁撴灉锛岄渶瑕佽繘涓€姝ュ鐞嗭紝鏄惁鏄痑鑷棴鏍囩銆傜幇鍦ㄨ鎴戜滑鐪嬬湅handleStartTag()鍑芥暟濡備綍澶勭悊瀹冿細functionhandleStartTag(match){vartagName=match.tagName;varunary=empty(tagName);varattrs=match.attrs.map(attr=>{return{name:attr[1],value:attr[3]||attr[4]||attr[5]||''};});//涓嶆槸鑷棴鏍囩if(!unary){tagStack.push({tag:tagName,attrs:attrs});}if(handler.start){handler.start(tagName,attrs,unary,match.start,match.end);}}handleStartTag()鍑芥暟灏辨槸涓婇潰杩斿洖鐨勫尮閰嶇粨鏋滐紝鑾峰彇鏍囩鍚嶇О锛屽垽鏂槸鍚︿负鑷棴鏍囩锛岀劧鍚庡皢灞炴€х粨鏋滃鐞嗘垚{name:'class',value:'container'鐨勫舰寮弣锛岀劧鍚庡鏋滀笉鏄嚜闂爣绛惧氨鎶婃爣绛句俊鎭帇鍏ユ爣绛炬爤锛堣繖涓€姝ユ槸鐢ㄦ潵涓哄悗缁尮閰嶇粨鏉熸爣绛惧仛閾哄灚锛夛紝鏈€鍚庤皟鐢ㄤ紶鍏ョ殑寮€濮嬪洖璋冿紝寮€濮嬫爣绛惧尮閰嶇粨鏉熴€傜劧鍚庤緭鍏ョ粨鏉熸爣绛剧殑鍖归厤閾炬帴锛岃繖閲屾瘮杈冪畝鍗曘€傞鍏堟槸鐢ㄦ鍒欐ā寮忓尮閰?/xxx>褰㈢姸鐨勭粨鏉熸爣绛撅紙鍖归厤鍚庢埅鍙栧師鏉ョ殑html锛夛紝鐒跺悗鑾峰彇鏍囩鍚嶏紝鍒版爣绛炬爤鐨勫熬閮ㄥ紑濮嬪鎵句綅缃?涓嬫爣)锛屾壘鍒板悗锛屽皢浣嶇疆绉诲姩鍒版爤灏俱€傚嚭鏍堬紝鐒跺悗璋冪敤浼犲叆鐨勭粨鏉熷洖璋冦€傛垜浠ュ墠涓€鐩翠笉鏄庣櫧鎴戜负浠€涔堣杩欐牱鍋氾紵闄や簡鑷棴鏍囩澶栵紝鍏冪礌鑺傜偣鐨勫紑濮嬪拰缁撴潫鏍囩涔熸槸鎴愬瀛樺湪鐨勩€傝繖閲屼妇涓緥瀛愶細鎷夸竴涓湁闂鐨刪tml瀛楃涓?ul>
  • 1锛屾晠鎰忓皯鍐檒i鐨勭粨鏉熸爣绛撅紝鏍堝垰寮€濮嬪帇鍏l锛屽啀鍘嬪叆li锛屽尮閰嶅埌ul鐨勭粨鏉熸爣绛惧悗锛屾爤涓殑li鍜寀l閮藉嚭鏍堜簡锛岃繖涓病闂锛佺湅涓€涓嬪嚱鏁颁腑鐨勭粏鑺傦細functionparseEndTag(tagName,start,end){varpos;濡傛灉锛堝紑濮?=null锛夊紑濮?绱㈠紩锛涘鏋滐紙缁撴潫==绌猴級缁撴潫=绱㈠紩锛沬f(tagName){varneedle=tagName.toLowerCase();//鍦ㄦ爣绛炬爤涓壘鍒扮粨鏉熸爣绛剧殑浣嶇疆for(pos=tagStack.length-1;pos>=0;pos--){if(tagStack[pos].tag.toLowerCase()===needle){浼戞伅;}}}if(pos>=0){for(vari=tagStack.length-1;i>=pos;i--){if(handler.end){handler.end(tagStack[i].tag,寮€濮嬨€佺粨鏉燂級锛泒}tagStack.length=pos;//寮瑰嚭鏍囩鏍坿}}鏈€鍚庯紝鎴戜滑鏉ョ湅鐪嬫枃鏈妭鐐圭殑澶勭悊鏂规硶~vartext,rest,next;if(textEnd>=0){rest=html.slice(textEnd);while(!endTag.test(rest)&&!startTagOpen.test(rest)){//澶勭悊鍏朵粬鏂囨湰锛屼緥濡傚皬浜庡彿next=rest.indexOf('<',1);濡傛灉锛堜笅涓€涓?0锛変腑鏂紱textEnd+=涓嬩竴涓紱rest=html.slice(textEnd);}text=html.substring(0,textEnd);advance(textEnd);}if(textEnd<0){text=html;html='';}if(handler.chars){handler.chars(text);}鐪嬬湅杩欎笁涓彉閲忔槸鍋氫粈涔堢敤鐨勶紝text(String)鐢ㄦ潵瀛樻斁鏂囨湰鑺傜偣淇℃伅锛宺est(String)鏄墿涓嬬殑html鍘绘帀鏂囨湰鑺傜偣鍚庯紝next(Number)鏄?鐨勭浜屼釜浣嶇疆锛屽墿涓嬬殑鍙兘鏈夌偣鐤戞儜锛岃繖鍏跺疄鏄负浜嗛槻姝㈡垜浠彂鐜扮殑<涓嶆槸鏍囩鐨勫紑濮嬫爣蹇楋紝涔熸湁鍙兘鏄竴涓皬浜庢爣蹇楃瓑绛夛紒鍐嶄妇涓緥瀛愶紝
    {{age<18?'adult':'nonage'}}
    锛屽尮閰嶅紑濮嬫爣绛惧悗锛屽墿涓嬬殑{{age<18?'adult':'nonage'}}/div>锛屾鏃跺彂鐜?涓嬫爣涓嶄负0锛屽緱鍒皗{age鐨偣鐨偣锛岃繘鍏ヤ笅涓€涓惊鐜紒鎵€浠ヤ负浜嗛槻姝㈣繖绉嶆儏鍐电殑鍙戠敓锛屾垜浠渶瑕佺湅鐪嬪墿涓嬬殑閮ㄥ垎<18?'adult':'nonage'}}
  • 鏄惁婊¤冻寮€濮嬫爣绛撅紝濡傛灉涓嶆弧瓒冲氨鎵句笅涓€涓?锛屾渶鍚庢壘鍒皗{age<18?'adult':'nonage'}}灏辨槸鎴戜滑瑕佺殑鏂囨湰鑺傜偣锛佸畬浜唦缁撹鍐欎簡濂戒箙缁堜簬瀹岀粨浜嗐€傘€傘€傝繖鏄垜瀵筕ue涓瑼ST璇硶鏍戝缓绔嬬殑鐪嬫硶銆備竴瀹氭湁寰堝闂銆傚笇鏈涘ぇ瀹跺強鏃舵寚鍑?鈹琠鈹?銆傚啓鍑烘潵瀹冲ぇ瀹讹紒鐪嬪埌杩欓噷锛岀偣涓禐鍚鍢垮樋鍢?/p>