深入理解vue的组件
- 一,vue组件
- 1,什么是vue组件
- 2,单文件组件和非单文件组件
- 3,非单组件的基本使用
- 4,vue组件命名规范
- 4.1,一个单词组成
- 4.2,多个单词组成
- 5,组件与组件间的嵌套
- 6,VueComponent组件
- 7,Vue和VueComponent的关系
- 7.1,Vue的原型对象
- 7.2,VueComponent的原型对象
- 8,单文件组件
- 8.1,单文件组件的实现
一,vue组件
1,什么是vue组件
下图摘自官网,其底层主要是利用封装的思想,将一个大的组件拆分成多个小组件,并且在一个组件中一定会有一个vm的root根组件。组件和组件之间可以嵌套,组件就是实现应用中局部功能代码和资源的集合。代码主要有一些css,html,js等组成;资源主要由MP3,MP4,zip压缩包等文件组成。这样就可以实现代码复用,简化项目编码,提高开发和运行效率。
2,单文件组件和非单文件组件
二者区别
非单文件组件:顾名思义就是不是单文件组件,表示一个文件中包含有n个单文件组件。类似于一个大文件还没有拆分成多个小文件,全部聚集在一起,这样子的代码不容易维护,耦合性高,并且复用性低。
单文件组件:就是说一个组件中只包含一个文件。利用封装的思想,将组件从一个全部挤在一起的大型组件抽取出来,拆分成多个小组件,实现代码复用性高,更加的容易维护。
3,非单组件的基本使用
在创建组件时,和之前最原始的创建组件方式稍有不同,如果不是root根组件,其内部不需要el关键字,由于最终这个组件都是被vm的根节点所管理,因此其内部不需要el关键字,并且通过Vue.extend来创建非根组件,其内部的data元素只能用函数式,不能用对象式。其代码实现如下
<body>
<!-- 一个容器,可以用于接收vue实力传来的数据,然后展示 -->
<div id="root">
<!-- 3,编写组件标签 -->
<school></school>
<student></student>
</div>
<script type="text/javascript" >
Vue.config.productionTip = false //阻止vue启动时提示生产提示
const school = Vue.extend({ //1,创建school组件
template:`
<div>
<h1>学校名称是:{{schoolName}}</h1>
<h1>学校地址是:{{address}}</h1>
</div>
`,
data(){ //数据只能以函数式返回,不能以对象式
return {
schoolName:'北京大学',
address:'北京'
}
}
})
const student = Vue.extend({ //1,创建student组件
template:`
<div>
<h1>学生姓名是:{{studentName}}</h1>
<h1>学生年龄是:{{age}}</h1>
</div>
`,
data(){ //数据只能以函数式返回,不能以对象式
return {
studentName:'zhs',
age:18
}
}
})
//2,注册组件,局部注册
new Vue({
el:'#root',
components:{ //用于注册组件
school,
student
}
})
</script>
</body>
总结来说就分三步,第一步就是创建组件,第二步就是注册组件,第三步就是编写组件标签到对应的父组件中。
如果组件需要变成全局组件,那么其第二步的注册组件的方式需要改成如下,这样这个book就变成了全局组件,在所有的vm中都可以使用。
Vue.component('book',book);
4,vue组件命名规范
4.1,一个单词组成
在官方文档中,如果是一个单词组成,那么可以直接使用这个单词作为组件名,也可以将这个单词的首字母大写之后再作为组件名。
Components:{
school:'school; //方式一
School:'school'; //方式二
}
4.2,多个单词组成
如果组件名是由多个单词组成的,那么可以全部让字母小写,单词与单词之间用一个 - 连接,也可以让多个单词直接使用大写字母拼接在一起(需要使用脚手架)。
Components:{
`my-school`:'school;
MySchool:'school'
}
并且在命名组件时,尽可能回避html中已有的元素名称,如h1,H1等都不行。并且在注册组件时,也可以简写将这个Vue.extend({}) 直接写成 {},如下。
const s = {...}
虽然说这里并没有显示的调用这个 Vue.extend,但是底层源码是会将这个补上的。
5,组件与组件间的嵌套
如上面的school组件,是一个root根组件下面的子组件,现在又想在school组件中再注册一个组件,形成一个嵌套组件,那么其代码实现如下。这里暂时还没有用到脚手架,因此在定义这个组件时,这个幼儿园组件要在这个定义在这个学校的前面,然后需要将子组件注册到这个父组件中,要和谁嵌套就将谁注册哪个组件中。
//定义一个幼儿园组件,实现和学校的嵌套,这里使用简洁式,省去Vue.extend
const kindergarten = {
template:`
<div>
<h1>学校名称是:{{schoolName}}</h1>
<h1>学校地址是:{{address}}</h1>
</div>
`,
data(){
return {
schoolName:'幼儿园',
address:'深圳南山区'
}
}
}
//1,创建组件
const school = Vue.extend({
template:`
<div>
<h1>学校名称是:{{schoolName}}</h1>
<h1>学校地址是:{{address}}</h1>
<kindergarten></kindergarten>
</div>
`,
data(){
return {
schoolName:'北京大学',
address:'北京'
}
},
components:{
kindergarten,kindergarten
}
})
6,VueComponent组件
上面的这个school的组件的本质,其就是一个名为Component的构造函数,由Vue.extend所生成。即在写school这个标签时,vue解析时就会创建这个school的组件的实例对象,即执行如下语句
new VueComponent(options)
在每次调用Vue.extend的时候,返回的都是一个全新的组件对象。其实这个用java理解也很简单,就是new出来的东西不会是同一个东西。如下,其实这两个东西并不相等
const a1 = new A();
const a2 = new A();
而且通过vue的源码也可以发现,每次这个sub对象都是一个全新的对象,因此也可以得知每次返回的都是一个全新的组件对象。
Vue.extend = function (extendOptions) {
var Sub = function VueComponent(options) {
this._init(options);
};
return Sub;
}
VueComponent的实例对象,也可以简称为vc,也可以称为组件实例对象。并且在这个vue的实例对象vm中,管理着一个个vc对象。
7,Vue和VueComponent的关系
7.1,Vue的原型对象
在引入这个vue.js之后,那么这个Vue组件的对象就有了,并且一定会有一个属性名为prototype,这个值就是对应的原型对象 ,那么这个vue原型对象上面的所有的这个函数,都可以被实例对象直接使用了。
而这个直接引入js所生成的vue对象,这个对象中有一个显示属性prototype,而直接通过new关键字构造出来的实例对象也一定会有一个隐式的__property__
属性,那么这个实例对象也会通过这个属性直接指向这个Vue的原型对象。
由于这个实例的隐式属性,永远指向自己的缔造者的对象。这个原型对象也是一个对象,那么肯定也会指向自己的缔造者的对象,因此可知这个vue的原型对象的这个隐式属性 __property__
,指向的就是自己的制造者对象Object。
7.2,VueComponent的原型对象
这个VueComponent和这个Vue的底层逻辑是一样的,VueComponent这个组件的原型对象一定会有一个显示属性prototype,该值一定是指向他的缔造者对象;这个VueComponent的实例对象也一定会有一个隐式属性 __property__
,该值指向的肯定也是他的缔造者对象,即VueComponent的原型对象。
但是这个VueComponent的原型对象和vue的原型对象不一样,vue的原型对象是直接指向Object对象,但是这个VueComponent的原型对象实例加了一层,是将这个VueComponent的原型对象的隐式属性指向Vue的原型对象,(21:57),
通过上图可知,VueComponent这个组件就是想让这个Vue的原型对象做一个兜底,首先去VueComponent的原型对象上找东西,没有的话再去VueComponent的原型对象上找东西,没有的话再去Vue的原型对象上找东西,没有的话再交给Object的原型对象。
这样做的好处就是:让组件实例对象(vc)也可以访问到Vue原型上的属性和方法。
VueComponent.prototype.__proto__ === Vue.prototype
而这个组件实例对象可以近似的认为就是一个小的vm,就是一个vue的实例对象,不同点就是这个vc不能用这个el属性,并且他的data只能写函数式,不能用对象式。
8,单文件组件
上面说了这么多都是在聊多文件组件,接下来主要理解一下什么时单文件组件。在此之前,需要先安装一个插件,这个推荐使用 vetur 这个插件。在安装完插件之后,新建一个.vue的文件,然后其结构主要如下,分别是由组件的结构,组件交互相关的代码(数据,方法等等),组件的样式等组成。在安装了这个插件之后,直接< + 回车就可以出现以下代码。
<template>
<div>
<!-- 组件的结构 -->
</div>
</template>
<script>
export default {
//组件交互相关的代码
}
</script>
<style>
/* 组件的样式 */
</style>
8.1,单文件组件的实现
那么接下来就根据这个多文件中的school和Student的这两组件,用这个单文件实现一下,主要会定义一些Student.vue,School.vue,App.vue,main.js,index.js,其步骤如下:
1,School.vue
这里主要编写一些关于学校的样式,数据结构个数据交互
<template>
<div>
<h1>学校姓名是:{{name}}</h1>
<h1>学校地址是:{{address}}</h1>
</div>
</template>
<script>
export default {
name:'School',
data(){
return{
name:'',
age:''
}
}
}
</script>
<style>
</style>
2,Student.vue
<template>
<div>
<h1>学生姓名是:{{name}}</h1>
<h1>学生年龄是:{{age}}</h1>
</div>
</template>
<script>
export default {
name:'Student',
data(){
return{
name:'',
age:''
}
}
}
</script>
<style>
</style>
3,App.vue
这个组件主要是作为一个汇总组件,将其他的所有的子组件汇总到该组件中。
<template>
<div>
<!-- 引入组件 -->
<School></School>
<Student></Student>
</div>
</template>
<script>
//引入组件
import School from './School.vue'
import Student from './School.vue'
export default {
name:'App',
components:{
School,
Student
}
}
</script>
<style>
</style>
4,main.js
import App from './App'
new Vue({
el:'#root',
template:`<App></App>`,
components:{
App
}
})
5,index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Vue的单文件组件学习</title>
</head>
<body>
<!-- 根组件 -->
<div id="root"></div>
<!-- 先引入vue.js -->
<script type="text/javascript" src="../js/vue.js"></script>
<!-- 再引入main.js -->
<script type="text/javascript" src="./main.js"></script>
</body>
</html>
这样就就完全的通过单文件代替多文件的编写了,当然这里只是一个初步的示例,具体的还得安装脚手架来跑通整个流程
<title>Vue的单文件组件学习</title>
```
这样就就完全的通过单文件代替多文件的编写了,当然这里只是一个初步的示例,具体的还得安装脚手架来跑通整个流程