深入解析Vue 组件命名那些事
ThereareonlytwothingsinComputerSciences:cacheinvalidationandnamingthings.
——PhilKarlton
诚如上述所言,编程中变量命名确实令人很头疼。我们模糊地知道,Vue组件的名称最好不要和原生HTML标签相同。为了避免重名,通常会在组件名称前面加上一个前缀,如el-button、el-input、el-date-picker。这通常不会有什么问题,但有时候你的模板中混杂了原生HTML标签和组件标签,要想区分它们并不是很容易。
当我看到Ant.design的React组件是下面这样的时候,我感觉到一种自由的味道。首先,组件名可以使用原生HTML标签名,意味着再也不用较劲脑汁去规避原生HTML标签了。另外,这些组件都使用了首字母大写标签名,使它们很容易地与原生小写的HTML标签区分。
ReactDOM.render(, mountNode );Primary .com .jp .cn .org
受Ant.design的启发,我思考Vue组件命名能不能达到同样的效果呢?要找到答案,必须摸清楚Vue组件命名到底有什么限制。下面将分别从Vue1.0和Vue2.0来谈谈组件命名的机制:
Vue1.0组件命名机制
组件注册
我们以一个最简单的例子来研究Vue组件的注册过程:
Vue.component('MyComponent',{ template:'hello,world' })
通过跟踪代码的执行过程,发现对组件的名称有两处检查。
检查名称是否与HTML元素或者Vue保留标签重名,不区分大小写。可以发现,只检查了常用的HTML元素,还有很多元素没有检查,例如button、main。
if(type==='component'&&(commonTagRE.test(id)||reservedTagRE.test(id))){ warn('Donotusebuilt-inorreservedHTMLelementsascomponent'+'id:'+id); } //varcommonTagRE=/^(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; //varreservedTagRE=/^(slot|partial|component)$/i;
检查组件名称是否以字母开头,后面跟字母、数值或下划线。
if(!/^[a-zA-Z][\w-]*$/.test(name)){ warn('Invalidcomponentname:"'+name+'".Componentnames'+'canonlycontainalphanumericcharacatersandthehyphen.'); }
基于以上两点,可以总结出组件的命名规则为:组件名以字母开头,后面跟字母、数值或下划线,并且不与HTML元素或Vue保留标签重名。
然而我们注意到,在上面的检查中,不符合规则的组件名称是warn而不是error,意味着检查并不是强制的。实际上,Vue组件注册的名称是没有限制的。你可以用任何JavaScript能够表示的字符串,不管是数字、特殊符号、甚至汉字,都可以成功注册。
模板解析
虽然Vue组件没有命名限制,但是我们终究是要在模板中引用的,不合理的组件名可能会导致我们无法引用它。
为了弄清楚Vue是如何将模板中的标签对应到自定义组件的,我们以一段简单的代码说明:
newVue({ el:'#app', template:'' })
总体来说,模板解析分为两个过程:
首先,Vue会将template中的内容插到DOM中,以方便解析标签。由于HTML标签不区分大小写,所以在生成的标签名都会转换为小写。例如,当你的template为
然后,通过标签名寻找对应的自定义组件。**匹配的优先顺序从高到低为:原标签名、camelCase化的标签名、PascalCase化的标签名。**例如
varcamelizeRE=/-(\w)/g; functioncamelize(str){ returnstr.replace(camelizeRE,toUpper); } functiontoUpper(_,c){ returnc?c.toUpperCase():''; } functionpascalize(str){ varcamelCase=camelize(str); returncamelCase.charAt(0).toUpperCase()+camelCase.slice(1) }
对于一个Vue新手,经常对以下示例代码不能正常运行感到非常疑惑:
Vue.component('MyComponent',{ template:'hello,world' }) newVue({ el:'#app', template:'' })
如果我们按照模板解析的过程推理,就很好解释了。模板
命名限制
通过分析组件注册和模板解析的过程,发现Vue组件命名限制并没有我们想象得多。大家可以尝试一下各种命名,我试过
但是,并不意味着完全没有限制。由于在模板需要插入到DOM中,所以模板中的标签名必须能够被DOM正确地解析。主要有三种情况:一是完全不合法的标签名,例如>;二是与HTML元素重名会产生不确定的行为,例如使用input做组件名不会解析到自定义组件,使用button在Chrome上正常但在IE上不正常;三是与Vue保留的slot、partial、component重名,因为会优先以本身的意义解析,从而产生非预期的结果。
上述命名限制存在的根本原因,在于模板解析的过程依赖了DOM。能不能对模板解析过程改进一下,使其不依赖于DOM呢?实际上,这正是Vue2.0的主要改进,将模板解析过程使用VirtualDOM实现,使得组件命名更加灵活。
Vue2.0组件命名机制
组件注册
Vue2.0的组件注册过程与Vue1.0基本相同,只是HTML标签和Vue保留标签范围有些不同:
//区分大小写 varisHTMLTag=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' ); //不区分大小写 varisSVG=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 ); varisReservedTag=function(tag){ returnisHTMLTag(tag)||isSVG(tag) }; //区分大小写 varisBuiltInTag=makeMap('slot,component',true);
虽然HTML元素重名警告的标签数大大增加了,但重要的是重名区分大小写,所以我们可以愉快地使用Input、Select、Option等而不用担心重名。这个功劳属于Vue2.0引入的VirtualDOM。
模板解析
前面提到,Vue2.0相对于1.0的最大改进就是引入了VirtualDOM,使模板的解析不依赖于DOM。
使用VirtualDOM解析模板时,不必像DOM方式那样将模板中的标签名转成小写,而是原汁原味地保留原始标签名。然后,使用原始的标签名进行匹配组件。例如,
之前在1.0不能正常运行的示例代码,在2.0中可以正常运行了:
Vue.component('MyComponent',{ template:'hello,world' }) newVue({ el:'#app', template:'' })
在Vue1.0和2.0中还有一种定义组件模板的方式,即使用DOM元素。在这种情况下,解析模板时仍然会将标签转为小写形式。所以下面的代码,在1.0和2.0均不能正常运行。
//index.html
命名限制
Vue2.0中组件的命名限制与1.0的最大区别在于区分了大小写。总结一下就是:一是不使用非法的标签字符;二是不与HTML元素(区分大小写)或SVG元素(不区分大小写)重名;三是不使用Vue保留的slot和component(区分大小写)。
除了以上三条,由于Vue2.0内置了KeepAlive、Transition、TransitionGroup三个组件,所以尽量避免与这三个组件重名。但从另一方面讲,你也可以故意重名来实现一些特殊的功能。例如,keep-alive的匹配顺序为keep-alive、keepAlive、KeepAlive,所以我们可以注册一个keep-alive组件来拦截KeepAlive匹配。
总结
到这里,我们可以知道Vue2.0完全可以像React那样使用PascalCase形式的组件标签。对于Vue1.0,想以PascalCase形态写模板,尽量以全小写或者仅首字母大写形式注册组件,例如
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。