TabContronl效果图
点击不同的选项,选项变红并底下高亮,显示对应的界面
1.结构
-
父:App.vue 子:TabControl.vue
实现思路:
(子)TabControl.vue构建tabControl组件:
-
1. 从App.vue文件动态获取数据("衣服","鞋子"),不能把数据写死: -父传子通信 -父写在自己的动态绑定的属性attribute里,子在props属性里接收 -子使用v-for遍历数据展示 2. 监听点击事件,用currentIndex记录选中项的index,实现动态添加active类别、传递index到App.vue 3. flex布局
(父)App.vue使用tabControl组件、显示对应界面:
-
1. 从TabControl.vue文件引入tab-control组件,注册组件 2. 切换界面 -子传父通信 -子通过$emit,向父发送事件"btnIndex",数据index -利用监听事件"btnIndex",事件绑定methods,传递index,切换界面
2.代码细节
TabControl.vue------template主要部分
<template v-for="(item, index) in titles" :key="item">
<div class="tab-item" @click="btnClick(index)" :class="{ active: currentIndex == index}">
{{item}}
</div>
</template>
这里有两个重点
-
v-for需要绑定属性key,方便渲染
个人理解:通过监听key有无改变,只重新渲染key发生改变的元素。不要用index作为key,因为中间插入新数据可能会改变对应的内容,key应为独一无二的标识,id或者item(没有重复的情况下)都是不错的选择
-
动态添加active类别
active: currentIndex == index}active: 布尔类型,active 这个 class 存在与否将取决于是否为true。利用currentIndex运行实现动态效果
TabControl.vue------script主要部分
export default {
props:{
titles:{
type: Array,
default() {
return{}
}
}
},
data(){
return{
currentIndex: 0,
}
},
emits: ["btnIndex"],
methods:{
btnClick(index){
this.currentIndex = index
this.$emit("btnIndex", index)
}
}
}
细节:
- 子在props接收父传来的数据,在props对象里,对象声明类型和默认值,如默认值为空对象,最好不要用箭头函数,
default() { return{} }这样比较稳妥,该文章有详细的解释 - 最好在emits里声明了要传给父组件的事件名,在父组件里使用时才会有提示
全部代码
TabControl.vue
<template>
<div class="tab-control">
<template v-for="(item, index) in titles" :key="item">
<div class="tab-item" @click="btnClick(index)" :class="{ active: currentIndex == index}">
{{item}}
</div>
</template>
</div>
</template>
<script>
export default {
props:{
titles:{
type: Array,
default() {
return{}
}
}
},
data(){
return{
currentIndex: 0,
}
},
emits: ["btnIndex"],
methods:{
btnClick(index){
this.currentIndex = index
this.$emit("btnIndex", index)
}
}
}
</script>
<style scoped>
.tab-control{
display: flex;
text-align: center;
line-height: 14px;
font-size: 14px;
}
.tab-item{
flex: 1;
}
.active{
/* box-sizing: border-box; */
color: red;
border-bottom: 3px solid red;
padding-bottom: 7px;
}
</style>
App.vue
<template>
<div class="app">
<tab-control :titles="['衣服', '鞋子', '裤子']" @btnIndex="changePage">
</tab-control>
<div class="page-content" >
{{pages[currentIndex]}}
</div>
</div>
</template>
<script>
import TabControl from "./TabControl.vue"
export default {
components:{
TabControl
},
data(){
return{
pages: ["cloths", "shoes", "pants"],
currentIndex: 0
}
},
methods:{
changePage(index){
this.currentIndex = index
console.log(this.currentIndex);
}
}
}
</script>
<style scoped>
</style>
总结
- 父传子:父组件把数据放在动态绑定的attribute里,子组件在props里接收,props对象内声明类型和默认值
- 子传父:$emit发送事件和传送的数据,在父组件里监听被发送事件,被发送事件绑定对应的methods,并将数据传入其中,监听到事件发生,执行方法