vue3之全局组件、局部组件、递归组件、动态组件

vue3之全局组件、局部组件、递归组合

vue3之全局组件

Card.vue 组件

<template>
  <div class="card">
    <div class="card-header">
      <div>主标题</div>
      <div>副标题</div>
    </div>
    <div class="card-content" v-if="content">{{ content }}</div>
  </div>
</template>

<script setup lang="ts">
import { ref } from 'vue'

type Prosp = {
  mainTitle?: String
  subTitle?: String
  content?: String
}
defineProps<Prosp>()
// 设置默认值的
// withDefaults(defineProps<Prosp>(), {
//   content: '我是内容',
// })
</script>
<style lang="scss" scoped>
$border: #ccc;
.card {
  border: 1px solid $border;
  &-hover {
    box-shadow: 0 0 10px $border;
  }
  &-header {
    display: flex;
    justify-content: space-between;
    padding: 10px;
    border-bottom: 1px solid $border;
  }
  &-content {
    padding: 10px;
  }
}
</style>

main.ts 挂载全局组件

import { createApp } from 'vue'
import App from './App.vue'

// 引入重置样式
import "./assets/css/reset.css"
// 引入全局组件
import Card from './components/card/Card.vue'

createApp(App).component('Card',Card).mount('#app')

使用组件

<template>
  <div class="main">
    <div class="main-items" v-for="item in 10" :key="item">
      <Card :content="`我是${item}个内容`"></Card>
    </div>
  </div>
</template>

<script setup lang="ts"></script>
<style lang="scss" scoped>
.main {
  flex: 1;
  margin: 14px;
  border: 1px solid #ccc;
  overflow: auto;
}
</style>
  • 效果:
    在这里插入图片描述

vue3之 局部组件

Test.vue

<template>
  <div>我是test {{ test }}</div>
</template>

<script setup lang="ts">
type Props = {
  test: String
}

withDefaults(defineProps<Props>(), {
  test: '我是测试的哦',
})
</script>
<style lang="scss" scoped></style>

使用组件

<template>
  <div class="main">
    <Test />
  </div>
</template>

<script setup lang="ts">
import Test from './childCom/Test.vue'
</script>
<style lang="scss" scoped>
.main {
  flex: 1;
  margin: 14px;
  border: 1px solid #ccc;
  overflow: auto;
}
</style>
  • 效果
    在这里插入图片描述

递归组件

  • menu.vue
<template>
  <div class="menu">
    menu
    <Tree :treeData="treeData" @on-click="TreeClick"></Tree>
  </div>
</template>

<script setup lang="ts">
import Tree from './tree/Tree.vue'
import { reactive } from 'vue'
type TreeList = {
  name: String
  icon?: ''
  children?: TreeList[] | []
}
const treeData = reactive<TreeList[]>([
  {
    name: 'no-1',
    children: [
      {
        name: 'no-1-1',
        children: [
          {
            name: 'no-1-1-1',
          },
        ],
      },
    ],
  },
  {
    name: 'no-2',
    children: [
      {
        name: 'no-2-1',
      },
    ],
  },
  {
    name: 'no-3',
  },
])

const TreeClick = (item: TreeList) => {
  console.log('父item', item)
}
</script>
<style lang="scss" scoped>
.menu {
  width: 200px;
  height: 100%;
  border: 1px solid #ccc;
}
</style>
  • tree.vue
<template>
  <!-- style="margin-left: 10px" 控制子组件的 层次显示 -->
  <div class="tree" style="margin-left: 10px">
    <div @click.stop="clickItem(item)" v-for="(item, idx) in treeData" :key="idx">
      {{ item.name }}
      <TreeItem @on-click="clickItem" v-if="item?.children?.length" :treeData="item.children"></TreeItem>
    </div>
  </div>
</template>

<script setup lang="ts">
import TreeItem from './Tree.vue' // 递归 当前组件
type TreeList = {
  name: String
  icon?: ''
  children?: TreeList[] | []
}
type Props = {
  treeData?: TreeList[]
}
defineProps<Props>()
const emit = defineEmits(['on-click'])
const clickItem = (item: TreeList[]) => {
  emit('on-click', item)
}
</script>
<script lang="ts">
export default {
  name: 'TreeItem',
}
</script>

<style lang="scss" scoped>
.tree {
}
</style>
  • 效果
    在这里插入图片描述

动态组件

  • 动态组件
    • :is是 控制渲染那个组件
  • 动态组件实现一个tab栏的切换
<template>
  <div class="main">
    <div class="tab">
      <div :class="['tab-item', currentTab.curName == item.curName ? 'tab-active' : '']" @click="tabChange(item.curName)" v-for="item in tabData" :key="item.name">{{ item.name }} -- {{ item.Com }}</div>
    </div>
    <component :is="currentTab.curName"></component>
  </div>
</template>

<script setup lang="ts">
import A from './childCom/A.vue'
import B from './childCom/B.vue'
import C from './childCom/C.vue'
import { reactive, ref, markRaw } from 'vue'

type Tabs = {
  name: String
  curName: any
  Com: String
}
type Com = Pick<Tabs, 'curName'>
// markRaw(C) 跳过 代理 组件
const tabData = reactive<Tabs[]>([
  {
    name: '我是组件A',
    curName: markRaw(A),
    Com: 'A',
  },
  {
    name: '我是组件B',
    curName: markRaw(B),
    Com: 'B',
  },
  {
    name: '我是组件C',
    curName: markRaw(C),
    Com: 'C',
  },
])
let currentTab = reactive<Com>({
  curName: tabData[0].curName,
})
const tabChange = (curName: Pick<Tabs, 'curName'>) => {
  // console.log('curName', curName)
  currentTab.curName = curName
}
</script>
<style lang="scss" scoped>
.main {
  flex: 1;
  margin: 14px;
  border: 1px solid #ccc;
  overflow: auto;
  .tab {
    display: flex;
    &-item {
      width: 33%;
      height: 30px;
      line-height: 30px;
      border: 1px solid #ccc;
      text-align: center;
    }
    &-active {
      color: red;
    }
  }
}
</style>
  • 效果
    在这里插入图片描述
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值