小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。
与 Vue2 相比,Vue3 中注册组件变得更加简单了。
1. 注册组件的方式
如果不使用组件,复杂逻辑堆积在一起,像这样:
<div id="app"></div>
<template id="my-app">
<input type="text" v-model="message">
<h2>{{ message }}</h2>
<h2>{{ title }}</h2>
<p>{{ desc }}</p>
<button @click="btnClick">按钮</button>
</template>
<script src="./js/vue.js"></script>
<script>
const App = {
data() {
return {
message: '你好啊',
title: '我是标题',
desc: '我是内容...'
}
},
methods: {
btnClick() {
console.log('按钮被点击了');
}
},
template: '#my-app'
};
Vue.createApp(App).mount('#app');
</script>
所有的内容都写在一起必然是不现实的。因此,我们可以使用组件将各部分内容抽离出去。就是说,如果现在有一部分内容(模板、逻辑等),我们希望将这部分内容抽取到一个独立的组件中去维护,那么该如何注册一个组件呢?
比如下面的模板希望抽离成一个单独的组件:
<h2>{{ title }}</h2>
<p>{{ message }}</p>
注册的组件分成两种:
- 全局组件:在任何其它的组件中都可以使用的组件;
- 局部组件:只有在注册的组件中才能使用的组件;
2. 注册全局组件
- 全局组件需要使用我们全局创建的
app来注册; - 通过
component方法传入组件名称、组件对象,即可注册一个全局组件了; - 之后,我们可以在
App组件的template中直接使用这个全局组件:
<body> 元素中的代码如下:
<div id="app"></div>
<template id="my-app">
<h2>我是标题</h2>
<p>我是内容...</p>
<component-a></component-a>
<component-a></component-a>
<component-a></component-a>
</template>
<template id="component-a">
<h2>我是标题</h2>
<p>我是内容...</p>
</template>
<script src="./js/vue.js"></script>
<script>
const App = {
template: '#my-app'
};
const app = Vue.createApp(App)
// 使用 Vue 的 createApp() 函数返回的 app 对象,注册一个全局组件
// 全局组件:意味着注册的这个组件可以在任何的组件模板中使用(但在开发中一般不推荐注册全局组件)
// app.component(组件名称, 组件对象);
app.component('component-a', {
// template: `<h3>我是component-a组件</h3>`
template: '#component-a'
});
app.mount('#app');
</script>
上面注册的全局组件中只有 template,其实,我们注册的组件中也可以有自己的代码逻辑(比如自己的 data、computed、methods 等等):
// 使用 Vue 的 createApp() 函数返回的 app 对象,注册一个全局组件
app.component('component-a', {
data() {
return {
title: '我是标题',
message: '我是内容...'
}
},
methods: {
btnClick() {
console.log('按钮发生了点击');
}
},
template: '#component-a'
});
<body> 元素中的代码如下:
<div id="app"></div>
<template id="my-app">
<!-- 使用组件 -->
<component-a></component-a>
<component-a></component-a>
<component-a></component-a>
</template>
<template id="component-a">
<h2>{{ title }}</h2>
<p>{{ message }}</p>
<button @click="btnClick">按钮</button>
</template>
<script src="./js/vue.js"></script>
<script>
const App = {
template: '#my-app'
};
const app = Vue.createApp(App)
// 使用 Vue 的 createApp() 函数返回的 app 对象,注册一个全局组件
app.component('component-a', {
data() {
return {
title: '我是标题',
message: '我是内容...'
}
},
methods: {
btnClick() {
console.log('按钮发生了点击');
}
},
template: '#component-a'
});
app.mount('#app');
</script>
当然,我们也可以注册多个全局组件:
<div id="app"></div>
<template id="my-app">
<component-a></component-a>
<component-b></component-b>
</template>
<template id="component-a">
<h2>{{ title }}</h2>
<p>{{ message }}</p>
<button @click="btnClick">按钮</button>
</template>
<template id="component-b">
<input type="text" v-model="message">
<h2>ComponentB</h2>
</template>
<script src="./js/vue.js"></script>
<script>
const App = {
template: '#my-app'
};
const app = Vue.createApp(App)
// 使用 Vue 的 createApp() 函数返回的 app 对象,注册一个全局组件
app.component('component-a', {
data() {
return {
title: '我是标题',
message: '我是内容...'
}
},
methods: {
btnClick() {
console.log('按钮发生了点击');
}
},
template: '#component-a'
});
// 再注册一个全局组件,名为 component-b
app.component('component-b', {
data() {
return {
message: 'Hello World!'
}
},
template: '#component-b'
})
app.mount('#app');
</script>
页面效果:
你可能会说,不对啊,为什么按钮和文本框在同一行啊?其实原因非常简单,因为在 Vue3 中,组件的 template 中不再需要用一个根元素包裹了。而在 Vue2 中,则需要用一个根元素包裹,一般会用一个 <div> 元素去包裹。因此,如果在这里我们也加上 <div> 元素去包裹,因为 <div> 元素是块级元素会独占一行的,那么就能让按钮和文本框不在同一行了。但是由于我们这里没有 <div> 元素,所以在渲染完行内元素 <button> 后就会来渲染行内元素 <input> ,结果就在同一行了。其实,后面我们读源码时就会知道为什么 Vue3 的 template 中不需要根元素了(其实是因为它会把 Fragment 当成根元素去处理)。
以上,就是注册多个全局组件的过程。需要说明的是,在开发中一般不推荐注册全局组件。另外,我们目前在注册多个全局组件的时候,所有代码仍然是放在一个 html 文件里的,看起来有点复杂。因此,后面我们会讲另外一种开发模式:SFC(Single File Components,单文件组件)的开发模式,就是把有关代码抽取到 .vue 文件中。