# 1. 动态组件 用 if else 实现

# Home

vue
// Home.vue 
<template>
  <div>
    Home组件
  </div>
</template>
<script>
  export default {
    name: "home",  
  }
</script>
<style scoped>
</style>

# About

vue
// About.vue
<template>
  <div>
    About组件
  </div>
</template>
<script>
  export default {
    name: "about",  
  }
</script>
<style scoped></style>

# Category

vue
// Category.vue
<template>
  <div>
    Category组件
  </div>
</template>
<script>
  export default {
    name: "category",  
  }
</script>
<style scoped></style>

# App

vue
// App.vue  
<template>
  <div>
    <button v-for="item in tabs" :key="item"
            @click="itemClick(item)"
            :class="{active: currentTab === item}">
     {{ item }}
    </button>
    <!-- 1.v-if 的判断实现 -->
    <template v-if="currentTab === 'home'">
      <home></home>
    </template>
    <template v-else-if="currentTab === 'about'">
      <about></about>
    </template>
    <template v-else>
      <category></category>
    </template>
  </div>
</template>
<script>
  import Home from './Home.vue';
  import About from './About.vue';
  import Category from './Category.vue';
  export default {
    components: {
      Home,
      About,
      Category
    },
    data() {
      return {
        tabs: ["home", "about", "category"],
        currentTab: "home"
      }
    },
    methods: {
      itemClick(item) {
        this.currentTab = item;
      },
    }
  }
</script>
<style scoped>
  .active {
    color: red;
  }
</style>

参考结果:

component_if_else

# 2. 动态组件 component

# App

vue
// App.vue  
<template>
  <div>
    <button v-for="item in tabs" :key="item"
            @click="itemClick(item)"
            :class="{active: currentTab === item}">
     {{ item }}
    </button>
    <!-- 2. 动态组件 -->
      <component :is="currentTab"
                 name="Neko"
                 :age="18">
      </component>
  </div>
</template>
<script>
  import Home from './Home.vue';
  import About from './About.vue';
  import Category from './Category.vue';
  export default {
    components: {
      Home,
      About,
      Category
    },
    data() {
      return {
        tabs: ["home", "about", "category"],
        currentTab: "home"
      }
    },
    methods: {
      itemClick(item) {
        this.currentTab = item;
      }
    }
  }
</script>
<style scoped>
  .active {
    color: red;
  }
</style>

参考结果:

component

# 3.keep-alive 的基本使用

# Home

vue
// Home.vue  
<template>
  <div @click="divClick">
    Home组件: {{ name }} - {{ age }}
  </div>
</template>
<script>
  export default {
    name: "home",  
    props: {
      name: {
        type: String,
        default: ""
      },
      age: {
        type: Number,
        default: 0
      }
    },
    emits: ["pageClick"],
    methods: {
      divClick() {
        this.$emit("pageClick");
      }
    }
  }
</script>
<style scoped></style>

# About

vue
// About  
<template>
  <div>
    About组件
    <button @click="counter++">{{ counter }}</button>
  </div>
</template>
<script>
  export default {
    name: "about",  
    data() {
      return {
        counter: 0
      }
    },
    // 请注意控制台 生命周期状态 变化  
    created() {
      console.log("about created");
    },
    unmounted() {
      console.log("about unmounted");
    },
    activated() {
      console.log("about activated");
    },
    deactivated() {
      console.log("about deactivated");
    }
  }
</script>
<style scoped></style>

# Category

vue
// Category.vue  
<template> 
  <div>
    Category组件
    <button @click="counter++">{{ counter }}</button>
  </div>
</template>
<script>
  export default {
    name: "category",  
    data() {
      return {
        counter: 0
      }
    }
  }
</script>
<style scoped></style>

# App

vue
// App.vue 
<template>
  <div>
    <button v-for="item in tabs" :key="item"
            @click="itemClick(item)"
            :class="{active: currentTab === item}">
      {{ item }}
    </button>
    <!-- 2. 动态组件 使用 keep-alive 保持状态,这里 include 没有写 Category,所以 Category 组件不会被缓存 -->
    <!-- include 三个属性:可以用逗号分隔、正则表达式或数组表示
        include:只有名称匹配的组件会被缓存
        exclude: 任何名称匹配的组件都不会被缓存
        max: 最多可以缓存多少组件实例,一旦达到这个数字,那么缓存组件中最近没有被访问的实例会被销毁
        匹配会先检查组件自身的 name 选项
     -->
    <keep-alive include="home,about">
      <component :is="currentTab"
                 name="Neko"
                 :age="18"
                 @pageClick="pageClick">
      </component>
    </keep-alive>
  </div>
</template>
<script>
  import Home from './pages/Home.vue';
  import About from './pages/About.vue';
  import Category from './pages/Category.vue';
  export default {
    components: {
      Home,
      About,
      Category
    },
    data() {
      return {
        tabs: ["home", "about", "category"],
        currentTab: "home"
      }
    },
    methods: {
      itemClick(item) {
        this.currentTab = item;
      },
      pageClick() {
        console.log("page内部发生了点击");
      }
    }
  }
</script>
<style scoped>
  .active {
    color: red;
  }
</style>

参考结果:控制台没有打印 Category 的 created 生命周期,是因为没有使用该函数

component_keep-alive

# 4. 异步组件 suspense

# AsyncCategory

vue
// AsyncCategory.vue 
<template>
  <div>
    <h2>{{ message }}</h2>
  </div>
</template>
<script>
  export default {
    data() {
      return {
        message: "Hello Category"
      }
    }
  }
</script>
<style scoped></style>

# Loading-

vue
// Loading.vue
<template>
  <div>
    Loading
  </div>
</template>
<script>
  export default {}
</script>
<style scoped></style>

# App

vue
// App.vue
<template>
  <div>
    App组件
    <suspense> <!-- 默认插槽占位组件 -->
      <template #default>
        <async-category></async-category>
      </template>
      <template #fallback> <!-- 应急计划 -->
        <loading></loading>
      </template>
    </suspense>
  </div>
</template>
<script>
  import { defineAsyncComponent } from 'vue';
  import Loading from './Loading.vue';
  // import AsyncCategory from './AsyncCategory.vue';
  const AsyncCategory = defineAsyncComponent(() => import("./AsyncCategory.vue"))
  // const AsyncCategory = defineAsyncComponent({
  //   loader: () => import("./AsyncCategory.vue"),
  //   loadingComponent: Loading,
  //   // errorComponent,
  //   // 在显示 loadingComponent 组件之前,等待多长时间
  //   delay: 2000,
  //   /**
  //    * err: 错误信息,
  //    * retry: 函数,调用 retry 尝试重新加载
  //    * attempts: 记录尝试的次数
  //    */
  //   onError: function(err, retry, fail, attempts) {
  //   }
  // })
  export default {
    components: {
      AsyncCategory,
      Loading // 加载时显示的组件,本地速度很快所以会一闪而过
    }
  }
</script>
<style scoped></style>

参考结果:

component_suspense

官方:

suspense