Vue中Mixin的正确用法详解

 更新时间:2023年06月14日 10:21:12   作者:cxy930123  
众所周知,vue 的 mixins 是个非常灵活,但又很容易带来混乱的 API,Mixins 本该是一种强大的重用代码的手段,但使用之后往往带来更多的混乱,代码变得不易维护,本文就详细介绍Vue Mixin的正确用法,需要的朋友可以参考下

令人头疼的 mixin

众所周知,vue 的 mixins 是个非常灵活,但又很容易带来混乱的 API。不知道你是否像我一样,常常因为项目中用了 mixins 而感到头疼。比如说:

  • 来回切换文件:有人会因为文件太大而把一部分内容提取到单独的 mixin 中,看起来文件变小了,但改代码的时候需要在多个文件之间不停切换
  • 找不到函数和变量:模板中用到一个函数,在 methods 中搜索不到,然后发现组件引入了很多 mixins,不知道要该去哪里找

Mixins 本该是一种强大的重用代码的手段,但使用之后往往带来更多的混乱,代码变得不易维护。所以,在 Vue3 中,不再推荐使用 mixins,而是改用组合式 API的方式来重用代码。

那么,我们是不是不应该在日常代码中使用 mixins 呢?我觉得也不是。Mixins 是个强大的工具,但本身存在一些严重的问题,如果我们能把 mixins 中存在的问题解决掉,那剩下的就会是:强大。

为什么会这样?

面对 mixins 这样灵活的工具,我们必须理解它的问题所在,才能避免在使用时带来混乱。

本质上,mixins 是一种重用代码的手段,它可以向一个对象中注入另一个对象中的所有属性。并且,一个对象可以同时从多个不同对象中注入属性,所以非常灵活。而这样的灵活导致了一些致命的问题:

  • 来源不明:使用的 mixins 越多,越难找到某个属性或方法来自哪里
  • 无法精确引入:引入一个 mixin 时,会引入这个 mixin 的全部属性,因此很可能会引入一些用不到的东西,也会导致很难清楚知道到底引入了哪些属性和方法
  • 命名冲突:引入多个 mixins 时,引入的属性名可能会冲突
  • 耦合问题:不规范地使用 mixins 功能,可能会导致耦合问题,比如因为组件太大而抽离一部分属性到 mixins 中,这样产生的 mixins 一般会互相依赖,造成强耦合

作为对比,我们看看其他类似技术为什么没有这些问题:

  • ES模块:一个模块可以导出很多东西,但我们可以选择性导入,这样就能清楚知道导入了哪些内容,并且导入的变量和函数可以重命名,这样就解决了命名冲突的问题
  • Vue3组合式函数:Vue3 推荐使用组合式函数来替代 mixins 实现逻辑重用,组合式函数一般返回一个对象,解构时可以只取出对象中的部分属性,从而可以精确控制引入内容,并且解构语法支持自定义变量名,因此不会导致命名冲突

如果我们想要放心使用 mixins 功能,就必须解决以上问题。从 ES模块Vue3组合式函数 的设计,我们可以看出一些关键点,那就是需要能 精确控制引入的内容,具体包括:

  • 清晰看到引入的内容:在引入 mixins 的地方,可以直接看到引入了哪些属性和方法
  • 支持部分引入:可以只引入需要用到的属性,而不是引入 mixin 对象上的全部属性
  • 自定义引入的属性名:可以指定要引入的属性和方法的名字,避免命名冲突

这看起来似乎是不可能的,因为 mixin 就是一个对象,一旦引入就要接受这个对象上的所有属性和方法,也不可能在引入的时候去修改对象的属性名。

那还能不能用?

当然,你可以只使用生命周期钩子的功能,而不引入 data、计算属性和方法,这样就不会往实例上添加额外属性,也就不会有这些问题。但是,这会使 mixins 的功能大打折扣。

幸运的是,确实有一个方法能够精确控制引入的内容,那就是动态创建 mixin 对象。

一般来说,我们习惯把 mixin 定义为一个对象,然后在组件中直接引入。但其实只要把它定义成一个函数,问题就会得到解决。

我们可以把 mixin 定义成一个函数,通过函数参数接收需要引入的属性名,然后生成并返回真正的 mixin 对象。这样的 mixin 就是动态生成的。引入时,调用这个函数,通过传入的参数就可以精确控制引入的内容,可以指定要引入哪些属性,也可以指定引入的属性名字。

import mouse from '@/mixins/mouse'
export default {
  mixins: [
    mouse({
      mouseX: 'x',
      mouseY: 'y'
    })
  ]
}

我们给这种方法取一个不冲突的名字,就称为 动态Mixin 好了。

当然,这种写法增加了编写 mixins 的难度,所以我认为,mixins 适合用来引入一些简单的属性。比如,VueUse 中的那些工具方法就很适合使用动态 Mixin 来实现。

动态Mixin示例

接下来我列举一些自己在项目中经常使用的 mixins,大家可以体会一下这种动态 Mixin 的适用场景以及带来的好处。

倒计时

倒计时是业务中经常会用到的一种场景,比如发送验证码时一般会显示倒计时。然后有些使用须知的弹窗,确认按钮也会在倒计时结束后才允许点击。

这种倒计时非常简单,只需要一个记录当前剩余时间的属性,加上一个设置倒计时时长的函数。这种场景就非常适合使用 mixins 来实现。实现过程先不考虑,使用效果是这样的:

<template>
  <button :disabled="!!seconds" @click="setCountdown(60)">
    {{ seconds || '发送验证码' }}
  </button>
</template>
<script>
import countdown from '@/mixins/countdown';
export default {
  // 引入 seconds 属性存储剩余秒数
  // 引入 setCountdown 方法设置倒计时秒数
  mixins: [countdown('seconds', 'setCountdown')],
};
</script>

这个 mixins 引入了一个属性和一个方法,引入的内容都是可以指定名字的。调用 setCountdown 方法时会设置 seconds 属性的值,并重新开始倒计时。

不过在 Vue 中,我们可以充分利用 Vue 自带的响应式特性。我们可以利用 watch 去进行监听,在检测到 seconds 变化时,重新开始倒计时。这样就可以少引入一个方法。

<template>
  <button :disabled="!!seconds" @click="seconds = 60">
    {{ seconds || '发送验证码' }}
  </button>
</template>
<script>
import countdown from '@/mixins/countdown';
export default {
  // 引入 seconds 属性记录倒计时秒数
  mixins: [countdown('seconds')],
};
</script>

看,使用 mixins 之后,代码变得特别简洁清晰。而且只需要写一次,今后就可以在其他项目中直接使用这个 mixin。而如果不使用 mixins 自己实现,就需要多写很多代码,完善的写法每次还需要考虑怎么清除定时器,防止内存泄漏。

这个 mixin 的具体实现可以看这里:vue-library/mixins/countdown at master · web1706/vue-library · GitHub。你可以直接在你的项目中使用。

路由query参数

编写一个操作路由 query 参数的 mixin 其实是挺有必要的。

想象这样一个场景:页面上有一个 Tabs 组件,有多个页签。当我们切换页签时,一般会把当前激活的页签的值存储在 data 中。

export default {
  data() {
    return {
      // 当前 tab 页
      currentTab: 'one'
    }
  }
}

这样其实会有一个问题,就是刷新页面后,或者进入其他页面再返回时,是回不到之前的页签的。如果有一天需要改成刷新时保留激活的页签,最好的方法就是把页签值存入路由 query 中。这时如果有这样一个操作 query 参数的 mixin 就方便了。

import routeQuery from '@/mixins/route-query';
export default {
  mixins: [
    // 当前 tab 页
    routeQuery('currentTab'),
  ],
};

这个 mixin 会从 this.$route.query 中读取对应的参数值,放到名为 currentTab 的属性中。并且这个属性是可写的!写入时会自动调用 this.$router.replace 去替换 query 中的参数值。

当然,你可能还需要指定默认值,这也没问题,只需要改成对象形式:

import routeQuery from '@/mixins/route-query';
export default {
  mixins: [
    routeQuery({
      // 当前 tab 页
      currentTab: {
        default: 'one'
      }
    }),
  ],
};

或许,你想在 query 中使用一个不一样的参数名。

import routeQuery from '@/mixins/route-query';
export default {
  mixins: [
    routeQuery({
      // 当前 tab 页
      currentTab: {
        from: 'tab'
      },
      // 简写形式
      activeTab: 'tab'
    }),
  ],
};

想要使用数字类型也没问题。

export default {
  mixins: [
    routeQuery({
      // 对引入的属性值进行转换
      companyId: {
        type: Number,
      },
      // 简写形式
      deptId: Number,
    }),
  ],
};

可以看到,这个 mixin 非常灵活,功能也比传统 mixins 强大很多。

后记

本文介绍的这种使用函数动态生成 Mixin 的方式,大家觉得怎么样呢?大家平时又是如何看待和使用 Mixin 的呢?快来交流一下各自的想法吧。

以上就是Vue中Mixin的正确用法详解的详细内容,更多关于Vue Mixin用法的资料请关注脚本之家其它相关文章!

相关文章

  • Vue封装全局toast组件的完整实例

    Vue封装全局toast组件的完整实例

    组件(Component)是 Vue.js 最强大的功能之一,组件可以扩展 HTML 元素,封装可重用的代码,这篇文章主要给大家介绍了关于Vue封装全局toast组件,需要的朋友可以参考下
    2021-07-07
  • Vue 3 中 h 方法示例详解

    Vue 3 中 h 方法示例详解

    Vue3中的h方法用于创建虚拟DOM节点,是渲染函数的核心,它接受三个参数:type(节点类型)、props(属性对象)和children(子节点),通过示例展示了如何使用h方法创建简单的HTML元素、带有属性的元素、嵌套元素和自定义组件,感兴趣的朋友一起看看吧
    2025-03-03
  • vue首次赋值不触发watch的解决方法

    vue首次赋值不触发watch的解决方法

    今天小编就为大家分享一篇vue首次赋值不触发watch的解决方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2018-09-09
  • 在Vue中使用SQLite数据库的基础应用详解

    在Vue中使用SQLite数据库的基础应用详解

    这篇文章主要为大家详细介绍了在Vue中使用SQLite数据库的基础应用,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下
    2025-02-02
  • 基于vue写一个全局Message组件的实现

    基于vue写一个全局Message组件的实现

    这篇文章主要介绍了基于vue写一个全局Message组件的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-08-08
  • nuxt.js服务端渲染中axios和proxy代理的配置操作

    nuxt.js服务端渲染中axios和proxy代理的配置操作

    这篇文章主要介绍了nuxt.js服务端渲染中axios和proxy代理的配置操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-11-11
  • VUE+Canvas实现财神爷接元宝小游戏

    VUE+Canvas实现财神爷接元宝小游戏

    这篇文章主要介绍了VUE+Canvas实现财神爷接元宝小游戏,需要的朋友可以参考下本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧
    2021-04-04
  • vue实现跨域的方法分析

    vue实现跨域的方法分析

    这篇文章主要介绍了vue实现跨域的方法,结合实例形式分析了vue.js跨域的原理与相关实现技巧,需要的朋友可以参考下
    2019-05-05
  • Vue3 Echarts通用的折线图带阴影效果实现

    Vue3 Echarts通用的折线图带阴影效果实现

    在环保仓管项目中,做了一个每月对药品、消耗品、设备的进出,进行统计百分比,效果好看,后面经常在用这个样式,下面通过示例代码分享Vue3 Echarts通用的折线图带阴影效果实现,感兴趣的朋友一起看看吧
    2024-07-07
  • vue3中addRoute路由变化页面未刷新问题解决

    vue3中addRoute路由变化页面未刷新问题解决

    这篇文章主要为大家介绍了vue3中addRoute路由变化但页面未刷新问题解决,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-06-06

最新评论