第980期在Vue.js中使用Mixins

Posted 前端早读课

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了第980期在Vue.js中使用Mixins相关的知识,希望对你有一定的参考价值。

前言

今日早读文章由 @ 池盛星翻译投稿分享。

正文从这开始~

一个很常见的场景: 你有两个非常相似的组件, 它们拥有非常相似的基本功能, 但是它们之间又有足够的不同的地方, 该如何选择呢? 我们是应该将它们分成两个完全不同的组件呢? 还是创建一个基础组件, 然后定义足够多的props以方便区分使用场景?

这两种方式都不是完美的: 如果你将它们分成两个完全不同的组件, 在需求变化(功能变化)时, 可能会增加需要同时修改两个组件的风险, 这违反了"DRY"的前提. 另一方面, 太多的props很快会让人变得凌乱, 并且, 迫使维护人员, 甚至是你自己, 要首先理解这些props的上下文才能使用它, 这会让人非常失望.

Vue的Mixins是非常实用的编程方式, 因为最终实用的编程是通过不断减少运动部件(moving parts)使代码变得容易理解. (关于这一点, Michael Feathers有一个很好的引用). 一个mixin允许你封装一个功能, 以便你能在整个应用程序中的不同组件中使用它. 如果mixin被正确的创建, 它们是纯粹的--它们不会修改或更改函数的作用范围(scope)之外的内容, 因此, 您可以在多个地方执行它们, 并且只要输入值相同, 总是能非常可靠得得到相同的结果. 这真的非常强大.

基本的例子

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

//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
 }
};




这个例子有意保持小而简单, 是我找到的在实际的应用程序中非常有用的关于mixins的易读的例子包括但不限于: 获取viewport和组件的维度, 收集特定的mousemove events, 以及基本的图表元素. Paul Pflugradt有一个非常不错的关于Vue Mixins的repo, 值得注意的是, 它们是用coffeescript所写的.

使用

这个Pen并没有真正的告诉我们如何在一个真正的应用程序中设置它, 所以, 让我们来看看:

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



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

import Child from './Child'
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将会出现在每一个单独的组件中. 在这种情况下还不是很糟(除了控制台里面多了许多噪音外). 但是您会发现, 如果使用不当, 将会带来多大的危害.

结论

Mixins对于封装一些可复用的功能非常实用. 它们当然不是您唯一可用的选项: 高阶组件(higher order components), 例如, 允许您组合类似的功能, 这只是一种工作方式. 我喜欢mixins, 是因为我们不需要到处传递状态(state), 但是, 这种模式当然也可以被滥用, 所以请仔细考虑哪个选项对您的应用程序是最有意义的 .

关于本文

译者:@池盛星

译文:https://zhuanlan.zhihu.com/p/27547999

原文:https://css-tricks.com/using-mixins-vue-js

以上是关于第980期在Vue.js中使用Mixins的主要内容,如果未能解决你的问题,请参考以下文章

vue.js 中的mixins 的用法

vue.js 中的mixins 的用法

vue.js基础__ mixins 选项

Vue Js如何在单个文件模板中使用mixins?

Vue.js 基础学习之混合mixins

有没有更好的方法或在 vue.js 中导入 mixins