Vue組件命名的一些問(wèn)題

原文:聊聊 Vue 組件命名那些事

組件注冊(cè)

我們以一個(gè)最簡(jiǎn)單的例子來(lái)研究 Vue 組件的注冊(cè)過(guò)程:

Vue.component('MyComponent', {
  template: '<div>hello, world</div>'
})

通過(guò)跟蹤代碼的執(zhí)行過(guò)程州胳,發(fā)現(xiàn)對(duì)組件的名稱有兩處檢查撕彤。

  1. 檢查名稱是否與 HTML 元素或者 Vue 保留標(biāo)簽重名,不區(qū)分大小寫(xiě)列肢。可以發(fā)現(xiàn)踪少,只檢查了常用的 HTML 元素挣惰,還有很多元素沒(méi)有檢查卧斟,例如buttonmain通熄。
if (type === 'component' && (commonTagRE.test(id) || reservedTagRE.test(id))) {
  warn('Do not use built-in or reserved HTML elements as component ' + 'id: ' + id);
}
// var commonTagRE = /^(div|p|span|img|a|b|i|br|ul|ol|li|h1|h2|h3|h4|h5|h6|code|pre|table|th|td|tr|form|label|input|select|option|nav|article|section|header|footer)$/i;
// var reservedTagRE = /^(slot|partial|component)$/i;
  1. 檢查組件名稱是否以字母開(kāi)頭谅猾,后面跟字母昆汹、數(shù)值或下劃線
if (!/^[a-zA-Z][\w-]*$/.test(name)) {
        warn('Invalid component name: "' + name + '". Component names ' + 'can only contain alphanumeric characaters and the hyphen.');
      }

基于以上兩點(diǎn),可以總結(jié)出組件的命名規(guī)則為:組件名以字母開(kāi)頭锉罐,后面跟字母能耻、數(shù)值或下劃線赏枚,并且不與 HTML 元素或 Vue 保留標(biāo)簽重名。
然而我們注意到晓猛,在上面的檢查中饿幅,不符合規(guī)則的組件名稱是 warn 而不是 error,意味著檢查并不是強(qiáng)制的戒职。實(shí)際上栗恩,Vue 組件注冊(cè)的名稱是沒(méi)有限制的。你可以用任何 JavaScript 能夠表示的字符串洪燥,不管是數(shù)字磕秤、特殊符號(hào)、甚至漢字捧韵,都可以成功注冊(cè)市咆。

模板解析

雖然 Vue 組件沒(méi)有命名限制,但是我們終究是要在模板中引用的再来,不合理的組件名可能會(huì)導(dǎo)致我們無(wú)法引用它蒙兰。
為了弄清楚 Vue 是如何將模板中的標(biāo)簽對(duì)應(yīng)到自定義組件的,我們以一段簡(jiǎn)單的代碼說(shuō)明:

       new Vue({
         el: '#app',
         template: '<my-component></my-component>'
       })

總體來(lái)說(shuō),模板解析分為兩個(gè)過(guò)程:
首先搜变,Vue 會(huì)將 template 中的內(nèi)容插到 DOM 中采缚,以方便解析標(biāo)簽。由于 HTML 標(biāo)簽不區(qū)分大小寫(xiě)痹雅,所以在生成的標(biāo)簽名都會(huì)轉(zhuǎn)換為小寫(xiě)仰担。例如,當(dāng)你的 template<MyComponent></MyComponent> 時(shí)绩社,插入 DOM 后會(huì)被轉(zhuǎn)換為 <mycomponent></mycomponent>摔蓝。
然后,通過(guò)標(biāo)簽名尋找對(duì)應(yīng)的自定義組件愉耙。匹配的優(yōu)先順序從高到低為:原標(biāo)簽名贮尉、camelCase化的標(biāo)簽名、PascalCase化的標(biāo)簽名朴沿。例如 <my-component>會(huì)依次匹配 my-component猜谚、myComponent、MyComponent赌渣。camelCase 和 PascalCase 的代碼如下:

       var camelizeRE = /-(\w)/g;
       
       function camelize(str) {
         return str.replace(camelizeRE, toUpper);
       }
       
       function toUpper(_, c) {
         return c ? c.toUpperCase() : '';
       }
       
       function pascalize(str) {
         var camelCase = camelize(str);
         return camelCase.charAt(0).toUpperCase() + camelCase.slice(1)
       }

對(duì)于一個(gè) Vue 新手魏铅,經(jīng)常對(duì)以下示例代碼不能正常運(yùn)行感到非常疑惑:

       Vue.component('MyComponent', {
         template: '<div>hello, world</div>'
       })
       
       new Vue({
         el: '#app',
         template: '<MyComponent></MyComponent>'
       })

如果我們按照模板解析的過(guò)程推理,就很好解釋了坚芜。模板 <MyComponent></MyComponent> 插入到 DOM 后會(huì)變成<mycomponent></mycomponent>览芳。標(biāo)簽 mycomponent 匹配的組件依次為 mycomponent(原標(biāo)簽名)、mycomponent(camelCase形式)鸿竖、Mycomponent(PascalCase形式)沧竟,并沒(méi)有匹配到注冊(cè)的組件名 MyComponent,所以會(huì)報(bào)找不到組件 <mycomponent> 的警告缚忧。

命名限制

通過(guò)分析組件注冊(cè)和模板解析的過(guò)程悟泵,發(fā)現(xiàn) Vue 組件命名限制并沒(méi)有我們想象得多。大家可以嘗試一下各種命名闪水,我試過(guò) <a_=-*%按鈕></a_=-*%按鈕> 都可正常運(yùn)行糕非。
但是,并不意味著完全沒(méi)有限制球榆。由于在模板需要插入到 DOM 中朽肥,所以模板中的標(biāo)簽名必須能夠被 DOM 正確地解析。主要有三種情況:一是完全不合法的標(biāo)簽名芜果,例如 </>鞠呈;二是與 HTML 元素重名會(huì)產(chǎn)生不確定的行為,例如使用 input 做組件名不會(huì)解析到自定義組件右钾,使用 button 在 Chrome 上正常但在 IE 上不正常蚁吝;三是與 Vue 保留的 slot旱爆、partial、component 重名窘茁,因?yàn)闀?huì)優(yōu)先以本身的意義解析怀伦,從而產(chǎn)生非預(yù)期的結(jié)果。
上述命名限制存在的根本原因山林,在于模板解析的過(guò)程依賴了 DOM房待。能不能對(duì)模板解析過(guò)程改進(jìn)一下,使其不依賴于 DOM 呢驼抹?實(shí)際上桑孩,這正是 Vue 2.0 的主要改進(jìn),將模板解析過(guò)程使用 Virtual DOM 實(shí)現(xiàn)框冀,使得組件命名更加靈活流椒。

Vue 2.0 組件命名機(jī)制

組件注冊(cè)

Vue 2.0 的組件注冊(cè)過(guò)程與 Vue 1.0 基本相同,只是 HTML 標(biāo)簽和 Vue 保留標(biāo)簽范圍有些不同:

    // 區(qū)分大小寫(xiě)
    var isHTMLTag = makeMap(
      'html,body,base,head,link,meta,style,title,' +
      'address,article,aside,footer,header,h1,h2,h3,h4,h5,h6,hgroup,nav,section,' +
      'div,dd,dl,dt,figcaption,figure,hr,img,li,main,ol,p,pre,ul,' +
      'a,b,abbr,bdi,bdo,br,cite,code,data,dfn,em,i,kbd,mark,q,rp,rt,rtc,ruby,' +
      's,samp,small,span,strong,sub,sup,time,u,var,wbr,area,audio,map,track,video,' +
      'embed,object,param,source,canvas,script,noscript,del,ins,' +
      'caption,col,colgroup,table,thead,tbody,td,th,tr,' +
      'button,datalist,fieldset,form,input,label,legend,meter,optgroup,option,' +
      'output,progress,select,textarea,' +
      'details,dialog,menu,menuitem,summary,' +
      'content,element,shadow,template'
    );
    
    // 不區(qū)分大小寫(xiě)
    var isSVG = makeMap(
      'svg,animate,circle,clippath,cursor,defs,desc,ellipse,filter,font,' +
      'font-face,g,glyph,image,line,marker,mask,missing-glyph,path,pattern,' +
      'polygon,polyline,rect,switch,symbol,text,textpath,tspan,use,view',
      true
    );
    
    var isReservedTag = function (tag) {
      return isHTMLTag(tag) || isSVG(tag)
    };
    
    // 區(qū)分大小寫(xiě)
    var isBuiltInTag = makeMap('slot,component', true);

雖然 HTML 元素重名警告的標(biāo)簽數(shù)大大增加了明也,但重要的是重名區(qū)分大小寫(xiě)宣虾,所以我們可以愉快 地使用 Input、Select温数、Option 等而不用擔(dān)心重名绣硝。這個(gè)功勞屬于 Vue 2.0 引入的 Virtual DOM。

模板解析

前面提到撑刺,Vue 2.0 相對(duì)于 1.0 的最大改進(jìn)就是引入了 Virtual DOM鹉胖,使模板的解析不依賴于 DOM。

使用 Virtual DOM 解析模板時(shí)猜煮,不必像 DOM 方式那樣將模板中的標(biāo)簽名轉(zhuǎn)成小寫(xiě)次员,而是原汁原味地保留原始標(biāo)簽名败许。然后王带,使用原始的標(biāo)簽名進(jìn)行匹配組件。例如市殷,<MyComponent></MyComponent> 不會(huì)轉(zhuǎn)為為小寫(xiě)形式愕撰,直接以 MyComponent 為基礎(chǔ)開(kāi)始匹配。當(dāng)然醋寝,匹配的規(guī)則與 1.0 是一樣的搞挣,即依次匹配:原標(biāo)簽名、camelCase化的標(biāo)簽名音羞、PascalCase化的標(biāo)簽名囱桨。

之前在 1.0 不能正常運(yùn)行的示例代碼,在 2.0 中可以正常運(yùn)行了:

Vue.component('MyComponent', {
  template: '<div>hello, world</div>'
})

new Vue({
  el: '#app',
  template: '<MyComponent></MyComponent>'
})

在 Vue 1.0 和 2.0 中還有一種定義組件模板的方式嗅绰,即使用 DOM 元素舍肠。在這種情況下搀继,解析模板時(shí)仍然會(huì)將標(biāo)簽轉(zhuǎn)為小寫(xiě)形式。所以下面的代碼翠语,在 1.0 和 2.0 均不能正常運(yùn)行叽躯。

// index.html
<div id="app">
  <MyComponent></MyComponent>
</div>

// main.js
Vue.component('MyComponent', {
  template: '<div>hello, world</div>'
})

new Vue({
  el: '#app'
})

命名限制

Vue 2.0 中組件的命名限制與 1.0 的最大區(qū)別在于區(qū)分了大小寫(xiě)〖±ǎ總結(jié)一下就是:一是不使用非法的標(biāo)簽字符点骑;二是不與 HTML 元素(區(qū)分大小寫(xiě))或 SVG 元素(不區(qū)分大小寫(xiě))重名;三是不使用 Vue 保留的 slot 和 component(區(qū)分大小寫(xiě))谍夭。

除了以上三條黑滴,由于 Vue 2.0 內(nèi)置了 KeepAlive、Transition紧索、TransitionGroup 三個(gè)組件跷跪,所以盡量避免與這三個(gè)組件重名。但從另一方面講齐板,你也可以故意重名來(lái)實(shí)現(xiàn)一些特殊的功能吵瞻。例如,keep-alive 的匹配順序?yàn)?keep-alive甘磨、keepAlive橡羞、KeepAlive,所以我們可以注冊(cè)一個(gè) keep-alive 組件來(lái)攔截 KeepAlive 匹配济舆。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末卿泽,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子滋觉,更是在濱河造成了極大的恐慌签夭,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,194評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件椎侠,死亡現(xiàn)場(chǎng)離奇詭異第租,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)我纪,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,058評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門慎宾,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人浅悉,你說(shuō)我怎么就攤上這事趟据。” “怎么了术健?”我有些...
    開(kāi)封第一講書(shū)人閱讀 156,780評(píng)論 0 346
  • 文/不壞的土叔 我叫張陵汹碱,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我荞估,道長(zhǎng)咳促,這世上最難降的妖魔是什么色难? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,388評(píng)論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮等缀,結(jié)果婚禮上枷莉,老公的妹妹穿的比我還像新娘。我一直安慰自己尺迂,他們只是感情好笤妙,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,430評(píng)論 5 384
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著噪裕,像睡著了一般蹲盘。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上膳音,一...
    開(kāi)封第一講書(shū)人閱讀 49,764評(píng)論 1 290
  • 那天召衔,我揣著相機(jī)與錄音,去河邊找鬼祭陷。 笑死苍凛,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的兵志。 我是一名探鬼主播醇蝴,決...
    沈念sama閱讀 38,907評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼想罕!你這毒婦竟也來(lái)了悠栓?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 37,679評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤按价,失蹤者是張志新(化名)和其女友劉穎惭适,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體楼镐,經(jīng)...
    沈念sama閱讀 44,122評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡癞志,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,459評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了鸠蚪。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片今阳。...
    茶點(diǎn)故事閱讀 38,605評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡师溅,死狀恐怖茅信,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情墓臭,我是刑警寧澤蘸鲸,帶...
    沈念sama閱讀 34,270評(píng)論 4 329
  • 正文 年R本政府宣布,位于F島的核電站窿锉,受9級(jí)特大地震影響酌摇,放射性物質(zhì)發(fā)生泄漏膝舅。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,867評(píng)論 3 312
  • 文/蒙蒙 一窑多、第九天 我趴在偏房一處隱蔽的房頂上張望仍稀。 院中可真熱鬧,春花似錦埂息、人聲如沸技潘。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,734評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)享幽。三九已至,卻和暖如春拾弃,著一層夾襖步出監(jiān)牢的瞬間值桩,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,961評(píng)論 1 265
  • 我被黑心中介騙來(lái)泰國(guó)打工豪椿, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留奔坟,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,297評(píng)論 2 360
  • 正文 我出身青樓搭盾,卻偏偏與公主長(zhǎng)得像蛀蜜,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子增蹭,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,472評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容

  • Vue 實(shí)例 屬性和方法 每個(gè) Vue 實(shí)例都會(huì)代理其 data 對(duì)象里所有的屬性:var data = { a:...
    云之外閱讀 2,204評(píng)論 0 6
  • 這篇筆記主要包含 Vue 2 不同于 Vue 1 或者特有的內(nèi)容滴某,還有我對(duì)于 Vue 1.0 印象不深的內(nèi)容。關(guān)于...
    云之外閱讀 5,046評(píng)論 0 29
  • 此文基于官方文檔滋迈,里面部分例子有改動(dòng)霎奢,加上了一些自己的理解 什么是組件? 組件(Component)是 Vue.j...
    陸志均閱讀 3,806評(píng)論 5 14
  • 目錄 UI組件 開(kāi)發(fā)框架 實(shí)用庫(kù) 服務(wù)端 輔助工具 應(yīng)用實(shí)例 Demo示例 UI組件 element★13489 ...
    余生社會(huì)閱讀 19,671評(píng)論 7 233
  • 最近饼灿,日更想寫(xiě)點(diǎn)什么幕侠,就是想寫(xiě)那種非生活流水賬的一些小感悟,但是想半天都寫(xiě)不出來(lái)碍彭,但是如果寫(xiě)生活晤硕,那倒是可以行云流...
    火然開(kāi)朗閱讀 226評(píng)論 0 1