Vue3 Tabs 动态组件

效果

 

 A.vue

<template>
  <div class="com">
    你说不会在爱情里犯错

  </div>
</template>
<script lang="ts" setup>

</script>


<style lang="less" scoped>
.com {
  height: 300px;
  border: 2px solid #CCC;
  font-size: 20px;
  display: flex;
  justify-content: center;
  align-items: center;

}
</style>

B

<template>
  <div class="com">
    也说过会永远的爱我

  </div>
</template>

<script lang="ts" setup>

</script>

<style lang="less" scoped>
  .com{
    height: 300px;
    border:2px solid #CCC;
    font-size: 20px;
    display: flex;
    justify-content: center;
    align-items: center;
    
  }
</style>

C

<template>
  <div class="com">
    才发现只剩下虚伪的承诺
  </div>
</template>

<script lang="ts" setup>

</script>

<style lang="less" scoped>
  .com{
    height: 300px;
    border:2px solid #CCC;
    font-size: 20px;
    display: flex;
    justify-content: center;
    align-items: center;
    
  }
</style>

App

<template>
  <div style="display: flex">
    <div :class="[active === index?'active':'']" class="tabs" v-for="(item,index) in data"
         :key="item.name"
         @click="switchCom(item,index)">
      {{ item.name }}
    </div>

  </div>
  <component :is="comId"></component>

</template>

<style scoped>
#app, html, body {

  height: 100%;
}

* {
  padding: 0;
  margin: 0;
}

.tabs {
  border: 1px solid #CCC;
  padding: 5px 10px;
  margin: 10px;
  cursor: pointer;
}

.active {
  background: skyblue;
}

</style>

<script setup lang="ts">

import AVue from "./components/A.vue";
import BVue from "./components/B.vue";
import CVue from "./components/C.vue";
import {reactive, ref} from "vue";

const data = reactive([
  {
    name: "A组件",
    com: AVue
  },
  {
    name: "B组件",
    com: BVue
  },
  {
    name: "C组件",
    com: CVue
  }

])
const comId = ref(AVue)
const active = ref(0)

const switchCom = (item: any, index: number) => {
  comId.value = item.com
  console.log( comId.value)
  active.value = index
}

</script>

这里控制台会报错

runtime-core.esm-bundler.js:40 [Vue warn]: Vue received a Component which was made a reactive object. This can lead to unnecessary performance overhead, and should be avoided by marking the component with `markRaw` or using `shallowRef` instead of `ref`. 
Component that was made reactive:  {__hmrId: '65097ce7', __scopeId: 'data-v-65097ce7', __file: 'H:/develop/project/web/learn/vite-demo/src/components/A.vue', render: ƒ} 
  at <App>

不过没关系 我们可以按照建议使用 markRaw 和 shallowRef 来避免报错 来正确应用这些组件

 

 最后代码

<template>
  <div style="display: flex">
    <div :class="[active === index?'active':'']" class="tabs" v-for="(item,index) in data"
         :key="item.name"
         @click="switchCom(item,index)">
      {{ item.name }}
    </div>

  </div>
  <component :is="comId"></component>

</template>

<style scoped>
#app, html, body {

  height: 100%;
}

* {
  padding: 0;
  margin: 0;
}

.tabs {
  border: 1px solid #CCC;
  padding: 5px 10px;
  margin: 10px;
  cursor: pointer;
}

.active {
  background: skyblue;
}

</style>

<script setup lang="ts">

import AVue from "./components/A.vue";
import BVue from "./components/B.vue";
import CVue from "./components/C.vue";
import {markRaw, reactive, ref, shallowRef} from "vue";

const data = reactive([
  {
    name: "A组件",
    com: markRaw(AVue)
  },
  {
    name: "B组件",
    com: markRaw(BVue)
  },
  {
    name: "C组件",
    com: markRaw(CVue)
  }

])
const comId = shallowRef(AVue)
const active = ref(0)

const switchCom = (item: any, index: number) => {
  comId.value = item.com
  console.log(comId.value)
  active.value = index
}

</script>

还有一种比较类似vue2的写法。先引入组件再使用字符串就行啦

<template>
  <div style="display: flex">
    <div :class="[active === index?'active':'']" class="tabs" v-for="(item,index) in data"
         :key="item.name"
         @click="switchCom(item,index)">
      {{ item.name }}
    </div>

  </div>
  <component :is="comId"></component>

</template>

<style scoped>
#app, html, body {

  height: 100%;
}

* {
  padding: 0;
  margin: 0;
}

.tabs {
  border: 1px solid #CCC;
  padding: 5px 10px;
  margin: 10px;
  cursor: pointer;
}

.active {
  background: skyblue;
}

</style>

<script setup lang="ts">


import {markRaw, reactive, ref, shallowRef} from "vue";

const data = reactive([
  {
    name: "A组件",
    com: 'AVue'
  },
  {
    name: "B组件",
    com: 'BVue'
  },
  {
    name: "C组件",
    com: 'CVue'
  }

])
const comId = shallowRef("AVue")
const active = ref(0)

const switchCom = (item: any, index: number) => {
  comId.value = item.com
  console.log(comId.value)
  active.value = index
}

</script>
<script lang="ts">
import AVue from "./components/A.vue";
import BVue from "./components/B.vue";
import CVue from "./components/C.vue";
export default {
  components: {
    AVue,
    BVue,
    CVue
  }
};
</script>

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
vue3动态组件实现tabs标签页的步骤如下: 1. 创建tabs组件,包含tabs和tab两个子组件tabs组件负责显示当前选中的tab和切换tab,tab组件则负责显示tab的内容。 2. 在tabs组件中定义一个数组,用于存储所有的tab信息。每个tab信息包括tab的名称和对应的组件。 3. 在tabs组件中使用v-for指令循环渲染所有的tab,同时使用动态组件来渲染对应的组件。 4. 在tab组件中定义一个插槽,用于显示tab的内容。 5. 在tabs组件中定义一个方法,用于切换tab。该方法接受一个index参数,表示要切换到的tab的索引。该方法根据索引更新当前选中的tab,并将对应的组件渲染出来。 6. 在tabs组件中使用v-on指令绑定点击事件,调用切换tab的方法。 7. 在父组件中引入tabs组件,并传入所有的tab信息。 8. 使用tabs组件来显示tab标签页。 示例代码如下: // Tabs.vue <template> <div class="tabs"> <div class="tab-list"> <div class="tab" v-for="(tab, index) in tabs" :key="tab.name" :class="{ active: isActiveTab(index) }" @click="selectTab(index)" >{{ tab.name }}</div> </div> <div class="tab-content"> <component :is="tabs[currentTab].component"></component> </div> </div> </template> <script> export default { name: "Tabs", props: ["tabs"], data() { return { currentTab: 0, }; }, methods: { isActiveTab(index) { return this.currentTab === index; }, selectTab(index) { this.currentTab = index; }, }, }; </script> // Tab.vue <template> <div class="tab-content"> <slot></slot> </div> </template> // App.vue <template> <div class="app"> <Tabs :tabs="tabs"></Tabs> </div> </template> <script> import Tabs from "./Tabs.vue"; import Tab from "./Tab.vue"; import Tab1 from "./Tab1.vue"; import Tab2 from "./Tab2.vue"; export default { name: "App", components: { Tabs, Tab, Tab1, Tab2, }, data() { return { tabs: [ { name: "Tab 1", component: "Tab1" }, { name: "Tab 2", component: "Tab2" }, ], }; }, }; </script>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

安果移不动

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值