一、组件化的思想
如果我们将一个页面中所有的处理逻辑全部放在一起,处理起来就会变得非常复杂,而且不利于后续的管理以及扩展。但如果,我们讲一个页面拆分成一个个小的功能块,每个功能块完成属于自己这部分独立的功能,那么之后整个页面的管理和维护就变得非常容易了。我们将一个完整的页面分成很多个组件。每个组件都用于实现页面的一个功能块。而每一个组件又可以进行细分。如下面的组件图,首先是整个框是一个组件,它除了里面自己的功能还有各组件的功能,里面分为三个大组件
二、注册组件的基本步骤
步骤:创建组件构造器、注册组件、使用组件。
1.Vue.extend():
调用Vue.extend()创建的是一个组件构造器。
通常在创建组件构造器时,传入template代表我们自定义组件的模板。
该模板就是在使用到组件的地方,要显示的HTML代码。
事实上,这种写法在Vue2.x的文档中几乎已经看不到了,它会直接使用下面我们会讲到的语法糖,但是在很多资料还是会提到这种方式,而且这种方式是学习后面方式的基础。
2.Vue.component():
调用Vue.component()是将刚才的组件构造器注册为一个组件,并且给它起一个组件的标签名称。
所以需要传递两个参数:1、注册组件的标签名 2、组件构造器
3、组件必须挂载在某个Vue实例下,否则它不会生效。 const app = new Vue({el: ‘#app’,}) 就是必须再它绑定的id的盒子里使用标签
如代码
//这里直接写下面注册组件时候定下的标签名,就可以直接使用下面的模板
三、全局组件和局部组件
当我们通过调用vue,Vue.component()注册组件时,组件的注册是全局的
那么如何才能注册局部组件呢
const app = new Vue({ //再Vue实例里面,其实vue实例就是一个大组件,再它里面注册组件就是局部组件
el: '#app',
data: {
message: '你好啊'
},
components: { //使用 components 这个属性
// cpn使用组件时的标签名
cpn: cpnC // cpn是使用这个局部组件的标签名,后面的value值是 创建的组件构造对象
}
})
四、父组件和子组件
再组件一的创建组件构造对象里面注册组件二,那么组件一就是组件二的父组件,父组件里面的模板就可以使用子组件所产生的模板标签
如代码
再这里使用再父组件里面注册子组件是不行的,因为这里是vue实例,vue实例只注册了父组件,所以会找不到,要是想再这里实现,那么也要把子组件也再vue实例里面注册就可以了
五、注册组件语法糖
主要是省去了调用Vue.extend()的步骤,而是可以直接使用一个对象来代替。
1.全局组件注册的语法糖
Vue.component('cpn1', { //直接再调用vue的注册实例的方法里创建构造器
template: `
我是标题1
我是内容, 哈哈哈哈
`
})
2、注册局部组件的语法糖
const app = new Vue({ //再vue实例里
el: '#app',
data: {
message: '你好啊'
},
components: { //再注册局部组件的属性里
'cpn2': { //cpn2(标签名) 后面跟的是 创建构造对象
template: `
我是标题2
我是内容, 呵呵呵
`
}
}
})
六、模板的分离写法
使用
1.script标签, 注意:类型必须是text/x-template
七、组件数据的存放
组件是一个单独功能模块的封装:
这个模块有属于自己的HTML模板,也应该有属性自己的数据data。
组件中不能直接访问Vue实例中的data,而且即使可以访问,如果将所有的数据都放在Vue实例中,Vue实例就会变的非常臃肿。
结论:Vue组件应该有自己保存数据的地方。
组件自己的数据存放在哪里呢?
组件对象也有一个data属性(也可以有methods等属性,下面我们有用到)
只是这个data属性必须是一个函数
而且这个函数返回一个对象,对象内部保存着数据
如下面代码:
//这里是模板
{{title}}
//这里使用胡子语法,现在探究的就是模板里的胡子语法该从哪里获取值,它不能从vue实例里获取
我是内容,呵呵呵
八、组件数据的存放为什么是一个函数
1、我们先来理解下下面这段代码
//1,通过下面的代码与函数,会发现产生的obj1,obj2,obj3都是指向obj,也就是说他们创造的其实就是同一个对象,那么如果obj的值发生改变了,那么所有对象的那一个值都会发生改变
const obj = {
name: 'why',
age: 18
}
function abc() {
return obj
}
let obj1 = abc()
let obj2 = abc()
let obj3 = abc()
//2,下面这种方法产生的是3种不同的obj,他们之间互相不影响,因为返回的值是只属性收到的对象,不会因为原来的值改变的而改变,而且随着三个对象的值一样,但是return产生的是三个不同的对象,所以他们之间的改变是互不影响的
function abc() {
return {
name: 'why',
age: 18
}
}
let obj1 = abc()
let obj2 = abc()
let obj3 = abc()
所以由此可以知道,为什么data在组件中必须是一个函数呢?
首先,如果不是一个函数,Vue直接就会报错。
其次,原因是在于Vue让每个组件对象都返回一个新的对象,因为如果是同一个对象的,组件在多次使用后会相互影响。
上面就是原因
九、组件通信之父子组件间传递数据
在开发中,往往一些数据确实需要从上层传递到下层:
比如在一个页面中,我们从服务器请求到了很多的数据。
其中一部分数据,并非是我们整个页面的大组件来展示的,而是需要下面的子组件进行展示。
这个时候,并不会让子组件再次发送一个网络请求,而是直接让大组件(父组件)将数据传递给小组件(子组件)
1、父组件传递数据给子组件
如何进行父子组件间的通信呢?
通过props向子组件传递数据
如代码,下面就是一个简单的父组件传递信息到子组件并且使用
//2然后这里就是父组件data数据传到子组件的props的对象里,并且必须要属性绑定v-bind
- {{item}}
//4最后使用数据,这里就是子组建的模板,这里使用从父组件哪里传递过来的数据,这里的数据是数组
{{message}} //这里也是使用数据
2、props数据验证
除了数组之外,我们也可以使用对象,当需要对props进行类型等验证时,就需要对象写法了。
也就是说props里面的值可以进行类型验证,而且还可以设置里面的值的默认值,和必须设置必须再子组件标签内传值进来
如下面代码,再cpn组件构造器里面
const cpn = {
template: '#cpn',
// props: ['cmovies', 'cmessage'],
props: { //这里是props的第二种写法
// 1.类型限制
// cmovies: Array, //这个值给它一个类型,那么它接收的数据都只能是数据类型
// cmessage: String, //比如这个字符串类型
// 2.提供一些默认值, 以及必传值
cmessage: { //里是props的第三法写法
type: String, //这里限制类型
default: 'aaaaaaaa', //这里是默认值
required: true //这里设置必须传值进来,必须v-bind绑定
},
// 类型是对象或者数组时, 默认值必须是一个函数
cmovies: {
type: Array, //这是第四种写法,当类型是对象或者数组的时候
default() { //默认值必须是函数,并且有返回值
return []
}
}
},
data() {
return {}
},
methods: {
}
}
验证还支持哪些数据类型呢?
可以支持一个对象多个类型, 自定义验证函数
//多个类型
props :{
propsA: [ string, Number ],
propsB: { //自定义验证函数
validator ( index ){ //如果传进来的值不是这里面的三个,就不行
return ['succes',' wraning','danger'].indexof( value )!==-1
}
}
}
//自定义类型
funcition person() {
this.name = name;
this.age = age;
}
Vue.component('cpn',{
props: {
auther : person
}
})
3、子级向父级传递
当子组件需要向父组件传递数据时,就要用到自定义事件了。
我们之前学习的v-on不仅仅可以用于监听DOM事件,也可以用于组件间的自定义事件。
自定义事件的流程:
在子组件中,通过$emit()来触发事件。
在父组件中,通过v-on来监听子组件事件。
// 5、这里就绑定子组件发射出来的事件名称带有值,这里就相当于父组件接受子组件的数据,并对数据下一步处理
父子组件通信与双向绑定案例
以下案例能实现的功能是再实现input框双向绑定子组件与父组件的值
Title
props:{{number1}}
data:{{dnumber1}}
//1这里开始双向绑定,但绑定value的值为什么是dnumber1而不是number呢,其实如果是为了展现出来,number也是可以的,但是这样子多了的话会造成混乱,所以vue把这样视为报错,然后看下面的1
data:{{dnumber2}}
props:{{number2}}
props中的驼峰标识与一些小问题
//第一,再子组件里面如果有太多标签,需要再标签外面定义一个div作为根标签,否则就会报错