Feed on
Posts
Comments
Email訂閱

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也可以分開設計。

 

留言區