JavaScript MVC スタイル フレームワークを実装するための簡単なコード例

黄舟
リリース: 2017-03-14 15:25:29
オリジナル
1552 人が閲覧しました

はじめに

JavaScriptフレームワーク (AngularJS、Backbone、Ember など) を使用したことのある人は、UI (ユーザー インターフェイス、フロントエンド) における mvc の動作メカニズムに精通しています。これらのフレームワークは MVC を実装しており、必要に応じて変更される views を 1 つのページで簡単に実装できるようにします。また、model-view-controller (mvc) の中心概念は次のとおりです: 受信リクエストを処理するコントローラー、表示情報、ビジネス ルールを表すモデル、およびデータ アクセス。

そのため、単一ページ内でさまざまなコンテンツを切り替える必要があるアプリケーションを作成する必要がある場合、通常は上記のフレームワークのいずれかを使用することを選択します。ただし、バンドル機能を追加せずに、URL 内でビューの切り替えを実装するフレームワークだけが必要な場合は、Angular や Ember などの複雑なフレームワークを使用する必要はありません。この記事は、同じ問題を解決するために、シンプルかつ効果的な方法を使用する試みです。

コンセプト

アプリケーションのコードは、URL の「#」を使用して、MVC パターンの ナビゲーション を実装します。アプリケーションはデフォルトの URL で開始され、ハッシュベースのコードがアプリケーション ビューを読み込み、object モデルをビュー テンプレートに適用します。

URL の形式は次のとおりです:

http://Domain Name/index.html#/Route Name

View content は {{Property-Name の形式である必要があります}} オブジェクト モデルの値と プロパティをバインドします。コードは、この特殊なテンプレート形式を検索し、オブジェクト モデル内のプロパティ値を置き換えます。

Ajax 経由で非同期的にロードされたビューは、ページのプレースホルダーに配置されます。ビュー プレースホルダーは任意の要素 (理想的には p) にすることができますが、特別な属性が必要です。コードはこの特別な属性に基づいてビュー プレースホルダーを見つけます。これは、コードの実装にも役立ちます。 URL が変更されると、シナリオが繰り返され、別のビューがロードされます。簡単そうに思えますか?以下のフロー図は、この特定の実装におけるメッセージ ジャンプを説明しています。

コードの記述

基本モジュールデザインパターンから始めて、最後にファサードデザインパターンを使用してライブラリをグローバルスコープに公開しました。

; (function (w, d, undefined) { //rest of the code })(window, document);
ログイン後にコピー

複数回使用できるように、ビュー要素を 変数 に保存する必要があります。

var _viewElement = null; //element that will be used to render the view
ログイン後にコピー

URL にルーティング情報がない状況に対処するには、空白のページを表示する代わりにデフォルトのビューをロードできるように、デフォルトの route が必要です。

var _defaultRoute = null;
ログイン後にコピー

それでは、メイン MVC オブジェクトの コンストラクター を作成しましょう。ルーティング情報を「_routeMap」に保存します

var jsMvc = function () {  
    //mapping object for the routes  
    this._routeMap = {};  
}
ログイン後にコピー

ルーティングオブジェクトを作成します。このオブジェクトにルーティング、テンプレート、コントローラー情報を保存します。

var routeObj = function (c, r, t) {  
    this.controller = c;  
    this.route = r;  
    this.template = t;  
}
ログイン後にコピー

各 URL には専用のルーティング オブジェクト、routeObj があり、これらのオブジェクトはすべて _routeMap オブジェクトに追加されるため、後でキーと値を介して取得できます。

MVC ライブラリにルーティング情報を追加するには、ライブラリ内のメソッドを公開する必要があります。そこで、それぞれのコントローラーで新しいルートを追加するために使用できるメソッドを作成しましょう。

jsMvc.prototype.AddRoute = function (controller, route, template) {  
    this._routeMap[route] = new routeObj(controller, route, template);  
}
ログイン後にコピー

AddRoute メソッドは、コントローラー、ルート、テンプレートの 3 つのパラメーターを受け取ります。

コントローラー: コントローラーの機能は、特定のルートにアクセスすることです。

route: ルートルート。 URLの#以降の部分です。

テンプレート: これは、このルートのビューとしてロードされる外部 HTML ファイルです。ここで、ライブラリには URL を解析し、関連する HTML テンプレート ページを提供するためのエントリ ポイントが必要です。これを達成するには、メソッドが必要です。

Initialize メソッドは次のことを行います:

1) ビュー関連の要素の初期化を取得します。このコードには、HTML ページ内の検索に使用できる view 属性を持つ要素が必要です。

2) デフォルト ルートを設定します

3) view 要素が適切かどうかを確認します

4)绑定窗口哈希变更事件,当url不同哈希值发生变更时视图可以被及时更新

5)最后,启动mvc

//Initialize the Mvc manager object to start functioning  
jsMvc.prototype.Initialize = function () {  
    var startMvcDelegate = startMvc.bind(this);  

    //get the html element that will be used to render the view    
    _viewElement = d.querySelector('[view]');          
    if (!_viewElement) return; //do nothing if view element is not found      

    //Set the default route  
    _defaultRoute = this._routeMap[Object.getOwnPropertyNames(this._routeMap)[0]];      

    //start the Mvc manager  
    w.onhashchange = startMvcDelegate;  
    startMvcDelegate();  
}
ログイン後にコピー

在上面的代码中,我们从startMvc 方法中创建了一个代理方法startMvcDelegate 。当哈希值变化时,这个代理都会被调用。下面就是当哈希值变化时我们做的操作的先后顺序:

1)获取哈希值

2)从哈希中获取路由值

3)从路由map对象_routeMap中获取路由对象routeObj

4)如果url中没有路由信息,需要获取缺省的路由对象

5)最后,调用跟这个路由有关的控制器并且为这个视图元素的视图提供服务

上面的所有步骤都被下面的startMvc方法所实现

//function to start the mvc support  
function startMvc() {  
    var pageHash = w.location.hash.replace('#', ''),  
        routeName = null,  
        routeObj = null;                  

    routeName = pageHash.replace('/', ''); //get the name of the route from the hash          
    routeObj = this._routeMap[routeName]; //get the route object      

    //Set to default route object if no route found  
    if (!routeObj)  
        routeObj = _defaultRoute;  

    loadTemplate(routeObj, _viewElement, pageHash); //fetch and set the view of the route  
}
ログイン後にコピー

下一步,我们需要使用XML HTTP请求异步加载合适的视图。为此,我们会传递路由对象的值和视图元素给方法loadTemplate。

//Function to load external html data  
function loadTemplate(routeObject, view) {  
    var xmlhttp;  
    if (window.XMLHttpRequest) {  
        // code for IE7+, Firefox, Chrome, Opera, Safari  
        xmlhttp = new XMLHttpRequest();  
    }  
    else {  
        // code for IE6, IE5  
        xmlhttp = new ActiveXObject('Microsoft.XMLHTTP');  
    }  
    xmlhttp.onreadystatechange = function () {  
        if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {  
            loadView(routeObject, view, xmlhttp.responseText);  
        }  
    }  
    xmlhttp.open('GET', routeObject.template, true);  
    xmlhttp.send();  
}
ログイン後にコピー

当前只剩加载视图和将对象模型与视图模板绑定了。我们会创建一个空的模型对象,然后传递与方法相关的模型来唤醒路由控制器。更新后的模型对象会与先前已经加载的XHR调用中的HTML模板绑定。

loadView 方法被用于调用控制器方法,以及准备模型对象。

replaceToken方法被用于与HTML模板一起绑定模型

//Function to load the view with the template  
function loadView(routeObject, viewElement, viewHtml) {  
    var model = {};   

    //get the resultant model from the controller of the current route    
    routeObject.controller(model);   

    //bind the model with the view      
    viewHtml = replaceToken(viewHtml, model);   

    //load the view into the view element  
    viewElement.innerHTML = viewHtml;   
}  

function replaceToken(viewHtml, model) {  
    var modelProps = Object.getOwnPropertyNames(model),  

    modelProps.forEach(function (element, index, array) {  
        viewHtml = viewHtml.replace('{{' + element + '}}', model[element]);  
    });  
    return viewHtml;  
}
ログイン後にコピー

最后,我们将插件曝光于js全局范围外

//attach the mvc object to the window  
w['jsMvc'] = new jsMvc();
ログイン後にコピー

现在,是时候在我们单页应用中使用这个MVC插件。在下一个代码段中,下面这些会实现:

1)在web页面中引入这个代码

2)用控制器添加路由信息和视图模板信息

3)创建控制器功能

4)最后,初始化lib。

除了上面我们需要的链接让我们导航到不同的路径外,一个容器元素的视图属性包含着视图模板html。

<!DOCTYPE html> 
<html> 
<head> 
    <title>JavaScript Mvc</title> 
    <script src="jsMvc.js"></script> 
    <!--[if lt IE 9]> <script src="jsMvc-ie8.js"></script> <![endif]--> 

    <style type="text/css"> 
        .NavLinkContainer {  
            padding: 5px;  
            background-color: lightyellow;  
        }  

        .NavLink {  
            background-color:black;  
            color: white;  
            font-weight:800;  
            text-decoration:none;  
            padding:5px;  
            border-radius:4px;  
        }  
            .NavLink:hover {  
                background-color:gray;  
            }  
    </style> 
</head> 
<body> 
    <h3>Navigation Links</h3> 
    <p class="NavLinkContainer"> 
        <a class="NavLink" href="index.html#/home">Home</a>   

        <a class="NavLink" href="index.html#/contact">Contact</a>   

        <a class="NavLink" href="index.html#/admin">Admin</a>   

    </p> 
    <br /> 
    <br /> 
    <h3>View</h3> 
    <p view></p> 
    <script> 
        jsMvc.AddRoute(HomeController, &#39;home&#39;, &#39;Views/home.html&#39;);  
        jsMvc.AddRoute(ContactController, &#39;contact&#39;, &#39;Views/contact.html&#39;);  
        jsMvc.AddRoute(AdminController, &#39;admin&#39;, &#39;Views/admin.html&#39;);  
        jsMvc.Initialize();  

        function HomeController(model) {  
            model.Message = &#39;Hello World&#39;;  
        }  

        function ContactController(model) {  
            model.FirstName = "John";  
            model.LastName = "Doe";  
            model.Phone = &#39;555-123456&#39;;  
        }  

        function AdminController(model) {  
            model.UserName = "John";  
            model.Password = "MyPassword";  
        }  
    </script> 
</body> 
</html>
ログイン後にコピー

上面的代码有一段包含一个为IE的条件注释

<!--[if lt IE 9]> <script src="jsMvc-ie8.js"></script> <![endif]-->
ログイン後にコピー

如果IE的版本低于9,那么function.bind,Object.getOwnPropertyNames和Array.forEach属性将不会被支持。因此我们要通过判断浏览器是否低于IE9来反馈代码是否支持。

其中的内容有home.html, contact.html 和 admin.html 请看下面:

home.html:

{{Message}}
ログイン後にコピー

contact.html:

{{FirstName}} {{LastName}}  
<br /> 
{{Phone}}
ログイン後にコピー

admin.html:

<p style="padding:2px;margin:2px;text-align:left;"> 
    <label for="txtUserName">User Name</label> 
    <input type="text" id="txtUserName" value="{{UserName}}" /> 
</p> 
<p style="padding:2px;margin:2px;text-align:left;"> 
    <label for="txtPassword">Password</label> 
    <input type="password" id="txtPassword" value="{{Password}}" /> 
</p>
ログイン後にコピー

完整的代码可以从给定的下载链接中得到。

如何运行代码

运行该代码比较简单,需要在你喜欢的Web服务器上创建一个Web应用,下面以IIS为例来说明。

首先在默认站点中新增一个Web应用.

然后设置必填信息:别名,物理路径,应用池,用户认证信息,点击OK。

最后定位到Web应用的内容目录,浏览你想打开的HTML页面即可。

跑在服务器里是必要的,因为代码加载从存储于外部文件中的视图,浏览器不会允许我们的代码在非宿主服务器环境下执行。当然如果你使用Visual Studio那么直接在目标html文件上右键,选择‘View In Browser’即可。

浏览器支持

大部分的现代浏览器都支持本代码。针对IE8及以下的浏览器,有一份单独的代码来支持,但很不幸,这份代码远多于100行。因此这代码不是百分百跨浏览器兼容的,所以当你决定在项目中使用时需要对代码进行微调。

注目点

この例は、非常に明確な要件に対して、それらを達成するためにすべての js ライブラリとフレームワークを使用する必要がないことを示しています。 Web アプリケーションはリソースを大量に消費するため、必要なコードのみを使用し、残りは破棄することが最善です。

現在のコードでできることはこれだけです。 Webサービス呼び出しや動的イベントバインディングなどの機能はありません。より多くの機能をサポートするアップグレード バージョンを間もなく提供する予定です。

JavaScript-Mvc.zip をダウンロード – 4.6 KB JavaScript Mvc on Github ライブデモ

以上がJavaScript MVC スタイル フレームワークを実装するための簡単なコード例の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート