
はじめに
過去数か月間、私はさまざまなJavaScriptフレームワークをMVCプロジェクトに統合することに注目してきました。 React、Angular、またはEmberの精神で.NETを操作するために何かを選択したらすぐに、アダプターモジュールをインストールし、すべてのコントローラーのすべてのルーティングロジックを書き換える必要があります。 最終的には、すでに動作しているスタックと並行して動作する場合、Webアプリケーション全体に影響します。 新しいプロジェクトを開始する場合は、バックエンドにWeb APIを使用することをお勧めします。これにより、選択したJSフレームワークにRESTインターフェイスが提供されますが、MVCの既存のプロジェクトにはこれはオプションではありません。
いくつかの調査の後、Vue.JSに出会い、いくつかの実験の後、MVCと連携して動作するようになりました。 Vue.JSは比較的軽量のフレームワークなので、追加のJS機能が必要なビューにそれを追加し、残りのWebアプリケーションはそのままにします。 現在、私が本番環境でVueを使用するとき、私の問題を共有しているすべての人のために、あなたといくつかの例を共有できてうれしいです。 私のワークフローは、 MigelのCastro [ tyk ]の概念を借用し、そこで彼がそれを使用してAngularJSとMVCを統合しました。
仕事を始める
- 最初にMVCプロジェクトが必要で、標準のMVC 5プロジェクトを作成します。
- npmにすべてのパッケージを処理させるため、プロジェクトにpackage.jsonファイルを作成します。
- VueJS依存関係を追加する
{ "version": "1.0.0", "Name": "ASP.NET", "private": true, "devDependencies": { }, "dependencies": { "vue": "^1.0.26" } }
- ファイルを保存すると、Visual Studio自体がnpm installコマンドを呼び出し、必要なすべてのパッケージをダウンロードします。
ビューでvueを使用しましょう
- デフォルトビュー(index.cshtml)で、標準のマークアップを削除し、node-modulesフォルダーからVueJSを含めました。
@{ ViewBag.Title = "Home Page"; } @Scripts.Render("~/node_modules/vue/dist/vue.min.js")
- VueJSのドキュメントとともにHello Worldの例をアプリケーションに追加しましょう。
@{ ViewBag.Title = "Home Page"; } <div id="app"> </div> @Scripts.Render("~/node_modules/vue/dist/vue.min.js") <script> const v = new Vue({ el: '#app', data: { message: 'Hello Vue.js!' } }) </script>
- プロジェクトを実行しましょう
明らかに、すべてのスクリプトをビューに配置することは頭痛の種になる保証された方法なので、コードを整理しましょう。
仕事を始める
VueJSで構築された大規模なアプリケーションがある場合、プロジェクトを部分に分割しました。 各コントローラーには、対応するVueアプリケーションがあります。これは、いくつかのVueコンポーネントで構成されています。 コントローラーとアプリケーションの間の1対1の関係により、コードが読みやすくなり、保守が容易になります。 各アプリケーションモジュールには、1つの大きなパッケージではなく、必要なJavaScriptライブラリのみが含まれます。
JavaScriptパッカーは長年にわたって改善されてきました。 Browserifyを使用すると、node.jsスタイルのモジュールを使用してブラウザーで動作できます。 依存関係を定義してから、Browserifyはそれらを1つの小さくてきれいなJavaScriptファイルに収集します。 require( "./ your_file.js")を使用してJavaScriptファイルを含めます。 表現。 これにより、必要なライブラリのみを使用できます。 そのため、ここで想定すると、各コントローラーはコンテナーであり、各コンテナーには1つ以上のjsファイルが含まれています。 これらのファイルは、プロジェクトのフォルダーに配置されるパッケージに配置され、ブラウザーをダウンロードして使用します。
私は通常、次の構造に従います。 すべてのVueコードはViewModelフォルダーに配置されます。 Vueを使用するコントローラーごとに、ViewModelフォルダーにサブフォルダーを作成し、 main.jsファイルでコンテナーを呼び出します。 その後、GulpとBrowserifyを使用して、すべてのファイルをプロジェクトフォルダーに格納されているパッケージにパックします。 ビューはパッケージを参照し、ブラウザがページを要求すると、パッケージがダウンロードされて起動されます。
ちょっとした練習
- このプロジェクトでは、新しいViewModelsフォルダーを作成し、その中にHomeControllerコントローラーを担当するHomeフォルダーを作成しました。
- ViewModelフォルダーで、main.jsも作成しました。
- いくつかの依存関係を追加します
"devDependencies": { "browserify": "^13.0.0", "watchify": "^3.7.0", "gulp": "^3.9.1", "gulp-util": "^3.0.7", "gulp-babel": "^6.1.2", "gulp-uglify": "^2.0.0", "gulp-sourcemaps": "^1.6.0", "fs-path": "^0.0.22", "vinyl-source-stream": "^1.1.0", "vinyl-buffer": "^1.0.0", "babel-preset-es2015": "^6.13.2" }
- gulpファイルをプロジェクトに追加し、次のコードを貼り付けます。
const gulp = require('gulp'); const gutil = require('gulp-util'); var babel = require('gulp-babel'); var minify = require('gulp-uglify'); var sourcemaps = require('gulp-sourcemaps'); const fs = require('fs'); const path = require('path'); const browserify = require('browserify'); const watchify = require('watchify'); const fsPath = require('fs-path'); var source = require('vinyl-source-stream'); var buffer = require('vinyl-buffer'); var es2015 = require('babel-preset-es2015'); function getFolders(dir) { return fs.readdirSync(dir) .filter(function (file) { return fs.statSync(path.join(dir, file)).isDirectory(); }); } const paths = [ process.env.INIT_CWD + '\\ViewModels\\home', process.env.INIT_CWD + '\\ViewModels\\home\\components', process.env.INIT_CWD + '\\ViewModels\\common\\components' ]; function watchFolder(input, output) { var b = browserify({ entries: [input], cache: {}, packageCache: {}, plugin: [watchify], basedir: process.env.INIT_CWD, paths: paths }); function bundle() { b.bundle() .pipe(source('bundle.js')) .pipe(buffer()) .pipe(sourcemaps.init({ loadMaps: true })) //.pipe(babel({ compact: false, presets: ['es2015'] })) // Add transformation tasks to the pipeline here. //.pipe(minify()) // .on('error', gutil.log) .pipe(sourcemaps.write('./')) .pipe(gulp.dest(output)); gutil.log("Bundle rebuilt!"); } b.on('update', bundle); bundle(); } function compileJS(input, output) { // set up the browserify instance on a task basis var b = browserify({ debug: true, entries: [input], basedir: process.env.INIT_CWD, paths: paths }); return b.bundle() .pipe(source('bundle.js')) .pipe(buffer()) .pipe(sourcemaps.init({ loadMaps: true })) .pipe(babel({ compact: false, presets: ['es2015'] })) // Add transformation tasks to the pipeline here. .pipe(minify()) .on('error', gutil.log) //.pipe(sourcemaps.write('./')) .pipe(gulp.dest(output)); } const scriptsPath = 'ViewModels'; gulp.task('build', function () { var folders = getFolders(scriptsPath); gutil.log(folders); folders.map(function (folder) { compileJS(scriptsPath + "//" + folder + "//main.js", "Scripts//app//" + folder); }); }); gulp.task('default', function () { var folders = getFolders(scriptsPath); gutil.log(folders); folders.map(function (folder) { watchFolder(scriptsPath + "//" + folder + "//main.js", "Scripts//app//" + folder); }); });
- また、ここではwatchifyを使用してViewModelsフォルダーの変更を監視しているため、変更されたすべてのファイルが再構築されます。 ブラウザでページを更新するだけです。
コードに戻りましょう
- Hello Worldアプリケーションをmain.jsに転送します。
- browserifyを使用すると、依存関係をインストールできます
- main.jsファイルは次のようになります。
const Vue = require('vue'); const v = new Vue({ el: '#app', data: { message: 'Hello Vue.js!' } });
- index.cshtmlファイルで、パッケージ化されたパッケージへのリンクを変更します
@{ ViewBag.Title = "Home Page"; } <div id="app"> { { message } } </div> @Scripts.Render("~/Scripts/app/home/bundle.js")
- ページを更新
- Vueに切り替える場合、各コントローラーにリンクを設定する必要があるため、何らかの種類のユニバーサルテンプレートを作成できます。
@{ var controllerName = HttpContext.Current.Request.RequestContext.RouteData.Values["Controller"].ToString(); } @Scripts.Render("~/Scripts/app/" + controllerName + "/bundle.js")
サーバーからデータをロードする
Vueを使用すると、サーバーから取得したデータを抽出して表示できます。
- コントローラーにデータを追加します
public JsonResult GetData() { return Json(new { Name = "Marco", Surname = "Muscat", Description = "Vue data loaded from razor!" },JsonRequestBehavior.AllowGet); }
- package.jsonにjQueryを追加し、Vueアプリケーションをアップグレードしてサーバーからデータを呼び出します
const Vue = require("vue"); const $ = require("jquery"); const v = new Vue({ el: '#app', ready: function () { this.loadData(); }, data: { message: 'Hello Vue.js!', serverData: null }, methods: { loadData: function (viewerUserId, posterUserId) { const that = this; $.ajax({ contentType: "application/json", dataType: "json", url: window.ServerUrl + "/Home/GetData", method: "GET", success: function (response) { console.log(response); that.$data.serverData = response; }, error: function () { console.log("Oops"); } }); } } })
- サーバーに接続するには、通常、現在のホストに簡単にアクセスできるように、グローバル変数window.ServerUrlを追加します。 このようなことをしたい場合は、次のコードをビューファイルに追加するだけです。
@{ var controllerName = HttpContext.Current.Request.RequestContext.RouteData.Values["Controller"].ToString(); var serverUrl = string.Format("{0}://{1}{2}", Request.Url.Scheme, Request.Url.Authority, Url.Content("~")); var controllerUrl = Url.Content("~") + controllerName; } <script> window.ServerUrl = '@serverUrl'; window.VueRouterUrl = '@controllerUrl'; </script> @Scripts.Render("~/Scripts/app/" + controllerName + "/bundle.js")
- プロジェクトを再構築して実行します。
- 次のステップでは、受信したデータを表示します。
<div id="app"> { { message } } <br/> <span>coming straight from mvc! { {serverData.Name} } { {serverData.Surname} }. { {serverData.Description} }</span> </div>
現時点では、vue.jsとMVCを使用するにはこれで十分ですが、他のフロントエンドフレームワークと同様に、vueは読み込みの遅延に悩まされます。 ページをリクエストするときは、JavaScriptをロードして起動する必要があります。 次に、フレームワークは、データを受信するためにサーバーにさらにいくつかの要求を行います。 これを防ぐには、アニメーションやその他のハックの読み込みに頼る必要がありますが、MVCも使用しているため、Razorを使用し、ページの残りの部分と一緒にプレゼンテーション用のデータを読み込むことで、読み込みプロセスを改善し、高速化できます。
初期データの読み込み
多くのJSフレームワークは現在、さまざまなプリレンダリングの実装に取り組んでいますが、.NETスタックを使用して、代替ソリューションを思いつくことができます。
警告! この方法は、ブートストラップに少量のデータが含まれる場合に適しています。 それ以外の場合は、ページネーションまたはAJAXリクエストを使用して、ページの読み込みをスムーズにし、待ち時間を短縮することをお勧めします。
作成を始めましょう。 このために、以前に行ったプロジェクトを使用します。
public ActionResult Index() { var serverModel = JsonConvert.SerializeObject(new { Name = "Marco", Surname = "Muscat", Description = "Vue data loaded from razor!" }); return View(new SampleModel() { Data = serverModel }); } public class SampleModel { public string Name { get; set; } public string Surname { get; set; } public string Description { get; set; } public string Data { get; set; } }
- SampleModelは単純なクラスです。Razorでのバインディングを容易にするために必要です。
- Index.cshtmlで、データをロードし、JavaScriptオブジェクトにシリアル化します。
<script> window.preLoadeddata = JSON.parse('@Html.Raw(Model.Data)')</script>
- 次に、Vueにデータの取得元を伝えましょう。
const Vue = require("vue"); const $ = require("jquery"); const v = new Vue({ el: '#app', ready: function () { }, data: { message: 'Hello Vue.js!', serverData: window.preLoadeddata }, methods: { } })
ルーティング
ルーティングが行われていないプロジェクトは完了したとは見なされません。 1ページに情報が多すぎるため、より複雑なアプリケーションでは複数の送信が必要になります。 MVCでVueを使用するのは素晴らしいことです。すべてのビューを同じページに完全にリロードすることなくロードできるからです。
- 実証するために、別のコントローラーを作成してみましょう。
- このコントローラーのindex.cshtmlビューを作成します
- viewmodelsフォルダーとmain.jsに「vuerouting」フォルダーを追加します。
- package.jsonにvue-routerを追加します。
- 最後に、このコードをmain.jsファイルに追加します
const Vue = require("vue"); const VueRouter = require("vue-router"); Vue.use(VueRouter); var Foo = Vue.extend({ template: '<p>This is foo!</p>' }); var Bar = Vue.extend({ template: '<p>This is bar!</p>' }); var App = Vue.extend({}); var router = new VueRouter({ history: true, root: "/vue-example/vuerouting" }); router.map({ '/foo': { component: Foo }, '/bar': { component: Bar } }); router.start(App, '#app');
- また、index.cshtmlファイルにマークアップを追加します。
<div id="app"> <h1>Hello App!</h1> <p> <!-- use v-link directive for navigation. --> <a v-link="{ path: '/foo' }">Go to Foo</a> <a v-link="{ path: '/bar' }">Go to Bar</a> </p> <!-- route outlet --> <router-view></router-view> </div>
- プロジェクトをビルドした後、次のようにします: localhost / vue-example / vuerouting
- リンクをクリックすると、対応するVueコンポーネントが読み込まれます。アドレスバーを見ると、Vueはこのコンポーネントにルートを追加します。
結果は非常に良いように見えるかもしれませんが、それだけではありません。 まだ問題があります。 Vueコンポーネント(http:// localhost / vue-example / vuerouting / bar)を使用してアドレスをコピーし、新しいタブに貼り付けると、サーバーがこのルートを見つけることができないため、404エラーが発生します。 Vueルートを無視するように、サーバーでルーティングを構成する必要があります。
- App_start / RouteConfig.csで、コードを次のように書き換えます。
routes.MapRoute( name: "Default", url: "{controller}/{action}/{id}/", defaults: new {controller = "Home", action = "Index", id = UrlParameter.Optional}, constraints:new { controller = "Home"} ); routes.MapRoute( name: "Silo Controller", url: "{controller}/{*.}", defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }, constraints: new { controller = "examplevuerouter|ExampleSeedingRazor" } );
- 上記のコードは、MVCの標準ルーティング実装を残し、Vueコンポーネントの代替ルーティングも追加します。
- 新しいルートは、ルートの残りを無視しながら、指定されたコントローラーのインデックスアクションにリダイレクトします。
- プロジェクトをビルドした後、 localhost / vue-example / vuerouting / barに切り替えると、ページにBarコンポーネントが完全にロードされたことがわかります。
- 改善できるもう1つの点は、Vueのルーティング設定のルート値です。 上記の例では、別のVueモジュールを追加する場合、ルート値を変更する必要があります。 代わりに、上記でserverUrlで行ったように、レイアウトに別のJavaScript変数を追加できます。 実際、プロジェクトページのレイアウトを変更するときに、window.VueRouterUrlを追加しました。 したがって、コードを少し変更するだけです。
var router = new VueRouter({ history: true, root: "/vue-example/vuerouting" });
var router = new VueRouter({ history: true, root: window.VueRouterUrl });
オリジナルへのリンク: tyk
この記事で提供した情報が、VueJSとMVCを使用してプロジェクトを作成する際に役立つことを願っています。 コメント、質問、提案がある場合は、コメントに残してください。
読んでくれてありがとう。