1.组件化
模块化:就是将系统功能分离成独立的功能部分的写法,一般值得是单个的某一种东西,例如js、css
组件化:就是针对的是页面的整个完整的功能模块划分,组件是一个html、css、js、image等外链资源,这些部分组成的一个聚合体。
优点:代码复用,独立性强
组件应该拥有的特性**:**可组合,可复用,可测试,可维护
2.组件
在vue中,我们通过Vue.extend;来创建vue的子类,这个东西其实就是组件,也就是说Vue实例和组件的实例有差别但是差别不是很大,以为毕竟一个是父类,一个是子类,一般的应用,会拥有一个根实例,在根实例里面都是一个一个的组件,因为组件嵌套到实例或者父组件里的,也就是说,组件可以相互嵌套,而且,所有的组件最外层必须有一个根实例,所以组件分为:全局组件和局部组件
全局组件在任意的实例、父级组件中都能使用,局部组件只能在创建自己的父级组件或者实例中使用
2-1.全局组件
<div id="app">
<!--调用组件-->
<hello></hello>
</div>
//1.创建组件
const Hello = Vue.extend({
template:`<h1>hello world</h1>`})
//2.全局注册组件
Vue.component("hello",Hello)
new Vue({
el:"#app"
})
可以将创建组件于组成组件集成到一起
Vue.component("hello",{
template:`<h1>hello world<h1>`
})
new Vue({
el:"#app"
})
2-2:局部组件
<div id="app">
<!--调用组件-->
<hellp></hello>
</div>
//1.创建组件
const Hello = Vue.extend({
template:`<h1>hello world</h1>`
})
new Vue({
el:"#app",
components:{//2.局部组件注册
hello:Hello
}
})
可以将创建组件于组成组件集成到一起
new vue({
el:"#app",
components:{
hello:{//在compontent里面声明局部组件
template:"<div>hello world</div>"
}
}
})
3.组件的模板结构
在body里面创建template模板标签在组件指定template,必须只能用id作为标记,模板内容外层必须要有根元素
<div id="app">
<!--调用组件-->
<my-header></my-header>
</div>
<!--定义组件的模板结构-->
<template id="my-header">
<div>
<div>我是header!!!</div>
</div>
</template>
Vue.component("my-header",{
template:"#my-header" //定义模板id名为my-header
})
new Vue({
el:"#app"
})
4.组件的嵌套
4-1:全局嵌套
<div id="app">
<Father></Father>
</div>
<template id="father>
<div>
<h3>这是父组件</h3>
<hr>
<Son></Son>
</div>
</template>
<template id="son">
<div>
<h3>这是子组件</h3>
</div>
</template>
Vue.component("Father",{
template:"#father"
})
Vue.conpoment("Son",{
template:"#son"
})
new Vue({
el:"#app"
})
4-2:局部嵌套
<div id="app">
<father></father>
</div>
new Vue({
el:"#app",
components:{ //定义局部组件
father:{ //定义了父组件
template:"<div>这是father组件哦...<son></son></div>",
components:{
son:{ //定义了子组件 (子组件只能在父组件的模板中进行调用!)
template:"<div>这是son组件哦...</div>"
}
}
},
}
})
5.组件中的父子通信
父组件给子组件传递数据的时候,子组件需要利用props的属性来确定自己的预期数据,如果中间有-(p-msg,需要驼峰的形式在接收),如果子组件没有通过props属性接收传递过来的数据,则数据会以自定义属性的方式,放在子组件最外层的根元素上面
为什么组件中的data必须是一个函数的返回对象的形式?
目的是:让每一个实例可以维护一份被返回对象的独立的拷贝(每个组件使用到的数据地址不一样的)
或者是:
内部必须要返回一个对象的写法,这样就可以保证每个组件用到的数据对象都是唯一的
也可以这样说:
组件之间的作用是相互独立的,组件的数据默认只能组件的模板里面使用
<div id="app">
<father></father>
</div>
<template id="father">
<div>
<p>这是父组件!!--->{{pMsg}}</p>
<son :p-msg="pMsg"></son>
</div>
</template>
Vue.component("father",{
template:"#father",
data () {
return {
pMsg:"hello is father"
}
},
components:{
son:{
template:"<div>这是son子组件...{{pMsg}}</div>"
props:["pMsg"] // 接收父组件传递过来的属性
}
}
})
let vm = new Vue({
el:"#app",
data:{
msg:"hello world"
}
})
6.组件中的子父通信
每一个组件或者实例都会有自定义事件,和触发事件的能力,父组件给子组件绑定一个自定义事件,这个事件的处理程序却是父组件的一个方法,<son @change=“父组件的函数”>,当子组件触发这个事件的时候,相当于组件的方法被执行了,(this.$emit(自定义事件,参数))
<div id="app">
<father></father>
</div>
<template id="father">
<div>
<p>我是父组件</p>
<p>这是子组件要和我说的话 ===> {{pMsg}}</p>
<!--3.在调用子组件的时候,需要给其自身绑定一个自定义事件 change-->
<son @change="changeMsg"></son>
</div>
</template>
<template id="son">
<div>
<p>我是子组件 {{msg}}</p>
<!--5.点击按钮的时候就可以通过change去执行了-->
<p><button @click="say">我要对父组件说的话</button></p>
</div>
</template>
Vue.component("father",{
template:"#father",
data () {
return {
pMsg:"" //1.需要在父组件内部声明一条数据
}
},
methods:{
changeMsg(msg){ //2.写一个更改自身数据的方法
this.pMsg = msg
}
}
})
Vue.component("son",{
template:"#son",
props:["change"],//4.子组件需要通过props接受父组件传递来的函数 <son :change="changeMsg"></son>
data () {
return {
msg:"完成子父之间的通信"
}
},
methods:{
say(){
// //需要触发其自身绑定的change方法 <son @change="changeMsg"></son>
this.$emit("change",this.msg)
}
}
})
new Vue({
el:"#app"
})
7.组件间不仅可以通过 r o o t 、 root、 root、parent、$children来获取对应关系的组件,父组件还可以主动的通过ref子组件做标记,也可以给dom做标记,也会形成ref链,也可以交互
<div id="app">
<aaa></aaa>
</div>
<template id="aaa">
<div>
<button ref="btn" @click="get">我是get按钮</button>
<bbb ref="bb"></bbb>
</div>
</template>
<template id="bbb">
<div>
<input type="text" v-model="msg">
</div>
</template>
Vue.component("aaa",{
template:"#aaa",
methods:{
get(){
// this.$children[0].msg = "get" //可以通过关系链(viewModel)去实现
console.log(this.$refs)
this.$refs.bb.msg = "get" //通过ref链给组件做标记
}
}
})
Vue.component("bbb",{
template:"#bbb",
data () {
return {
msg:"hello world"
}
}
})
new Vue({
el:"#app"
})
8.在兄弟组件之间的通信,可以采用关系链和ref链去使用,解决兄弟之间的通信问题
<div id="app">
<brother></brother>
<younger ref="littel"></younger>
</div>
<template id="brother">
<div>
<p>我是哥哥组件</p>
<button @click="hitLittel">弟弟,你好!</button>
</div>
</template>
<template id="younger">
<div>
<p>我是弟弟组件</p>
<p v-if="crying">哥哥,你好!</p>
</div>
</template>
Vue.component("brother",{
template:"#brother",
methods:{
hitLittel(){
//this.$parent.$children[1].crying = true //通过关系链
this.$parent.$refs.littel.crying = true //通过关系链 + ref链
}
}
})
Vue.component("younger",{
template:"#younger",
data(){
return {
crying:false
}
}
})
new Vue({
el:"#app"
})
9.使用event bus事件总线,也可以实现兄弟组件之间的通信
<div id="app">
<brother></brother>
<younger></younger>
</div>
<template id="brother">
<div>
<p>我是哥哥组件</p>
<button @click="hitLittel">弟弟,你好!</button>
</div>
</template>
<template id="younger">
<div>
<p>我是弟弟组件</p>
<p v-if="crying">哥哥,你好!</p>
</div>
</template>
//1.创建一个公共的vue实例
var angel = new Vue()
Vue.component("brother",{
template:"#brother",
methods:{
hitLittel(){
//3.触发事件hit
angel.$emit("hit")
}
})
Vue.component("younger",{
template:"#younger",
data(){
return {
crying:false
}
},
methods:{
changeCrying(){
this.crying = true
}
},
mounted(){ //生命周期钩子函数
//2.绑定好事件
angel.$on("hit",this.changeCrying)
}
})
new Vue({
el:"#app"
})