vue.extend(component)
vue.extend我們在開發中較少用到,相比於vue.component,它的使用會比較複雜些。但是在一些獨立組件開發中,比如彈框組件,需要掛載到body中,而不是#app中,這時就需要用到vue.extend+$mount了。
vue.extend()的官方定義:
vue.extend(options)
- 參數:{object} options
- 用法:
使用基礎 Vue 構造器,創建一個“子類”。參數是一個包含組件選項的對象。
data
選項是特例,需要注意 - 在Vue.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>
注:可以看到vue.extend創建的是Vue構造器,而不是我們平時寫的組件實例,所以不可以通過new Vue({ components: testExtend }) 來直接使用,需要用new Profile().$mount('#mount-point')來掛載到#mount-point'元素上。
爲什麼使用extend
在vue項目中,有了初始化的根實例後,所有頁面基本上都是通過router來管理,組件也是通過import來進行局部註冊,所以組件的創建我們不需要去關注,相比extend來更簡單一點。但是會有如下幾個缺點:
- 組件模板都是事先定義好的,如果我要從接口動態渲染組件怎麼辦?
- 所有內容都是在#app下渲染,註冊組件都是在當前位置下渲染,如果我們要實現一個類似於window.alert()組件,要求像調用js函數一樣調用它怎麼辦?
所以這時候就需要用到extend。它可以實現在body上掛載組件,使用document.body.appendChild(Profile.$el)。
下面的例子是用extend和render兩種方式創建的彈框提示組件:
Notice.vue組件:
<template>
<div class="box" v-if="isShow">
<h3>{{title}}</h3>
<p class="box-content">{{message}}</p>
</div>
</template>
<script>
export default {
props: {
title: {
type: String,
default: ""
},
message: {
type: String,
default: ""
},
duration: {
type: Number,
default: 2000
}
},
data() {
return {
isShow: false
};
},
methods: {
show() {
this.isShow = true;
setTimeout(this.hide, this.duration);
},
hide() {
this.isShow = false;
this.remove();
}
}
};
</script>
<style>
.box {
position: fixed;
width: 100%;
top: 16px;
left: 0;
text-align: center;
pointer-events: none;
background-color: #fff;
border: grey 3px solid;
box-sizing: border-box;
}
.box-content {
width: 200px;
margin: 10px auto;
font-size: 14px;
padding: 8px 16px;
background: #fff;
border-radius: 3px;
margin-bottom: 8px;
}
</style>
src/utils/create.js
import Vue from 'vue';
// import Notice from '@/components/Notice.vue';
//create方法最終的目標是把組件實例返回
function create(component, props) {
//組件構造函數如何獲取?
//1、Vue.extend()
const Ctor = Vue.extend(component)
//創建組件實例
const comp = new Ctor({ propsData: props })
comp.$mount()
document.body.appendChild(comp.$el)
comp.remove = function () {
document.body.removeChild(comp.$el)
comp.$destroy()
}
/* //2、render
const vm = new Vue({
//h是createElement,返回的是vNode,是虛擬dom,需要掛載才能變成真實dom
render: h => h(component, { props })
}).$mount() //不指定宿主元素,則會創建真實dom,但是不會做追加dom操作,切記這裏不能把body作爲宿主元素
//vm.$el是獲取真實dom,把真實dom放到body中
document.body.appendChild(vm.$el)
const comp = vm.$children[0]
//刪除彈框組件,不能一直往body中追加彈框,這樣程序會崩
comp.remove = function () {
document.body.removeChild(vm.$el)
vm.$destroy()
} */
return comp
}
// export default create
export default {
install(Vue) {
Vue.prototype.$notice = function (options) {
return create(Notice, options)
}
}
}
main.js中註冊成全局組件
import create from './utils/create';
// Vue.prototype.$create = create
Vue.use(create) //create已經是組件對象了,進行全局註冊
在頁面中調用彈框提示組件:index.vue
import Notice from "@/components/Notice.vue";
login() {
this.$refs["kLoginForm"].validate(valid => {
/* const notice = this.$create(Notice, {
title: "社會你楊哥喊你來搬磚",
message: valid ? "請求登錄!" : "校驗失敗!",
duration: 3000
});
notice.show(); */
//這種用法更好,因爲不用再在用的時候引和Notice組件了,create.js中已經有了,利用install
console.log("this.$notice():===", this.$notice());
const notice = this.$notice({
title: "社會你楊哥喊你來搬磚",
message: valid ? "請求登錄!" : "校驗失敗!",
duration: 2000
});
notice.show();
});
}
至此,一個全局的彈框組件就寫好了。
總結:
1、component中寫一個Notice.vue的組件的dom結構。src/component/Notice.vue
2、把Notice寫成一個全局的工具函數,返回一個組件,並掛載到body上。src/utils/create.js
3、在main.js中註冊成全局組件。
4、在頁面中使用這個全局彈框組件。index.vue