文章目录
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,并将数据传入其中,监听到事件发生,执行方法