定义 实现应用中局部功能代码和资源的集合 为什么要用组件化编程? 传统方式编写:依赖关系混乱,不好维护,且代码复用率不高 模块化编写:只关注解决js,复用js,简化js的编写与效率 组件方式编写:好维护、复用率更高、提高运行效率
在组件出现之前,我们开发基本都是用html、js、css,
1 组件
单文件组件
一个文件中只有1个组件
非单文件组件
一个文件中包含有n个组件
1.1 组件使用流程
1 创建组件
使用Vue.extend(options)
创建,其中options和new Vue(options)时传入的那个options几乎一样,但也有点区别:
1
不写el
。最终所有的组件都要经过一个vm的管理,由vm中的el决定服务哪个容器 2.data必须写成函数
。避免组件被复用时,数据存在引用关系,data是对象会导致,组件值改变会影响另一个组件的值
使用template可以配置组件结构。
在Vue2官网中中也明确规定,组件的data必须是一个函数
const School = Vue.extend({
name:'School', // 组件名
template:`<div>School----</div>`,
data(){
return{}
},
methods:{}
})
2 注册组件
const vm = new Vue({
el: '#root',
components:{School},
data() {
return {
}
},
})
3 使用组件
<div id="root">
<School></School>
</div>
1.2 组件细节点
1.关于组件名:
- 单个单词组成: 第一种写法(首字母小写):school 第二种写法(首字母大写):Schoo1
- 多个单词组成: 第一种写法(kebab-case而名): my-school(不建议如此) 第二种写法(CamelCase命名): Myschool (需要Vue脚手架支持)
(1).组件名尽可能回避HTML中已有的元素名称,例如: h2、H2都不行。
(2).可以使用name配置项指定组件在开发者工具中呈现的名字。
2.关于组件标签:
第一种写法: < school></ schoo1>
第二种写法: < school/> (不用使用脚手架时,< schoo1/>会导致后续组件不能渲染)
3 简写方式:
const school = Vue.extend(options) 可简写为: const school = options
1.3 关于VueComponent
1.school组件本质是一个名为VueComponent的构造函数,且不是程序员定义的,是Vue.extend生成的
2.只需要写< school/>或< school></ school>,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实例对象
]。 5.VueComponent的实例对象,可称之为: 组件实例对象。 vue的实例对象,一般都简称为vm。
2 Vue与VueComponent的关系(内置关系)
在了解Vue与组件的关系之前,我们要先了解一下原型链 原型 原型又分为显式与隐式 显式:每一个类(构造函数)都有一个显式原型 prototype(对象) 隐式:每一个实例化对象都有一个隐式原型 proto(对象)
function getObj(){
this.a = 1
this.b = 2
}
// 打印出该对象的所有属性和属性值
console.dir(getObj)
const obj = new getObj() // 创建实例
console.log('实例的原型',obj.__proto__)
console.log('构造函数原型是否等于实例的原型',obj.__proto__ === getObj.prototype)
console.dir
:打印出该对象的所有属性和属性值
实例的原型__propto等于构造函数的原型prototype
vm.__propto === obj.prototype
Vue与组件的关系
正常来说一个构造函数的实例 实例的的原型__proto__指向 = 构造函数的原型对象
通过构造函数创建一个实例,顺着实例的原型链向上查找,发现最终指向的是Object构造函数的原型对象
graph LR
A[实例] -- __proto__--> B[原型对象]
B --__proto__--> C[Object的原型对象]
function getObj(){
this.a = 1
this.b = 2
}
const d = new getObj() // 创建实例
console.log('隐式实例',d)
如果不引入Vue实例的原型链,应该如上所示,但是引入Vue后。Vue对VueCompomnent的原型队形的 __proto__指向进行了修改,指向了Vue的原型对象
3 单文件组件
使用命令好之前请把环境配置好:node、npm或yarn、vue-cli
低版本的vue可以匹配高版本的vue-cli
反过来就会失败
命令行创建一个Vue项目
vue create 项目名
创建完成根据提示运行项目yarn serve 封装组件 helloWorld.vue 在这里只有hellWorld.vue一个文件,就将组件实现了,这个组件就是一个单文件组件
<template>
<div class="hello">
<p>
For a guide and recipes on how to configure / customize this project,<br>
check out the
<a href="https://cli.vuejs.org" target="_blank" rel="noopener">vue-cli documentation</a>.
</p>
</div>
</template>
<script>
// 完整的组件注册写法,注册完成后,将组件暴露出去,方便
// import Vue from 'vue'
// const HelloWorld = Vue.extend({
// name: 'HelloWorld',
// props: {
// msg: String
// }
// })
// export default HelloWorld
// 实际开发中会省略extend的
export default {
name: 'HelloWorld', // 组件中的name值尽量都要写,防止用户随意更改组件名
props: {
msg: String
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
</style>
组件注册到App.vue文件中使用,App.vue注册到main.js文件中使用
每一个.vue
文件都相当于一个组件,最终都由main.js去new Vue,其他组件就不需要单独的去new Vue了
graph LR
A[组件] -- 注册 --> B[App.vue]
B --注册--> C[main.js]
Tips:
组件命名:School.vue 或 MySchool.vue 每一个组件都相当于一个小型的VM,组件间不会互相影响