Vue 之 Mixins (混入)和extend

Vue 之 Mixins (混入)

Mixins

Mixins是一种分发Vue组件中可复用功能的非常灵活的一种方式。

什么时候使用Mixins

页面的风格不用,但是执行的方法和需要的数据类似,我们是选择每个都写呢还是提取出公共部分呢?

基础实例

我们有一对不同的组件,它们的作用是切换一个状态布尔值,一个模态框和一个提示框。这些提示框和模态框除了在功能上,没有其他共同点:它们看起来不一样,用法不一样,但是逻辑一样。

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

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

解决办法如下:

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

// 下面即可使用了
// mixins: [变量名]

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

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

选项合并

当组件和混入对象含有同名选项时,这些选项会以恰当的方式混合。 比如数据对象在内部会进行浅合并(一层属性的深度),在和组件的数据发生冲突时,以组件数据优先。

var mixin = {
  data() {
    return {
      msg_mixins: 'mixins',
      msg: '123'
    }
  }
}

var app = new Vue({
  el: '#app',
  mixins: [mixin],
  data: {
    msg: 'app'
  },
  created: function ( ) {
    console.log(this.$data)
    // => { "msg": "app", "msg_mixins": "mixins" }
  }
})

同名的钩子函数将混合为一个数组,所以都会被调用,另外,混入对象的钩子函数会在组件自身的钩子函数之前先进行调用。

var mixin = {
  data() {
    return {
      msg_mixins: 'mixins',
      msg: '123'
    }
  },
  created: function ( ) {
    console.log('混入对象的钩子被调用')
  }
}

var app = new Vue({
  mixins: [mixin],
  el: '#app',
  data: {
    msg: 'app'
  },
  created: function ( ) {
    console.log('组件钩子被调用')
  }
})
混入对象的钩子被调用
组件钩子被调用
vue.js:9058 You are running Vue in development mode.
Make sure to turn on production mode when deploying for production.
See more tips at https://vuejs.org/guide/deployment.html

当混合值为对象的选项,例如 methods,components,directive,将被混合为同一个对象,两个对象键名冲突时,取组件的。

混入对象的钩子被调用
merge3.html:47 组件钩子被调用
vue.js:9058 You are running Vue in development mode.
Make sure to turn on production mode when deploying for production.
See more tips at https://vuejs.org/guide/deployment.html
app.foo
ƒ () {
          console.log('foo')
        }
app.foo
ƒ () {
          console.log('foo')
        }
app.conflicting
ƒ () {
          console.log('from self')
        }

注意:Vue.extend() (扩展)也使用同样的策略进行合并。

全局混入

我们也可以进行全局注册混入对象,注意使用。一旦使用全局混入对象,将会影响所有你创建的 vue 实例,如果使用恰当可以对自定义的对象注入逻辑。比如全局的判断等,会方便一些,不需要每个页面判断,直接取值就行了。

Vue.mixin({
  created: function ( ) {
      console.log('全局混入')
  }
})

var mixin = {
  data() {
    return {
      msg_mixins: 'mixins',
      msg: '123'
    }
  },
  created: function ( ) {
    console.log('混入对象的钩子被调用')
  },
  methods: {
    foo: function ( ) {
      console.log('foo')
    },
    conflicting: function ( ) {
      console.log('from mixin')
    }
  }
}

var app = new Vue({
  mixins: [mixin],
  el: '#app',
  data: {
    msg: 'app'
  },
  created: function ( ) {
    console.log('组件钩子被调用')
  },
  methods: {
    bar: function ( ) {
      console.log('bar')
    },
    conflicting: function ( ) {
      console.log('from self')
    }
  }
})
全局混入
mixin.html:34 混入对象的钩子被调用
mixin.html:53 组件钩子被调用
vue.js:9058 You are running Vue in development mode.
Make sure to turn on production mode when deploying for production.
See more tips at https://vuejs.org/guide/deployment.html

谨慎使用全局混入对象,因为会影响到每个单独创建的 Vue 实例 (包括第三方模板)。大多数情况下,只应当应用于自定义选项。也可以将其用作 Plugins 以避免产生重复应用。

自定义选项合并策略

自定义选项使用默认策略,就是简单的覆盖默认值。如果想让自定义选项以自定义的逻辑合并, 可以向 Vue.config.optionMergeStrategies 添加一个函数:

Vue.config.optionMergeStrategies.myOption = function (toVal, fromVal) {
  // 返回合并后的值
}

也就是说,本来的选项的合并方式是默认的,但是我们可以通过修改添加一个函数,来修改合并的方式逻辑。

对于大多数的合并策略来说,可以使用 methods:

var strategies = Vue.config.optionMergeStrategies
strategies.myOption = strategies.methods

可以在 Vuex 1.x 的混入策略里找到一个更高级的例子:

const merge = Vue.config.optionMergeStrategies.computed
Vue.config.optionMergeStrategies.vuex = function (toVal, fromVal) {
  if (!toVal) return fromVal
  if (!fromVal) return toVal
  return {
    getters: merge(toVal.getters, fromVal.getters),
    state: merge(toVal.state, fromVal.state),
    actions: merge(toVal.actions, fromVal.actions)
  }
}

extend

在vue3的官方文档中,是这样说的:

从实现的角度看,extends 几乎等同于 mixins。可以认为其作为第一个 mixin 作用在被 extends 的组件上。

然而,extends 和 mixins 表达了不同的意图。mixins 选项主要用来组合功能,而 extends 主要用来考虑继承性。

和 mixins 类似,任何选项都会通过对应的合并策略被合并

<div id="mount-point"></div>
// 创建构造器
var Profile = Vue.extend({
  template: '<p>{{firstName}} {{lastName}} aka {{alias}}</p>',
  data: function () {
    return {
      firstName: 'Walter',
      lastName: 'White',
      alias: 'Heisenberg'
    }
  }
})
// 创建 Profile 实例,并挂载到一个元素上。
new Profile().$mount('#mount-point')

  

posted @ 2020-03-04 17:21  太阳锅锅  阅读(831)  评论(0编辑  收藏  举报