【Vue.js】017-Vue组件:基本使用、组件注册、父子组件、父子组件通信
目录
一、组件化的实现和使用步骤
1、什么是组件化
2、Vue的组件化思想
3、组件的基本步骤
步骤:
图示:
二、组件化的基本使用过程
1、代码演示
2、运行结果
三、全局组件和局部组件
1、全局组件
代码演示:
运行结果:
2、局部组件
代码演示:
运行结果(只能用在特定实例之内了):
四、父组件和子组件
1、简单使用
代码演示:
运行结果:
五、注册组件语法糖
1、概述
2、演示
六、组件模板的分离写法
1、概述
2、两种写法
代码演示:
运行结果:
七、组件数据的存放
1、概述
2、代码演示
3、运行结果
八、父子组件的通信
1、概述
2、props基本用法
概述:
props的值有两种方式:
图解:
代码演示:
运行结果:
3、props数据验证
概述:
自定义类型:
演示:
4、子级向父级传递
概述:
什么时候需要自定义事件呢?
自定义事件的流程:
图解:
自定义事件代码演示:
运行结果:
九、父子组件的访问方式
1、概述
2、$children
概述:
图解(截图大多来自老师的教学PPT):
代码演示:
运行结果:
3、$refs
$children的缺陷:
$refs的使用:
图解:
4、$parent
概述:
图解:
十、非父子组件通信
1、概述
一、组件化的实现和使用步骤
1、什么是组件化
人的大脑处理问题的能力是有限的,当人们面对复杂问题的时候,很难一次性解决,但人的大脑也天生具有将问题拆解的能力,化繁为简,逐个解决,这种复杂问题拆解成多个小问题在程序中的表现就是组件化。在程序开发中,如果我们将一个复杂页面的所有逻辑都放在一起,势必导致逻辑混乱,难以阅读,不利于后续的管理和扩展。但如果我们将页面拆解成一个个小的功能块,每个功能块完成自己独立的功能,且这些功能块能够被应用到其他页面(可复用),那么程序的开发就会非常易于管理和扩展。
类似此图:
2、Vue的组件化思想
3、组件的基本步骤
步骤:
创建组件构造器——注册组件——使用组件;
图示:
二、组件化的基本使用过程
1、代码演示
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
<div id="app">
<!-- 3、使用组件 -->
<my-cpn></my-cpn>
</div>
<script src="../../js/vue.js"></script>
<script>
//1、创建组件构造器对象
const cpnC = Vue.extend({
template:`
<div>
<h2>我是二级标题</h2>
<p>我是P标签</p>
</div>
`
});
//2、注册组件,传入组件名和组件构造器对象
Vue.component('my-cpn',cpnC);
const app = new Vue({
el:'#app',
data:{
}
})
</script>
</body>
</html>
2、运行结果
三、全局组件和局部组件
1、全局组件
在上面《组件化的基本使用过程》中我们所使用的就是全局组件,全局组件意味着可以在多个vue的实例下使用;
代码演示:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
<div id="app">
<!-- 3、使用组件 -->
<my-cpn></my-cpn>
</div>
<div id="app2">
<my-cpn></my-cpn>
</div>
<script src="../../js/vue.js"></script>
<script>
//1、创建组件构造器对象
const cpnC = Vue.extend({
template:`
<div>
<h2>我是二级标题</h2>
<p>我是P标签</p>
</div>
`
});
//2、注册组件,传入组件名和组件构造器对象
Vue.component('my-cpn',cpnC);
const app = new Vue({
el:'#app',
data:{
}
})
const app2 = new Vue({
el:'#app2',
data:{
}
})
</script>
</body>
</html>
运行结果:
2、局部组件
那么怎么样才能注册局部组件呢?
答案是:在特定的vue实例下注册;
代码演示:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
<div id="app">
<!-- 3、使用组件 -->
<my-cpn></my-cpn>
</div>
<div id="app2">
<my-cpn></my-cpn>
</div>
<script src="../../js/vue.js"></script>
<script>
//1、创建组件构造器对象
const cpnC = Vue.extend({
template:`
<div>
<h2>我是二级标题</h2>
<p>我是P标签</p>
</div>
`
});
//2、注册组件,传入组件名和组件构造器对象
// Vue.component('my-cpn',cpnC);
const app = new Vue({
el:'#app',
data:{
},
components:{
// 注意这里的my-cpn要用引号引起
'my-cpn': cpnC
}
})
const app2 = new Vue({
el:'#app2',
data:{
}
})
</script>
</body>
</html>
运行结果(只能用在特定实例之内了):
四、父组件和子组件
1、简单使用
代码演示:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
<div id="app">
<!-- 5、使用 -->
<cpn2></cpn2>
</div>
<script src="../../js/vue.js"></script>
<script>
// 1、创建第一个组件的内容构造器
const cpnC1 = Vue.extend({
template:`
<div>
<h1>我是标题1</h1>
<p>我是内容1</p>
</div>
`
})
// 2、创建第二个组件的内容构造器
const cpnC2 = Vue.extend({
template:`
<div>
<h1>我是标题2</h1>
<p>我是内容2</p>
<!-- 注意:这里的cpn1必须放在div之内 -->
<cpn1></cpn1>
</div>
`,
// 3、在组件的内容构造器中注册组件
components:{
'cpn1': cpnC1
}
})
const app = new Vue({
el:'#app',
data:{
},
// 4、局部注册
components:{
'cpn2': cpnC2
}
})
</script>
</body>
</html>
运行结果:
五、注册组件语法糖
1、概述
上面我们演示的基本使用注册组件的方式,在新版本的vue中已经不常见了,现在都使用语法糖进行注册;
2、演示
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
<div id="app">
<!-- 3、使用组件 -->
<my-cpn></my-cpn>
</div>
<script src="../../js/vue.js"></script>
<script>
// 之前的写法
//1、创建组件构造器对象
// const cpnC = Vue.extend({
// template:`
// <div>
// <h2>我是二级标题</h2>
// <p>我是P标签</p>
// </div>
// `
// });
//2、注册组件,传入组件名和组件构造器对象
// Vue.component('my-cpn',cpnC);
// 语法糖写法:等于是二者的合并
// 这是全局注册的写法
Vue.component('my-cpn',{
template:`
<div>
<h2>我是二级标题</h2>
<p>我是P标签</p>
</div>
`
})
const app = new Vue({
el:'#app',
data:{
},
components:{
// 这是局部组件的语法糖写法
'my-cpn': {
template:`
<div>
<h2>我是二级标题</h2>
<p>我是P标签</p>
</div>
`
}
}
})
</script>
</body>
</html>
六、组件模板的分离写法
1、概述
我们之前在注册组件的时候,将组件的模板html代码写在vue实例中,如果html代码比较复杂的话会因为文件内容过多而导致混乱;
2、两种写法
代码演示:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
<div id="app">
<my-cpn></my-cpn>
</div>
<!-- 分离写法方式一 -->
<!-- <script type="text/x-temolate" id="myCpn">
<div>
<h2>我是二级标题</h2>
<p>我是P标签</p>
</div>
</script> -->
<!-- 分离写法方式二 -->
<template id="myCpn">
<div>
<h2>我是二级标题</h2>
<p>我是P标签</p>
</div>
</template>
<script src="../../js/vue.js"></script>
<script>
Vue.component('my-cpn',{
template: '#myCpn'
});
const app = new Vue({
el:'#app',
data:{
}
})
</script>
</body>
</html>
运行结果:
七、组件数据的存放
1、概述
组件对象也有一个data属性,只是这个data属性必须是一个函数,而且这个函数返回一个对象,对象内部保存着数据;
之所以data属性必须是一个函数,是因为当返回的是同一个对象的时,组件多次使用的话会相互影响;
2、代码演示
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
<div id="app">
{
{message}}
<my-cpn></my-cpn>
</div>
<template id="myCpn">
<div>
<h1>{
{title}}</h1>
<p>{
{content}}</p>
</div>
</template>
<script src="../../js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
message: '你好!'
},
components:{
'my-cpn': {
template: '#myCpn',
data(){
return{
title: "我是标题",
content: "我是p标签"
}
}
}
}
})
</script>
</body>
</html>
3、运行结果
八、父子组件的通信
1、概述
在开发中,往往一些数据确实需要从上层传递到下层:比如在一个页面中,我们从服务器请求到了很多的数据。其中一部分数据,并非是我们整个页面的大组件来展示的,而是需要下面的子组件进行展示。这个时候,并不会让子组件再次发送一个网络请求,而是直接让大组件(父组件)将数据传递给小组件(子组件);
如何进行父子组件间的通信呢?Vue官方提到通过props向子组件传递数据,通过事件向父组件发送消息;
真实的开发中,Vue实例和子组件的通信和父组件和子组件的通信过程是一样的;
2、props基本用法
概述:
在组件中,使用选项props来声明需要从父级接收到的数据;
props的值有两种方式:
方式一:字符串数组,数组中的字符串就是传递时的名称;
方式二:对象,对象可以设置传递时的类型,也可以设置默认值等;
图解:
代码演示:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
<div id="app">
{
{message}}
<my-cpn :title="title" :content="content"></my-cpn>
</div>
<template id="myCpn">
<div>
<h1>{
{title}}</h1>
<p>{
{content}}</p>
</div>
</template>
<script src="../../js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
message: '你好!',
title: "我是标题啊",
content: "我是内容啊"
},
components:{
'my-cpn': {
template: '#myCpn',
props:['title','content']
}
}
})
</script>
</body>
</html>
运行结果:
3、props数据验证
概述:
在前面,我们的props选项是使用一个数组;
我们说过,除了数组之外,我们也可以使用对象,当需要对props进行类型等验证时,就需要对象写法了。
验证都支持哪些数据类型呢?
String、Number、Boolean、Array、Object、Date、Function、Symbol;
当我们有自定义构造函数时,验证也支持自定义的类型;
自定义类型:
演示:
4、子级向父级传递
概述:
props用于父组件向子组件传递数据,还有一种比较常见的是子组件传递数据或事件到父组件中;
我们应该如何处理呢?这个时候,我们需要使用自定义事件来完成;
什么时候需要自定义事件呢?
当子组件需要向父组件传递数据时,就要用到自定义事件了;
我们之前学习的v-on不仅仅可以用于监听DOM事件,也可以用于组件间的自定义事件;
自定义事件的流程:
在子组件中,通过$emit()来触发事件;
在父组件中,通过v-on来监听子组件事件;
图解:
自定义事件代码演示:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
<div id="app">
<!-- 注意:这里的方法不可带括号 -->
<child-cpn @increment='changeTotal' @decrement='changeTotal'></child-cpn>
当前值:{
{total}}
</div>
<template id="myCpn">
<div>
<button @click="increment">+1</button>
<button @click="decrement">-1</button>
</div>
</template>
<script src="../../js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data:{
total: 0
},
methods:{
changeTotal(counter){
this.total = counter;
}
},
components:{
'child-cpn':{
template: '#myCpn',
data(){
return{
counter: 0
}
},
methods:{
increment(){
this.counter++;
this.$emit('increment',this.counter);
},
decrement(){
this.counter--;
this.$emit('decrement',this.counter);
}
}
}
}
})
</script>
</body>
</html>
运行结果:
九、父子组件的访问方式
1、概述
有时候我们需要父组件直接访问子组件,子组件直接访问父组件,或者是子组件访问跟组件;
父组件访问子组件:使用$children或$refs;
子组件访问父组件:使用$parent;
2、$children
概述:
我们先来看下$children的访问:
this.$children是一个数组类型,它包含所有子组件对象;
我们这里通过一个遍历,取出所有子组件的message状态,不常用!
图解(截图大多来自老师的教学PPT):
代码演示:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
<div id="app">
<parent-cpn></parent-cpn>
</div>
<template id="p1">
<div>
<child-cpn1></child-cpn1>
<child-cpn2></child-cpn2>
<button @click="showChildCpnMessage">显示所有子组件信息</button>
</div>
</template>
<template id="c1">
<h1>我是子组件1</h1>
</template>
<template id="c2">
<h1>我是子组件2</h1>
</template>
<script src="../../js/vue.js"></script>
<script>
const app = new Vue({
el: "#app",
components:{
'parent-cpn':{
template: '#p1',
components:{
'child-cpn1': {
template: '#c1'
},
'child-cpn2': {
template: '#c2'
}
},
methods:{
showChildCpnMessage(){
for(let i=0;i<this.$children.length;i++){
// 通过下标拿取
console.log(this.$children[i]);
}
}
}
},
}
})
</script>
</body>
</html>
运行结果:
3、$refs
$children的缺陷:
通过$children访问子组件时,是一个数组类型,访问其中的子组件必须通过索引值;
但是当子组件过多,我们需要拿到其中一个时,往往不能确定它的索引值,甚至还可能会发生变化;
有时候,我们想明确获取其中一个特定的组件,这个时候就可以使用$refs;
$refs的使用:
$refs和ref指令通常是一起使用的:
首先,我们通过ref给某一个子组件绑定一个特定的ID;
其次,通过this.$refs.ID就可以访问到该组件了;
图解:
4、$parent
概述:
如果我们想在子组件中直接访问父组件,可以通过$parent;
注意事项:
尽管在Vue开发中,我们允许通过$parent来访问父组件,但是在真实开发中尽量不要这样做;
子组件应该尽量避免直接访问父组件的数据,因为这样耦合度太高了;
如果我们将子组件放在另外一个组件之内,很可能该父组件没有对应的属性,往往会引起问题;
另外,更不要做的是通过$parent直接修改父组件的状态,那么父组件中的状态将变得飘忽不定,很不利于我的调试和维护;
图解:
十、非父子组件通信
1、概述
刚才我们讨论的都是父子组件间的通信,那如果是非父子关系呢?
非父子组件关系包括多个层级的组件,也包括兄弟组件的关系;
在Vue1.x的时候,可以通过$dispatch和$broadcast完成:
$dispatch用于向上级派发事件;
$broadcast用于向下级广播事件;
但是在Vue2.x都被取消了:
在Vue2.x中,有一种方案是通过中央事件总线,也就是一个中介来完成;
但是这种方案和直接使用Vuex的状态管理方案还是逊色很多;
并且Vuex提供了更多好用的功能,所以这里我们暂且不讨论这种方案,后续我们专门学习Vuex的状态管理;
还没有评论,来说两句吧...