使用場景
我們在寫 Vue.js 時,不論是用 CDN 的方式還是在 Webpack 裡用 npm 引入的 Vue.js,都會有一個根節點,並且創建一個根實例,比如:
Webpack 也類似,一般在入口文件 main.js 裡,最後會創建一個實例:
import Vue from 'vue';
import App from './app.vue';
new Vue({
el: '#app',
render: h => h(App)
});
因為用 Webpack 基本都是前端路由的,它的 html 裡一般都只有一個根節點 ,其餘都是通過 JavaScript 完成,也就是許多的 Vue.js 組件(每個頁面也是一個組件)。
有了初始化的實例,之後所有的頁面,都由 vue-router 幫我們管理,組件也都是用 import 導入後局部註冊(也有在 main.js 全局註冊的),不管哪種方式,組件(或頁面)的創建過程我們是無需關心的,只是寫好 .vue 文件並導入即可。這樣的組件使用方式,有幾個特點:
- 所有的內容,都是在 #app 節點內渲染的;
- 組件的模板,是事先定義好的;
- 由於組件的特性,註冊的組件只能在當前位置渲染。
比如你要使用一個組件 <i-date-picker>,渲染時,這個自定義標籤就會被替換為組件的內容,而且在哪寫的自定義標籤,就在哪裡被替換。換句話說,常規的組件使用方式,只能在規定的地方渲染組件,這在一些特殊場景下就比較侷限了,例如:/<i-date-picker>
- 組件的模板是通過調用接口從服務端獲取的,需要動態渲染組件;
- 實現類似原生 window.alert() 的提示框組件,它的位置是在 下,而非 ,並且不會通過常規的組件自定義標籤的形式使用,而是像 JS 調用函數一樣使用。
一般來說,在我們訪問頁面時,組件就已經渲染就位了,對於場景 1,組件的渲染是異步的,甚至預先不知道模板是什麼。對於場景 2,其實並不陌生,在 jQuery 時代,通過操作 DOM,很容易就能實現,你可以沿用這種思路,只是這種做法不那麼 Vue,既然使用 Vue.js 了,就應該用 Vue 的思路來解決問題。對於這兩種場景,Vue.extend 和 vm.$mount 語法就派上用場了。
用法
上文我們說到,創建一個 Vue 實例時,都會有一個選項 el,來指定實例的根節點,如果不寫 el 選項,那組件就處於未掛載狀態。Vue.extend 的作用,就是基於 Vue 構造器,創建一個“子類”,它的參數跟 new Vue 的基本一樣,但 data 要跟組件一樣,是個函數,再配合 $mount ,就可以讓組件渲染,並且掛載到任意指定的節點上,比如 body。
比如上文的場景,就可以這樣寫:
import Vue from 'vue';
const AlertComponent = Vue.extend({
template: '{{ message }}',
data () {
return {
message: 'Hello, World!'
};
},
});這一步,我們創建了一個構造器,這個過程就可以解決異步獲取 template 模板的問題,下面要手動渲染組件,並把它掛載到 body 下:
const component = new AlertComponent().$mount();
這一步,我們調用了 $mount 方法對組件進行了手動渲染,但它僅僅是被渲染好了,並沒有掛載到節點上,也就顯示不了組件。此時的 component 已經是一個標準的 Vue 組件實例,因此它的 $el 屬性也可以被訪問:
document.body.appendChild(component.$el);
當然,除了 body,你還可以掛載到其它節點上。
$mount 也有一些快捷的掛載方式,以下兩種都是可以的:
// 在 $mount 裡寫參數來指定掛載的節點
new AlertComponent().$mount('#app');
// 不用 $mount,直接在創建實例時指定 el 選項
new AlertComponent({ el: '#app' });實現同樣的效果,除了用 extend 外,也可以直接創建 Vue 實例,並且用一個 Render 函數來渲染一個 .vue 文件:
import Vue from 'vue';
import Notification from './notification.vue';
const props = {}; // 這裡可以傳入一些組件的 props 選項
const Instance = new Vue({
render (h) {
return h(Notification, {
props: props
});
}
});
const component = Instance.$mount();
document.body.appendChild(component.$el);這樣既可以使用 .vue 來寫複雜的組件(畢竟在 template 裡堆字符串很痛苦),還可以根據需要傳入適當的 props。渲染後,如果想操作 Render 的 Notification 實例,也是很簡單的:
const notification = Instance.$children[0];
因為 Instance 下只 Render 了 Notification 一個子組件,所以可以用 $children[0] 訪問到。
如果你還不理解這樣做的目的,沒有關係,後面小節的兩個實戰你會感受到它的用武之地。
需要注意的是,我們是用 $mount 手動渲染的組件,如果要銷燬,也要用 $destroy 來手動銷燬實例,必要時,也可以用 removeChild 把節點從 DOM 中移除。
結語
這兩個 API 並不難理解,只是不常使用罷了,因為多數情況下,我們只關注在業務層,並使用現成的組件庫。
歡迎關注
閱讀更多 代碼開發 的文章
關鍵字: 路由器 jQuery JavaScript