VueJS: Đăng ký component
Bài viết này giả định bạn đã đọc Component. Hãy đọc trước nếu bạn chưa quen với component.
Tên cho Component
Khi đăng ký một component thì ta luôn luôn cần có một tên. Ví dụ như trong đăng ký global thì có sẽ có dạng như thế này:
Vue.component('my-component-name', { /* ... */ })
Tên của component là đối số đầu tiên của Vue.component
.
Tên của component có thể phụ thuộc vào nơi bạn sử dụng nó. Khi sử dụng component trực tiếp trong DOM (đối nghịch với mẫu chuỗi hoặc single-file component) thì ta cần tuân theo quy chuẩn của W3C dành cho tên thẻ tùy chỉnh (tất cả đều viết bằng chữ thường và phải có dấu gạch nối giưa các từ). Điều này sẽ giúp ta tránh conflict với các phần HTML hiện thời hoặc tương lai.
Đặt tên
Có hai lựa chọn khi đặt tên cho component:
Theo cách kebab-case
Vue.component('my-component-name', { /* ... */ })
Khi đặt tên theo cách thức kebab-case
thì ta ta cũng phải sử dụng kebab-case khi tham chiếu tới phần tử tùy chỉnh của nó, chẳng hạn như <my-component-name>
.
Theo cách PascalCase
Vue.component('MyComponentName', { /* ... */ })
Khi đặt tên cho component theo cách thức PascalCase thì ta có thể sử dụng tên component theo cả cách thức kebab-case nữa. Có nghĩa là cả <my-component-name>
và <MyComponentName>
thì đều hợp lệ khi tham chiếu component tương ứng. Tuy nhiên thì chỉ có tên theo kebab-case là hợp lệ trong DOM.
Đăng ký global
So far, we’ve only created components using Vue.component
:
Vue.component('my-component-name', { // ... các tùy chọn ... })
Những component này được đăng ký theo dạng global, tức là chúng có thể được dùng trong template của bất kỳ đối tượng Vue root nào (new Vue
) được tạo sau khi đăng ký. Ví dụ:
Vue.component('component-a', { /* ... */ }) Vue.component('component-b', { /* ... */ }) Vue.component('component-c', { /* ... */ }) new Vue({ el: '#app' })
<div id="app"> <component-a></component-a> <component-b></component-b> <component-c></component-c> </div>
Cả 3 component con ở trên đều được sử dụng trong nhau.
Đăng ký local
Đăng ký global thường không phải là ý hay. Ví dụ như khi ta dùng một hệ thống build như là Webpack chẳng hạn, thì việc đăng ký global cho tất cả các component sẽ dẫn đến vấn đề là ngay cả khi dừng sử dụng một component nào đó thì nó vẫn có thể được đưa vào build. Điều này là không cần thiết vì sẽ làm tăng lượng JavaScript cần phải download.
Trong trường hợp này thì ta nên định nghĩa component theo hướng local dưới dạng đối tượng JavaScript:
var ComponentA = { /* ... */ } var ComponentB = { /* ... */ } var ComponentC = { /* ... */ }
Sau đó ta sử dụng những component này bằng cách đưa vào tùy chọn components
:
new Vue({ el: '#app' components: { 'component-a': ComponentA, 'component-b': ComponentB } })
Trong đó, với mỗi thuộc tính trong components
thì key là tên do ta tự đặt, còn value chính là tên của component đã được định nghĩa theo cách thức local ở trên.
Nếu you want a local registered component inside another local register component, you can do the follow:
var ComponentA = { /* ... */ } var ComponentB = { components: { 'component-a': ComponentA }, // ... }
Or if you use ES6 modules, such as Webpack and Babel, you can do follow:
import ComponentA from './ComponentA.vue' export default { components: { ComponentA }, // ... }
Các hệ thống module
If you are not using module system with import/require, you can skip this section for now. If you are, we have some special instructions and tips as bellow.
Đăng ký local trong hệ thống module
We use components
to contain each component. For example, if we have a file ComponentB.vue and we want to use ComponentA and ComponentC in it, we can do following:
import ComponentA from './ComponentA' import ComponentC from './ComponentC' export default { components: { ComponentA, ComponentC }, // ... }
Then, we can use both ComponentA and ComponentC inside the template of ComponentB.
We can apply this way in practice. For example, we can create some base components as Button, Input, Icon, ... Then we include them in a component to use them as bellow:
import Button from './Button.vue' import Icon from './Icon.vue' import Input from './Input.vue' export default { components: { Button, Icon, Input } }
<Input v-model="searchText" @keydown.enter="search" /> <Button @click="search"> <Icon name="search"/> </Button>
Just to support relatively little markup in a template:
If you're using Webpack (or Vue CLI 3+, which uses Webpack internally), you can use require.context to globally register for only these very common base components. Here is an example to show that we can import globally base components in your app's entry file (i.e. store.js):
import Vue from 'vue' import upperFirst from 'lodash/upperFirst' import camelCase from 'lodash/camelCase' const requireComponent = require.context( // The relative path of the components folder './components', // Whether or not to look in subfolders false, // The regular expression used to match base component filenames /Base[A-Z]\w+\.(vue|js)$/ ) requireComponent.keys().forEach(fileName => { // Get component config const componentConfig = requireComponent(fileName) // Get PascalCase name of component const componentName = upperFirst( camelCase( // Strip the leading `'./` and extension from the filename fileName.replace(/^\.\/(.*)\.\w+$/, '$1') ) ) // Register component globally Vue.component( componentName, // Look for the component options on `.default`, which will // exist if the component was exported with `export default`, // otherwise fall back to module's root. componentConfig.default || componentConfig ) })