me

Vue3 的组件化


理解插槽

默认插槽

当插槽内部不具有 name 属性时,vue 会自动给一个隐式名称name:default

且子组件不管有多少个插槽,每个插槽都会显示一样的内容

 父组件中:
<Category>
  <div>html 结构</div>
</Category>
子组件中:
<template>
   <div>
    <!--定义插槽-->
      <slot>插槽默认值</slot>
   </div>
</template>

具名插槽

//父组件中
<Footer>
  <template v-slot:footer>
    <div>
      你好
    </div>
  </template>
</Footer>
//子组件中
<slot name="footer">插槽默认值</slot>
<template v-slot:[name]>
  <div>
    你好
  </div>
</template>
<script>
  //...
  data(){
    return {
      name:"footer"
    }
  }
</script>

作用域插槽

<!-- 子组件中:有一个 names 的数组 -->
  <template v-for="(item,index) in names" :key="item">
     <slot name="footer" :item="item" :index="index"></slot>
  </template>

<!-- 具名插槽与作用域插槽 -->
<Footer>
  <template #footer="slotProps">
    <button>{{slotProps.item}}-{{slotProps.index}}</button>
  </template>
</Footer>
<Foot v-slot="slotProps">
  <button>{{slotProps.item}}-{{slotProps.index}}</button>
</Footer>

动态组件

动态组件是使用 component 组件,通过一个特殊的attribute is 来实现,is 属性是一个组件

<component 
  :is="currentTab" 
  :age="18" 
  name="张三" 
  @pageClick="pageClick">
</component>

缓存组件 keep-alive

默认情况下,我们在切换组件后,组件会被销毁掉,再次回来时会重新创建组件

然而某些情况我们希望继续保持组件的状态,而不是销毁掉,这个时候我们就可以使用一个内置组件:keep-alive

<keep-alive include="home,about">
  <component 
    :is="currentTab" 
    :age="18" 
    name="张三" 
    @pageClick="pageClick">
  </component>
</keep-alive>

keep-alive 的一些属性

缓存组件的生命周期

对于缓存的组件来说,再次进入时,我们是不会执行 created 或者 mounted 等生命周期函数的

异步组件的实现 (多在路由中用到)

默认情况下,在构建整个组件树的过程中,因为组件和组件之间是通过模块化直接依赖的,那么 webpack 在打包时就会将组件模块打包到一起(比如一个 app.js 文件中)

webpack 的代码分包

import("./utils/math").then(
  (res) => {
    console.log(res.sum(20, 30));
  },
);

vue 中实现异步组件

属性描述
loadingComponent传入一个组件,如果没有加载出异步组件,占位组件会占位
errorComponent传入一个组件,组件加载失败时显示的组件
delay在显示 loadingComponents 组件之前,等待多长时间
onError传入一个带有四个参数的函数,

异步组件与 Suspense(还在实验中,API 随时可能修改)

<template #default>
  <AsyncHeader></AsyncHeader>
</template>
<template #fallback>
  <Loading></Loading>
</template>

引用元素和组件

组件的 v-model

在 input 中可以使用 v-model 来完成双向绑定

在封装一个组件,其他地方在使用这个组件时,也可以使用 v-model 来同时完成这两个功能

<!-- 父组件 -->
<MainInput v-model="message"></MainInput>

<!-- 组件直接绑定 v-model,相当于写成以下模式 -->
<MainInput :modelValue="message" 
           @update:modelValue="message=$event">
</MainInput>
<!-- 子组件 -->
<template>
  <div>
     <input v-model="value">
     <h2>Main 的 message:{{modelValue}}</h2>
  </div>
</template>
<script>
export default {
  props:{
    modelValue:String,
  },
  emits:["update:modelValue"],
  computed:{
    value:{
      get(){
        return this.modelValue
      },
      set(value){
        this.$emit("update:modelValue",value)
      }
    }
  },
}
</script>
<!-- 父组件 -->
<MainInput v-model:demo="message" v-model:tittle="tittle"></MainInput>
<!-- 子组件 -->
<template>
  <div>
     <input v-model="tittleValue">
     <h2>Main 的 message:{{tittleValue}}</h2>
      <input v-model="demoValue">
     <h2>Main 的 message:{{demoValue}}</h2>
  </div>
</template>
<script>
export default {
  props:{
    demo:String,
    tittle:String
  },
  emits:["update:tittle","update:demo"],
  computed:{
    tittleValue:{
      get(){
        return this.tittle
      },
      set(value){
        this.$emit("update:tittle",value)
      }
    },
    demoValue:{
      get(){
        return this.demo
      },
      set(value){
        this.$emit("update:demo",value)
      }
    }
  },
}
</script>