全局组件

<template>
  <div class="card">
     <div class="card-header">
         <div>标题</div>
         <div>副标题</div>
     </div>
     <div v-if='content' class="card-content">
         {{ content }}
     </div>
  </div>
</template>
 
<script setup lang="ts">
type Props = {
    content:string
}
defineProps<Props>()
</script>
 
<style scoped lang='less'>
@border:#ccc;
.card{
    width: 300px;
    border: 1px solid @border;
    border-radius: 3px;
    &:hover{
        box-shadow:0 0 10px @border;
    }
 
    &-content{
        padding: 10px;
    }
    &-header{
        display: flex;
        justify-content: space-between;
        padding: 10px;
        border-bottom: 1px solid @border;
    }
}
</style>

Untitled

注册

main.ts 引入我们的组件跟随在 createApp(App) 后面 切记不能放到 mount 后面这是一个链式调用

其次调用 component 第一个参数组件名称 第二个参数组件实例

import { createApp } from 'vue'
import App from './App.vue'
import './assets/css/reset/index.less'
import Card from './components/Card/index.vue'
 
 
createApp(App).component('Card', Card).mount('#app')

使用

直接在其他 vue 页面立即使用即可,无需引入

<template>
 <Card></Card>
</template>

递归组件

原理跟我们写 js 递归是一样的,自己调用自己,通过一个条件来结束递归,否则导致内存泄漏。

案例 递归 Tree

在父组件配置数据结构,数组对象格式,传给子组件

App.vue

<template>
  <Tree :data="data"></Tree>
</template>
<script setup lang="ts">
import {ref, reactive} from "vue";
import Tree from './components/Tree.vue';

interface TreeList {
  name: string;
  checked: boolean;
  children?: TreeList[]
}

const data = reactive<TreeList[]>([
  {
    name: "no.1",
    checked: true,
    children: [
      {
        name: "no.1-1",
        checked: true,
        children: [
          {
            name: "no.1-1-1",
            checked: true
          },
        ],
      },
    ],
  },
  {
    name: "no.2",
    checked: false,
    children: [
      {
        name: "no.2-1",
        checked: false
      },
    ],
  },
  {
    name: "no.3",
    checked: true,
  },
]);
</script>

components/Tree.vue

<template>
  <div v-for="(item, idx) of data" :key="idx" class="item" @click.stop="clickTap(item)">
    <input type="checkbox" v-model="item.checked">
    <span>{{ item.name }}</span>
    <Tree v-if="item.children?.length" :data="item.children" />
  </div>
</template>
<script setup lang="ts">
interface TreeList {
  name: string;
  checked: boolean;
  children?: TreeList[]
}
defineProps<{
  data?: TreeList[]
}>();
const clickTap = (item: TreeList) => {
  console.log(item);
}
</script>

<style lang="less">
.item {
  margin-left: 10px;
}
</style>

自定义组件名

除了上面直接用文件名默认当组件名的方式外,我们还有两种方案自定义组件名