初始化导航栏
1、准备数据
[
{
name: 'all', label: '全部订单' },
{
name: 'unpay', label: '待付款' },
{
name: 'deliver', label: '待发货' },
{
name: 'receive', label: '待收货' },
{
name: 'comment', label: '待评价' },
{
name: 'complete', label: '已完成' },
{
name: 'cancel', label: '已取消' }
]
2、组件编写
tab.vue和tab-panel.vue组件准备
使用组件
1、在app.vue中引入组件
<template>
<tab v-model:activeName="activeName" @update:activeName="changeActiveName">
<tabPaanel v-for="item in rderStatus" :key="item.name" :label="item.label" :name="item.name"> </tabPaanel>
</tab>
</template>
<script setup>
import tab from './components/tab.vue'
import tabPaanel from './components/tab-paanel.vue';
import {
reactive, ref } from 'vue'
const activeName = ref('all')
const changeActiveName = (data) => {
console.log(data)
}
const rderStatus = reactive([
{
name: 'all', label: '全部订单' },
{
name: 'unpay', label: '待付款' },
{
name: 'deliver', label: '待发货' },
{
name: 'receive', label: '待收货' },
{
name: 'comment', label: '待评价' },
{
name: 'complete', label: '已完成' },
{
name: 'cancel', label: '已取消' }
])
</script>
<style scoped lang="less"></style>
遍历循环rderStatus中的数据,通过v-model实现双向绑定,当点击其他标签时,当前页面的activeName也会改变
2、编写tab.vue
import {
useVModel } from '@vueuse/core'
export default {
name: 'tab',
props: {
activeName: {
type: String,
default: 'all'
}
},
setup(props, {
emit }) {
// 接收v-model
const activeName = useVModel(props, 'activeName', emit)
const changetab=(Name)=>{
activeName.value=Name
}
provide('activeName', activeName)
return {
activeName,changetab }
},
通过使用useVModel方法,实现组件内数据与父组件数据,双向绑定,当activeName被改变时,会自动调用@update:activeName=“changeActiveName” 这个回调函数,且携带改变后的值
3、通过render()函数渲染页面,在tab.vue的setup函数后编写render()函数
render() {
//拿到tab的slot内容
const main = this.$slots.default()
// 动态面板
const dypanels = []
// 遍历获取dom节点
main.forEach(element => {
if (element.type.name === 'tabpanel') {
console.log(element)
// 加入dom节点
dypanels.push(element)
} else {
element.children.forEach(item => {
dypanels.push(item)
})
}
});
// console.log('dypanels',dypanels)
// 定义渲染结构
const nav = (
// 将数据带入到nav标签中,在jsx中,{}内写的是js语法
<nav className="nav">
{
// 将动态面板的数据全部渲染到a标签中,加上click事件 和 选中样式
dypanels.map((item,i)=>{
return <a onClick={
()=>this.changetab(item.props.name)} class={
this.activeName===item.props.name?'active':''}>{
item.props.label}</a>
})
}
</nav>
)
return <div>{
nav}</div>
}
main的结构如下图所示
完整的tab.vue
<script lang="jsx">
import {
useVModel } from '@vueuse/core'
import {
provide } from 'vue'
export default {
name: 'tab',
props: {
activeName: {
type: String,
default: 'all'
}
},
setup(props, {
emit }) {
// 接收v-model
const activeName = useVModel(props, 'activeName', emit)
const changetab=(Name)=>{
activeName.value=Name
}
provide('activeName', activeName)
return {
activeName,changetab }
},
render() {
const main = this.$slots.default()
console.log(main)
// 动态面板
const dypanels = []
// 遍历获取dom节点
main.forEach(element => {
if (element.type.name === 'tabpanel') {
console.log(element)
// 加入dom节点
dypanels.push(element)
} else {
element.children.forEach(item => {
dypanels.push(item)
})
}
});
// console.log('dypanels',dypanels)
// 定义渲染结构
const nav = (
<nav className="nav">
{
dypanels.map((item,i)=>{
return <a onClick={
()=>this.changetab(item.props.name)} class={
this.activeName===item.props.name?'active':''}>{
item.props.label}</a>
})
}
</nav>
)
return <div>{
nav}</div>
}
}
</script>
<style scoped lang="less">
.nav{
font-size: 20px;
margin-left: 20px;
.active{
color: red;
}
}
</style>
3、编写tabpanel.vue
<template>
<div class="label" v-show="name===activeName">
<slot></slot>
</div>
</template>
<script>
import {
inject } from 'vue';
export default {
name:'tabpanel',
props:{
label:{
type:String,
default:''
},
name:{
type:String,
default:''
}
},
setup(){
const activeName=inject('activeName')
return {
activeName}
}
}
</script>
<style scoped lang="less">
</style>
通过tab.vue传过来的activeName来控制tab-panel里面内容的展示
实际应用
在查看订单中,通过切换不同的label标签,用于展示不同的订单,在app。vue中切换activeName,获取对应的订单数据
eName’)
return {activeName}
}
}
通过tab.vue传过来的activeName来控制tab-panel里面内容的展示
# 实际应用
在查看订单中,通过切换不同的label标签,用于展示不同的订单,在app。vue中切换activeName,获取对应的订单数据