组件
组件:组成页面一部分的部件比如:导航条、轮播、侧边栏、底部、抽屉...
- 为什么组件化:
vue强烈推荐组件化思想:扩展HTML元素(自定义标签),封装可以【重用】的代码(可以把html+css+js封装在一起)
组件的创建/注册方式:
全局/局部组件
//全局组件
Vue.component("全局组件名",{
template:"<div css/js>内容
<局部组件名></局部组件名>
</div>", - html模板
data(){return {}},
methods:{},
...//之前的模板语法都是支持的,但是data必须写为函数时写法,vue3的语法
components:{//局部组件
"局部组件名":{
套娃
}
}
})
//以前这个new Vue({})我们可以看作是一个根组件
使用:在HTML直接写双标签,你的组件名就是标签名:<全局组件名></全局组件名>
注意:
1、起名字,如果js写驼峰,html不支持,必须替换写为横线连接符-
2、html片段,没有代码提示,没有高亮显示,但是不担心 - 以后vue单文件组件解决
3、css只能写成内联样式 - 以后vue单文件组件解决
4、template只能包含一个根节点
5、组件是一座孤岛,无法直接访问外面的组件的状态和方法 - 需要使用间接的组件通信才可以解决
6、data必须写为函数时写法,vue3的语法
7、所有的组件都放在一起的话,太乱了太丑了 - 以后vue单文件组件解决
何时使用全局或局部:
1、如果一个组件只会使用过一次推荐定义为局部
2、如果一个组件在不同的页面或者各个组件中都会使用到,推荐全局
组件通信
父传子:提升组件的复用性
比如:一个网页上任何一个页面都有一个导航条,但是显示效果可能不同,我们也可以实现一个组件,传入不同的参数进行通信
<div id="box">
<paoge-navbar></paoge-navbar>
<paoge-navbar 自定义属性="值/根组件的变量"></paoge-navbar>
//自定义属性要来进行传参
</div>
Vue.component("paogeNavbar",{
template:`<div style="background:red;">
<button v-show="bool"><</button>
<span>{{自定义属性}}</span>
<button>></button>
</div>`,
//props:["自定义属性",...],//第一种写法 数组语法糖
props:{//第2种写法 对象语法糖
自定义属性:{
type:String/Number/Boolean,
default:"默认值,不传自定义属性的时候使用的"
}
},
}
子传父:但是封装了组件后,完成开关门
<div id="box">
<navbar @自定义事件名="爸爸的函数名"></navbar>
</div>
Vue.component("navbar",{
template:`
<div style="background: red;">
<button @click="change">三</button>
导航条
</div>`
,
methods:{
change(){
this.$emit("自定义事件名",this.data);
}
}
})
//一个页面只能有一个这个【根组件】
new Vue({
el:"#box",
data:{
bool:true,
},
methods:{
爸爸的函数名(data){
console.log("父组件定义的事件,操作");
}
}
})
总结:
父传子 - 用自定义属性搭配props
子传父 - 用自定义事件搭配this.$emit("自定义事件名")
非父子关系通信bus
bus:中央事件总线,实现较为复杂的通信
创建:var bus=new Vue();
方法:2个:使用前,考虑清楚谁是发布者,谁是订阅者,订阅者需要使用生命周期mounted来触发 - dom渲染完毕后
1、订阅者:
bus.$on("自定义名称",(data)=>{
data->下方发布者传输的数据
})
2、发布者:
bus.$emit("自定义名称",传输的数据);
refs:父组件可以随意的摆弄子组件(获取/修改)
ref - 绑定在dom节点上,拿到的就是这个dom对象
ref - 绑定在组件上,拿到的就是当前组件对象
<组件 ref="自定义名称"></组件>
根组件中:
this.$refs - 得到所有添加了ref属性的组件对象
this.$refs.自定义名称 - 拿到某个子组件对象
this.$refs.自定义名称.变量 - 拿到某个子组件对象上的变量
组件注意:
1、ref和refs是固定关键字,不能修改
2、他打破了传统的通信流程,比如我们想要获取一个input的value值,再vue中可以用v-model,确实很棒,但是react中没有,则可以使用ref完成
3、尽量不要使用组件中的props去改变状态data,会导致数据流混乱(不易读) - 不推荐,也没有意义
4、如果组件中写了一个指令v-once,一次性的,状态改变,页面上的组件也不会变化,只需要打开页面渲染一次时
内置组件:
<component :is="组件名"></component>
<!-- 告诉他哪个需要显示 -->
<keep-alive></keep-alive>
<!-- 活着,就算选项卡切换,回来依然存在你输入的东西 -->
<keep-alive>
<component :is="组件名"></component>
</keep-alive>
以上包含了组建的通信,都要一个给,一个拿
面试题:Vue组件的通信有哪些方式?
1、父传子 - 用props自定义
2、子传父 - 用this.$emit("自定义事件")
3、兄弟:中间人模式
4、bus
5、refs
6、vuex - 状态管理器,最舒服,Vue由三部分组成:vue基础+vue router+vuex
slot:插槽
组件标签中默认是不允许再嵌套别的标签的,所有提供了slot扩展组件能力,提高了组件的复用性 比如:
<组件>
<template v-slot:名字>
<span>111111111</span>
<span>222222222</span>
<span>333333333</span>
<template>
<template>
<span>777777777</span>
<span>888888888</span>
<span>999999999</span>
<template>
<span slot="user">个人中心</span>
<span>111111111</span>
<span>222222222</span>
<span>333333333</span>
<span>777777777</span>
<span>888888888</span>
<span>999999999</span>
</组件>
默认是不允许再嵌套别的标签的,但是搭配上slot就可以了,以下代码教你如何搭配
Vue.component("组件",{
template:`
<div>
<slot name="user"></slot>
//用上你写的<span slot="user">个人中心</span>
<slot></slot>
//用上所有没有名字的slot
</div>
`
})