1.extend是什么?
首先看文档就能知道它是一个基于Vue构造函数的‘子类’,Vue是一个构造函数,而extend创造出来的也是一个构造函数,只不过.extend是Vue的子构造函数,也就是说.extend继承Vue上的东西,其次.extend是Vue2中的东西,Vue3移除掉了。那它具体是什么?应用于哪些方面呢?请看案例:实现的是一个MessageBox组件==》归属于MyUI组件库。
//构造器:
var Contructor = Vue.extend({
name: '',
components: {},
props: {},
render: h => h();
})
//so
new Contructor();
如上:他创造的很明显是一个构造器,所以可以通过new
获得了一个当前组件的实例(如下案例代码中的messageBox
是一个新的应用了,可以使用.$mount()挂载它
),称之为子应用的实例,返回一个组件实例(如下案例代码中的this.vm
),然后通过原生DOM进行相应的操作。
// MessageBox/index.js
import _MessageBox from './MessageBox.vue'
export default {
install(vue) { // install开发插件,因为该构造器有vue这个实例,可以使用vue.component和vue.extend,直接use触发调用。
let messageBox = null;
// 全局注册组件
vue.component(_MessageBox.name, _MessageBox);
// 将方法放到vue实例的原型对象上,注册一个对象用来保存
vue.prototype.$messageBox = {
show,
hide,
info,
success,
warn,
danger
}
//3.实现.info .success .warn .danger四个方法直接使用不同弹框
function info(props, callback) {
this.show({...props, type: 'primary'}, callback);
}
function success(props, callback) {
this.show({...props, type: 'success'}, callback);
}
function warn(props, callback) {
this.show({...props, type: 'warn'}, callback);
}
function danger(props, callback) {
this.show({...props, type: 'danger'}, callback);
}
function show(props, callback) {
if(!messageBox){ // 判断是否存在messageBox这个实例,如果不存在则去创造这个实例
const MessageBox = vue.extend({
render(h){
return h('message-box', { props })
}
});
messageBox = new MessageBox(); // 同main.js中的new vue 构造函数
this.vm = messageBox.$mount(); // 调用$mount 获取$el
document.body.appendChild(this.vm.$el);
// 2.增加回调函数
callback && callback();
}
}
function hide(callback) {
document.body.removeChild(this.vm.$el);
messageBox.$destroy();
messageBox = null;
this.vm = null;
callback && callback();
}
}
};
简单说一下render函数中的h:
它返回一个‘虚拟节点’,即h
,其中可传入三个参数:type(Html标签名|组件|异步组件|函数式组件),一个对象如props、attribute等。我们通过上面代码中的show(props){}实例传递props。
render() {
return h('message-box',{},'')
}
如下:是MessageBox组件,但它并不存在与<div id='app'></div>
根节点中,而是脱离根节点,存在于body标签中
// MessageBox/MessageBox.vue
<template>
<div :class="['message-box', type]">
<div class="inner">
<header class="header">
<h1 class="title">{{ title }}</h1>
<span class="close-btn" @click="hideMessageBox">X</span>
</header>
<div class="countent">{{ countent }}</div>
</div>
</div>
</template>
<script>
export default {
name: "MessageBox",
props: {
title: {
type: String,
default: 'This is Title',
},
countent: {
type: String,
default: "This is Countent"
},
type: {
type: String,
default: 'primary',
validator (value) { // 传入的值必须在这个数组之内
return [
'primary',
'success',
'warn',
'danger'
].includes(value);
}
}
},
methods: {
hideMessageBox() {
this.$messageBox.hide(()=>{
console.log('Hide')
})
}
}
}
</script>
<style lang="scss">
body {
margin: 0;
}
h1 {
margin: 0;
font-weight: normal;
}
.message-box {
position: fixed;
top: 0;
left: 0;
height: 100%;
width: 100%;
background-color: rgba(0,0,0,.5);
.inner {
position: absolute;
top: 100px;
left: 50%;
width: 500px;
margin-left: -250px;
background-color: #fff;
box-shadow: 1px 3px 5px #ededed;
border-radius: 5px;
overflow: hidden;
.header {
height: 44px;
padding: 0 10px;
line-height: 44px;
box-sizing: border-box;
.title {
float: left;
font-size: 16px;
}
.close-btn {
float: right;
cursor: pointer;
}
}
.countent{
padding: 20px;
box-sizing: border-box;
}
}
&.primary {
header {
background-color: blue;
color: #fff;
}
}
&.success {
header {
background-color: green;
color: #fff;
}
}
&.warn {
header {
background-color: orange;
color: #333;
}
}
&.danger {
header {
background-color: red;
color: #fff;
}
}
}
</style>
最后在MyUI组件库中导出:
// components/MyUI/index.js
import MessageBox from './MessageBox'
export {
MessageBox
};
在main.js中引入
import { MessageBox } from './components/MyUI'
Vue.use(MessageBox);
在vue组件使用
<template>
<div>
<button @click="openMessageBox">show</button>
</div>
</template>
<script>
export default {
name: "App",
methods: {
openMessageBox() {
this.$messageBox.show({
title: 'App',
countent: 'This is Countent for App',
type: "success"
}, ()=> {
console.log('Open')
});
}
}
}
</script>
<style>
</style>