美文网首页
在 Vue.js 中使用Mixins

在 Vue.js 中使用Mixins

作者: Sunny_MYJ | 来源:发表于2019-03-09 10:00 被阅读0次

原文链接: Using Mixins in Vue.js
vue文档: mixins文档链接

一个很常见场景:
你有两个非常相似的组件, 它们拥有非常相似的基本功能, 但是它们之间又有足够的不同的地方, 该如何选择呢? 我们是应该将它们分成两个完全不同的组件呢? 还是创建一个基础组件, 然后定义足够多的props以方便区分使用场景?
这两种方式都不是完美的: 如果你将它们分成两个完全不同的组件, 在需求变化(功能变化)时, 可能会增加需要同时修改两个组件的风险, 这违反了"DRY"的前提. 另一方面, 太多的props很快会让人变得凌乱, 并且, 迫使维护人员, 甚至是你自己, 要首先理解这些props的上下文才能使用它, 这会让人非常失望.
VueMixins是非常实用的编程方式, 因为最终实用的编程是通过不断减少运动部件(moving parts)使代码变得容易理解.一个mixin允许你封装一个功能, 以便你能在整个应用程序中的不同组件中使用它.

基础实例

假设我们有一些不同的组件, 它们的工作是切换状态boolean, 一个模态(modal)和一个提示(tooltip). 这些tooltipsmodals没有很多共同之处, 除了这个功能: 它们看起来不一样, 它们使用起来也不尽相同, 但是它们的逻辑是相似的.

//modal
const Modal = {
  template: '#modal',
  data() {
    return {
      isShowing: false
    }
  },
  methods: {
    toggleShow() {
      this.isShowing = !this.isShowing;
    }
  },
  components: {
    appChild: Child
  }
}

//tooltip
const Tooltip = {
  template: '#tooltip',
  data() {
    return {
      isShowing: false
    }
  },
  methods: {
    toggleShow() {
      this.isShowing = !this.isShowing;
    }
  },
  components: {
    appChild: Child
  }
}

我们可以从中提取逻辑, 并创建可以复用的部分:(在CODEPEN中查看效果)

const toggle = {
  data() {
    return {
      isShowing: false
    }
  },
  methods: {
    toggleShow() {
      this.isShowing = !this.isShowing;
    }
  }
}

const Modal = {
  template: '#modal',
  mixins: [toggle],
  components: {
    appChild: Child
  }
};

const Tooltip = {
  template: '#tooltip',
  mixins: [toggle],
  components: {
    appChild: Child
  }
};

查看 Sarah Drasner(@sdras) 在CodePen上编写 混合的例子

为了更容易理解混合,这个例子故意编写的简单一些。真实应用中使用混合的有,包含但不限于:获取视窗和组件的尺寸,采集特定的鼠标事件和图表的基本元素。

使用

您可以设置您的目录结构以任何您喜欢的方式, 但我喜欢创建一个单独的mixin目录以方便管理它们. 我们将创建的文件将具有".js"扩展名(而不是.vue, 就像我们其他的文件), 然后我们将导出(export)一个对象为mixin:


v2-496d78156ff3ee6174173a6030687f8a_hd.png

然后, 在modal.vue里, 我们可以通过import刚才的toggle来访问它, 就像这样:

import { toggle } from './mixins/toggle'

export default {
  name: 'modal',
  mixins: [toggle],
  components: {
    appChild: Child
  }
}

很重要的需要意识到的一点是, 尽管如此, 我们使用的是一个对象(object)而不是一个组件(component), 生命周期(lifecycle)内的方法(methods)是可用的. 我们可以挂载(hook)到mounted(), 这样它就会被应用于组件的生命周期, 使得这种方法非常的灵活和强大

合并(Merging)

看看最后一个例子, 我们发现, 我们不仅仅拥有我们的功能, 生命周期的钩子(hooks)也可用于mixin, 所以, 当我们将它应用与具有重叠进程(overlapping processes)的时候, 顺序很重要. 默认情况下, mixins将首先被调用, 然后是组件, 所以我们可以根据需要来覆盖它(override). 就是说, 组件有最后的发言权. 这只有当冲突发生时才变得非常重要, 在这个时候, 组件必须决定哪一个胜出, 否则一切将被放置在一个数组中执行, mixins相关的放在前面, 然后是组件相关的.

//mixin
const hi = {
  mounted() {
    console.log('hello from mixin!')
  }
}

//vue instance or component
new Vue({
  el: '#app',
  mixins: [hi],
  mounted() {
    console.log('hello from Vue instance!')
  }
});

//Output in console
> hello from mixin!
> hello from Vue instance!

如果两个冲突, Vue实例和组件将胜出:

//mixin
const hi = {
  methods: {
    sayHello: function() {
      console.log('hello from mixin!')
    }
  },
  mounted() {
    this.sayHello()
  }
}

//vue instance or component
new Vue({
  el: '#app',
  mixins: [hi],
  methods: {
    sayHello: function() {
      console.log('hello from Vue instance!')
    }
  },
  mounted() {
    this.sayHello()
  }
})

// Output in console
> hello from Vue instance!
> hello from Vue instance!

您可能已经注意到, 在Vue实例中, 我们有两个console.log打印而不是一个. 这是因为, mixin解析以后, 在Vue实例中的mounted()里面会有两个this.sayHello()调用, 但是由于mixin中的sayHello函数会在Vue实例的sayHello函数之前, 因此被Vue实例中的sayHello函数覆盖了. 所以, mounted()中调用的两次sayHello实际上都是Vue实例中的sayHello函数.

全局Mixins

当我们使用术语global参考mixins时, 我们不是指能够在每个组件访问它们, 就像过滤器一样. 我们已经可以在组件中访问mixins以这种方式: mixins: [toggle].

Global mixins如字面上的意思一样, 会被应用于所有的组件. 因此, 它们的用例非常有限, 应该慎重考虑. 我可以想到的能够合理使用的一个场景是像插件一样的东西, 你可能需要访问一切. 但是, 即使在这种情况下, 我也会对您正在应用的内容感到担心, 特别是当您将功能扩展到可能是黑匣子的应用程序时.

要创建全局实例, 我们应将其放在Vue实例之前. 在典型的Vue-cli构建中, 这将在您的main.js文件中.

Vue.mixin({
  mounted() {
    console.log('hello from mixin!')
  }
})

new Vue({
  ...
})

还是那句话, 谨慎使用这种方式的mixin! 现在, mixin中的console.log将会出现在每一个单独的组件中. 在这种情况下还不是很糟(除了控制台里面多了许多噪音外). 但是您会发现, 如果使用不当, 将会带来多大的危害.

结论

混合对于封装一小段想要复用的代码来讲是有用的。对你来说它们当然不是唯一可行的选择:高阶组件,例如,允许组合相似函数,这只是实现的一种方式。我喜欢混合,因为我不需要传递状态,但是这种模式当然也可能会被滥用,所以,仔细思考哪种选择对你的应用最有意义。

相关文章

网友评论

      本文标题:在 Vue.js 中使用Mixins

      本文链接:https://www.haomeiwen.com/subject/gnhhuqtx.html