定义Vue组件
- 什么是模块化:模块化是从代码的角度出发,分析项目,把项目中一些功能类似的代码,单独的抽离为一个个的模块;那么为了保证大家以相同的方式去封装模块,于是我们就创造了模块化的规范(CommonJS规范);
- 模块化的好处:方便项目的开发;和后期的维护与扩展;今后如果需要某些固定功能的模块,则直接拿来引用就行,提高了项目开发效率!
- 什么是组件化:从UI的角度出发考虑问题,把页面上有重用性的UI解构和样式,单独的抽离出来,封装为单独的组件;
- 组件化的好处:随着项目规模的发展,我们手里的组件,会越来越多,这样,我们今后一个页面中的UI,几乎都可以从手中拿现成的组件拼接出来;方便项目的开发和维护;
全局组件定义的三种方式
第一种方式:
1.先调用 Vue.extend() 得到组件的构造函数:
// 创建全局组件的第一种方式: component
const com1 = Vue.extend({
template: '<h1>这是创建的第一个全局组件</h1>' // template 属性,表示这个组件的 UI 代码解构
})
2.通过 Vue.component(‘组件的名称’, 组件的构造函数) 来注册全局组件:
// 使用 Vue.component 向全局注册一个组件
// Vue.component('组件的名称', 组件的构造函数)
Vue.component('mycom1', com1)
3.把注册好的全局组件名称,以标签形式引入到页面中即可:
<!--如何引入一个全局的Vue组件呢?直接把组件的名称,以标签的形式,放到页面上就好了!-->
<mycom1></mycom1>
第二种方式:
1.直接使用 Vue.component(‘组件名称’, { 组件模板对象 })
const com2Obj = {
// 1. template 属性中,不能单独放一段文本,必须用标签包裹起来;
// 2. 如果在 template 属性中,想要放多个元素了,那么,在这些元素外,必须有唯一的一个根元素进行包裹;
template: '<div><h2>这是直接使用 Vue.component 创建出来的组件</h2><h3>哈哈</h3></div>'
}
// 定义全局的组件
// Vue.component 的第二个参数,既接收 一个 组件的构造函数, 同时,也接受 一个对象
Vue.component('mycom2', com2Obj)
第三种方式:
1.先使用 template 标签定义一个模板的代码解构:
<!-- 定义一个 template 标签元素 -->
<!-- 使用 Vue 提供的 template 标签,可以定义组件的UI模板解构 -->
<template id="tmpl">
<div>
<h3>哈哈,这是在外界定义的组件UI解构</h3>
<h3>我是来捣乱的</h3>
</div>
</template>
2.使用 Vue.component 注册组件:
// 这是定义的全局组件
Vue.component('mycom3', {
template: '#tmpl'
})
组件中展示数据和响应事件
Vue.component('mycom', {
template: '<h3 @click="show">这是自定义的全局组件:{{ msg }}</h3>',
data: function () { // 在 组件中,可以有自己的私有数据,但是,组件的 data 必
须是一个 function,并且内部 return 一个 数据对象
return {
msg: '哈哈哈'
}
},
methods: { // 尝试定义组件的私有方法
show() {
console.log('出发了组件的私有show方法!')
}
}
})
为什么组件中的data属性必须定义为一个方法并返回一个对象?
如果返回的不是一个对象,那么做计数器案例时所有的组件都会增加
官方解释:
组件会被用来创建多个实例,如果data是个纯粹的对象,那么所以实例将会引用同一个数据对象。所以每个组件都返回了一个新的初始变量,这样组件间不会互相干扰。
父组件向子组件传值
父组件向子组件传递普通数据
传递数据使用v-bind(:), 传递的数据需要使用props注册才能使用
1.把要传递给子组件的数据,作为 自定义属性,通过 v-bind: 绑定到子组件身上:
<com1 :msg123="parentMsg"></com1>
2.在子组件中,不能直接使用父组件传递过来的数据,需要先使用props 数组来接收一下:
props: ['msg123']
3.注意:在接收父组件传递过来的 props的时候,接收的名称,一定要和父组件传递过来的自定义属性,名称保持一致!
父组件向子组件传递方法
1.把要传递给子组件的方法,作为 自定义属性,通过 v-on: 绑定到子组件身上:
<com1 @func1="show"></com1>
2.调用父组件传来的方法
components: {
'com1': {
template: `<div>
<!-- 当点击子组件的 按钮时候, 调用一下 父组件传递过来的 func 方法 -->
<input type="button" value="这是子组件的按钮" @click="btnClick" />
</div>`,
data() { // 子组件的数据
return {
sonMsg: '这是子组件中的数据'
}
},
methods: {
btnClick() {
// 调用一下 父组件传递过来的 func 方法
// 子组件向父组件传值,本质上,还是调用了父组件传递过来的方法,只不过,子组件在调用的时候,把 数据 当作参数,传给这个方法了;
this.$emit('func1', this.sonMsg)
}
}
}
}
总结:
传递数据使用v-bind(:), 传递的数据需要使用props注册才能使用
传递方法使用v-on(@),传递的方法需要使用$emit来唤醒触发方法
无论是传递数据还是方法,都是需要使用v-bind或者v-on 赋值一个变量供子组件调用,然后变量指向父组件中的属性或者方法
在Vue组件中data和props的区别
- data 在组件中,要被定义成function并返回一个对象
- props在组件中,要被定义成数组,其中,数组的值都是字符串名,表示父组件传递过来的数据;
- props的数据,不要直接拿来修改,如果想要修改,必须在 data 上重新定义一个 属性,然后把属性的值 从 this.props 拿过来;
data 上的数据,都是组件自己私有的, data 上的数据,都是可读可写的
props 数据,都是外界传递过来的数据,props中的数据只能读取,不能重新写入