Vue Mixin 的理解与应用

Vue 中 mixin 的概念、使用方式和合并策略

问题

如何理解 Vue 的 mixin,以及它的应用场景?

解答

什么是 Mixin

Mixin 是一种代码复用机制。在 Vue 中,mixin 是一个包含组件选项的 JavaScript 对象,可以包含 data、methods、computed、生命周期钩子等任意选项。当组件使用 mixin 时,mixin 的选项会被混入到组件自身的选项中。

局部混入

定义一个 mixin 对象:

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

在组件中使用:

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

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

全局混入

通过 Vue.mixin() 进行全局混入:

Vue.mixin({
  created() {
    console.log("全局混入")
  }
})

注意:全局混入会影响每一个组件实例(包括第三方组件),需谨慎使用。常用于插件开发。

合并规则

当组件和 mixin 存在相同选项时:

数据对象合并:组件数据优先,递归合并。

// mixin 的 data
{ msg: 'mixin', count: 1 }

// 组件的 data
{ msg: 'component' }

// 合并结果
{ msg: 'component', count: 1 }

生命周期钩子合并:合并为数组,mixin 钩子先执行。

// 执行顺序:mixin created -> 组件 created

其他选项:组件选项覆盖 mixin 选项。

应用场景

当多个组件需要相同或相似的功能时,可以使用 mixin 提取公共逻辑。例如,多个组件都需要控制显示/隐藏状态:

// 提取公共逻辑
const toggleMixin = {
  data() {
    return {
      isShowing: false
    }
  },
  methods: {
    toggleShow() {
      this.isShowing = !this.isShowing;
    }
  }
}

// 在不同组件中复用
const Modal = {
  mixins: [toggleMixin],
  // 组件特有逻辑
}

const Dropdown = {
  mixins: [toggleMixin],
  // 组件特有逻辑
}

合并策略源码分析

Vue 对不同类型的选项采用不同的合并策略:

替换型(props、methods、computed):后者替换前者。

strats.props = strats.methods = strats.computed = function (parentVal, childVal) {
  if (!parentVal) return childVal
  const ret = Object.create(null)
  extend(ret, parentVal)
  if (childVal) extend(ret, childVal)
  return ret
}

合并型(data):递归合并对象属性。

strats.data = function(parentVal, childVal, vm) {
  return mergeDataOrFn(parentVal, childVal, vm)
}

队列型(生命周期钩子、watch):合并为数组,顺序执行。

function mergeHook (parentVal, childVal) {
  return childVal
    ? parentVal
      ? parentVal.concat(childVal)
      : Array.isArray(childVal)
        ? childVal
        : [childVal]
    : parentVal
}

叠加型(components、directives、filters):通过原型链叠加。

strats.components = strats.directives = strats.filters = function (parentVal, childVal) {
  const res = Object.create(parentVal || null)
  if (childVal) {
    for (const key in childVal) {
      res[key] = childVal[key]
    }
  }
  return res
}

关键点

  • Mixin 是一个包含组件选项的对象,用于提取和复用组件间的公共逻辑
  • 支持局部混入(组件的 mixins 选项)和全局混入(Vue.mixin),全局混入需谨慎使用
  • 选项合并遵循不同策略:数据对象递归合并组件优先,生命周期钩子合并为数组依次执行,其他选项组件覆盖 mixin
  • 适用于多个组件共享相同功能的场景,如通用的状态管理、权限检查、日志记录等
  • Vue 3 推荐使用 Composition API 替代 mixin,避免命名冲突和来源不清晰的问题