您好,登錄后才能下訂單哦!
There are only two things in Computer Sciences: cache invalidation and naming things.
—— Phil Karlton
誠如上述所言,編程中變量命名確實令人很頭疼。我們模糊地知道,Vue 組件的名稱最好不要和原生 HTML 標簽相同。為了避免重名,通常會在組件名稱前面加上一個前綴,如 el-button、el-input、el-date-picker。這通常不會有什么問題,但有時候你的模板中混雜了原生 HTML 標簽和組件標簽,要想區分它們并不是很容易。
當我看到 Ant.design 的 React 組件是下面這樣的時候,我感覺到一種自由的味道。首先,組件名可以使用原生 HTML 標簽名,意味著再也不用較勁腦汁去規避原生 HTML 標簽了。另外,這些組件都使用了首字母大寫標簽名,使它們很容易地與原生小寫的 HTML 標簽區分。
ReactDOM.render( <div> <Button type="primary">Primary</Button> <Input placeholder="Basic usage" /> <Select defaultValue=".com" style={{ width: 70 }}> <Option value=".com">.com</Option> <Option value=".jp">.jp</Option> <Option value=".cn">.cn</Option> <Option value=".org">.org</Option> </Select> </div>, mountNode );
受 Ant.design 的啟發,我思考 Vue 組件命名能不能達到同樣的效果呢?要找到答案,必須摸清楚 Vue 組件命名到底有什么限制。下面將分別從 Vue 1.0 和 Vue 2.0 來談談組件命名的機制:
Vue 1.0 組件命名機制
組件注冊
我們以一個最簡單的例子來研究 Vue 組件的注冊過程:
Vue.component('MyComponent', { template: '<div>hello, world</div>' })
通過跟蹤代碼的執行過程,發現對組件的名稱有兩處檢查。
檢查名稱是否與 HTML 元素或者 Vue 保留標簽重名,不區分大小寫。可以發現,只檢查了常用的 HTML 元素,還有很多元素沒有檢查,例如 button、main。
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|h2|h3|h4|h5|h6|h7|code|pre|table|th|td|tr|form|label|input|select|option|nav|article|section|header|footer)$/i; // var reservedTagRE = /^(slot|partial|component)$/i;
檢查組件名稱是否以字母開頭,后面跟字母、數值或下劃線。
if (!/^[a-zA-Z][\w-]*$/.test(name)) { warn('Invalid component name: "' + name + '". Component names ' + 'can only contain alphanumeric characaters and the hyphen.'); }
基于以上兩點,可以總結出組件的命名規則為:組件名以字母開頭,后面跟字母、數值或下劃線,并且不與 HTML 元素或 Vue 保留標簽重名。
然而我們注意到,在上面的檢查中,不符合規則的組件名稱是 warn 而不是 error,意味著檢查并不是強制的。實際上,Vue 組件注冊的名稱是沒有限制的。你可以用任何 JavaScript 能夠表示的字符串,不管是數字、特殊符號、甚至漢字,都可以成功注冊。
模板解析
雖然 Vue 組件沒有命名限制,但是我們終究是要在模板中引用的,不合理的組件名可能會導致我們無法引用它。
為了弄清楚 Vue 是如何將模板中的標簽對應到自定義組件的,我們以一段簡單的代碼說明:
new Vue({ el: '#app', template: '<my-component></my-component>' })
總體來說,模板解析分為兩個過程:
首先,Vue 會將 template 中的內容插到 DOM 中,以方便解析標簽。由于 HTML 標簽不區分大小寫,所以在生成的標簽名都會轉換為小寫。例如,當你的 template 為 <MyComponent></MyComponent> 時,插入 DOM 后會被轉換為 <mycomponent></mycomponent>。
然后,通過標簽名尋找對應的自定義組件。**匹配的優先順序從高到低為:原標簽名、camelCase化的標簽名、PascalCase化的標簽名。**例如 <my-component> 會依次匹配 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) }
對于一個 Vue 新手,經常對以下示例代碼不能正常運行感到非常疑惑:
Vue.component('MyComponent', { template: '<div>hello, world</div>' }) new Vue({ el: '#app', template: '<MyComponent></MyComponent>' })
如果我們按照模板解析的過程推理,就很好解釋了。模板 <MyComponent></MyComponent> 插入到 DOM 后會變成 <mycomponent></mycomponent>。標簽 mycomponent 匹配的組件依次為 mycomponent(原標簽名)、mycomponent(camelCase形式)、Mycomponent(PascalCase形式),并沒有匹配到注冊的組件名 MyComponent,所以會報找不到組件 <mycomponent> 的警告。
命名限制
通過分析組件注冊和模板解析的過程,發現 Vue 組件命名限制并沒有我們想象得多。大家可以嘗試一下各種命名,我試過 <a_=-*%按鈕></a_=-*%按鈕> 都可正常運行。
但是,并不意味著完全沒有限制。由于在模板需要插入到 DOM 中,所以模板中的標簽名必須能夠被 DOM 正確地解析。主要有三種情況:一是完全不合法的標簽名,例如 </>;二是與 HTML 元素重名會產生不確定的行為,例如使用 input 做組件名不會解析到自定義組件,使用 button 在 Chrome 上正常但在 IE 上不正常;三是與 Vue 保留的 slot、partial、component 重名,因為會優先以本身的意義解析,從而產生非預期的結果。
上述命名限制存在的根本原因,在于模板解析的過程依賴了 DOM。能不能對模板解析過程改進一下,使其不依賴于 DOM 呢?實際上,這正是 Vue 2.0 的主要改進,將模板解析過程使用 Virtual DOM 實現,使得組件命名更加靈活。
Vue 2.0 組件命名機制
組件注冊
Vue 2.0 的組件注冊過程與 Vue 1.0 基本相同,只是 HTML 標簽和 Vue 保留標簽范圍有些不同:
// 區分大小寫 var isHTMLTag = makeMap( 'html,body,base,head,link,meta,style,title,' + 'address,article,aside,footer,header,h2,h3,h4,h5,h6,h7,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' ); // 不區分大小寫 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) }; // 區分大小寫 var isBuiltInTag = makeMap('slot,component', true);
雖然 HTML 元素重名警告的標簽數大大增加了,但重要的是重名區分大小寫,所以我們可以愉快地使用 Input、Select、Option 等而不用擔心重名。這個功勞屬于 Vue 2.0 引入的 Virtual DOM。
模板解析
前面提到,Vue 2.0 相對于 1.0 的最大改進就是引入了 Virtual DOM,使模板的解析不依賴于 DOM。
使用 Virtual DOM 解析模板時,不必像 DOM 方式那樣將模板中的標簽名轉成小寫,而是原汁原味地保留原始標簽名。然后,使用原始的標簽名進行匹配組件。例如,<MyComponent></MyComponent> 不會轉為為小寫形式,直接以 MyComponent 為基礎開始匹配。當然,匹配的規則與 1.0 是一樣的,即依次匹配:原標簽名、camelCase化的標簽名、PascalCase化的標簽名。
之前在 1.0 不能正常運行的示例代碼,在 2.0 中可以正常運行了:
Vue.component('MyComponent', { template: '<div>hello, world</div>' }) new Vue({ el: '#app', template: '<MyComponent></MyComponent>' })
在 Vue 1.0 和 2.0 中還有一種定義組件模板的方式,即使用 DOM 元素。在這種情況下,解析模板時仍然會將標簽轉為小寫形式。所以下面的代碼,在 1.0 和 2.0 均不能正常運行。
// 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 的最大區別在于區分了大小寫。總結一下就是:一是不使用非法的標簽字符;二是不與 HTML 元素(區分大小寫)或 SVG 元素(不區分大小寫)重名;三是不使用 Vue 保留的 slot 和 component(區分大小寫)。
除了以上三條,由于 Vue 2.0 內置了 KeepAlive、Transition、TransitionGroup 三個組件,所以盡量避免與這三個組件重名。但從另一方面講,你也可以故意重名來實現一些特殊的功能。例如,keep-alive 的匹配順序為 keep-alive、keepAlive、KeepAlive,所以我們可以注冊一個 keep-alive 組件來攔截 KeepAlive 匹配。
總結
到這里,我們可以知道 Vue 2.0 完全可以像 React 那樣使用 PascalCase 形式的組件標簽。對于 Vue 1.0,想以 PascalCase 形態寫模板,盡量以全小寫或者僅首字母大寫形式注冊組件,例如 <InputNumber> 組件,可以注冊為 inputnumber 或者 Inputnumber。但是,如果你想在 1.0 中使用 Input、Select 這類與 HTML 元素重名的標簽名,基本上是無解的,所以是時候嘗試下 Vue 2.0 了。
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持億速云。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。