文章目录
Vue组件化
什么是组件化
如果我们将一个页面中所有的处理逻辑全部放在一起,处理起来就会变得非常复杂,而且不利于后续的管理以及扩展.
但是如果我们将一个页面拆分为一个个小的功能块,每个功能块完成属于自己这部分独立的功能,那么之后整个页面的管理和维护就变得非常容易了.如下图所示:
Vue组件化思想
组件化是Vue.js中的重要思想:
- 它提供了一种抽象,让我们可以开发出一个个独立可复用的小组件来构造我们的应用
- 任何的应用都会被抽象成一颗组件树
如下图:
组件化思想的应用:
- 有了组件化的思想,在开发中就要充分的利用它
- 尽可能的将页面拆分成一个个小的, 可复用的组件
- 这样让我们的代码更加方面组织和管理,并且扩展性也更强
注册组件的基本步骤
组件的使用分成三个步骤:
- 创建组件构造器
- 注册组件
- 使用组件
注册组件步骤解析:
-
Vue.extend():
- 调用Vue.extend()创建的是一个组件构造器
- 通常在创建组件构造器时,传入template代表我们自定义组件的模板
- 该模板就是在使用到组件的地方,要显示的HTML代码
-
Vue.component():
- 调用Vue.component()是将刚才的组件构造器注册为一个组件,并且给它起一个组件的标签名称
- 所以需要传递两个参数: 1.注册组件的标签名 2.组件构造器
-
组件必须挂载在某个Vue实例下,否则不会生效
如图
全局组件 和 局部组件
当我们通过调用Vue.component()注册组件时,组件是全局的.
这意味着该组件可以在任意Vue实例下使用.
如果我们注册的组件时挂载在某个实例中,那么就是一个局部组件
<script>
// 1.创建组件构造器
const comC = Vue.extend({
template:`
<div>
<h2>我是标题</h2>
<p>我是内容...</p>
</div>`
});
// 2.注册组件(全局组件,意味着可以在多个Vue实例下使用)
// Vue.component('cmp',comC);
const app = new Vue({
el: '#app', // 用于挂载要管理的元素
components: {
// 注册局部组件
cmp: comC
}
})
</script>
父组件和子组件
子组件和父组件的基本使用
<script>
// 创建组件构造器(子组件)
const comp1 = Vue.extend({
template: `
<div>
<h2>我是子组件</h2>
<p>我的内容1.....</p>
</div>`
});
// 创建组件构造器(父组件)
const comp2 = Vue.extend({
template: `
<div>
<h2>我是父组件</h2>
<p>我的内容2.....</p>
<cmp1></cmp1>
</div>`,
components: {
cmp1: comp1
}
})
const app = new Vue({
el: '#app', // 用于挂载要管理的元素
components: {
cmp2: comp2
}
})
</script>
注册组件语法糖
Vue为了简化这个过程,提供了注册的语法糖
主要是省去了调用Vue.extend()的步骤,而是可以直接使用一个对象来代替
<script>
// 注册组件语法糖
// const cmpC = Vue.extend({
// template: `
// <div>
// <h2>标题</h2>
// <p>内容....</p>
// </div>`
// });
// 注册组件
Vue.component('cnp',{
template: `
<div>
<h2>全局组件</h2>
<p>内容....</p>
</div>`
});
const app = new Vue({
el: '#app', // 用于挂载要管理的元素
components: {
'cmp': {
template: `
<div>
<h2>局部组件</h2>
<p>内容....</p>
</div>`
}
}
})
</script>
模板的分离
Vue提供了两种方案来定义HTML模板内容:
-
使用<script type="text/x-template> 标签
-
使用标签
<body>
<div id="app">
<com-script></com-script>
</div>
<!--1.script标签模板-->
<script type="text/x-template" id="scriptId">
<div>
<h3>我是script标签模板</h3>
</div>
</script>
<!--2.template标签模板-->
<template id="templateId">
<div>
<h3>我是template标签模板</h3>
</div>
</template>
<script src="../js/vue.js" ></script>
<script>
// Vue.component('comScript',{
// template: "#scriptId"
// })
const app = new Vue({
el: '#app', // 用于挂载要管理的元素
components: {
// 'comScript': {
// template: "#scriptId"
// },
'comScript': {
template: "#templateId"
}
}
})
</script>
</body>
组件访问
组件可以访问Vue实例数据吗?
组件是一个单独功能模块的封装;Vue组件不能访问Vue实例数据,这个模块有属于自己的HTML模板,也应该有属于自己的数据data.
Vue可以通过两种方法访问组件
- $children
- $refs
点击按钮去访问第二个组件的name(通过$refs.xxx.xxxx
去访问组件中的具体属性)
<body>
<div id="app">
<conp></conp>
<conp ref="xxx"></conp>
<conp></conp>
<button @click="butClick">按钮</button>
</div>
<template id="conpId">
<div>
我是子组件
</div>
</template>
<script src="../js/vue.js" ></script>
<script>
const conp = {
template: '#conpId',
data() {
return {
name: '我是子组件name'
}
},
methods: {
showMessage() {
console.log('我是子组件方法');
}
}
}
const app = new Vue({
el: '#app', // 用于挂载要管理的元素
components: {
conp
},
methods: {
butClick() {
// $refs =>对象类型,默认为一个空对象,ref='xxx'
console.log(this.$refs.xxx.name);
}
}
})
</script>
</body>
通过点击按钮访问整个组件元素使用$children
:
组件数据的存放
组件自己的数据存放在哪里?
- 组件对象也有一个data属性
- 只是这个data属性必须是一个函数,不能为对象
- 而且这个函数返回一个对象,对象内部保存着数据
Vue.component('comPon',{
template: '#cnp',
data() {
return {
title: '组件'
}
}
})
父子组件的通信
在开发中,有一些数据需要从上层传递到下层
- 如在一个页面中,我们从服务器请求到了很多的数据
- 其中一部分数据,并非是我们整个页面的大组件来展示的,而是需要下面的子组件进行展示
- 这个时候,并不会让子组件再次发送一个网路请求,而是直接让大组件(父组件)将数据传递给小组件(子组件)
如何进行父子组件间的通信?
- 通过Props 向子组件传递数据
- 通过事件向父组件发送消息
Vue实例和子组件的通信和 父组件和子组件的通信过程是一样的
props基本使用
在组件中,使用选项props来声明需要从父级接收到的数据
props的值有两种方式:
- 方式一:字符串数组,数组中的字符串就是传递的名称
- 方式二: 对象,对象可以设置传递时的类型,也可以设置默认值等
<body>
<div id="app">
<obj :cmovies="movies" :cmessage="message"></obj>
</div>
<template id="tempId">
<div>
<ul>
<li v-for="item in cmovies">{{item}}</li>
</ul>
<h2>{{cmessage}}</h2>
</div>
</template>
<script src="../js/vue.js" ></script>
<script>
const obj = {
template: "#tempId",
// 一、数组写法
// props: ['cmovies','cmessage'],
// 二、对象写法,当需要对props进行类型等验证时,需用对象写法
props: {
// 1. 类型限制
// cmovies: Array,
// cmessage: String
// 2. 提供一些默认值
cmovies: {
type: Array,
// 类型是对象或者数组时,默认值必须是一个函数
default() {
return []
}
},
cmessage: {
type: String,
default: 'Vue defalut', // 当在#app元素下div中,如果没有上下赋值会给默认值
required: true // 当为true时,cmessage属性必填的
}
},
data() {
return {}
}
}
const app = new Vue({
el: '#app', // 用于挂载要管理的元素
data: { // 定义数据
message: 'Hello Vue',
movies: ['海贼王','进击的巨人','海尔兄弟','熊大']
},
components: {
obj
}
})
</script>
</body>
子组件访问父组件
- 访问父组件 $parent
- 访问根组件 $root
<body>
<div id="app">
<cnpp></cnpp>
</div>
<template id="tteId">
<div>
<h3>我是tteId子组件</h3>
<button @click="cnppClick">按钮</button>
</div>
</template>
<script src="../js/vue.js" ></script>
<script>
const cnpp = {
template : '#tteId',
methods: {
cnppClick() {
// 1. 访问父组件 $parent
console.log(this.$parent.message);
// 2. 访问根组件 $root
console.log(this.$root.message);
}
}
}
const app = new Vue({
el: '#app', // 用于挂载要管理的元素
data: { // 定义数据
message: 'Hello Vue'
},
components: {
cnpp
}
})
</script>
</body>
子级传向父级(自定义事件)
什么时候需要使用自定义事件呢?
- 当子组件需要向父组件传递数据时,就要用到自定义事件
- v-on不仅仅可以用于监听DOM事件,也可以用于组件键的自定义事件
自定义事件的流程
- 在子组件中,通过$emit() 来触发事件
- 在父组件中,通过v-on来监听子组件事件
<body>
<div id="app">
<!-- 第二步:监听自定义事件 -->
<cnp @item-click="cnpClick"></cnp>
</div>
<template id="temId">
<div>
<button v-for="item in categories" @click="butClick(item)">{{item.name}}</button>
</div>
</template>
<script src="../js/vue.js" ></script>
<script>
const cnp = {
template: '#temId',
data() {
return {
categories: [
{id:'aaa',name:'热门推荐'},
{id:'bbb',name:'手机数码'},
{id:'ccc',name:'家用家电'},
{id:'ddd',name:'电脑办公'},
]
}
},
methods: {
butClick(item) {
// 第一步:发射自定义事件
this.$emit('item-click',item)
}
}
}
const app = new Vue({
el: '#app', // 用于挂载要管理的元素
components: {
cnp
},
methods: {
cnpClick(item) {
console.log("子组件传父组件的数据:",item);
}
}
})
</script>
</body>