# 一.动态组件

# 1.什么是动态组件

动态组件指的是动态切换组件的显示与隐藏。

# 2.如何实现动态组件

在 Vue 中,<component>是一个特殊的组件,它用于渲染动态组件。动态组件是指在运行时根据数据或条件动态地选择要渲染的组件。

<component>组件可以通过is属性来指定要渲染的组件。这个属性的值可以是一个组件的名称,也可以是一个组件对象。当is的值发生变化时,<component>会销毁当前渲染的组件实例,并创建和渲染新的组件实例。

以下是一个使用<component>动态组件的示例:

<template>
  <div>
    <button @click="changeComponent('ComponentA')">组件A</button>
    <button @click="changeComponent('ComponentB')">组件B</button>

    <component :is="currentComponent"></component>
  </div>
</template>

<script>
  import ComponentA from "./ComponentA.vue";
  import ComponentB from "./ComponentB.vue";

  export default {
    data() {
      return {
        currentComponent: null,
      };
    },
    methods: {
      changeComponent(componentName) {
        if (componentName === "ComponentA") {
          this.currentComponent = ComponentA;
        } else if (componentName === "ComponentB") {
          this.currentComponent = ComponentB;
        }
      },
    },
  };
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

在上面的示例中,当点击"组件 A"按钮时,currentComponent会被设置为ComponentA组件;当点击"组件 B"按钮时,currentComponent会被设置为ComponentB组件。<component>会根据currentComponent的值动态渲染相应的组件。

需要注意的是,被动态渲染的组件必须在父组件的作用域内注册或导入。在示例中,ComponentAComponentB被导入并通过按钮点击事件来切换。

# 3.keep-alive

默认情况下,切换动态组件时无法保持组件的状态。此时可以使用 vue 内置的 <keep-alive> 组件保持动态组

件的状态。示例代码如下:

<template>
  <div>
    <button @click="changeComponent('ComponentA')">组件A</button>
    <button @click="changeComponent('ComponentB')">组件B</button>

    <keep-alive>
      <component :is="currentComponent"></component>
    </keep-alive>
  </div>
</template>

<script>
  import ComponentA from "./ComponentA.vue";
  import ComponentB from "./ComponentB.vue";

  export default {
    data() {
      return {
        currentComponent: null,
      };
    },
    methods: {
      changeComponent(componentName) {
        if (componentName === "ComponentA") {
          this.currentComponent = ComponentA;
        } else if (componentName === "ComponentB") {
          this.currentComponent = ComponentB;
        }
      },
    },
  };
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

# 4.keep-alive 对应的生命周期函数

当组件被缓存时,会自动触发组件的 deactivated 生命周期函数。

当组件被激活时,会自动触发组件的 activated 生命周期函数。

  • activated:当组件被激活(从缓存中取出并重新渲染)时,会调用 activated 钩子函数。你可以在这个钩子函数中执行一些特定于组件激活时需要的操作。
  • deactivated:当组件被离开(被缓存)时,会调用 deactivated 钩子函数。你可以在这个钩子函数中执行一些特定于组件离开时需要的操作。

需要注意的是,被缓存的组件不会被销毁和重新创建,而是被保留在内存中。因此,如果你希望在组件每次激活时都执行某些操作,可以使用 activated 钩子函数;如果你希望在组件离开时执行某些操作,可以使用 deactivated 钩子函数。

export default {
	created(){console.log('组件被创建了'},
  destroyed({console.log('组件被销毁了'},
  activated(){console.log('Left 组件被激活了!')},
  deactivated(){console.log('Left组件被缓存了!')}
}
1
2
3
4
5
6

# 5.include 属性

在 Vue 的 <keep-alive> 组件中,你可以使用 includeexclude 属性来进一步控制哪些组件应该被缓存或排除在缓存之外。

  • include 属性用于指定要缓存的组件名称或组件名称的数组。只有在 include 中列出的组件才会被缓存。
  • exclude 属性用于指定不应被缓存的组件名称或组件名称的数组。列出的组件将被排除在缓存之外。
<template>
  <div>
    <button @click="toggleCache">切换缓存</button>

    <keep-alive :include="includeComponents" :exclude="excludeComponents">
      <component :is="currentComponent"></component>
    </keep-alive>
  </div>
</template>

<script>
import ComponentA from "./ComponentA.vue";
import ComponentB from "./ComponentB.vue";
import ComponentC from "./ComponentC.vue";

export default {
  data() {
    return {
      currentComponent: ComponentA,
      includeComponents: ["ComponentA", "ComponentB"],
      excludeComponents: ["ComponentC"],
      useCache: true,
    };
  },
  methods: {
    toggleCache() {
      this.useCache = !this.useCache;
      this.currentComponent = this.useCache ? ComponentA : ComponentC;
    },
  },
};
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

在上述示例中,includeComponents 数组中包含了要缓存的组件名称,即 'ComponentA''ComponentB'。而 excludeComponents 数组中包含了要排除在缓存之外的组件名称,即 'ComponentC'

初始状态下,currentComponent 被设置为 ComponentA,因此 ComponentA 会被缓存,而 ComponentBComponentC 则不会被缓存。

点击 "切换缓存" 按钮会在 ComponentAComponentC 之间切换。当 useCachetrue 时,currentComponent 被设置为 ComponentA,从而将 ComponentA 缓存起来。当 useCachefalse 时,currentComponent 被设置为 ComponentC,从而将 ComponentA 从缓存中移除,并不会缓存 ComponentC

通过使用 includeexclude 属性,你可以灵活地控制缓存的组件,并排除不需要缓存的组件,以满足你的具体需求。

# 二.插槽

# 1.什么是插槽

插槽(Slot)是 vue 为组件的封装者提供的能力。允许开发者在封装组件时,把不确定的、希望由用户指定的

部分定义为插槽。

image-20230710180509242

可以把插槽认为是组件封装期间,为用户预留的内容的占位符。

# 2.体验插槽的基础用法

在 Vue 中,<slot> 元素是用于插入组件内容的插槽。它允许在组件的模板中定义一个或多个占位符,以便在组件的使用者提供内容。

以下是一个示例,展示了如何使用 <slot>

<!-- ParentComponent.vue -->
<template>
  <div>
    <h1>父组件</h1>
    <slot></slot>
  </div>
</template>
1
2
3
4
5
6
7

在上述示例中,<slot> 标签被放置在父组件的模板中。这表示在组件使用的地方,任何内容都可以被插入到这个插槽中。

<!-- App.vue -->
<template>
  <div>
    <ParentComponent>
      <h2>子组件插入的内容</h2>
      <p>更多子组件内容</p>
    </ParentComponent>
  </div>
</template>

<script>
import ParentComponent from "./ParentComponent.vue";

export default {
  components: {
    ParentComponent,
  },
};
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

在上述示例中,我们在 <ParentComponent> 标签中插入了一些内容,包括一个 <h2> 元素和一个 <p> 元素。这些内容将被插入到 <slot> 标签所在的位置。

当渲染父组件时,插入的内容将替换 <slot> 元素。在这个例子中,最终渲染的结果将包含父组件中的 <h1> 标题和子组件中插入的内容。

你还可以在 <slot> 标签中定义默认内容,以便在没有提供插入内容时显示。例如:

<!-- ParentComponent.vue -->
<template>
  <div>
    <h1>父组件</h1>
    <slot> 默认内容 </slot>
  </div>
</template>
1
2
3
4
5
6
7

在这种情况下,如果在 <ParentComponent> 标签中没有提供插入的内容,那么默认内容 "默认内容" 将被渲染。

使用 <slot> 元素允许你以灵活的方式定义组件的结构,并允许使用者在使用组件时提供自定义的内容。这对于构建可重用的组件非常有用。

# 3.后备内容

封装组件时,可以为预留的 <slot> 插槽提供后备内容(默认内容)。如果组件的使用者没有为插槽提供任何

内容,则后备内容会生效。示例代码如下:

<template>
  <p>这是MyCom1组件的第1个p标签</p>
  <slot>这是后备内容</slot>
  <p>这是MyCom1组件最后一个 p标签</p>
</template>
1
2
3
4
5

# 4.具名插槽

如果在封装组件时需要预留多个插槽节点,则需要为每个<slot> 插槽指定具体的 name 名称。这种带有具体

名称的插槽叫做“具名插槽”。示例代码如下:

<!-- ParentComponent.vue -->
<template>
  <div>
    <h1>父组件</h1>
    <slot name="header"></slot>
    <div>
      <slot></slot>
    </div>
    <slot name="footer"></slot>
  </div>
</template>
1
2
3
4
5
6
7
8
9
10
11

注意:没有指定 name 名称的插槽,会有隐含的名称叫做 “default”。

<!-- App.vue -->
<template>
  <div>
    <parent-component>
      <template v-slot:header>
        <h2>头部插槽的内容</h2>
      </template>
      <p>默认插槽的内容</p>
      <template v-slot:footer>
        <footer>底部插槽的内容</footer>
      </template>
    </parent-component>
  </div>
</template>

<script>
import ParentComponent from "./ParentComponent.vue";

export default {
  components: {
    ParentComponent,
  },
};
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

在上述示例中,我们使用 v-slot 指令来为具名插槽指定内容。v-slot 后面的参数指定了要插入的具名插槽的名称。

在这个例子中,我们在父组件中插入了三个具名插槽的内容:头部插槽、默认插槽和底部插槽。这些内容将被插入到父组件的相应位置。

注意,在 Vue 2.6.0 版本之前,我们使用 slot 元素的 name 属性来定义具名插槽,而在 Vue 2.6.0 版本及更高版本中,可以使用 v-slot 指令来定义具名插槽。

# 5.具名插槽的简写形式

跟 v-on 和 v-bind 一样,v-slot 也有缩写,即把参数之前的所有内容 (v-slot:) 替换为字符 #。例如 v-slot:header

可以被重写为 #header:

<my-com-2>
  <template #header>
  	<h1>滕王阁序</h1>
  </template>
  <template #default>
    <p>豫章故郡,洪都新府。</p>
    <p>星分翼轸,地接衡庐。</p>
    <p>襟三江而带五湖,控蛮荆而引瓯越。</p>
  </template>
  <template #footer>
    <p>落款:王勃</p>
  </template>
</my-com-2>
1
2
3
4
5
6
7
8
9
10
11
12
13

# 6.作用域插槽

作用域插槽(Scoped Slots)是 Vue 中一种特殊的插槽类型,允许组件向使用者暴露数据,使得使用者可以在插槽中访问该数据并进行自定义渲染。

以下是一个示例,展示了如何使用作用域插槽:

<!-- ParentComponent.vue -->
<template>
  <div>
    <h1>父组件</h1>
    <slot :data="message"></slot>
  </div>
</template>

<script>
export default {
  data() {
    return {
      message: "Hello, World!",
    };
  },
};
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

在上述示例中,<slot> 元素的 :data 属性绑定了组件的 message 数据。这样就创建了一个作用域插槽,将 message 数据传递给插槽内容的使用者。

<!-- App.vue -->
<template>
  <div>
    <parent-component>
      <template v-slot:default="slotProps">
        <p>{{ slotProps.data }}</p>
      </template>
    </parent-component>
  </div>
</template>

<script>
import ParentComponent from "./ParentComponent.vue";

export default {
  components: {
    ParentComponent,
  },
};
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

在上述示例中,我们使用 v-slot 指令来定义作用域插槽。v-slot 后面的参数指定了要插入的插槽的名称,并通过参数 slotProps 访问作用域插槽的数据。

在这个例子中,我们在父组件中定义了一个作用域插槽,并将 message 数据传递给插槽的使用者。插槽内容中的 slotProps.data 将渲染出父组件传递的数据。

通过作用域插槽,组件可以向使用者提供更多的灵活性,使得使用者可以自定义渲染插槽内容,并且可以访问到组件的数据。这在一些需要自定义逻辑和样式的情况下非常有用,同时也提升了组件的可复用性和扩展性。

# 7.解构插槽 Prop

作用域插槽对外提供的数据对象,可以使用解构赋值简化数据的接收过程。示例代码如下:

<my-com-3>
  <!--v-slot:可以简写成#-->
  <!--作用域插槽对外提供的数据对象,可以通过“解构赋值”简化接收的过程--
  <template #default="{user}">
    <tr>
      <td>{{user.id}}</td>
      <td>{{user.name}}</td>
      <td>{{user.state}}</td>
    </tr>
  </template>
</my-com-3>
1
2
3
4
5
6
7
8
9
10
11

# 三.自定义指令

# 1.什么是自定义指令?

vue 官方提供了 v-text、v-for、v-model、v-if 等常用的指令。除此之外 vue 还允许开发者自定义指令。

# 2.自定义指令的分类

vue 中的自定义指令分为两类,分别是:

  • 私有自定义指令
  • 全局自定义指令

# 3.私有自定义指令

在每个 vue 组件中,可以在 directives 节点下声明私有自定义指令。示例代码如下:

directives: {
  color: {
    //为绑定到的HTML元素设置红色的文字
    bind(el){
      //形参中的el是绑定了此指令的、原生的DOM对象
      el.style.color = 'red'
    }
  }
}
1
2
3
4
5
6
7
8
9

# 4.使用自定义指令

在使用自定义指令时,需要加上 v- 前缀。示例代码如下:

<!--声明自定义指令时,指令的名字是 color -->
<!--使用自定义指令时,需要加上v-指令前缀-->
<h1 v-color>App 组件</h1>
1
2
3

# 5.动态绑定参数值

为自定义指令动态绑定参数值

在 template 结构中使用自定义指令时,可以通过等号(=)的方式,为当前指令动态绑定参数值:

data() { return { color:'red'//定义 color颜色值 } }
<!--在使用指令时,动态为当前指令绑定参数值color-->
<h1 v-color="color">App 组件</h1>
1
2
3

通过 binding 获取指令的参数值

在声明自定义指令时,可以通过形参中的第二个参数,来接收指令的参数值:

directives: {
  color: {
    bind(el,binding){
      //通过 binding 对象的.value 属性,获取动态的参数值
      el.style.color = binding.value
    }
   }
}
1
2
3
4
5
6
7
8

# 6.update 函数

bind 函数只调用 1 次:当指令第一次绑定到元素时调用,当 DOM 更新时 bind 函数不会被触发。 update 函

数会在每次 DOM 更新时被调用。示例代码如下:

directives: {
  color: {
    //当指令第一次被绑定到元素时被调用
    bind(el,binding){
      el.style.color = binding.value
    }//每次 DOM 更新时被调用
    update(el, binding) {
      el.style.color = binding.value
    }
  }
}
1
2
3
4
5
6
7
8
9
10
11
12

# 7.函数简写

如果 insert 和 update 函数中的逻辑完全相同,则对象格式的自定义指令可以简写成函数格式:

directives: {
  //在 insert 和 update 时,会触发相同的业务逻辑
  color(el,binding){
    el.style.color = binding.value
  }
}
1
2
3
4
5
6

# 8.全局自定义指令

全局共享的自定义指令需要通过“Vue.directive()”进行声明,示例代码如下:

//参数1:字符串,表示全局自定义指令的名字
//参数2:对象,用来接收指令的参数值
Vue.directive('color', function(el, binding){
  el.style.color = binding.value
}
1
2
3
4
5
上次更新: 10/29/2024, 10:27:50 AM