什么是组件化
如果我们将一个页面中所有的处理逻辑全部放在一起,处理起来就会变得非常复杂,而且不利于后续的管理以及扩展。 但如果,我们讲一个页面拆分成一个个小的功能块,每个功能块完成属于自己这部分独立的功能,那么之后整个页面的管理和维护就变得非常容易了
组件化思想
组件化是Vue.js中的重要思想
它提供了一种抽象,让我们可以开发出一个个独立可复用的小组件来构造我们的应用 任何的应用都会被抽象成一颗组件树
组件化思想的应用:
有了组件化的思想,我们在之后的开发中就要充分的利用它 尽可能的将页面拆分成一个个小的、可复用的组件 这样让我们的代码更加方便组织和管理,并且扩展性也更强
注册组件的基本步骤
组件的使用分成三个步骤:
创建组件构造器:调用Vue.extend()方法 注册组件:调用Vue.component()方法 使用组件:在Vue实例的作用范围内
我们来看看通过代码如何注册组件
<div id="app">
<!--3.使用组件-->
<my-cpn></my-cpn>
<script src="../js/vue.js"></script>
<script>
// 1.创建组件构造器对象
const cpnC = Vue.extend({
template: `
<div>
<h2>我是标题</h2>
<p>我是内容, 哈哈哈哈</p>
<p>我是内容, 呵呵呵呵</p>
</div>`
})
// 2.注册组件
Vue.component('my-cpn', cpnC)
const app = new Vue({
el: '#app',
data: {
message: '你好啊'
}
})
</script>
查看运行结果: 和直接使用一个div看起来并没有什么区别。 但是我们可以设想,如果很多地方都要显示这样的信息,我们是不是就可以直接使用 来完成呢?
注册组件步骤解析
Vue.extend():
调用Vue.extend()创建的是一个组件构造器。 通常在创建组件构造器时,传入template代表我们自定义组件的模板。 该模板就是在使用到组件的地方,要显示的HTML代码。 事实上,这种写法在Vue2.x的文档中几乎已经看不到了,它会直接使用下面我们会讲到的语法糖,但是在很多资料还是会提到这种方式,而且这种方式是学习后面方式的基础。
Vue.component():
调用Vue.component()是将刚才的组件构造器注册为一个组件,并且给它起一个组件的标签名称。 所以需要传递两个参数: 注册组件的标签名 组件构造器
组件必须挂载在某个Vue实例下,否则它不会生效。
我们来看下面我使用了三次 而第三次其实并没有生效
<div id="app">
<!-- 使用组件 -->
<my-cpn></my-cpn>
<my-cpn></my-cpn>
</div>
<my-cpn></my-cpn>
全局组件和局部组件
当我们通过调用Vue.component()注册组件时,组件的注册是全局的
这意味着该组件可以在任意Vue示例下使用。
如果我们注册的组件是挂载在某个实例中, 那么就是一个局部组件
<div id="app">
<cpn></cpn>
</div>
<script src="../js/vue.js"></script>
<script>
// 1.创建组件构造器
const cpnC = Vue.extend({
template: `
<div>
<h2>我是标题</h2>
<p>我是内容,哈哈哈哈啊</p>
</div>
`
})
const app = new Vue({
el: '#app',
data: {
message: '你好啊'
},
components: {//注册的局部组件
// cpn使用组件时的标签名
cpn: cpnC
}
})
父组件和子组件
在前面我们看到了组件树:
组件和组件之间存在层级关系 而其中一种非常重要的关系就是父子组件的关系
我们来看通过代码如何组成的这种层级关系:
div id="app">
<parent-cpn></parent-cpn>
<!--<child-cpn></child-cpn>-->
</div>
<script src="../js/vue.js"></script>
<script>
// 1.创建第一个组件构造器(子组件)
const childComponent = Vue.extend({
template: `
<div>
<h2>我是子组件</h2>
<p>我是内容, 哈哈哈哈</p>
</div>
`
})
// 2.创建第二个组件构造器(父组件)
const parentComponent = Vue.extend({
template: `
<div>
<h2>我是父组件</h2>
<p>我是内容, 呵呵呵呵</p>
<child-cpn></child-cpn>
</div>
`,
components: {
child-cpn: childComponent
}
})
// root组件
const app = new Vue({
el: '#app',
data: {
message: '你好啊'
},
components: {
parent-cpn: parentComponent
}
})
</script>
父子组件错误用法:以子标签的形式在Vue实例中使用 因为当子组件注册到父组件的components时,Vue会编译好父组件的模块 该模板的内容已经决定了父组件将要渲染的HTML(相当于父组件中已经有了子组件中的内容了) 是只能在父组件中被识别的。 类似这种用法, 是会被浏览器忽略的。
注册组件语法糖
在上面注册组件的方式,可能会有些繁琐。
Vue为了简化这个过程,提供了注册的语法糖。 主要是省去了调用Vue.extend()的步骤,而是可以直接使用一个对象来代替。
语法糖注册全局组件和局部组件:
<div id="app">
<cpn1></cpn1>
<cpn2></cpn2>
</div>
<script src="../js/vue.js"></script>
<script>
// 1.全局组件注册的语法糖
Vue.component('cpn1', {
template: `
<div>
<h2>我是标题1</h2>
<p>我是内容, 哈哈哈哈</p>
</div>
`
})
// 2.注册局部组件的语法糖
const app = new Vue({
el: '#app',
data: {
message: '你好啊'
},
components: {
'cpn2': {
template: `
<div>
<h2>我是标题2</h2>
<p>我是内容, 呵呵呵</p>
</div>
`
}
}
})
</script>
模板的分离写法
刚才,我们通过语法糖简化了Vue组件的注册过程,另外还有一个地方的写法比较麻烦,就是template模块写法。
如果我们能将其中的HTML分离出来写,然后挂载到对应的组件上,必然结构会变得非常清晰。
Vue提供了两种方案来定义HTML模块内容:
使用script标签 使用template标签
<!--1.script标签, 注意:类型必须是text/x-template-->
<script type="text/x-template" id="cpn">
<div>
<h2>我是标题</h2>
<p>我是内容,哈哈哈</p>
</div>
</script>
<!--2.template标签-->
<template id="cpn">
<div>
<h2>我是标题</h2>
<p>我是内容,呵呵呵</p>
</div>
</template>
组件数据存放
组件可以访问Vue实例数据吗?
组件是一个单独功能模块的封装:
这个模块有属于自己的HTML模板,也应该有属性自己的数据data。
组件中的数据是保存在哪里呢?顶层的Vue实例中吗?
我们先来测试一下,组件中能不能直接访问Vue实例中的data
<div id="app">
<my-cpn></my-cpn>
</div>
<template id="myCpn">
<div>数据: {{message}}</div>
</template>
<script>
let app = new Vue({
el:'#app',
data: {
message: 'Hello lazy'
},
components: {
'my-cpn': {
template: '#myCpn'
}
}
})
</script>
我们用组件里的message去访问定义在Vue实例data中的数据,并没有效果
所以组件是不能直接访问Vue实例中的data数据
即使可以访问,如果将所有的数据都放在Vue实例中,Vue实例就会变的非常臃肿
Vue组件应该有自己保存数据的地方。
组件数据的存放
组件自己的数据存放在哪里呢?
组件对象也有一个data属性(也可以有methods等属性,下面我们有用到)
只是这个data属性必须是一个函数
而且这个函数返回一个对象,对象内部保存着数据
<div id="app">
<my-cpn></my-cpn>
</div>
<template id="myCpn">
<div>数据: {{message}}</div>
</template>
<script>
let app = new Vue({
el:'#app',
components: {
'my-cpn': {
template: '#myCpn',
data() {
message: 'Hello lazy'
}
}
}
})
</script>
组件访问了自己的data数据
为什么是一个函数呢?
组件是可复用的vue实例,一个组件被创建好之后,就可能被用在各个地方 而组件不管被复用了多少次,组件中的data数据都应该是相互隔离,互不影响的 基于这一理念,组件每复用一次,data数据就应该被复制一次,之后,当某一处复用的地方组件内data数据被改变时,其他复用地方组件的data数据不受影响 组件中的data写成一个函数,数据以函数返回值形式定义,这样每复用一次组件,就会返回一份新的data,类似于给每个组件实例创建一个私有的数据空间,让各个组件实例维护各自的数据 而单纯的写成对象形式,就使得所有组件实例共用了一份data,就会造成一个变了全都会变的结果。
逼着你往前走的,不是前方梦想的微弱光芒,而是身后现实的万丈深渊。 ---------致自己