This Post is under 軟體開發
這篇文章是針對不想放棄MVC,但又想要試試看Vue這類的前端框架的網頁渲染、資料繫結等功能,而且「不想編譯前端網頁程式,又不想因為使用Vue就得分成前後端兩個專案」的人,嘗試提出一個解決方案。而且如果還有使用Bootstrap這類前端框架的元件,搭配Vue之後要放進MVC,會遇到擺不太進去的問題。譬如在外層Layout使用Bootstap的Collapse來縮放內層View的內容,而在內層的View如果會使用到不同的BS元件(如按鈕),就會有外層的Layout必須一次註冊所有View可能使用的BS元件的問題,因為Vue使用元件需要先註冊。
如果不想在外層一次註冊所有外部元件,外層Layout與內層的View應該要成為不會互相包含的兩個獨立Vue App。實作上可等到View App初始化之後,再把View 的Vue app 用操作DOM的方式搬進Layout中為View保留的位置。
以ASP.NET MVC為例:
_Layout.cshtml 內容
<!DOCTYPE html>
<html>
<head>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.7/dist/css/bootstrap.min.css" rel="stylesheet" crossorigin="anonymous">
<link href="https://cdn.jsdelivr.net/npm/bootstrap-vue-next@0.30.4/dist/bootstrap-vue-next.min.css" rel="stylesheet" />
</head>
<body>
<div id="app">
<BCollapse>
<div class="content">
@if (!IsSectionDefined("vueScript"))
{
@RenderBody()
}
</div>
</BCollapse>
</div>
<script type="importmap">
{
"imports": {
"vue": "https://unpkg.com/vue@3/dist/vue.esm-browser.prod.js",
"bootstrapVueNext": "https://cdn.jsdelivr.net/npm/bootstrap-vue-next@0.30.4/dist/bootstrap-vue-next.mjs"
}
}
</script>
<script type="module">
import { createApp, ref } from 'vue'
import { createBootstrap, BCollapse } from 'bootstrapVueNext'
const app = createApp({
//...
});
app.component('BCollapse', BCollapse);
app.use(createBootstrap());
app.mount('#app');
</script>
@if (IsSectionDefined("vueScript"))
{
<div id="app-content">
@RenderBody()
</div>
@RenderSection("vueScript", required: false)
}
</body>
</html>
Index.cshtml 內容
<BButton>Click me</BButton>
@section vueScript {
<script type="module">
import { createApp } from 'vue'
import { createBootstrap, BButton } from 'bootstrapVueNext';
const appContent = createApp({
//...
onMounted(() => {
document.querySelector(".content").appendChild(document.querySelector("#app-content"));
});
});
appContent.component('BButton', BButton);
appContent.use(createBootstrap());
appContent.mount('#app-content')
</script>
}
以上範例在 _Layout.cshtml 與 Index.cshtml 分別使用了不同的 bootstrap-vue 元件,運用Razor 語法中的 RenderSection,將兩個 vue app 分開來初始化,然後在 Index view 的 vue app onMounted 中再做整併。如此就可避免一個Vue App中直接內含另一個Vue App,且Layout與真正的內容的View也可以分開設計。


