Vue Component Overview
Component is one of the most powerful features. Components can extend HTML elements and encapsulate reusable code. According to project requirements, abstract some components, each component contains presentation, functions and styles. Each page uses different components to splice the pages according to your needs. This development model makes front-end pages easy to expand, have high flexibility, and also enables decoupling between components.
In Vue, a component is essentially a Vue instance with predefined options
A component is a custom element or a module that includes the required templates, logic, and styles. In HTML templates, components exist in the form of a custom tag, serving as placeholders. After the declarative rendering is passed, the placeholder will be replaced with the actual content
Here is a simplest example of the module
<div > <xiaohuochai></xiaohuochai> </div>
Vue Registration Components
Component registration includes global registration and local registration.
Global registration
To register a global component, you can use (tagName, options)
('my-component', { // Options})
After the component is registered, it can be used as a custom element <my-component></my-component> in the module of the parent instance.
[Note] Make sure that the component is registered before initializing the root instance
<div > <my-component></my-component> </div> <script> // register('my-component', { template: '<div>A custom component!</div>' }) // Create a root instancenew Vue({ el: '#example' }) </script>
Local registration
By using the component instance option components registration, you can make a component available only in the scope of another instance/component
<div > <my-component></my-component> </div> <script> // registervar Child = { template: '<div>A custom component!</div>' }; // Create a root instancenew Vue({ el: '#example', components: { // <my-component> will only be available in the parent template 'my-component': Child } }) </script>
Component Tree
Use component instance option components registration to achieve the effect of component tree
<div > <my-component></my-component> </div> <script> // registervar headerTitle = { template: '<p>I am the title</p>', }; var headerContent = { template: '<p>I am content</p>', }; var header = { template: ` <div class="hd"> <header-content></header-content> <header-title></header-title> </div> `, components: { 'header-content': headerContent, 'header-title': headerTitle } }; // Create an instancenew Vue({ el: '#example', components: { 'my-component': header } }) </script>
For large applications, it is necessary to divide the entire application into components so that development can be managed. The general component application template is as follows
<div > <app-nav></app-nav> <app-view> <app-sidebar></app-sidebar> <app-content></app-content> </app-view> </div>
v-once
Although rendering HTML in Vue is fast, when the component contains a lot of static content, you can consider using v-once to cache the rendering results.
('my-component', { template: '<div v-once>hello world!...</div>' })
Template separation of Vue components
In component registration, it is more troublesome to splice HTML elements in the template option, which also leads to high coupling between HTML and JS. Thankfully, there are two ways to separate HTML templates defined in JS
script
Use the text/x-template type in the script tag and specify an id
<script type="text/x-template" > <p>Hello hello hello</p> </script> ('hello-world', { template: '#hello-world-template' })
The above code is equivalent to
('hello-world', { template: '<p>Hello hello hello</p>' })
Here is a simple example
<div > <my-component></my-component> </div> <script type="text/x-template" > <div>hello world!</div> </script> <script> ('my-component', { template: '#hello-world-template' }) new Vue({ el: '#example' }) </script>
template
If you use the <template> tag, you do not need to specify the type attribute
<div > <my-component></my-component> </div> <template > <div>hello world!</div> </template> <script> // register('my-component', { template: '#hello-world-template' }) // Create a root instancenew Vue({ el: '#example' }) </script>
Naming convention for Vue components
For component naming, the W3C specification is lowercase letters and contains a midscore (-). Although Vue does not require it, it is best to follow the specification.
<!-- existHTMLAlways used in templates kebab-case --> <kebab-cased-component></kebab-cased-component> <camel-cased-component></camel-cased-component> <pascal-cased-component></pascal-cased-component>
When registering components, you can use any of these three types: medium marking, small hump, and large hump.
// In component definitioncomponents: { // Register with the medium marking 'kebab-cased-component': { /* ... */ }, // Register with small camel 'camelCasedComponent': { /* ... */ }, // Register with Big Hump 'PascalCasedComponent': { /* ... */ } }
Vue component nesting restrictions
Not all elements can be nested with templates because they are restricted by HTML element nesting rules, especially <ul>, <ol>, <table>, <select>, which limit elements that can be wrapped, and some elements like <option> can only appear inside some other elements.
[Note] Detailed nesting rules about HTML tags are moved here
Using these restricted elements in custom components can cause some problems, e.g.
<table > <my-row>...</my-row> </table>
Custom component <my-row> is considered invalid content, so it will cause errors when rendering
<script> // registervar header = { template: '<div class="hd">I'm the title</div>' }; // Create an instancenew Vue({ el: '#example', components: { 'my-row': header } }) </script>
is attribute
The workaround is to use special is attributes
<table > <tr is="my-row"></tr> </table> <script> // registervar header = { template: '<div class="hd">I'm the title</div>' }; // Create an instancenew Vue({ el: '#example', components: { 'my-row': header } }) </script>
The root element of the Vue component
Vue forces each Vue instance (component is essentially a Vue instance) to have a root element
As shown below, an error will be reported
<div > <my-component></my-component> </div> <script> // register('my-component', { template: ` <p>The first paragraph</p> <p>Paragraph 2</p> `, }) // Create a root instancenew Vue({ el: '#example' }) </script>
Need to be rewritten as follows
<script> // register('my-component', { template: ` <div> <p>The first paragraph</p> <p>Paragraph 2</p> </div> `, }) // Create a root instancenew Vue({ el: '#example' }) </script>
Vue component data delivery
Generally, in Vue instance object or Vue component object, we pass data through data.
<div > <my-component></my-component> <my-component></my-component> <my-component></my-component> </div> <script> // register('my-component', { template: '<div>{{message}}</div>', data:{ message: 'hello' } }) // Create a root instancenew Vue({ el: '#example' }) </script>
Running the above code will stop Vue from executing and issue an error message on the console telling you that data must be a function in the component.
You can use the following method to bypass Vue's error prompts
<script> // registervar data = {counter: 0} ('my-component', { template: '<button v-on:click="counter += 1">{{ counter }}</button>', data:function(){ return data; } }) // Create a root instancenew Vue({ el: '#example' }) </script>
Since these three components share the same data, adding a counter affects all components
When a component is defined, data needs to be declared as a function that returns an initial data object, because the component may be used to create multiple instances. If data is still a pure object, all instances will share references to the same data object. By providing the data function, each time a new instance is created, the data function can be called, thus returning a brand new copy of the data object of the initial data
Therefore, this problem can be solved by returning a brand new data object for each component:
<script> // register('my-component', { template: '<button v-on:click="counter += 1">{{ counter }}</button>', data:function(){ return {counter: 0}; } }) // Create a root instancenew Vue({ el: '#example' }) </script>
Now each counter has its own internal state
Vue component native events
Sometimes, you may want to listen for a native event on the root element of a component. Directly using the v-bind directive will not take effect
<div > <my-component @click="doTheThing"></my-component> <p>{{message}}</p> </div> <script> ('my-component', { template: '<button>button</button>', }) new Vue({ el: '#example', data:{ message:0 }, methods:{ doTheThing(){ ++; } } }) </script>
You can use .native to modify the v-on command
<div > <my-component @="doTheThing"></my-component> <p>{{message}}</p> </div> <script> ('my-component', { template: '<button>button</button>', }) new Vue({ el: '#example', data:{ message:0 }, methods:{ doTheThing(){ ++; } } })
For more information about how to use Vue components, please click the relevant link below