(二十)Vue之非单文件组件
文章目录
- 基本使用
- 一、如何定义一个组件?
- 二、如何注册组件?
- 三、如何使用组件?
- 演示程序
- 普通Vue程序
- 单文件组件程序
- 局部注册
- 全局注册
- 几个注意点
- 1.关于组件名
- 2.关于组件标签
- 3.一个简写方式
- 组件的嵌套使用
- 关于VueComponent
- 一个重要的内置关系(重点)
- 回顾原型对象
- 重要的内置关系
Vue学习目录
上一篇:(十九)Vue之组件和模块概念
基本使用
Vue中使用非单文件组件的三大步骤:
- 一、定义组件(创建组件)
- 二、注册组件
- 三、使用组件(写组件标签)
一、如何定义一个组件?
使用Vue的API extend,传一个配置对象,这个配置项几乎和实例Vue一样,但也有点区别;
区别如下:
- 1.el不要写,为什么? ——— 因为最终所有组件都要被一个vm管理,由vm决定服务于哪个容器。
- 2.data必须写成函数,为什么? ———— 避免组件被复用时,数据存在引用关系。
备注:使用template可以配置组件结构。
二、如何注册组件?
1.局部注册:靠new Vue的时候传入components选项
2.全局注册:靠Vue.component(‘组件名’,组件)
三、如何使用组件?
<xxx></xxx>或<xxx/>
,xxx是在component配置的组件名
演示程序
普通Vue程序
<h2>学校名称:{{schoolName}}</h2>
<h2>学校地址:{{address}}</h2>
<hr>
<h2>学生姓名:{{studentName}}</h2>
<h2>学生年龄:{{age}}</h2>
new Vue({
el:'#root',
data:{
schoolName:'一中',
address:'广州',
studentName:'jack',
age:20
}
});
效果:
单文件组件程序
局部注册
靠new Vue的时候传入components选项,特点是在哪个Vue实例注册的组件,就在哪个Vue实例使用
const school = Vue.extend({
template:`
<div class="demo">
<h2>学校名称:{{schoolName}}</h2>
<h2>学校地址:{{address}}</h2>
<button @click="showName">点我提示学校名</button>
</div>
`,
data(){
return{
schoolName:'一中',
address:'广州'
}
},
methods:{
showName(){
alert(this.schoolName)
}
}
})
//创建student组件
const student = Vue.extend({
template:`
<div>
<h2>学生姓名:{{studentName}}</h2>
<h2>学生年龄:{{age}}</h2>
</div>
`,
data(){
return{
studentName:'jack',
age:20
}
}
})
new Vue({
el:'#root',
components:{//局部注册
school,
student
}
});
效果:
全局注册
靠Vue.component(‘组件名’,组件)注册组件,特点是如何一个Vue实例都可以使用
为了演示,新定义一个hello组件
<div id="root">
<!--编写组件标签-->
<school></school>
<hr>
<student></student>
<hr>
<hello></hello>
</div>
<div id="root2">
<hello></hello>
</div>
//hello组件
const hello = Vue.extend({
template:`
<div>
<h2>你好啊!{{name}}</h2>
</div>
`,
data(){
return {
name:'Tom'
}
}
})
//注册组件
Vue.component('hello',hello)//全局注册
new Vue({
el:'#root',
components:{//局部注册
school,
student
}
});
new Vue({
el:'#root2',
})
效果:
几个注意点
1.关于组件名
一个单词组成:
- 第一种写法(首字母小写):school
- 第二种写法(首字母大写):School
多个单词组成:
- 第一种写法(kebab-case命名):my-school
- 第二种写法(CamelCase命名):MySchool (需要Vue脚手架支持)
注意:
- (1).组件名尽可能回避HTML中已有的元素名称,例如:h2、H2都不行。
- (2).可以使用name配置项指定组件在开发者工具中呈现的名字。
例如给上面组件都取个名字name:'xuexiao',
效果:
不取名字,正常以在component配置的组件名首字母大写呈现
取了名字,是以name所指定的名字首字母大写呈现
2.关于组件标签
第一种写法:<school></school>
第二种写法:<school/>
注意:不用使用脚手架时,会导致后续组件不能渲染。
3.一个简写方式
因为Vue在components里遇到组件的时候会进行一个判断,如果直接是一个配置项,Vue会帮你补一个Vue.extend
例如:const school = Vue.extend(options) 可简写为:const school = options
组件的嵌套使用
组件可以发生嵌套,在众多嵌套关系当中,为了不产生混乱,一般都会受一个app组件进行引导,而vm就只需引导app组件即可
<div id="root">
<!--编写组件标签-->
<hello></hello>
<school></school>
</div>
//创建student组件
const student = Vue.extend({
template:`
<div>
<h2>学生姓名:{{studentName}}</h2>
<h2>学生年龄:{{age}}</h2>
</div>
`,
data(){
return{
studentName:'jack',
age:20
}
}
})
//创建school组件
const school = Vue.extend({
template:`
<div class="demo">
<h2>学校名称:{{schoolName}}</h2>
<h2>学校地址:{{address}}</h2>
<student></student>
</div>
`,
data(){
return{
schoolName:'一中',
address:'广州'
}
},
components:{//注册组件
student
}
})
//定义hello组件
const hello = Vue.extend({
template:`<h1>{{msg}}</h1>`,
data(){
return {
msg:'欢迎学习Vue!'
}
}
})
//定义app组件
const app = Vue.extend({
template:`
<div>
<hello></hello>
<school></school>
</div>
`,
components:{
school,
hello
}
})
//注册组件
new Vue({
template:'<app></app>',
el:'#root',
components:{//局部注册
app
}
});
效果:
关于VueComponent
我们可以输出上面school组件console.log(school)
发现是一个VueComponent函数
我们去到源码,发现我们每次调用Vue.extend,都会实例一个VueComponent对象
- 1.组件本质是一个名为VueComponent的构造函数,且不是程序员定义的,是Vue.extend生成的。
- 2.我们只需要写
<xxx/>或<xxx></xxx>
,Vue解析时会帮我们创建school组件的实例对象,即Vue帮我们执行的:new VueComponent(options)。 - 3.特别注意:每次调用Vue.extend,返回的都是一个全新的VueComponent!!!!
- 4.关于this指向:
- (1).组件配置中:
data函数、methods中的函数、watch中的函数、computed中的函数它们的this均是【VueComponent实例对象】。 - (2).new Vue(options)配置中:
data函数、methods中的函数、watch中的函数、computed中的函数 它们的this均是【Vue实例对象】。
一个重要的内置关系(重点)
回顾原型对象
什么是原型?
原型是Javascript中的继承的基础,JavaScript的继承就是基于原型的继承。
显示原型属性:
在JavaScript中,我们创建一个函数A, 那么浏览器就会在内存中创建一个对象A,而且每个函数都默认会有一个属性 prototype 指向了这个对象( 即:A.prototype = 对象A )。这个对象A就是函数A的原型对象,简称函数的原型。这个原型对象A 默认会有一个属性 constructor 指向了这个函数A 。
隐式原型属性:
当把一个函数A作为构造函数使用new创建对象的时候赋值给B,浏览器同样在内存中创建一个对象A,那么这个对象B就会存在一个默认的不可见的属性__proto__,来指向了构造函数的原型对象A。同样这个原型对象A 默认会有一个属性 constructor 指向了这个函数A 。
function Demo(){
this.a = 1
this.b = 2
}
//创建一个Demo的实例对象
const d = new Demo()
console.log(Demo.prototype) //显示原型属性
console.log(d.__proto__) //隐式原型属性
console.log(Demo.prototype === d.__proto__) //true
//程序员通过显示原型属性操作原型对象,追加一个x属性,值为99
Demo.prototype.x = 99
console.log(d.x)
Vue.prototype.x = 99
重要的内置关系
Vue的原型关系:跟普通的原型关系一样
- Vue我们可以看作是一个函数,浏览器同样在内存中创建一个原型对象Vue,那么
Vue.prototype => Vue的原型对象
- 当我们实例Vue时,我们可以通过实例对象
vm.__proto__ => Vue的原型对象
- 由于所有原型对象默认是继承Object,所以
Vue原型对象. __proto__ => Object的原型对象
VueComponent的原型关系:前两步是一样的,在VueCompont的原型对象的原型对象做出来重要的变化
- VueComponent我们同样看作是一个函数,浏览器同样在内存中创建一个原型对象VueComponent,那么
VueComponent.prototype => VueComponent的原型对象
- 当我们实例VueComponent时,我们可以通过实例对象
vc.__proto__ => VueComponent的原型对象
- 原本VueCompont的原型对象的原型对象是Object的原型对象,但是Vue把这条线改成了:
VueComponent.prototype.__proto__ === Vue.prototype(VueCompont的原型对象的原型对象 => Vue的原型对象)
,为什么要有这个关系:让组件实例对象(vc)可以访问到 Vue原型上的属性、方法。