Vue全家桶之Vue组件化开发
Posted 生命是有光的
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Vue全家桶之Vue组件化开发相关的知识,希望对你有一定的参考价值。
✍、目录脑图
🔥Vue🔥
🔥Vue全家桶 | 地址 |
---|---|
🔥Vue全家桶之Vue基础指令(一) | https://blog.csdn.net/Augenstern_QXL/article/details/120117044 |
🔥Vue全家桶之Vue组件化开发(二) | https://blog.csdn.net/Augenstern_QXL/article/details/120117322 |
🔥Vue全家桶之VueCLI 脚手架V2→V4版本(三) | https://blog.csdn.net/Augenstern_QXL/article/details/120117453 |
- 参考视频讲解: CoderWhy老师的Vuejs讲解
1、组件化开发
我们将一个完整的页面分成很多个组件,每个组件都用于实现页面的一个功能块,而每一个组件又可以进行细分
1.1、组件的使用
步骤:
- 创建组件构造器: 调用
Vue.extend()
方法创建组件构造器 - 注册组件:调用
Vue.component()
方法注册组件 - 使用组件:在 Vue 实例的作用范围内使用组件
<div id="app">
<!--3.使用组件-->
<my-cpn></my-cpn>
<my-cpn></my-cpn>
<my-cpn></my-cpn>
<my-cpn></my-cpn>
<div>
<div>
<my-cpn></my-cpn>
</div>
</div>
</div>
<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.注册组件
// 参数1:字符串格式,表示组件的注册名称
// 参数2:需要被全局注册的那个组件
Vue.component('my-cpn', cpnC)
const app = new Vue({
el: '#app',
data: {
message: '你好啊'
}
})
</script>
1.2、步骤解析
-
Vue.extend():
- 调用
Vue.extend()
创建的是一个组件构造器 - 通常在创建组件构造器时,传入
template
代表我们自定义组件的模板 - 该模板就是在使用到组件的地方,要显示的html代码
- 事实上,这种写法在Vue2.x的文档中几乎已经看不到了,它会直接使用下面我们会讲到的语法糖,但是在很多资料还是会提到这种方式,而且这种方式是学习后面方式的基础。
- 调用
-
Vue.component():
- 调用
Vue.component()
是将刚才的组件构造器注册为一个组件,并且给它起一个组件的标签名称 - 所以需要传递两个参数:1、注册组件的标签名。 2、组件构造器
- 调用
-
组件必须挂载在某个Vue实例下,否则它不会生效
我们来看下面我使用了三次
<my-cpn></my-cpn>
,而第三次其实并没有生效
1.3、全局组件和局部组件
当我们调用Vue.component()
注册组件时,组件的注册是全局的
-
这意味着该组件可以在任意Vue示例下使用
-
但是如果我们注册的组件是挂载在某个实例中,那么就是一个局部组件
<div id="app2">
<cpn></cpn>
</div>
<script src="../js/vue.js"></script>
<script>
// 1.创建组件构造器
const cpnC = Vue.extend({
template: `
<div>
<h2>我是标题</h2>
<p>我是内容,哈哈哈哈啊</p>
</div>
`
})
// 2.注册组件(全局组件, 意味着可以在多个Vue的实例下面使用)
// Vue.component('cpn', cpnC)
// 疑问: 怎么注册的组件才是局部组件了?
// 答:将组件构造器放在实例当中
const app = new Vue({
el: '#app',
data: {
message: '你好啊'
},
components: {
// 将组件构造器放在实例当中
// cpn使用组件时的标签名
cpn: cpnC
}
})
const app2 = new Vue({
el: '#app2'
})
</script>
通过Vue.component()方法注册的组件是全局组件,通过 components 注册的是私有子组件
1.4、父组件和子组件
组件与组件之间存在层级关系,其中一种最重要的关系就是父子组件
<div id="app">
<cpn2></cpn2>
<!--<cpn1></cpn1>-->
</div>
<script src="../js/vue.js"></script>
<script>
// 1.创建第一个组件构造器(子组件)
const cpnC1 = Vue.extend({
template: `
<div>
<h2>我是标题1</h2>
<p>我是内容, 哈哈哈哈</p>
</div>
`
})
// 2.创建第二个组件构造器(父组件)
const cpnC2 = Vue.extend({
template: `
<div>
<h2>我是标题2</h2>
<p>我是内容, 呵呵呵呵</p>
<cpn1></cpn1>
</div>
`,
components: {
// 在父组件中注册子组件,这样就可以在父组件里面使用子组件
// 例如上面的<cpn1></cpn1>
cpn1: cpnC1
}
})
// root组件
const app = new Vue({
el: '#app',
data: {
message: '你好啊'
},
components: {
// cpn1子组件在cpn2父组件中注册,父组件cpn2在Vue实例里面注册
cpn2: cpnC2
}
})
</script>
1.4.1、父子组件的错误用法
<div id="app">
<cpn2></cpn2>
<!--父子组件的错误用法:以子组件的形式在 Vue 实例中使用-->
<!--<cpn1></cpn1>-->
</div>
<script src="../js/vue.js"></script>
<script>
// 1.创建第一个组件构造器(子组件)
const cpnC1 = Vue.extend({
template: `
<div>
<h2>我是标题1</h2>
<p>我是内容, 哈哈哈哈</p>
</div>
`
})
// 2.创建第二个组件构造器(父组件)
const cpnC2 = Vue.extend({
template: `
<div>
<h2>我是标题2</h2>
<p>我是内容, 呵呵呵呵</p>
<cpn1></cpn1>
</div>
`,
components: {
// 在父组件中注册子组件,这样就可以在父组件里面使用子组件
// 例如上面的<cpn1></cpn1>
cpn1: cpnC1
}
})
// root组件
const app = new Vue({
el: '#app',
data: {
message: '你好啊'
},
components: {
// cpn1子组件在cpn2父组件中注册,父组件cpn2在Vue实例里面注册
cpn2: cpnC2
}
})
</script>
父子组件的错误用法: 以子组件的形式在 Vue 实例中使用
- 因为当子组件注册到父组件的 components 时,Vue 会编译好父组件的模块
- 该模板的内容已经决定了父组件将要渲染的 HTML(相当于父组件中已经有了子组件的内容了)
<cpn1></cpn1>
是只能在父组件中被识别的- 类似这种用法,
<cpn1></cpn1>
是会被浏览器忽略的。
1.5、注册组件语法糖🔥
- Vue 为了简化这个过程,提供了注册的语法糖
- 主要是省去了调用
Vue.extend()
的步骤,而是可以直接使用一个对象来代替
语法糖注册全局组件和局部组件语法糖:看图片左边
<div id="app">
<cpn1></cpn1>
<cpn2></cpn2>
</div>
<script src="../js/vue.js"></script>
<script>
// 1.全局组件注册的语法糖
// 1.创建组件构造器
// const cpn1 = Vue.extend()
// 2.注册组件
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>
1.6、模板的分离写法
通过语法糖简化了 Vue 组件的注册过程,另外还有一个地方的写法比较麻烦,就是 template
模块写法
- 如果我们能将其中的HTML分离出来写,然后挂载到对应的组件上,必然结构会变得非常清晰
- Vue 提供了两种方案来定义HTML模板内容
- 使用 < script > 标签
- 使用 < template > 标签
1.6.1、使用 script 标签
<div id="app">
<cpn></cpn>
<cpn></cpn>
<cpn></cpn>
</div>
<!--1.script标签, 注意:类型必须是text/x-template-->
<script type="text/x-template" id="cpn">
<div>
<h2>我是标题</h2>
<p>我是内容,哈哈哈</p>
</div>
</script>
<script src="../js/vue.js"></script>
<script>
// 1.注册一个全局组件
Vue.component('cpn', {
template: '#cpn'
})
const app = new Vue({
el: '#app',
data: {
message: '你好啊'
}
})
</script>
1.6.2、使用template标签🔥
<div id="app">
<cpn></cpn>
<cpn></cpn>
<cpn></cpn>
</div>
<!--2.template标签-->
<template id="cpn">
<div>
<h2>我是标题</h2>
<p>我是内容,呵呵呵</p>
</div>
</template>
<script src="../js/vue.js"></script>
<script>
// 1.注册一个全局组件
Vue.component('cpn', {
template: '#cpn'
})
const app = new Vue({
el: '#app',
data: {
message: '你好啊'
}
})
</script>
1.7、组件数据存放
问题:组件可以访问Vue实例数据吗?我们来测试一下
结论:组件不能直接访问Vue实例中的 data
组件是一个单独功能模块的封装:
- 这个模块有属于自己的 HTML 模板,也应该有属于自己的数据 data
组件自己的数据存放在哪呢?
-
组件对象也有一个 data 属性(也可以有 methods 属性)
-
只是这个 data 属性必须是一个函数
-
而且这个函数返回一个对象,对象内部保存着数据
<div id="app">
<cpn></cpn>
<cpn></cpn>
<cpn></cpn>
</div>
<!--2.template标签-->
<template id="cpn">
<div>
<h2>{{title}}</h2>
<p>我是内容,呵呵呵</p>
</div>
</template>
<script src="../js/vue.js"></script>
<script>
// 1.注册一个全局组件
Vue.component('cpn', {
template: '#cpn',
data() {
return {
title: 'abc'
}
}
})
const app = new Vue({
el: '#app',
data: {
message: '你好啊',
// title: '我是标题'
}
})
</script>
为什么 data 在组件中必须是一个函数呢?
- 首先,如果不算是一个函数,Vue 直接就会报错
- 其次,原因是在于 Vue 让每个组件对象都返回一个新的对象,因为如果是同一个对象,组件在多次使用后会相互影响
1.8、父子组件通信🔥
在上一个小节中,我们提到了子组件是不能引用父组件或者Vue实例的数据的
但是,在开发中,往往一些数据确实需要从上层传递到下层
- 比如在一个页面中,我们从服务器请求到了很多的数据
- 其中的一部分数据,并非是我们整个页面的大组件来展示的,而是需要下面的子组件进行展示
- 这个时候,并不会让子组件再次发送一个网络请求,而是直接让大组件(父组件) 将数据传递给小组件(子组件)
如何进行父子组件间的通信呢?
- 通过
props
向子组件传递数据 - 通过事件向父组件发送消息
1.9、props 基本用法
在组件中,使用选项 props
来声明需要从父级接收到的数据(properties)
props
的值有两种方式:
- 方式一:字符串数组,数组中的字符串就是传递时的名称
- 方式二:对象,对象可以设置传递时的类型,也可以设置默认值等。
1.9.1、传数组
<div id="app">
<!-- 4.使用组件(v-bind动态绑定) -->
<cpn :cmessage="message" :cmovies="movies"></cpn>
</div>
<!-- 2.组件构造器的模板分离写法 -->
<template id="cpn">
<div>
<h1>{{cmovies}}}</h1>
<h1>{{cmessage}}</h1>
</div>
</template>
<script src="../js/vue.js"></script>
<script>
// 1.创建组件构造器(子组件)
const cpn = {
template: '#cpn',
props: ['cmovies', 'cmessage'] //父传子,props
}
// 3.注册组件(将子组件在父组件里面注册)
const app = new Vue({
el: '#app',
data: {
message: '你好啊',
movies: ['海王', '海贼王', '海尔兄弟']
},
components: {
//对象字面量增强写法的属性增强写法
cpn
}
})
</script>
注意:我们在使用组件时,需要用v-bind
动态绑定数据。
1.9.2、传对象
- 在前面,我们的
props
选项是使用一个数组 - 除了数组之外,我们也可以使用对象,当需要对
props
进行类型等验证时,就需要对象写法了
验证支持的数据类型有:
- String
- Number
- Boolean
- Array
- Object
- Date
- Function
- Symbol
①类型限制
我们可以在 props 里面限制父组件给子组件传递的数据类型
<!--父组件模板-->
<div id="app">
<cpn :cmessage="message" :cmovies="movies"></cpn>
</div>
<!--子组件模板-->
<template id="cpn">
<div>
<h1>{{cmovies}}}</h1>
<h1>{{cmessage}}</h1>
</div>
</template>
<script src="../js/vue.js"></script>
<script>
// 父传子: props
const cpn = {
template: '#cpn',
props: {
// 1.类型限制
cmovies: Array, // 限制父组件传的是数组类型
cmessage: String, // 限制父组件传的是字符串类型
}
}
// root组件,我们当作父组件
const app = new Vue({
el: '#app',
data: {
message: '你好啊',
movies: ['海王', '海贼王', '海尔兄弟']
},
components: {
//对象字面量增强写法的属性增强写法
cpn
}
})
</script>
②默认值和必传值
type
: 限制的类型default
: 如果没有传值,给一个默认值- 注意:类型是对象或者数组时, 默认值必须是一个函数
required
: 必须的,即意味着这个值是必须要传递的,不传就报错
<div id="app">
<!--在这里传值-->
<cpn :cmessage="message" :cmovies="movies"></cpn>
</div>
<template id="cpn">
<div>
<h1>{{cmovies}}}</h1>
<h1>{{cmessage}}</h1>
</div>
</template>
<script src="../js/vue.js"></script>
<script>
// 父传子: props
const cpn = {
template: '#cpn',
// props: ['cmovies', 'cmessage'],
props: {
// 2.提供一些默认值, 以及必传值
cmessage: {
type: String, // 类型限制为 String
default: 'aaaaaaaa', // 如果没有传值,则给一个默认值
required: true // required 必须的,即意味着这个值是必须要传递的,不传就报错
},
// 类型是对象或者数组时, 默认值必须是一个函数
cmovies: {
type: Array,
default() {
return []
}
}
},
// root组件,我们当作父组件
const app = new Vue({
el: '#app',
data: {
message: '你好啊',
movies: ['海王', '海贼王', '海尔兄弟']
},
components: {
//对象字面量增强写法的属性增强写法
cpn
}
})
</script>
③自定义类型
以上是关于Vue全家桶之Vue组件化开发的主要内容,如果未能解决你的问题,请参考以下文章