參考網站
前情提要
在小專案裡我主要用 Vue.js 來處理 MVVM,用 <script>
載入 vue.js,寫幾行 JavaScript 搞定,走不寫模組,不用 TypeScript,免編譯打包的「輕前端」模式,但常用邏輯還是會寫成元件(Component)方便共用。
在 Vue 2 時代,我習慣在網頁共用的 .js
裡使用 Vue.component("my-component", ...)
註冊元件,註冊一次,各網頁不需宣告就能使用元件。
正式擺脫 IE 後,終於不用再死守 Vue 2,試著將一個小專案升級到 Vue 3,遇到小麻煩。
Vue 3 改變了元件註冊方式,不再提供全域註冊,必須先 Vue.createApp()
建立實體,app.component("my-component", ...)
註冊或用 components 屬性引用才能使用元件。參考:重新認識 Vue.js - 元件的宣告與註冊
全域元件改成區域元件可減少程式間互相干擾,在軟體架構來說是正確的方向,但對簡單應用來說(例如:程式很單純,全域元件打架機率趨於零的場合),這番調整讓元件註冊變得繁瑣。
用個範例來說明。
Vue 2 註冊多個元件
原本 Vue 2 做法是在 my-components-vue2.js 中註冊多個元件:
my-components-vue2.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
| Vue.component('date-tag', {
template: '<div>{{date}}</div>',
data: function () {
return {
date: new Date().toJSON().slice(0, 10)
};
}
});
Vue.component('time-tag', {
template: '<div>{{time}}</div>',
data: function () {
return {
time: new Date().toJSON().slice(11, 19)
};
}
});
Vue.component('host-tag', {
template: '<div>{{host}}</div>',
data: function () {
return {
host: location.host
};
}
});
|
如此,數十支 HTML 只需載入 my-components-vue2.js 便能在網頁使用 <date-tag>
、<time-tag>
插入元件。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
| <!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script>
<script src="my-components-vue2.js"></script>
</head>
<body>
<div id="app">
<date-tag></date-tag>
<time-tag></time-tag>
<host-tag></host-tag>
</div>
<script>
var app = new Vue({
el: '#app'
});
</script>
</body>
</html>
|
升級 Vue 3 之後
升級 Vue 3 之後,元件的 js 跟網頁都要做一些修改:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
| var dateTag = {
template: '<div>{{date}}</div>',
data: function () {
return {
date: new Date().toJSON().slice(0, 10)
};
}
};
var timeTag = {
template: '<div>{{time}}</div>',
data: function () {
return {
time: new Date().toJSON().slice(11, 19)
};
}
};
var hostTag = {
template: '<div>{{host}}</div>',
data: function () {
return {
host: location.host
};
}
};
|
建立 app 寫法改為 Vue.createApp
,並在宣告中透過 components
列舉要註冊的物件:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
| <!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script src="https://unpkg.com/vue@3"></script>
<script src="my-components-vue3-upgrade.js"></script>
</head>
<body>
<div id="app">
<date-tag></date-tag>
<time-tag></time-tag>
<host-tag></host-tag>
</div>
<script>
var app = Vue.createApp({
components: {
'date-tag': dateTag,
'time-tag': timeTag,
'host-tag': hostTag
}
// 若元件物件名稱與標籤相符,可簡寫成
// components: { dateTag, timeTag, hostTag }
})
.mount('#app');
</script>
</body>
</html>
|
假設我有 30 個網頁,30 個 app 都要加 components: { dateTag, timeTag, hostTag }
,未來若新增其他元件,所有 components
列舉都要改,這是標準的「Copy & Paste 負面教材」呀,一想就覺得很不 OK 呀。
這種情境,就是套件
(Plugin
,也有人翻成插件、外掛)上場的時刻。最簡單的套件寫法是寫一個 function,接收 app 及 options 參數,內部呼叫 app.component(...)
逐一註冊元件,options 則是自訂參數,可用來決定要註冊哪些元件或變更元件設定值,提高運用彈性。以下是簡單示範:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
| function myComponentsPlugin(app, options) {
app.component('date-tag', {
template: '<div>{{date}}</div>',
data: function () {
return {
date: new Date().toJSON().slice(0, 10)
};
}
});
app.component('time-tag', {
template: '<div>{{time}}</div>',
data: function () {
return {
time: new Date().toJSON().slice(11, 19)
};
}
});
app.component('host-tag', {
template: '<div>{{host}}</div>',
data: function () {
return {
host: location.host
};
}
});
}
|
如此,呼叫端可簡化為 .use(myComponentsPlugin)
,不需把所有元件列出來,未來要新增元件,修改 my-components-vue3.js
即可,保留原先全域元件的簡單方便:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
| <!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script src="https://unpkg.com/vue@3"></script>
<script src="my-components-vue3.js"></script>
</head>
<body>
<div id="app">
<date-tag></date-tag>
<time-tag></time-tag>
<host-tag></host-tag>
</div>
<script>
var app = Vue.createApp({
//...
}).use(myComponentsPlugin)
.mount('#app');
</script>
</body>
</html>
|