在早期的前端开发中,HTML,CSS,JavaScript的引用关系是混乱的,给维护带来难度。
Vue中有一个组件的概念:用来实现局部(特定)功能效果的代码集合。
在Vue中,使用组件分为3步:定义组件、注册组件、使用组件。
在定义组件的时候,使用Vue.extend(option)
传入组件的配置,注意这里不要指定el,因为所有组件都被Vue实例对象管理,由实例对象中的el指明模板。组件中的data必须写成函数的形式,避免a组件修改data.x,影响到b组件中data.x的值。
在注册组件的时候,由分为局部注册和全局注册两种。
局部注册:在new Vue()
的时候传入components参数。
全局注册:在Vue实例化之前,使用Vue.component('组件名', 组件);
即可。
在使用组件的时候,直接通过标签即可引入组件。
一个文件中,定义了多个组件。
<div id="root">
<hello>hello>
<hr>
<h1>{{msg}}h1>
<hr>
<school>school>
<hr>
<student>student>
div>
<div id="root2">
<hello>hello>
div>
const school = Vue.extend({
template:`
学校名称:{{schoolName}}
学校地址:{{address}}
`,
data(){
return {
schoolName:'尚硅谷',
address:'北京昌平'
}
},
methods: {
showName(){
alert(this.schoolName);
}
},
});
const student = Vue.extend({
template:`
学生姓名:{{studentName}}
学生年龄:{{age}}
`,
data(){
return {
studentName:'张三',
age:18
}
}
});
const hello = Vue.extend({
template:`
你好啊!{{name}}
`,
data(){
return {
name:'Tom'
}
}
});
// 全局注册组件
Vue.component('hello',hello);
new Vue({
el:'#root',
data:{
msg:'你好啊!'
},
// 局部注册组件
components:{
school,
student
}
});
new Vue({
el:'#root2',
});
组件名如果只有一个单词,使用全小写或者首字母大写都可以。
组件名如果有多个单词,需要使用kebab-case的方式或者CamelCase方式(需要Vue脚手架,否则会报错),自定义组件名不能和现有的HTML元素重名,否则组件是不起作用的。在没有Vue脚手架的时候,不要写自闭合单标签,会导致后续组件无法渲染,这里先采用双标签写法。
组件是允许嵌套的,a组件包含b组件,那么需要先定义b组件,再定义a组件,将a组件放在b组件定义的components中。Vue中有一个习惯写法:定义一个app组件,通过app组件包括所有的自定义组件。
const student = Vue.extend({
name:'student',
template:`
学生姓名:{{name}}
学生年龄:{{age}}
`,
data(){
return {
name:'尚硅谷',
age:18
}
}
});
const school = Vue.extend({
name:'school',
template:`
学校名称:{{name}}
学校地址:{{address}}
`,
data(){
return {
name:'尚硅谷',
address:'北京'
}
},
// school组件嵌套student组件
components:{
student
}
});
const hello = Vue.extend({
template:`{{msg}}
`,
data(){
return {
msg:'欢迎来到尚硅谷学习!'
}
}
});
const app = Vue.extend({
template:`
`,
// app组件嵌套student组件和school组件
components:{
school,
hello
}
});
定义好一个组件之后,我们尝试在方法里输出this,看看组件里面的this是什么。
const person = Vue.extend({
name:'person',
template:`
姓名:{{name}}
地址:{{address}}
`,
data(){
return {
name:'王劭阳',
address:'山东济南'
}
}
});
console.log(person);
通过输出,我们看到this是VueComponent的构造函数,这个函数是Vue.extend
生成的,在页面上只需要写
,Vue解析的时候,会帮助我们创建Person组件的实例对象,Vue会帮我们执行new VueComponent(options)
。每次调用Vue.extend()
,返回的都是一个全新的VueComponent。
在组件配置中的this指向VueComponent实例对象,在Vue配置中this指向Vue实例对象。
关于VueComponent和Vue,这里存在一个关系:VueComponent.prototype.__proto__ === Vue.prototype
,为了让VueComponent可以访问到Vue原型上的属性和方法。
prototype
是显式原型属性,__proto__
是隐式原型属性。
VueComponent在访问属性的时候,先在自身查找,自身查找不到再去原型里查找,原型里也查找不到,再去__proto__
里查找,也就是去Vue的原型里查找。
// 给Vue添加一个属性
Vue.prototype.x = 99;
//定义school组件
const school = Vue.extend({
name:'school',
template:`
名称:{{name}}
地址:{{address}}
`,
data(){
return {
name:'王劭阳',
address:'山东济南'
}
},
methods: {
showX(){
// 组件里访问x属性,一直找到Vue里才找到x的值
console.log(this.x);
}
},
});
单文件组件就是一个*.vue的文件,一个*.vue文件就是一个组件,一个组件又分为3部分:template
、script
、style
,分别表示模板、脚本、样式。
Vue文件在命名的时候也有规范:一个单词的,直接首字母大写,比如Person.vue
,多个单词的使用大驼峰,比如MySchool.vue
。这样的好处是和Vue开发者工具里保持一致。
首先定义一个Person
组件。
<template>
<div class="demo">
<h2>名称:{{name}}h2>
<h2>地址:{{address}}h2>
<button @click="showName">点我提示名称button>
div>
template>
<script>
// Vue.extend可以省略,要想让其他地方可以使用这个组件,需要用export default将组件进行暴露
export default {
name:'Person',// 指定这个组件的名称
data(){
return {
name:'王劭阳',
address:'山东济南'
}
},
methods: {
showName(){
alert(this.name);
}
},
}
script>
<style>
.demo{background-color: orange;}
style>
前面提到,所有的组件都由App.vue来管理,创建一个App.vue。
<template>
<div>
<Person>Person>
<Person>Person>
div>
template>
<script>
//引入组件
import School from './Person.vue'
export default {
name:'App',
components:{
Person
}
}
script>
有了App.vue,再往上就是Vue实例了,通过一个main.js
实现Vue的实例化,并把组件也加进去。
import App from './App.vue'
new Vue({
el:'#root',
// template:` `,
components:{App},
});
还差一个模板文件:index.html。
<div id="root">
<App>App>
div>
此时的项目是运行不起来的,需要有Vue脚手架才能运行。