前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Vue 组件扩展

Vue 组件扩展

作者头像
奋飛
发布2019-08-14 18:03:21
1.2K0
发布2019-08-14 18:03:21
举报
文章被收录于专栏:Super 前端Super 前端

最近,新项目架构搭建在扩展组件的场景中:图表使用了extends方式,而公共业务server和view之间使用了mixins方式。对于二者的选择,我们通常会解释为extends的优先级高于mixins,但其真实的差异是由于其合并策略不同或者说在合并策略中执行的顺序不同导致的 – 源码

下述,简单阐述Vue中涉及到组件扩展的相关API及自定义合并策略等相关内容

定义公共基础的组件配置模板,下述示例使用

代码语言:javascript
复制
const BaseComponent = {
    name: 'BaseComponent',
    template: `<div>{{message}}</div>`,
    data () {
        return {
            message: 'My is BaseComponent!'
        }
    },
    created () {
        console.log(`BaseComponent ${this.message}`)
    }
}

Vue.extend( options )

返回的是一个“扩展实例构造器”,也就是一个预设了部分选项的 Vue 实例构造器,方便创建可复用的组件。参数是一个包含组件选项的对象,其中data必须为函数。

代码语言:javascript
复制
<div id="app"></div>
<script>
    const HelloWorld = Vue.extend(BaseComponent)
    // 创建 HelloWorld 实例,并挂载到一个元素上。
    new HelloWorld().$mount('#app')
</script>

Vue.extend 是构造一个组件的语法器。可以作用到 Vue.component 中;也可以作用到 vue 实例或者某个组件中的 components 属性。

示例1:作用于 Vue.component 中,其为全局注册,也就是说它们在注册之后可以用在任何新创建的 Vue 根实例 ( new Vue ) 的模板中

代码语言:javascript
复制
Vue.component('myBase', BaseComponent)

示例2: 作用于某组件中

代码语言:javascript
复制
const base = Vue.extend(BaseComponent)

上述两者都可以生效:

代码语言:javascript
复制
<div id="app">
	<my-base></my-base>
    <base-component></base-component>
</div>
<script>
	new Vue({
		el: '#app',
	  	components: {
	    	baseComponent: base
	  	}
	})
</script>
Vue.component() & Vue.extend(options) 区别:

前者创建的是组件(组件是可复用的 Vue 实例),后者创建的是组件构造器。Vue.component('my-component', { /* ... */ }) 注册组件,传入一个选项对象 (自动调用 Vue.extend)

代码语言:javascript
复制
// 注册组件,传入一个扩展过的构造器
Vue.component('my-component', Vue.extend({ /* ... */ }))
// 注册组件,传入一个选项对象 (自动调用 Vue.extend)
Vue.component('my-component', { /* ... */ })
// 获取已注册的组件 (始终返回构造器)
var MyComponent = Vue.component('my-component')

Vue.mixin( mixin )

全局注册一个混入,影响注册之后所有创建的每个 Vue 实例。使用恰当时,可以为自定义对象注入处理逻辑。但不推荐在应用代码中使用。因为会影响到每个单独创建的 Vue 实例 (包括第三方模板)!

代码语言:javascript
复制
Vue.mixin({
	created () {
	  var myOption = this.$options.myOption
	  if (myOption) {
	    console.log(myOption)
	  }
	}
})
new Vue({
	myOption: 'hello!'
})

vm.$options 用于当前 Vue 实例的初始化选项。需要在选项中包含自定义属性时会有用处。

代码语言:javascript
复制
new Vue({
	customOption: 'foo',
   	created: function () {
    	console.log(this.$options.customOption) // => 'foo'
   	}
})

同时,其也可以获取Vue内部的一些初始选项,如在自动销毁的vue event Bus可以使用到:

代码语言:javascript
复制
// 当前调用组件的 destroyed 钩子
const destroyed = vm.$options.destroyed
// 为当前组件destroyed钩子增加销毁方法
!destroyed.includes(destroyHandler) && destroyed.push(destroyHandler)

extends

允许声明扩展另一个组件(可以是一个简单的选项对象或构造函数),而无需使用 Vue.extend。这主要是为了便于扩展单文件组件。

代码语言:javascript
复制
const vm = new Vue({
    el: '#app',
    extends: BaseComponent,
    data () {
        return {
            message: 'My is Mixins!'
        }
    },
    created: function () {
        console.log(`mixins ${this.message}`)
    }
})
代码语言:javascript
复制
# DOM展示
My is Mixins! 
# 控制台输出结果:
BaseComponent My is Mixins!
mixins My is Mixins!

mixins

接受一个混入对象的数组。这些混入实例对象可以像正常的实例对象一样包含选项,他们将在 Vue.extend() 里最终选择使用相同的选项合并逻辑合并。

代码语言:javascript
复制
const vm = new Vue({
    el: '#app',
    mixins: [BaseComponent],
    data () {
        return {
            message: 'My is Mixins!'
        }
    },
    created: function () { 
       console.log(`mixins ${this.message}`)
    }
})

输出结果和extends一致!!!

extends和mixins的区别
代码语言:javascript
复制
let myMixin = {
    data () {
        return {
            message: 'local mixin'
        }
    },
    created () {
        console.log('local mixin')
    }
}
let myExtend = {
    data () {
        return {
            message: 'local extend'
        }
    },
    created () {
        console.log('local extend')
    }
}
new Vue({
    el: '#app',
    extends: myExtend,
    mixins: [myMixin],
    template: `<div>{{message}}</div>`,
    created () {
        console.log('current Vue instance')
    }
})
代码语言:javascript
复制
# DOM展示
local mixin
# 控制台输出结果
Vue.mixin
local extend
local mixin
current Vue instance
Vue合并策略
Vue合并策略

通过Vue的 源码 可知,extends 优先于 mixins 进行合并,所以会先执行 extends 的 created,但是对于相同的data属性,后面的会覆盖前面的!这些都是由合并策略所决定的!!!

合并策略

代码语言:javascript
复制
/**
 * Default strategy.
 */
const defaultStrat = function (parentVal: any, childVal: any): any {
  return childVal === undefined
    ? parentVal
    : childVal
}

上述代码为Vue源码中关于策略合并的默认配置。子组件为主,子组件存在则使用子组件的,否则使用父组件的!!!

下述根据Vue源码,说明各个属性的合并策略,具体可以通过后面的链接查看Vue源码!

  • options.el 合并策略就是默认的合并策略,即以子组件的选项为主,子组件的选项不存在时,才使用父组件的。源码地址
  • options.data 子组件没有响应的属性则使用父组件的,否则子组件的会覆盖父组件的! 源码地址
  • options.props options.methods options.computed 先拓展的是 parentVal 对象,然后再拓展 childVal 对象,存在相同的 childVal 会覆盖 parentVal 值。源码地址
  • options.hook 父组件和子组件都设置了钩子函数选项,那么它们会合并到一个数组里,而且父组件的钩子函数会先执行,最后返回一个合并后的数组。 源码地址
  • options.components options.directives options.filters 合并的策略就是返回一个合并后的新对象,新对象的自有属性全部来自 childVal,但是通过原型链委托在了 parentVal 上。事实上,和 defaultStrat 一个道理。源码地址
  • options.watch 相同属性会做合并处理,父组件在前,子组件在后。源码地址
自定义合并策略

通过查看 源码,我们可以发现所有的策略都是依赖strats进行的,也就是基于config.optionMergeStrategies完成的。

代码语言:javascript
复制
/**
 * Option overwriting strategies are functions that handle
 * how to merge a parent option value and a child option
 * value into the final value.
 */
const strats = config.optionMergeStrategies

Vue提供了自定义合并策略的选项的API,optionMergeStrategies 合并策略选项分别接收在父实例和子实例上定义的该选项的值作为第一个和第二个参数,Vue 实例上下文被作为第三个参数传入。

optionMergeStrategies
optionMergeStrategies

示例: 修改默认合并策略

代码语言:javascript
复制
new Vue({
    el: '#app',
    mixins: [{
        created () {
            console.log(`BaseComponent`)
        }
    }],
    created () {
        console.log('this instance')
    }
})

由上述总结的默认合并策略可知,hook 会合并到一个数组中,且父组件优先执行,因此输出结果为:

代码语言:javascript
复制
BaseComponent
this instance

修改合并策略

代码语言:javascript
复制
Vue.config.optionMergeStrategies.created = function (parentVal, childVal) {
    return Array.isArray(childVal) ? childVal : [childVal]
}

再次执行上述代码,可发现只输出 this instance 。合并策略已被修改!对于Vue内部定义的策略强烈不建议进行修改!!!

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2018年06月18日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Vue.extend( options )
    • Vue.component() & Vue.extend(options) 区别:
    • Vue.mixin( mixin )
    • extends
    • mixins
      • extends和mixins的区别
      • 合并策略
        • 自定义合并策略
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档