混入策略

Vue 允许自定义混入策略,通过 Vue.config.optionMergeStrategies 配置选项的合并方式。

默认合并策略

Vue 内置了几种合并策略:

const strats = Vue.config.optionMergeStrategies

strats.data
strats.created
strats.methods
strats.computed
strats.watch

自定义合并策略

基本语法

Vue.config.optionMergeStrategies.myOption = function(toVal, fromVal) {
  return mergedValue
}

参数说明:

  • toVal:目标值(通常是组件选项)
  • fromVal:来源值(通常是混入选项)
  • 返回合并后的值

自定义选项合并

Vue.config.optionMergeStrategies.customOption = function(toVal, fromVal) {
  if (!toVal) return fromVal
  if (!fromVal) return toVal
  return toVal + ',' + fromVal
}

const mixin = {
  customOption: 'mixin'
}

new Vue({
  mixins: [mixin],
  customOption: 'component',
  created() {
    console.log(this.$options.customOption)
  }
})

输出:component,mixin

使用默认策略

Vue.config.optionMergeStrategies.myMethod = Vue.config.optionMergeStrategies.methods

合并为数组

类似钩子函数的合并策略:

Vue.config.optionMergeStrategies.myHook = function(toVal, fromVal) {
  return toVal
    ? fromVal
      ? toVal.concat(fromVal)
      : toVal
    : fromVal
}

实际应用示例

插件配置合并

Vue.config.optionMergeStrategies.pluginConfig = function(toVal, fromVal) {
  return {
    ...fromVal,
    ...toVal
  }
}

const mixin = {
  pluginConfig: {
    theme: 'dark',
    locale: 'en'
  }
}

new Vue({
  mixins: [mixin],
  pluginConfig: {
    theme: 'light',
    debug: true
  },
  created() {
    console.log(this.$options.pluginConfig)
  }
})

输出:

{
  theme: 'light',
  locale: 'en',
  debug: true
}

权限配置合并

Vue.config.optionMergeStrategies.permissions = function(toVal, fromVal) {
  const merged = new Set()
  
  if (fromVal) {
    fromVal.forEach(p => merged.add(p))
  }
  if (toVal) {
    toVal.forEach(p => merged.add(p))
  }
  
  return Array.from(merged)
}

const mixin = {
  permissions: ['read', 'write']
}

new Vue({
  mixins: [mixin],
  permissions: ['read', 'delete'],
  created() {
    console.log(this.$options.permissions)
  }
})

输出:['read', 'write', 'delete']

事件处理合并

Vue.config.optionMergeStrategies.eventHandlers = function(toVal, fromVal) {
  if (!toVal) return fromVal
  if (!fromVal) return toVal
  
  const merged = { ...fromVal }
  for (const key in toVal) {
    if (merged[key]) {
      merged[key] = [merged[key], toVal[key]].flat()
    } else {
      merged[key] = toVal[key]
    }
  }
  return merged
}

调试合并结果

Vue.config.optionMergeStrategies.debug = function(toVal, fromVal) {
  console.log('toVal:', toVal)
  console.log('fromVal:', fromVal)
  const result = { ...fromVal, ...toVal }
  console.log('merged:', result)
  return result
}

完整示例

<!DOCTYPE html>
<html>
<head>
  <script src="https://cdn.jsdelivr.net/npm/vue@2.7.14/dist/vue.js"></script>
</head>
<body>
  <div id="app">
    <p>Theme: {{ theme }}</p>
    <p>Permissions: {{ permissions.join(', ') }}</p>
  </div>

  <script>
    Vue.config.optionMergeStrategies.theme = function(toVal, fromVal) {
      return toVal || fromVal
    }
    
    Vue.config.optionMergeStrategies.permissions = function(toVal, fromVal) {
      const merged = new Set()
      if (fromVal) fromVal.forEach(p => merged.add(p))
      if (toVal) toVal.forEach(p => merged.add(p))
      return Array.from(merged)
    }
    
    const mixin = {
      theme: 'dark',
      permissions: ['read', 'write'],
      data() {
        return {
          theme: this.$options.theme,
          permissions: this.$options.permissions
        }
      }
    }
    
    new Vue({
      el: '#app',
      mixins: [mixin],
      theme: 'light',
      permissions: ['read', 'delete']
    })
  </script>
</body>
</html>

策略选择指南

需求推荐策略
简单覆盖组件优先
都要执行合并为数组
深度合并递归合并对象
去重合并使用 Set

注意事项

  1. 在 Vue 实例化前配置:合并策略必须在创建实例前定义
  2. 保持一致性:自定义策略应与 Vue 内置策略风格一致
  3. 文档说明:为自定义策略添加注释说明
  4. 测试覆盖:确保合并策略在各种情况下正确工作

自定义混入策略提供了灵活的选项合并方式,但大多数情况下,使用默认策略已经足够。