【vue3】10-vue组件化额外知识补充(下)-动态组件-组件缓存-v-model在组件上的应用

动态组件的使用(了解)

切换组件案例:

比如我们现在想要实现了一个功能:

  • 点击一个tab-bar,切换不同的组件显示;

在这里插入图片描述

这个案例我们可以通过两种不同的实现思路来实现:

  • 方式一:通过v-if来判断,显示不同的组件;
  • 方式二:动态组件的方式;

方式一代码示例:

<template>
    <div class="app">
        <div class="tabs">
            <template v-for="(item, index) in tabs" :key="item">
                <button @click="changeColor(index)" :class="{ active: index === currentIndex }">
                    {{ item }}
                </button>
            </template>
        </div>
        <div class="view">
            <!-- 1.第一种做法:v-if进行逻辑判断,决定要显示哪一个组件 -->
            <template v-if="currentIndex === 0">
            <home></home>
        </template>
        <template v-else-if="currentIndex ===1">
            <about></about>
        </template>
       
        <template v-else-if="currentIndex === 2">
            <category></category>
        </template>
            <!-- 最后一个写<template v-else> 也可以,但是不推荐-->
        </div>

    </div>
</template>
<script>
import About from "./views/About.vue";
import Category from "./views/Category.vue";
import Home from "./views/Home.vue";

export default {
    components: {
        Home,
        Category,
        About
    },
    data() {
        return {
            tabs: ["home", "about", "category"],
            currentIndex: 0
        }
    },
    methods: {
        changeColor(index) {
            this.currentIndex = index
        }
    }
}

</script>

动态组件方式实现

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

<template>
    <div class="app">
        <div class="tabs">
            <template v-for="(tab, index) in tabs" :key="item">
                <button @click="changeColor(tab)" :class="{ active: currentTab === tab }">
                    {{ tab }}
                </button>
            </template>
        </div>
        <div class="view">
          <!-- 2.第二种做法:动态组件:component -->
            <!-- is中的组件:(1)要么是全局注册的组件;(2)要么是局部注册过的组件 -->
            <!-- <component is="about"></component> -->

            <!-- 动态组件传参(了解),如果是数组类型就和age一样:  监听发送的事件也在component上 -->
            <!-- <component name="sevgilid" :age="19" :is="tabs[currentIndex]"></component> -->
            <component name="sevgilid" :age="19" :is="currentTab"></component>
        </div>

    </div>
</template>

在上面的演示中,我们可以看到:

  • 首先使用了component组件,is:组件名,来展示对应的组件;
  • 然后绑定事件点击按钮时获取对应的tab来作为组件名实现动态组件的展示
  • 传递参数和监听子组件事件正常在component组件内使用即可,如在home组件中使用props接收数据:
    在这里插入图片描述

(动态组件了解即可,后边会讲解路由,使用路由切换更为简洁遍历)


keep-alive(理解)

认识keep-alive

在 Vue.js 中, keep-alive 内置组件可以缓存不活动的组件实例,它通过包裹动态组件来实现缓存,避免了组件的频繁销毁和重建,从而提升了页面性能

我们先对之前的案例中Home组件进行改造:

  • 在其中增加了一个按钮,点击可以递增的功能;
    在这里插入图片描述

比如我们将counter点到10,那么在切换到about再切换回来Home时,状态是否可以保持呢?

  • 答案是否定的;
  • 这是因为默认情况下,我们在切换组件后,Home组件会被销毁掉,再次回来时会重新创建组件;

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

keep-alive的使用

使用 keep-alive 内置组件很简单,只需要将需要缓存的组件用 <KeepAlive> 标签包裹即可。例如在刚才的案例中:

在这里插入图片描述

像上面这样包裹后,我们在点击递增按钮到一定数值后来回切换发现已经数值不会再被重置;
但通过再各个组件内部使用created和unmounted钩子函数发现都没有回调,这说明里面被包裹的所有组件都被缓存了;


如果想要精准控制组件的缓存对保持keep-alive组件监听有没有切换该怎么办呢?

(1)精准控制组件缓存

keep-alive有一些属性:

  • include - string | RegExp |Array。只有名称匹配的组件会被缓存;
  • exclude - string | RegExp | Array。任何名称匹配的组件都不会被缓存;
  • max - number | string。最多可以缓存多少组件实例,一旦达到这个数字,那么缓存组件中最近没有被访问的实例会被销毁;

include和exclude prop允许组件有条件地缓存:

  • 二者都可以用逗号分隔字符串、正则表达式或一个数组来表示;
  • 匹配首先检查组件自身的name选项;

使用示例:

Home组件中:

<template>
    <h2>home组件</h2>
    <h2>计数器:{{ counter }}</h2>
    <button @click="counter++">+1</button>
</template>

<script>
export default {
    // 此处的name提供给Keep-Alive中的include属性使用的
    name: "home",
    data() {
        return {
            counter: 0
        }
    }

}
</script>

App根组件中:

在这里插入图片描述

(2)缓存组件的生命周期

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

  • 但是有时候我们确实希望监听到何时重新进入到了组件,何时离开了组件;
  • 这个时候我们可以使用activated和deactivated这两个生命周期钩子函数来监听;

在这里插入图片描述

需要注意的是,由于 keep-alive 是内置组件,所以不支持动态组件模式下的异步组件:

  • 因为异步组件的加载是异步的, keep-alive 无法知道异步组件何时完成加载,从而无法对其进行缓存;
  • 如果需要缓存异步组件,可以使用工厂函数与异步组件创建一个高阶组件,再将其包裹在 keep-alive 内;

异步组件的使用

在学习异步组件使用前,先来了解一下webpack的分包处理,因为异步组件打包时会进行分包的处理

webpack分包处理(了解)

默认的打包过程:

  • 默认情况下,在构建整个组件树的过程中,因为组件和组件之间是通过模块化直接依赖的,那么webpack在打包时就会将组件模块打包到一起(比如一个app.js文件中);
  • 这个时候随着项目的不断庞大,app.js文件的内容过大,会造成首屏的渲染速度变慢;

打包时,代码的分包:

  • 所以,对于一些不需要立即使用的组件,我们可以单独对它们进行拆分,拆分成一些小的代码块chunk.js;
  • 这些chunk.js会在需要时从服务器加载下来,并且运行代码,显示对应的内容;

那么webpack中如何可以对代码进行分包呢?

在这里插入图片描述

Vue中实现异步组件

如果我们的项目过大了,对于某些组件我们希望通过异步的方式来进行加载(目的是可以对其进行分包处理),那么Vue中给我们提供了一个函数: defineAsyncComponent

defineAsyncComponent接受两种类型的参数:

  • 类型一:工厂函数,该工厂函数需要返回一个Promise对象;
  • 类型二:接受一个对象类型,对异步函数进行配置;

工厂函数类型一的写法:

<script>
import { defineAsyncComponent } from "vue";
//  import Category from "./views/Category.vue";
// 异步组件写法一(了解):工厂函数:返回的是一个promise对象
const AsyncCategory = defineAsyncComponent(() => import("./views/Category.vue"))


export default {
    components: {
        Home,
        // 异步组件:打包的时候会进行分包处理
        Category: AsyncCategory,
    }

}

</script>

异步组件写法二(了解):

在这里插入图片描述

(异步组件的使用仅作了解即可,因为实际开发中路由懒加载的写法会更多)


组件的v-model

前面我们在input中可以使用v-model来完成双向绑定:

  • 这个时候往往会非常方便,因为v-model默认帮助我们完成了两件事;
  • v-bind:value的数据绑定@input的事件监听;

如果我们现在封装了一个组件,其他地方在使用这个组件时,是否也可以使用v-model来同时完成这两个功能呢?

  • 也是可以的,vue也支持在组件上使用v-model;

当我们在组件上使用的时候,等价于如下的操作:

  • 我们会发现和input元素不同的只是属性的名称和事件触发的名称而已;
    在这里插入图片描述

那么,为了我们的counter组件可以正常的工作,这个组件内的click必须:

  • 将其value attribute绑定到一个名叫modelValue 的prop上;
  • 在其click事件被触发时,将新的值通过自定义的update:modelValue事件抛出;

Counter组件代码如下:

<template>
    <h2>counter:{{ modelValue }}</h2>
    <button @click="changeCounter">修改counter</button>
</template>

<script>
    export default{
        props:{
            modelValue:{
                type:Number,
                default:0
            }
        },
        emits:["update:modelValue"],
        methods:{
            changeCounter(){
                // this.$emit("update:modelValue", 1000)
                this.$emit("update:modelValue", 999)
            }
        }
    }
</script>

v-model默认绑定的参数名和事件名是modelValue;
此处的@click绑定click事件;换成@input则表示的是绑定的是input事件,当input表有input输入时触发事件

绑定多个属性(高级用法):

我们现在通过v-model是直接绑定了一个属性,如果我们希望绑定多个属性呢?

  • 也就是我们希望在一个组件上使用多个v-model是否可以实现呢?
  • 我们知道,默认情况下的v-model其实是绑定了modelValue属性@update:modelValue的事件;
  • 如果我们希望绑定更多,可以给v-model传入一个参数,那么这个参数的名称就是我们绑定属性的名称;

默认绑定一个属性和绑定多个自定义属性的代码对比:

(1)子组件部分:

在这里插入图片描述
(2)父组件部分:

在这里插入图片描述

总结:

  1. v-model可以绑定多个自定义属性
  2. v-model在组件上的应用实际上是将一个代表数据的属性和一个代表数据修改的事件绑定到了一起,使得在父子组件之间进行数据通信变得简单和直观。 比如v-model:title相当于做了两件事:
  • 绑定了title属性;

  • 监听了@update:title的事件;


组件的混入Mixin(了解)

Mixin主要在Vue2中使用,在Vue3中基本不用

虽然mixin在Vue中给我们带来了很多的代码复用和逻辑复用的好处,但是也存在一些弊端:

  1. 命名冲突:mixin可以将通用的逻辑和代码分离出来,但是它也可能导致命名冲突。如果多个Mixin中有同名的选项,或者Mixin中的选项与组件中的选项重名,就会导致选项的合并冲突。而且如果有多个mixin混合使用可能会更加复杂,因为难以判断选项的来源和优先级。为了避免命名冲突,我们需要在编写Mixin时格外小心,同时在开发过程中也需要保持清晰的组织结构。
  2. 耦合性高:mixin虽然可以让我们方便地复用代码和逻辑,但是也可能导致组件与Mixin之间的耦合性增加。因为mixin需要了解组件的内部实现细节和数据结构,从而才能正确地暴露需要的数据和方法。这就导致了Mixin与组件之间的耦合度会比较高,一旦需要修改Mixins,可能会对组件产生意外的影响。

在Vue 3中,Composition API的出现主要是为了解决mixin中所存在的问题和局限性。Composition API可以更好地实现逻辑复用,并且可以更好地组织组件代码。通过Composition API,我们可以将逻辑功能组织成一组Hooks(钩子函数)并进行复用。


目前我们是使用组件化的方式在开发整个Vue的应用程序,但是组件和组件之间有时候会存在相同的代码逻辑,我们希望对相同的代码逻辑进行抽取

在Vue2和Vue3中都支持的一种方式就是使用Mixin来完成:

  • Mixin提供了一种非常灵活的方式,来分发Vue组件中的可复用功能;
  • 一个Mixin对象可以包含任何组件选项;
  • 当组件使用Mixin对象时,所有Mixin对象的选项将被混合进入该组件本身的选项中;

(1)基本使用:

Vue中的Mixin分为全局Mixin与组件级Mixin。下面我们以组件级Mixin为例讲解其基本使用方法。
首先,定义一个名为myMixin的mixin:

var myMixin = {
  data: function () {
    return {
      message: 'Hello world!'
    }
  },
  methods: {
    greet: function () {
      console.log(this.message)
    }
  }
}

然后,可以在Vue组件中使用这个mixin了。我们需要在组件中使用mixins选项来将Mixin混入(mixin)到组件中。

Vue.component('my-component', {
  mixins: [myMixin],
  template: '<div>{{ message }}</div>',
  created: function () {
    this.greet() // 执行myMixin中的方法greet
  }
})

在上面的代码中,我们将myMixin混入到了my-component组件中。所以在my-component组件中,我们可以使用myMixin中定义的message实例属性和greet方法

(2)mixin的合并规则

多个Mixin共同作用于一个组件的时候,Vue中的Mixin会按照一定的规则进行合并;如果多个Mixin有相同的选项,这些选项会被合并到一个选项中,合并规则如下:

  • 数据对象:在组件和Mixin中定义的数据对象会被合并成一个对象。当组件与Mixin同名的属性冲突时,以组件数据为准。
  • 生命周期钩子函数:合并两个Mixin中的同名生命周期钩子时,都会被调用。Mixin的钩子总是在组件的钩子之前被调用。
  • 方法:Mixin中的方法会被合并到组件中,并且优先级高于组件中的同名方法。
  • 其他选项:如props、computed等,都会以和方法相同的方式进行合并。

(3)全局混入mixin

全局混入Mixin的主要作用是向所有的Vue实例添加一些全局的逻辑或方法。这样一来,我们就可以在所有Vue实例内使用这些全局的逻辑或方法。

比如,我们可以在全局Mixin中添加一个$myMethod方法:

Vue.mixin({
  methods: {
    $myMethod: function () {
      console.log('This is a global method.')
    }
  }
})

通过上面的代码,我们就向所有的Vue实例中添加了一个全局方法$myMethod,可以在任何Vue组件内使用。

new Vue({
  created: function () {
    this.$myMethod() //这里就可以调用到已经全局混合的$myMethod方法了
  }
})

总结:

  1. 全局的Mixin可以使用应用app的方法mixin来完成注册;
  2. 一旦注册,那么全局混入的选项将会影响每一个组件;
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值