Vue(四) 组件、单文件组件、非单文件组件,重要的内置关系
文章目录
- 1. 组件
- 2. 非单文件组件
- 2.1 定义组件
- 2.2 注册组件
- 2.3 使用组件
- 2.4 组件命名、标签等注意点
- 2.5 组件嵌套
- 2.6 VueComponent构造(这部分看视频更易理解)
- 2.7 内置关系
- 3. 单文件组件
1. 组件
组件是实现局部功能代码和资源的集合
- 传统方式:
复用的意思是只有一个文件,大家都可以用
依赖关系混乱:a.js 中引入了b.js,c.js若引入想引入a,则必须也要引入b - 组件方式
所有组件都由vm掌管,且组件可以嵌套组件。一般vue实例对象vm直接掌管一个App的组件,App内管理着其他所有的组件。
2. 非单文件组件
非单文件组件:一个文件中包含有n个组件
Vue使用组件的三大步骤:定义组件、注册组件、使用组件
2.1 定义组件
语法:Vue.extend(options)
其中的options与创建vm时new Vue(options)
的options几乎一样,区别有两点:
- el不需要写,因为最终所有的组件都要经过一个vm的管理,由vm中的el决定服务哪个容器。
- data必须写成函数, 避免组件被复用时,数据存在引用关系。(如果把data定义为对象,若有两个school组件,则都指向都一个地址中的data,其中一个组件data中的属性值改了,另一个组件的data属性值也会变)
使用template选项可配置组件内容结构
<div id="root">
<!-- 这里的标签名取决于注册组件时定义的名称 -->
<school></school>
</div>
<script>
// 创建组件
const school = Vue.extend({
// 这里的name属性改变的仅是开发工具里显示的组件名
name:'SCH',
template: `
<div class="demo">
<h2>学校名称:{{schoolName}}</h2>
<h2>学校地址:{{address}}</h2>
</div>
`,
data () {
return {
schoolName: '中学',
address: '火星'
}
}
}),
// 创建第二个组件
const student = Vue.extend({...})
new Vue({
el: '#root',
....
})
</script>
2.2 注册组件
- 局部注册:new Vue的时候传入components配置项
new Vue({
el: '#root',
...
components: {
// 2. 注册组件,这里写的什么名,模板里组件的标签就是什么名
school
//或 给组件定义新的名字
// xuexiao: school
}
})
- 全局注册:
语法:Vue.component('组件名',组件)
在上述局部注册中,root容器里可以使用school组件,若是再有一个vue实例对象,接管另一个容器,则另一个容器无法使用school组件。全局注册之后,则这个文件里的所有vm接管的容器都可以使用该组件
<div id="root">
<school/>
</div>
<div id="root2">
<school/>
</div>
<script>
Vue.component('school',school)
new Vue({el:'root',...})
new Vue({el:'root2',...})
</script>
2.3 使用组件
写组件标签即可使用组件<school></school>
或<school/>
2.4 组件命名、标签等注意点
组件命名:
- 可以使用name配置项指定组件在开发者工具中呈现的名字。
- 一个单词
- 方式一:首字母小写school
- 方式二:首字母大写School
- 多个单词
- 方式一:my-school
- 方式二:MySchool(需要脚手架支持)
为了与开发者工具中的名字呼应,无论是一个单词还是两个单词,最好采用首字母大写的方式。
组件标签
- 方式一:
<school></school>
- 方式二:
<school/>
,这种最好也是在使用脚手架的情况下使用,如果不使用脚手架,模板中有多个标签时,页面只渲染一个组件标签的内容
组件简写
const school = Vue.extend(options)
可简写为const school = options
这种简写方式其实底层也是给补上一个Vue.extend。也就是底层会做一个判断,要是写了Vue.extend,就不管了;要是没写,就补一个。
2.5 组件嵌套
用哪个组件就在components里注册哪个组件,
比如:app嵌套school,school嵌套student
// school组件(简写)
const school = ({
template: `
<div>
<student></student>
</div> `,
...
// 注册组件
components: {
student
}
})
app只嵌套类school,因此不用注册student
// app组件
const app = Vue.extend({
template: `
<div>
<school></school>
</div>
`,
components: {
school
}
})
2.6 VueComponent构造(这部分看视频更易理解)
1.组件的本质是一个名为VueComponent的构造函数,且不是程序员定义的,是Vue.extend生成的(调用vue.extend则会生成student, student是VueComponent构造函数)
问题:组件的本质是什么?
答:VueComponent构造函数
// 创建组件
const student = Vue.extend({
template: `
<h2>学生姓名:{{stuName}}</h2>
`,
data () {
return {
stuName: 'tom'
}
}
})
console.log(student);
// vue源码
var Sub = function VueComponent (options) {
console.log('VueComponent构造函数');
this._init(options);
};
结果证明这个函数被调用了。
- 我们只需写
<student/>
或<student></student>
,Vue解析时会帮我们创建student组件的实例对象
<!--写两个组件标签,构造函数被调用两次-->
<student></student>
<student></student>
3. 特别注意:每次调用Vue.extend,返回的都是一个全新的VueComponent
// vue源码
// Vue.extend是个函数,所以他能被调用
Vue.extend = function (extendOptions) {
...
var Sub = function VueComponent (options) {
console.log('VueComponent构造函数');
this._init(options);
};
...
return Sub
};
}
所以每调用一次Vue.extend,都会生成一个Sub(Sub是VueComponent函数)。所以每次调用Vue.extend返回的VueComponent都是现定义的,所以返回的是一个全新的VueComponent。
//创建两个组件
const student = Vue.extend({..})
const school = Vue.extend({..})
console.log(school === student);// false
- 关于this指向:
- 组件配置中:
- data函数、methods中的函数、watch中的函数、computed中的函数,它们的this均是【VueComponent实例对象】(简称vc,也可称之为组件实例对象)
- new Vue()配置中:
- data函数、methods中的函数、watch中的函数、computed中的函数,它们的this均是【Vue实例对象】(简称vm)
打印vm可以看出,vm管理着一个一个的vc
- data函数、methods中的函数、watch中的函数、computed中的函数,它们的this均是【Vue实例对象】(简称vm)
2.7 内置关系
- 一个重要的内置关系:
VueComponent.prototype._proto === Vue.prototype
- 为什么要有这个关系:让组件实例对象vc可以访问到Vue原型上的属性、方法。如果没有这个关系,Vue原型上的东西只能vm可以用。
回顾原型链的内容:
// 定义一个构造函数
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
// 程序员通过显式原型属性放东西
Demo.prototype.x = 99
// 通过隐式原型属性取东西
console.log(d.x); // 99
只有函数才有显式原型属性prototype
只要是对象,就有隐式原型属性__proto__
实例的隐式原型属性永远指向自己缔造者的原型对象
Vue的实例对象的__proto__
永远指向自己缔造者(Vue)的原型对象,也就是蓝色框的蓝色虚线
Vue是个构造函数:
<div id="root">
<!--写了这个标签才算是构建了VueComponentde的实例对象-->
<student></student>
</div>
<script>
Vue.prototype.x = 99
// student获得的是VueComponentde构造函数
const student = Vue.extend({
template: `
<div>
<h2>学生姓名:{{stuName}}</h2>
<button @click="showX">点击显示x</button>
</div>
`,
data () {
return {
stuName: 'tom'
}
},
methods: {
showX () {
console.log(this.x); // 99
}
}
})
console.log(student.prototype.__proto__ === Vue.prototype);
</script>
3. 单文件组件
单文件组件的后缀名都是.vue。可借助插件运行.vue文件
.vue文件的内容包括:
<template>
<!-- 组件结构 -->
</template>
<script>
// 组件交互相关的代码(数据、方法)
</script>
<style>
/* 组件的样式 */
</style>