1、认识组件化
我们将一个完整的页面分成很多个组件,每个组件都用于实现页面的一个功能块,而每一个组件又可以进行细分。
组件化是Vuejs中的重要思想,它提供了一种抽象,让我们可以开发出一个个独立可复用的小组件来构造我们的应用,任何的应用都会被抽象成一颗组件树。
组件化思想的应用使我们在开发中尽可能的将页面拆分成一个个小的、可复用的组件,让我们的代码更加方便组织和管理,并且扩展性也更强。
2、注册组件的基本步骤
组件的使用分成三个步骤:
1、创建组件构造器
2、注册组件
3、使用组件
基本使用:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<!--3、使用组件-->
<my-cpn></my-cpn>
<my-cpn></my-cpn>
</div>
<script src="../js/vue.js"></script>
<script>
//1、创建组件构造器对象
const cpnC = Vue.extend({
template: `
<div>
<h2>我是标题</h2>
<p>我是内容1</p>
<p>我是内容2</p>
</div>`
})
//2、注册组件
Vue.component('my-cpn',cpnC)
const app = new Vue({
el: '#app'
})
</script>
</body>
</html>
注册组件步骤解析
1、Vue.extend():
调用Vue.extend()创建的是一个组件构造器。
通常在创建组件构造器时,传入template代表我们自定义组件的模板。该模板就是在使用到组件的地方,要显示的HTML代码。
2、Vue.component():
调用Vue.component()是将刚才的组件构造器注册为一个组件,并且给它起一个组件的标签名称。
所以需要传递两个参数:
1、注册组件的标签名。2、组件构造器。
3、组件必须挂载在某个Vue实例下,否则它不会生效。
全局组件和局部组件
上述举的代码案例是全局组件,那么什么是全局组件和局部组件呢?
全局组件在任何vue管理的容器中都可以使用,但是局部组件只有在指定被管理的容器中才能够使用。
<body>
<div id="app">
<cpn></cpn>
<cpn></cpn>
<cpn></cpn>
</div>
<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',
})
const app2 = new Vue({
el: '#app2',
//局部组件
components: {
cpn: cpnC
}
})
</script>
</body>
局部组件是直接挂载在指定vue下面。
注册组件语法糖
在上述注册组件的方式,可能会有些繁琐,Vue为了简化这个过程,提供了注册的语法糖,主要是省去了调用Vue.extend()的步骤,而是可以直接使用一个对象来替代。
components: {
cpn1: {
template: `
<div>
<h2>标题1</h2>
<p>内容1</p>
</div> `
}
}
3、父组件和子组件
在组件和组件之间存在层级关系,而其中非常重要的关系就是父子组件的关系
<script>
//1、创建第一个组件构造器
const cpnC1 = Vue.extend({
template: `
<div>
<h2>标题1</h2>
<p>内容1</p>
</div>
`
})
//1、创建第二个组件构造器
const cpnC2 = Vue.extend({
template: `
<div>
<h2>标题2</h2>
<p>内容2</p>
<cpn1></cpn1>
</div>
`,
components: {
cpn1: cpnC1
}
})
const app = new Vue({
el: '#app',
data: {
message: '你好啊',
},
components: {
cpn2: cpnC2
}
})
</script>
其中,cpnC2是cpnC1的父组件,子组件注册在父组件中。
组件不可以直接访问Vue实例中的数据
组件是一个单独功能模块的封装,这个模块有属于自己的HTML模块,也应该有属于自己的数据data。
组件对象也有一个data属性(也可以有methods等属性),只是这个data属性必须是一个函数,而且这个函数返回一个对象,对象内部保存着数据。
4、父子组件通信
子组件是不能引用父组件或者Vue实例的数据的。但是,在开发中,往往一些数据确实需要从上层传递到下层:
比如在一个页面中,我们从服务器请求到了很多数据,其中一部分数据,并非是我们整个页面的大组件来展示的,而是需要下面的子组件进行展示。这个时候,并不会让子组件再次发送一个网络请求,而是直接让父组件将数据传递给子组件。
如何进行父子组件间的通信呢?Vue官方提到:
1、通过props向子组件传递数据
2、通过事件向父组件发送消息
父级向子级传递
在组件中,使用选项props来声明需要从父级接收到的数据。
props的值有两种方式:
方式一:字符串数组,数组中的字符串就是传递时的名称。
方式二:对象,对象可以设置传递时的类型,也可以设置默认值等。
当需要对props进行类型等验证时,就需要对象写法。
验证都支持以下数据类型:
- String
- Number
- Boolean
- Array
- Object
- Date
- Function
- Symbol
子级向父级传递
当子组件需要向父组件传递数据时,就要用到自定义事件了,之前学习的v-on不仅仅可以用于监听DOM事件,也可以用于组件间的自定义事件。
自定义事件的流程:
- 在子组件中,通过$emit()来触发事件
- 在父组件中,通过v-on来监听子组件事件
父子组件的访问方式:$children
有时候我们需要父组件直接访问子组件,子组件直接访问父组件,或者是子组件访问根组件。
- 父组件访问子组件:使用$children
- 父组件访问子组件:使用$refs
- 子组件访问父组件:使用$parent
父访问子
$children使用:
<body>
<div id="app">
<cpn></cpn>
<button @click="btnClick">按钮</button>
</div>
<template id="cpn">
<div>我是子组件</div>
</template>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
message: '你好啊',
},
methods: {
btnClick() {
console.log(this.$children);
this.$children[0].showMessage();
}
},
components: {
cpn: {
template: '#cpn',
methods: {
showMessage() {
console.log('showMessage');
}
}
}
}
})
</script>
</body>
$refs使用:
<body>
<div id="app">
<cpn></cpn>
<cpn ref="aaa"></cpn>
<button @click="btnClick">按钮</button>
</div>
<template id="cpn">
<div>我是子组件</div>
</template>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
message: '你好啊',
},
methods: {
btnClick() {
console.log(this.$refs.aaa.name);
}
},
components: {
cpn: {
template: '#cpn',
data() {
return {
name: '我是子组件的name'
}
},
methods: {
showMessage() {
console.log('showMessage');
}
}
}
}
})
</script>
</body>
$refs是一个对象类型,默认是一个空的对象
子访问父
$parent使用:
<body>
<div id="app">
<cpn></cpn>
</div>
<template id="cpn">
<div>
<h2>我是cpn组件</h2>
<ccpn></ccpn>
</div>
</template>
<template id="ccpn">
<div>
<h2>我是子组件</h2>
<button @click="btnClick">按钮</button>
</div>
</template>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
message: '你好啊',
},
components: {
cpn: {
template: '#cpn',
data() {
return {
name: '我是cpn组件的name'
}
},
components: {
ccpn: {
template: '#ccpn',
methods: {
btnClick() {
console.log(this.$parent);
console.log(this.$parent.name);
}
}
}
}
},
}
})
</script>
</body>
$root使用:
<body>
<div id="app">
<cpn></cpn>
</div>
<template id="cpn">
<div>
<h2>我是cpn组件</h2>
<ccpn></ccpn>
</div>
</template>
<template id="ccpn">
<div>
<h2>我是子组件</h2>
<button @click="btnClick">按钮</button>
</div>
</template>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
message: '你好啊',
},
components: {
cpn: {
template: '#cpn',
data() {
return {
name: '我是cpn组件的name'
}
},
components: {
ccpn: {
template: '#ccpn',
methods: {
btnClick() {
console.log(this.$root);
console.log(this.$root.message);
}
}
}
}
},
}
})
</script>
</body>