<span id="mktg5"></span>

<i id="mktg5"><meter id="mktg5"></meter></i>

        <label id="mktg5"><meter id="mktg5"></meter></label>
        最新文章專(zhuān)題視頻專(zhuān)題問(wèn)答1問(wèn)答10問(wèn)答100問(wèn)答1000問(wèn)答2000關(guān)鍵字專(zhuān)題1關(guān)鍵字專(zhuān)題50關(guān)鍵字專(zhuān)題500關(guān)鍵字專(zhuān)題1500TAG最新視頻文章推薦1 推薦3 推薦5 推薦7 推薦9 推薦11 推薦13 推薦15 推薦17 推薦19 推薦21 推薦23 推薦25 推薦27 推薦29 推薦31 推薦33 推薦35 推薦37視頻文章20視頻文章30視頻文章40視頻文章50視頻文章60 視頻文章70視頻文章80視頻文章90視頻文章100視頻文章120視頻文章140 視頻2關(guān)鍵字專(zhuān)題關(guān)鍵字專(zhuān)題tag2tag3文章專(zhuān)題文章專(zhuān)題2文章索引1文章索引2文章索引3文章索引4文章索引5123456789101112131415文章專(zhuān)題3
        問(wèn)答文章1 問(wèn)答文章501 問(wèn)答文章1001 問(wèn)答文章1501 問(wèn)答文章2001 問(wèn)答文章2501 問(wèn)答文章3001 問(wèn)答文章3501 問(wèn)答文章4001 問(wèn)答文章4501 問(wèn)答文章5001 問(wèn)答文章5501 問(wèn)答文章6001 問(wèn)答文章6501 問(wèn)答文章7001 問(wèn)答文章7501 問(wèn)答文章8001 問(wèn)答文章8501 問(wèn)答文章9001 問(wèn)答文章9501
        當(dāng)前位置: 首頁(yè) - 科技 - 知識(shí)百科 - 正文

        探索angularjs+requirejs全面實(shí)現(xiàn)按需加載的套路_AngularJS

        來(lái)源:懂視網(wǎng) 責(zé)編:小采 時(shí)間:2020-11-27 20:51:27
        文檔

        探索angularjs+requirejs全面實(shí)現(xiàn)按需加載的套路_AngularJS

        探索angularjs+requirejs全面實(shí)現(xiàn)按需加載的套路_AngularJS:在進(jìn)行有一定規(guī)模的項(xiàng)目時(shí),通常希望實(shí)現(xiàn)以下目標(biāo):1、支持復(fù)雜的頁(yè)面邏輯(根據(jù)業(yè)務(wù)規(guī)則動(dòng)態(tài)展現(xiàn)內(nèi)容,例如:權(quán)限,數(shù)據(jù)狀態(tài)等);2、堅(jiān)持前后端分離的基本原則(不分離的時(shí)候,可以在后端用模版引擎直接生成好頁(yè)面);3、頁(yè)面加載時(shí)間短(業(yè)務(wù)邏輯復(fù)雜就需
        推薦度:
        導(dǎo)讀探索angularjs+requirejs全面實(shí)現(xiàn)按需加載的套路_AngularJS:在進(jìn)行有一定規(guī)模的項(xiàng)目時(shí),通常希望實(shí)現(xiàn)以下目標(biāo):1、支持復(fù)雜的頁(yè)面邏輯(根據(jù)業(yè)務(wù)規(guī)則動(dòng)態(tài)展現(xiàn)內(nèi)容,例如:權(quán)限,數(shù)據(jù)狀態(tài)等);2、堅(jiān)持前后端分離的基本原則(不分離的時(shí)候,可以在后端用模版引擎直接生成好頁(yè)面);3、頁(yè)面加載時(shí)間短(業(yè)務(wù)邏輯復(fù)雜就需

        在進(jìn)行有一定規(guī)模的項(xiàng)目時(shí),通常希望實(shí)現(xiàn)以下目標(biāo):1、支持復(fù)雜的頁(yè)面邏輯(根據(jù)業(yè)務(wù)規(guī)則動(dòng)態(tài)展現(xiàn)內(nèi)容,例如:權(quán)限,數(shù)據(jù)狀態(tài)等);2、堅(jiān)持前后端分離的基本原則(不分離的時(shí)候,可以在后端用模版引擎直接生成好頁(yè)面);3、頁(yè)面加載時(shí)間短(業(yè)務(wù)邏輯復(fù)雜就需要引用第三方的庫(kù),但很可能加載的庫(kù)和用戶(hù)本次操作沒(méi)關(guān)系);4,還要代碼好維護(hù)(加入新的邏輯時(shí),影響的文件盡量少)。

        想同時(shí)實(shí)現(xiàn)這些目標(biāo),就必須有一套按需加載的機(jī)制,頁(yè)面上展現(xiàn)的內(nèi)容和所有需要依賴(lài)的文件,都可以根據(jù)業(yè)務(wù)邏輯需要按需加載。最近都是基于angularjs做開(kāi)發(fā),所以本文主要圍繞angularjs提供的各種機(jī)制,探索全面實(shí)現(xiàn)按需加載的套路。

        一、一步一步實(shí)現(xiàn)
        基本思路:1、先開(kāi)發(fā)一個(gè)框架頁(yè)面,它可以完成一些基本的業(yè)務(wù)邏輯,并且支持?jǐn)U展的機(jī)制;2、業(yè)務(wù)邏輯變復(fù)雜,需要把部分邏輯拆分到子頁(yè)面中,子頁(yè)面按需加載;3、子頁(yè)面中的展現(xiàn)內(nèi)容也變了復(fù)雜,又需要進(jìn)行拆分,按需加載;4、子頁(yè)面的內(nèi)容復(fù)雜到依賴(lài)外部模塊,需要按需加載angular模塊。

        1、框架頁(yè)
        提到前端的按需加載,就會(huì)想到AMD( Asynchronous Module Definition),現(xiàn)在用requirejs的非常多,所以首先考慮引入requires。

        index.html

        <script src="static/js/require.js" defer async data-main="/test/lazyspa/spa-loader.js"></script>

        注意:采用手動(dòng)啟動(dòng)angular的方式,因此html中沒(méi)有ng-app。

        spa-loader.js

        require.config({
         paths: {
         "domReady": '/static/js/domReady',
         "angular": "//cdn.bootcss.com/angular.js/1.4.8/angular.min",
         "angular-route": "//cdn.bootcss.com/angular.js/1.4.8/angular-route.min",
         },
         shim: {
         "angular": {
         exports: "angular"
         },
         "angular-route": {
         deps: ["angular"]
         },
         },
         deps: ['/test/lazyspa/spa.js'],
         urlArgs: "bust=" + (new Date()).getTime()
        });

        spa.js

        define(["require", "angular", "angular-route"], function(require, angular) {
         var app = angular.module('app', ['ngRoute']);
         require(['domReady!'], function(document) {
         angular.bootstrap(document, ["app"]); /*手工啟動(dòng)angular*/
         window.loading.finish();
         });
        });

        2、按需加載子頁(yè)面
        angular的routeProvider+ng-view已經(jīng)提供完整的子頁(yè)面加載的方法,直接用。
        注意必須設(shè)置html5Mode,否則url變化以后,routeProvider不截獲。

        index.html

        <div>
         <a href="/test/lazyspa/page1">page1</a>
         <a href="/test/lazyspa/page2">page2</a>
         <a href="/test/lazyspa/">main</a>
        </div>
        <div ng-view></div>

        spa.js

        app.config(['$locationProvider', '$routeProvider', function($locationProvider, $routeProvider) {
         /* 必須設(shè)置生效,否則下面的設(shè)置不生效 */
         $locationProvider.html5Mode(true);
         /* 根據(jù)url的變化加載內(nèi)容 */
         $routeProvider.when('/test/lazyspa/page1', {
         template: '<div>page1</div>',
         }).when('/test/lazyspa/page2', {
         template: '<div>page2</div>',
         }).otherwise({
         template: '<div>main</div>',
         });
        }]);

        3、按需加載子頁(yè)面中的內(nèi)容
        用routeProvider的前提是url要發(fā)生變化,但是有的時(shí)候只是子頁(yè)面中的局部要發(fā)生變化。如果這些變化主要是和綁定的數(shù)據(jù)相關(guān),不影響頁(yè)面布局,或者影響很小,那么通過(guò)ng-if一類(lèi)的標(biāo)簽基本就解決了。但是有的時(shí)候要根據(jù)頁(yè)面狀態(tài),完全改變局部的內(nèi)容,例如:用戶(hù)登錄前和登錄后局部要發(fā)生的變化等,這就意味著局部的布局可能也挺復(fù)雜,需要作為獨(dú)立的單元來(lái)對(duì)待。

        利用ng-include可以解決頁(yè)面局部?jī)?nèi)容加載的問(wèn)題。但是,我們可以再考慮更復(fù)雜一些的情況。這個(gè)頁(yè)面片段對(duì)應(yīng)的代碼是后端動(dòng)態(tài)生成的,而且不僅僅有html還有js,js中定義了代碼片段對(duì)應(yīng)的controller。這種情況下,不僅僅要考慮動(dòng)態(tài)加載html的問(wèn)題,還要考慮動(dòng)態(tài)定義controller的問(wèn)題。controller是通過(guò)angular的controllerProvider的register方法注冊(cè),因此需要獲得controllerProvider的實(shí)例。

        spa.js

        app.config(['$locationProvider', '$routeProvider', '$controllerProvider', 
        function($locationProvider, $routeProvider, $controllerProvider) {
         app.providers = {
         $controllerProvider: $controllerProvider //注意這里!??!
         };
         /* 必須設(shè)置生效,否則下面的設(shè)置不生效 */
         $locationProvider.html5Mode(true);
         /* 根據(jù)url的變化加載內(nèi)容 */
         $routeProvider.when('/test/lazyspa/page1', {
         /*!!!頁(yè)面中引入動(dòng)態(tài)內(nèi)容!!!*/
         template: '<div>page1</div><div ng-include="\'page1.html\'"></div>',
         controller: 'ctrlPage1'
         }).when('/test/lazyspa/page2', {
         template: '<div>page2</div>',
         }).otherwise({
         template: '<div>main</div>',
         });
         app.controller('ctrlPage1', ['$scope', '$templateCache', function($scope, $templateCache) {
         /* 用這種方式,ng-include配合,根據(jù)業(yè)務(wù)邏輯動(dòng)態(tài)獲取頁(yè)面內(nèi)容 */
         /* !!!動(dòng)態(tài)的定義controller!!! */
         app.providers.$controllerProvider.register('ctrlPage1Dyna', ['$scope', function($scope) {
         $scope.openAlert = function() {
         alert('page1 alert');
         };
         }]);
         /* !!!動(dòng)態(tài)定義頁(yè)面的內(nèi)容!!! */
         $templateCache.put('page1.html', '<div ng-controller="ctrlPage1Dyna">
         <button ng-click="openAlert()">alert</button></div>');
         }]);
        }]);

        4、動(dòng)態(tài)加載模塊
        采用上面子頁(yè)面片段的加載方式存在一個(gè)局限,就是各種邏輯(js)要加入到啟動(dòng)模塊中,這樣還是限制子頁(yè)面片段的獨(dú)立封裝。特別是,如果子頁(yè)面片段需要使用第三方模塊,且這個(gè)模塊在啟動(dòng)模塊中沒(méi)有事先加載時(shí),就沒(méi)有辦法了。所以,必須要能夠?qū)崿F(xiàn)模塊的動(dòng)態(tài)加載。實(shí)現(xiàn)模塊的動(dòng)態(tài)加載就是把a(bǔ)ngular啟動(dòng)過(guò)程中加載模塊的方式提取出來(lái),再處理一些特殊情況。

        但是,實(shí)際跑起來(lái)發(fā)現(xiàn)文章中的代碼有問(wèn)題,就是“$injector”到底是什么?研究了angular的源代碼injector.js才大概搞明白是怎么回事。

        一個(gè)應(yīng)用有兩個(gè)$injector,providerInjector和instanceInjector。invokeQueue和用providerInjector,runBlocks用instanceProvider。如果$injector用錯(cuò)了,就會(huì)找到需要的服務(wù)。

        routeProvider中動(dòng)態(tài)加載模塊文件。

        template: '<div ng-controller="ctrlModule1"><div>page2</div><div>
        <button ng-click="openDialog()">open dialog</button></div></div>',
        resolve: {
         load: ['$q', function($q) {
         var defer = $q.defer();
         /* 動(dòng)態(tài)加載angular模塊 */
         require(['/test/lazyspa/module1.js'], function(loader) {
         loader.onload && loader.onload(function() {
         defer.resolve();
         });
         });
         return defer.promise;
         }]
        }

        動(dòng)態(tài)加載angular模塊

        angular._lazyLoadModule = function(moduleName) {
         var m = angular.module(moduleName);
         console.log('register module:' + moduleName);
         /* 應(yīng)用的injector,和config中的injector不是同一個(gè),是instanceInject,返回的是通過(guò)provider.$get創(chuàng)建的實(shí)例 */
         var $injector = angular.element(document).injector();
         /* 遞歸加載依賴(lài)的模塊 */
         angular.forEach(m.requires, function(r) {
         angular._lazyLoadModule(r);
         });
         /* 用provider的injector運(yùn)行模塊的controller,directive等等 */
         angular.forEach(m._invokeQueue, function(invokeArgs) {
         try {
         var provider = providers.$injector.get(invokeArgs[0]);
         provider[invokeArgs[1]].apply(provider, invokeArgs[2]);
         } catch (e) {
         console.error('load module invokeQueue failed:' + e.message, invokeArgs);
         }
         });
         /* 用provider的injector運(yùn)行模塊的config */
         angular.forEach(m._configBlocks, function(invokeArgs) {
         try {
         providers.$injector.invoke.apply(providers.$injector, invokeArgs[2]);
         } catch (e) {
         console.error('load module configBlocks failed:' + e.message, invokeArgs);
         }
         });
         /* 用應(yīng)用的injector運(yùn)行模塊的run */
         angular.forEach(m._runBlocks, function(fn) {
         $injector.invoke(fn);
         });
        };

        定義模塊
        module1.js

        define(["angular"], function(angular) {
         var onloads = [];
         var loadCss = function(url) {
         var link, head;
         link = document.createElement('link');
         link.href = url;
         link.rel = 'stylesheet';
         head = document.querySelector('head');
         head.appendChild(link);
         };
         loadCss('//cdn.bootcss.com/bootstrap/3.3.6/css/bootstrap.min.css');
         /* !!! 動(dòng)態(tài)定義requirejs !!!*/
         require.config({
         paths: {
         'ui-bootstrap-tpls': '//cdn.bootcss.com/angular-ui-bootstrap/1.1.2/ui-bootstrap-tpls.min'
         },
         shim: {
         "ui-bootstrap-tpls": {
         deps: ['angular']
         }
         }
         });
         /*!!! 模塊中需要引用第三方的庫(kù),加載模塊依賴(lài)的模塊 !!!*/
         require(['ui-bootstrap-tpls'], function() {
         var m1 = angular.module('module1', ['ui.bootstrap']);
         m1.config(['$controllerProvider', function($controllerProvider) {
         console.log('module1 - config begin');
         }]);
         m1.controller('ctrlModule1', ['$scope', '$uibModal', function($scope, $uibModal) {
         console.log('module1 - ctrl begin');
         /*!!! 打開(kāi)angular ui的對(duì)話(huà)框 !!!*/
         var dlg = '<div class="modal-header">';
         dlg += '<h3 class="modal-title">I\'m a modal!</h3>';
         dlg += '</div>';
         dlg += '<div class="modal-body">content</div>';
         dlg += '<div class="modal-footer">';
         dlg += '<button class="btn btn-primary" type="button" ng-click="ok()">OK</button>';
         dlg += '<button class="btn btn-warning" type="button" ng-click="cancel()">Cancel</button>';
         dlg += '</div>';
         $scope.openDialog = function() {
         $uibModal.open({
         template: dlg,
         controller: ['$scope', '$uibModalInstance', function($scope, $mi) {
         $scope.cancel = function() {
         $mi.dismiss();
         };
         $scope.ok = function() {
         $mi.close();
         };
         }],
         backdrop: 'static'
         });
         };
         }]);
         /* !!!動(dòng)態(tài)加載模塊!!! */
         angular._lazyLoadModule('module1');
         console.log('module1 loaded');
         angular.forEach(onloads, function(onload) {
         angular.isFunction(onload) && onload();
         });
         });
         return {
         onload: function(callback) {
         onloads.push(callback);
         }
         };
        });

        二、完整的代碼
        index.html

        <!DOCTYPE html>
        <html>
         <head>
         <meta charset="utf-8">
         <meta content="width=device-width,user-scalable=no,initial-scale=1.0" name="viewport">
         <base href='/'>
         <title>SPA</title>
         </head>
         <body>
         <div ng-controller='ctrlMain'>
         <div>
         <a href="/test/lazyspa/page1">page1</a>
         <a href="/test/lazyspa/page2">page2</a>
         <a href="/test/lazyspa/">main</a>
         </div>
         <div ng-view></div>
         </div>
         <div class="loading"><div class='loading-indicator'><i></i></div></div>
         <script src="static/js/require.js" defer async data-main="/test/lazyspa/spa-loader.js?_=3"></script>
         </body>
        </html>

        spa-loader.js

        window.loading = {
         finish: function() {
         /* 保留個(gè)方法做一些加載完成后的處理,我實(shí)際的項(xiàng)目中會(huì)在這里結(jié)束加載動(dòng)畫(huà) */
         },
         load: function() {
         require.config({
         paths: {
         "domReady": '/static/js/domReady',
         "angular": "//cdn.bootcss.com/angular.js/1.4.8/angular.min",
         "angular-route": "//cdn.bootcss.com/angular.js/1.4.8/angular-route.min",
         },
         shim: {
         "angular": {
         exports: "angular"
         },
         "angular-route": {
         deps: ["angular"]
         },
         },
         deps: ['/test/lazyspa/spa.js'],
         urlArgs: "bust=" + (new Date()).getTime()
         });
         }
        };
        window.loading.load();

        spa.js

        'use strict';
        define(["require", "angular", "angular-route"], function(require, angular) {
         var app = angular.module('app', ['ngRoute']);
         /* 延遲加載模塊 */
         angular._lazyLoadModule = function(moduleName) {
         var m = angular.module(moduleName);
         console.log('register module:' + moduleName);
         /* 應(yīng)用的injector,和config中的injector不是同一個(gè),是instanceInject,返回的是通過(guò)provider.$get創(chuàng)建的實(shí)例 */
         var $injector = angular.element(document).injector();
         /* 遞歸加載依賴(lài)的模塊 */
         angular.forEach(m.requires, function(r) {
         angular._lazyLoadModule(r);
         });
         /* 用provider的injector運(yùn)行模塊的controller,directive等等 */
         angular.forEach(m._invokeQueue, function(invokeArgs) {
         try {
         var provider = providers.$injector.get(invokeArgs[0]);
         provider[invokeArgs[1]].apply(provider, invokeArgs[2]);
         } catch (e) {
         console.error('load module invokeQueue failed:' + e.message, invokeArgs);
         }
         });
         /* 用provider的injector運(yùn)行模塊的config */
         angular.forEach(m._configBlocks, function(invokeArgs) {
         try {
         providers.$injector.invoke.apply(providers.$injector, invokeArgs[2]);
         } catch (e) {
         console.error('load module configBlocks failed:' + e.message, invokeArgs);
         }
         });
         /* 用應(yīng)用的injector運(yùn)行模塊的run */
         angular.forEach(m._runBlocks, function(fn) {
         $injector.invoke(fn);
         });
         };
         app.config(['$injector', '$locationProvider', '$routeProvider', '$controllerProvider', 
         function($injector, $locationProvider, $routeProvider, $controllerProvider) {
         /**
         * config中的injector和應(yīng)用的injector不是同一個(gè),是providerInjector,獲得的是provider,
         而不是通過(guò)provider創(chuàng)建的實(shí)例
         * 這個(gè)injector通過(guò)angular無(wú)法獲得,所以在執(zhí)行config的時(shí)候把它保存下來(lái)
         */
         app.providers = {
         $injector: $injector,
         $controllerProvider: $controllerProvider
         };
         /* 必須設(shè)置生效,否則下面的設(shè)置不生效 */
         $locationProvider.html5Mode(true);
         /* 根據(jù)url的變化加載內(nèi)容 */
         $routeProvider.when('/test/lazyspa/page1', {
         template: '<div>page1</div><div ng-include="\'page1.html\'"></div>',
         controller: 'ctrlPage1'
         }).when('/test/lazyspa/page2', {
         template: '<div ng-controller="ctrlModule1"><div>page2</div><div>
         <button ng-click="openDialog()">open dialog</button></div></div>',
         resolve: {
         load: ['$q', function($q) {
         var defer = $q.defer();
         /* 動(dòng)態(tài)加載angular模塊 */
         require(['/test/lazyspa/module1.js'], function(loader) {
         loader.onload && loader.onload(function() {
         defer.resolve();
         });
         });
         return defer.promise;
         }]
         }
         }).otherwise({
         template: '<div>main</div>',
         });
         }]);
         app.controller('ctrlMain', ['$scope', '$location', function($scope, $location) {
         console.log('main controller');
         /* 根據(jù)業(yè)務(wù)邏輯自動(dòng)到缺省的視圖 */
         $location.url('/test/lazyspa/page1');
         }]);
         app.controller('ctrlPage1', ['$scope', '$templateCache', function($scope, $templateCache) {
         /* 用這種方式,ng-include配合,根據(jù)業(yè)務(wù)邏輯動(dòng)態(tài)獲取頁(yè)面內(nèi)容 */
         /* 動(dòng)態(tài)的定義controller */
         app.providers.$controllerProvider.register('ctrlPage1Dyna', ['$scope', function($scope) {
         $scope.openAlert = function() {
         alert('page1 alert');
         };
         }]);
         /* 動(dòng)態(tài)定義頁(yè)面內(nèi)容 */
         $templateCache.put('page1.html', '<div ng-controller="ctrlPage1Dyna">
         <button ng-click="openAlert()">alert</button></div>');
         }]);
         require(['domReady!'], function(document) {
         angular.bootstrap(document, ["app"]);
         });
        });

        module1.js

        'use strict';
        define(["angular"], function(angular) {
         var onloads = [];
         var loadCss = function(url) {
         var link, head;
         link = document.createElement('link');
         link.href = url;
         link.rel = 'stylesheet';
         head = document.querySelector('head');
         head.appendChild(link);
         };
         loadCss('//cdn.bootcss.com/bootstrap/3.3.6/css/bootstrap.min.css');
         require.config({
         paths: {
         'ui-bootstrap-tpls': '//cdn.bootcss.com/angular-ui-bootstrap/1.1.2/ui-bootstrap-tpls.min'
         },
         shim: {
         "ui-bootstrap-tpls": {
         deps: ['angular']
         }
         }
         });
         require(['ui-bootstrap-tpls'], function() {
         var m1 = angular.module('module1', ['ui.bootstrap']);
         m1.config(['$controllerProvider', function($controllerProvider) {
         console.log('module1 - config begin');
         }]);
         m1.controller('ctrlModule1', ['$scope', '$uibModal', function($scope, $uibModal) {
         console.log('module1 - ctrl begin');
         var dlg = '<div class="modal-header">';
         dlg += '<h3 class="modal-title">I\'m a modal!</h3>';
         dlg += '</div>';
         dlg += '<div class="modal-body">content</div>';
         dlg += '<div class="modal-footer">';
         dlg += '<button class="btn btn-primary" type="button" ng-click="ok()">OK</button>';
         dlg += '<button class="btn btn-warning" type="button" ng-click="cancel()">Cancel</button>';
         dlg += '</div>';
         $scope.openDialog = function() {
         $uibModal.open({
         template: dlg,
         controller: ['$scope', '$uibModalInstance', function($scope, $mi) {
         $scope.cancel = function() {
         $mi.dismiss();
         };
         $scope.ok = function() {
         $mi.close();
         };
         }],
         backdrop: 'static'
         });
         };
         }]);
         angular._lazyLoadModule('module1');
         console.log('module1 loaded');
         angular.forEach(onloads, function(onload) {
         angular.isFunction(onload) && onload();
         });
         });
         return {
         onload: function(callback) {
         onloads.push(callback);
         }
         };
        });

        聲明:本網(wǎng)頁(yè)內(nèi)容旨在傳播知識(shí),若有侵權(quán)等問(wèn)題請(qǐng)及時(shí)與本網(wǎng)聯(lián)系,我們將在第一時(shí)間刪除處理。TEL:177 7030 7066 E-MAIL:11247931@qq.com

        文檔

        探索angularjs+requirejs全面實(shí)現(xiàn)按需加載的套路_AngularJS

        探索angularjs+requirejs全面實(shí)現(xiàn)按需加載的套路_AngularJS:在進(jìn)行有一定規(guī)模的項(xiàng)目時(shí),通常希望實(shí)現(xiàn)以下目標(biāo):1、支持復(fù)雜的頁(yè)面邏輯(根據(jù)業(yè)務(wù)規(guī)則動(dòng)態(tài)展現(xiàn)內(nèi)容,例如:權(quán)限,數(shù)據(jù)狀態(tài)等);2、堅(jiān)持前后端分離的基本原則(不分離的時(shí)候,可以在后端用模版引擎直接生成好頁(yè)面);3、頁(yè)面加載時(shí)間短(業(yè)務(wù)邏輯復(fù)雜就需
        推薦度:
        • 熱門(mén)焦點(diǎn)

        最新推薦

        猜你喜歡

        熱門(mén)推薦

        專(zhuān)題
        Top
        主站蜘蛛池模板: 丁香花免费高清视频完整版| 区久久AAA片69亚洲| 全部在线播放免费毛片| 亚洲综合精品香蕉久久网| 啦啦啦完整版免费视频在线观看| 亚洲一卡2卡三卡4卡无卡下载| 国产亚洲av人片在线观看| 免费H网站在线观看的| xxxxx做受大片视频免费| 亚洲人成777在线播放| 国产亚洲视频在线播放| 日韩精品福利片午夜免费观着| 中国好声音第二季免费播放| 日韩亚洲产在线观看| 亚洲精品成人无码中文毛片不卡| 成年在线观看免费人视频草莓| 免费人成激情视频在线观看冫| 亚洲精品女同中文字幕| 亚洲久本草在线中文字幕| 亚洲AV无码乱码在线观看性色扶 | 免费福利在线播放| 国产成人自产拍免费视频| 亚洲黄页网在线观看| 亚洲第一精品在线视频| 亚洲A∨精品一区二区三区| 久久WWW免费人成人片| 免费高清国产视频| 精品女同一区二区三区免费播放| 亚洲色图.com| 亚洲成AV人片一区二区密柚| 四虎影视在线永久免费观看| 中文字幕乱码免费视频| 久草视频在线免费看| 羞羞视频在线观看免费| 日本亚洲欧美色视频在线播放| 亚洲成人午夜电影| 亚洲国产精品久久久久| 国产成人亚洲综合色影视| 亚洲中文字幕伊人久久无码| 国产男女猛烈无遮挡免费视频网站| 免费观看美女用震蛋喷水的视频|