vue.js

关注公众号 jb51net

关闭
首页 > 网络编程 > JavaScript > javascript类库 > vue.js > Vue Mixin用法

Vue中Mixin的正确用法详解

作者:cxy930123

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

令人头疼的 mixin

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

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

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

为什么会这样?

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

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

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

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

这看起来似乎是不可能的,因为 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用法的资料请关注脚本之家其它相关文章!

您可能感兴趣的文章:
阅读全文