目录
- Vue.extend()只是创建一个构造器,为了创建可复用的组件;
- Vue.component() 创建或者获取组件;
- mixins,extedns是为了扩展组件;
1,mixins混入
参考mixins混入官方文档和例子
混入 (mixin) :分发 Vue 组件中的可复用功能。一个混入对象可以包含任意组件选项。当组件使用混入对象时,所有混入对象的选项将被“混合”进入该组件本身的选项。
- 方法和参数在各组件中不共享
- 值为
对象
的选项,如methods,components等,选项会被合并,键冲突的组件会覆盖混入对象
的 - 值为
函数
的选项,如created,mounted等,就会被合并调用,混合对象里的钩子函数在组件里的钩子函数之前
调用 - 4、全局混入和局部混入
mixins混入案例—elementUI源码broadcast与dispatch
elementUI源码以局部混入minix的方式引入, 实现多层级分发对应事件的组件间通信: broadcast与dispatch
/src/mixins/emitter.js文件
function broadcast(componentName, eventName, params) {
this.$children.forEach(child => {
... ...
broadcast.apply(child, [componentName, eventName].concat([params]));
});
}
export default {
methods: {
dispatch(componentName, eventName, params) {
... ...
if (parent) { parent.$emit.apply(parent, [eventName].concat(params)); }
},
broadcast(componentName, eventName, params) {
broadcast.call(this, componentName, eventName, params);
}
}
};
局部混入引进
import Emitter from 'element-ui/src/mixins/emitter';
export default{
mixins: [Emitter],
mounted(){
this.broadcast('ElDropdownMenu', 'visible', val);
}
}
以全局混入minix的方式,分发Action请求使用:this.dispatchAction('getBusinessList', params)
;
Vue.mixin({
methods: {
dispatchAction(action, params = {}, plain = false) {
return new Promise((resolve, reject) => {
this.$store.dispatch(action, plain ? params : Object.assign({}, params)).then(resp => {
resolve(resp)
}).catch(error => {
reject(error)
})
})
}
}
})
mixins混入原理
原因:修改Vue.options属性进而影响之后的所有Vue实例。
做法: 将传入的mixin对象与this.options合并,然后将合并后的新对象作为this.options传给之后的所有Vue实例。
Vue.mixin = function (mixin: Object) {
this.options = mergeOptions(this.options, mixin)
return this
}
2,extends
-
与mixins 类似,原理都是mergeOptions实现,组件自身的选项会比要扩展的源组件具有更高的优先级,但是执行顺序:extend > extends > mixins > component
-
允许声明扩展另一个组件 (可以是一个简单的选项对象或构造函数),而无需使用 Vue.extend;
mixins接受的是数组:mixins: [Popup, emitter]
; extends单继承,只接受一个选项对象或构造函数:extends: baseOptions
var CompA = { ... }
// 在没有调用 `Vue.extend` 时候继承 CompA
var CompB = {
extends: CompA,
...
}
3,component组件
用法: Vue.component(id, [definition])
有第二个参数{Function | Object} [definition]
,则为注册组件,没有则为获取组件
<div id="itany">
<hello></hello>
<my-world></my-world>
</div>
<script>
// 方式1:先创建组件构造器,然后由组件构造器创建组件
// 使用Vue.extend()创建一个组件构造器
var MyComponent = Vue.extend({ template: '<h3>Hello World</h3>' });
// 使用Vue.component(标签名,组件构造器),根据组件构造器来创建组件
Vue.component('hello', MyComponent);
// 方式2:直接创建组件(推荐) , 传入一个选项对象 (自动调用 Vue.extend)
Vue.component('my-world', { template: '<h1>你好,世界</h1>' });
// 在初始化根实例之前注册组件
var vm = new Vue({ //这里的vm也是一个组件,称为根组件Root
el: '#itany',
data: {}
});
</script>
获取注册的组件 (始终返回构造器) : var MyComponent = Vue.component('my-world')
Vue.component() 原理
Vue.component()、Vue.directive()和Vue.filter()的注册方法类似,给指定的一个构造函数与一个字符串ID关联起来。
之后Vue可以把它用作模板,当传递第二个参数definition给Vue.component()的时候,实际上内部调用Vue.extend(),这就是Vue.extend()和Vue.component()的区别。
源码如下:
Vue[type] = function (id,definition) {
if (!definition) {
return this.options[type + 's'][id]
} else {
definition = this.options._base.extend(definition)
this.options[type + 's'][id] = definition
}
}
4,extend构造器
<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')
结果: <p>Walter White aka Heisenberg</p>
extend 创建的是 Vue 构造器,而不是我们平时常写的组件实例,所以不可以通过 new Vue({ components: Profile })
来直接使用,需要通过 new Profile().$mount('#mount-point')
来挂载到指定的元素上,通常组合: Vue.extend + vm.$mount
extend案例—elementUI源码notification
elementUI源码中 loading、message、notification都使用到了Vue.extend()
- 1,先创建一个组件,也就是弹窗的Dom结构样式以及需要用的数据等;
2-1,再创建一个js文件,引入刚刚创建的组件;
2-2,利用Vue.extend()构造一个子类实例,然后把包装的数据和方法传进去;
2-3,调用$mount()方法生成需要的DOM,然后插入body中,这样就可以通过 $el 属性来访问组件实例
const NotificationConstructor = Vue.extend(Main);
instance = new NotificationConstructor({ data: options });
instance.$mount();
document.body.appendChild(instance.$el);
instance.dom = instance.$el;
instance.dom.style.zIndex = PopupManager.nextZIndex();
-
3,将第二步的方法挂载到Vue原型上,以保证在项目中可以直接调用:
Vue.prototype.$notify = Notification;
-
4,使用:
this.$notify({ title: '提示', message: '这是一条消息' });