There ara only two things in Computer Sciences: cache invalidation and naming things.
- Phil Karlton
As mentioned above, variable naming in programming is a real headache. We vaguely know that the name of the Vue component is better not to be the same as the original HTML tag. To avoid renaming, a prefix, such as el-button, el-input, el-date-picker, is usually prefixed to the component name. This is usually not a problem, but sometimes your template is mixed with native HTML tags and component tags, and it's not easy to distinguish them.
When I saw that Ant.design's React component was the following, I felt a sense of freedom. First, component names can use native HTML tag names, which means that native HTML tags can no longer be avoided. In addition, these components all use capitalized tag names, making them easily distinguishable from native lowercase HTML tags.
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
);
Inspired by Ant.design, I wonder if Vue component naming can achieve the same effect. To find the answer, you have to figure out what the limitations of Vue component naming are. Next, we will discuss the mechanism of component naming from Vue 1.0 and Vue 2.0 respectively.
Vue 1.x Component Naming Mechanism
Component registration
Let's take a simple example to study the registration process of Vue components:
Vue.component('MyComponent', {
template: '<div>hello, world</div>'
})
By tracking the execution of the code, it is found that there are two checks for the name of the component.
1. Check whether the name is renamed with HTML elements or Vue tags, case-insensitive. It can be found that only commonly used HTML elements are checked, and many elements are not checked, such as 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|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;
2. Check whether the component name begins with an alphabet followed by a letter, a numeric value, or an underscore.
if (!/^[a-zA-Z][\w-]*$/.test(name)) {
warn('Invalid component name: "' + name + '". Component names ' + 'can only contain alphanumeric characaters and the hyphen.');
}
Based on the above two points, we can conclude that the naming rules of components are: component names begin with letters, followed by letters, values or underscores, and do not reserve tags with HTML elements or Vue.
However, we noticed that in the above check, the name of the component that does not conform to the rule is warn rather than error, which means that the check is not mandatory. In fact, there is no limit to the name registered by the Vue component. You can register any string that JavaScript can represent, whether it's a number, a special symbol, or even a Chinese character.
Template analysis
Although there is no naming restriction for Vue components, we need to refer to them in templates after all, and unreasonable component names may make it impossible for us to refer to them.
To figure out how Vue maps tags in templates to custom components, we use a simple piece of code to illustrate:
new Vue({
el: '#app',
template: '<my-component></my-component>'
})
Overall, template parsing is divided into two processes:
First, Vue inserts the content of template into DOM to facilitate tag parsing. Because HTML tags are case-insensitive, the generated tag names are converted to lowercase. For example, when your template is <MyComponent> </MyComponent>, when you insert DOM, it will be converted to <mycomponent> </mycomponent>. (Note: We are now discussing the scenario under vue 1.x)
Then, the tag name is used to find the corresponding custom component. The priority of matching is from high to low: original tag name, camelCase tag name, PascalCase tag name. For example, <my-component> matches my-component, myComponent, and MyComponent in turn.
The code for how camelCase and Pascal Case are implemented is as follows:
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)
}
For a novice Vue, you often wonder if the following sample code is not working properly: (Note: We're talking about the scenario under vue 1.x)
Vue.component('MyComponent', {
template: '<div>hello, world</div>'
})
new Vue({
el: '#app',
template: '<MyComponent></MyComponent>'
})
If we reasoned according to the process of template parsing, it would be well explained. Template <MyComponent></MyComponent> will become <mycomponent></mycomponent> when inserted into DOM. The components matched by the tag mycomponent are mycomponent (original tag name), mycomponent (camelCase form), and Mycomponent (PascalCase form), which do not match the registered component name MyComponent, so the warning that the component can not be found will be reported.
Naming restrictions
By analyzing the process of component registration and template parsing, we find that the Vue component naming restriction is not as much as we expected. You can try various naming, I tried < a = - *% button > </a = - *% button > can work properly.
However, it does not mean that there are no restrictions at all. Since the template needs to be inserted into the DOM, the tag name in the template must be parsed correctly by the DOM.
There are three main situations:
One is completely illegal label names, such as </>;
Second, renaming with HTML elements will lead to uncertain behavior, such as using input to make component names will not resolve to custom components, using button on Chrome is normal but not normal on IE;
Thirdly, the slot, partial and component renames reserved with Vue will give priority to parsing in its own sense, thus producing unexpected results.
The fundamental reason for the above naming restrictions is that the template parsing process relies on DOM. Can you improve the template parsing process to make it independent of DOM? In fact, this is the main improvement of Vue 2.0. The template parsing process is implemented using Virtual DOM, which makes component naming more flexible.
Vue 2.0 Component Naming Mechanism
Component registration
The component registration process of Vue 2.0 is basically the same as that of Vue 1.0, except that HTML tags and Vue reserved tag ranges are somewhat different:
// Case-sensitive
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'
);
// Case insensitive
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)
};
// Case-sensitive
var isBuiltInTag = makeMap('slot,component', true);
Although the number of tags for HTML element rename warnings has increased dramatically, it is important that renames distinguish between case and case, so we can use Input, Select, Option and so on happily without worrying about renaming. This contribution belongs to the Virtual DOM introduced by Vue 2.0.
(For new features in vue 2.0, see: Vue 2.0 was released!,Announcing Vue.js 2.0)