Definition
Component is one of the most powerful functions of Vue. js. Components can extend HTML elements and encapsulate reusable code. At a higher level, components are custom elements for which the compiler of Vue.js adds special functionality. In some cases, components can also represent native HTML elements that have been extended with is features. All Vue components are also instances of Vue, so the same option objects such as data, computed, watch, methods and lifecycle hooks are acceptable. The only exception is the root instance-specific option like el.
Global component
We know that we can create a Vue instance in the following way:
new Vue({ el:"#app", //option })
To register a global component, you can use Vue.component(tagName, options). Example:
Vue.component('my-component',{ //option })
Once registered, the component can be used as a custom element <my-component> </my-component> in the template of an instance. Be careful to ensure that components are registered before initializing the root instance:
<div id="app"> <!-----Reference component-----> <my-component></my-component> </div> <script> // register Vue.component('my-component', { template: '<h3>I am a global component!</h3>' }) // Create a root instance new Vue({ el: '#app' }) </script>
A globally registered component can be used in any newly created Vue root instance after it has been registered (through the new Vue), as well as in the template of all the subcomponents in its component tree.
Local components
You don't have to register every component globally. You can register components that are available only in their domain of action through an instance option of a Vue instance/component:
<div id="app"> <!-----Reference component-----> <my-component></my-component> </div> <script> var Child = { template: '<h3>I am a local component!</h3>' } new Vue({ el:"#app", components: { // < my-component > will only be available in the parent component template 'my-component': Child } }) </script>
Notes in parsing DOM templates
Some HTML elements, such as <ul>, <ol>, <table> and <select>, have strict restrictions on which elements can appear within them. Some elements, such as <li>, <tr> and <option>, can only appear within certain other elements.
This leads to some problems when we use these constrained elements. For example:
<table> <blog-post-row></blog-post-row> </table> |
This custom component <blog-post-row> is promoted to the outside as invalid content and results in an error in the final rendering result. Fortunately, this special is feature gives us a flexible approach:
<table> <tr is="blog-post-row"></tr> </table> |
It should be noted that this limitation does not exist if we use templates from the following sources:
- String (for example: template:'...')
- Single file component (.vue)
- <script type="text/x-template">
Therefore, use string templates whenever possible.
The above means that the following example will not work:
<div id="app"> <select> <optioncomp></optioncomp> </select> </div> <script> new Vue({ el: '#app', components:{ 'optioncomp':{ template: '<option >a</option>' } } }) </script>
But with is special attributes, you can:
<div id="app"> <select> <option is="optioncomp"></option> </select> </div> <script> new Vue({ el: '#app', components:{ 'optioncomp':{ template: '<option >a</option>' } } }) </script>
Or temp template tags can be: \\\\\\\
<div id="app"> <select> <option is="optioncomp"></option> </select> <!--Template content storage area--> <script type="x-template" id="optioncompTemp"> <option>a</option> </script> </div> <script> new Vue({ el: '#app', components:{ 'optioncomp':{ template: '#optioncompTemp' } } }) </script>
Or inline Template Strings
<div id="app"> <selectcomp></selectcomp> </div> <script> Vue.component('optioncomp', { template: '<option >a</option>' }); new Vue({ el: '#app', components:{ 'selectcomp':{ template: ' <select><optioncomp></optioncomp></select>' } } }) </script>
data must be a function
Most of the options passed in when constructing Vue instances can be used in components. There is only one exception: data must be a function. So each instance can maintain a separate copy of the returned object:
data: function () { return { count: 0 } }
If Vue does not have this rule, clicking a button may affect all other instances as follows:
<div id="components-demo"> <button-counter></button-counter> <button-counter></button-counter> <button-counter></button-counter> </div> <script> var data={ count:0 } // Define a new component called button-counter Vue.component('button-counter', { data: function () { return data }, template: '<button v-on:click="count++">You clicked me {{ count }} times.</button>' }) new Vue({ el: '#components-demo' }) </script>
Since these three component instances share the same data object, increasing a counter affects all components! We can fix this problem by returning new data objects for each component:
data: function () { return { count: 0 } }
Note that each component maintains its count independently when the button is clicked. Because every time you use a component, a new instance of it is created.