Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

你好,请问怎么不通过使用路由,来异步加载HTML及JS,并使它成功编译成ANGULAR局部应用? #7

Open
vrbvillor opened this issue Aug 18, 2016 · 11 comments

Comments

@vrbvillor
Copy link

vrbvillor commented Aug 18, 2016

这是这块代码的压缩包。
https://github.com/CHIheart/CHIanimate/blob/master/async.rar

index.html

<!DOCTYPE html>
<html ng-controller="CtrlMain">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title>Examples</title>
<meta name="description" content="">
<meta name="keywords" content="">
<link href="" rel="stylesheet">
</head>
<body>


<button>load!!!</button>
<div id="Sync" ng-controller="CtrlSync">{{message}}{{LoginInfo.username}}</div>

</body>
</html>

<script src="./angular1.2.29.js"></script>
<script src="./sea2.3.0.js"></script>
<script>

seajs.use('./js')
</script>

js.js

define(function(require,exports,module){
    angular.module('AppLogin',[])
        .value('LoginInfo',{
            login:false,
            username:'用户名称'
        })
    angular.module('AppMain',['AppLogin'])
        .controller('CtrlMain',['$scope',function($scope){}])
        .controller('CtrlSync', ['$scope','LoginInfo', function($scope,LoginInfo){
            $scope.message="This is a sync controller."
            $scope.LoginInfo=LoginInfo;
        }]);
    angular.element(document.getElementsByTagName("button")[0]).on('click',function(event) {
        require.async(['./try.css','./try.html','./try.js'],function(css,html,js){
            angular.element(document.body).append(html)
        });
    });
    angular.bootstrap(document, ['AppMain'])
});

try.css

body{
    background-color: gray;
}

div{
    width: 100px;
    height: 100px;
    border: 1px solid red;
}

try.html

<div ng-app="AppTry" ng-controller="CtrlTry">{{message}}{{LoginInfo.username}}
<button ng-click="login();">登录</button>
</div>

try.js

define(function(require,exports,module){

    angular.module('AppMain')
        .controller('CtrlTry', ['$scope','$timeout','LoginInfo' , function ($scope,$timeout,LoginInfo) {
            $scope.message="This is the message!";
            $scope.login=function(){
                $timeout(function(){
                    $scope.LoginInfo.username="已登录用户";
                alert(1)

                });
            }
        }]);
});

sea2.3.0.js,这里边混入了sea的两个插件sea-textsea-css

/*! Sea.js 2.3.0 | seajs.org/LICENSE.md */
!function(a,b){function c(a){return function(b){return{}.toString.call(b)=="[object "+a+"]"}}function d(){return z++}function e(a){return a.match(C)[0]}function f(a){for(a=a.replace(D,"/"),a=a.replace(F,"$1/");a.match(E);)a=a.replace(E,"/");return a}function g(a){var b=a.length-1,c=a.charAt(b);return"#"===c?a.substring(0,b):".js"===a.substring(b-2)||a.indexOf("?")>0||"/"===c?a:a+".js"}function h(a){var b=u.alias;return b&&w(b[a])?b[a]:a}function i(a){var b=u.paths,c;return b&&(c=a.match(G))&&w(b[c[1]])&&(a=b[c[1]]+c[2]),a}function j(a){var b=u.vars;return b&&a.indexOf("{")>-1&&(a=a.replace(H,function(a,c){return w(b[c])?b[c]:a})),a}function k(a){var b=u.map,c=a;if(b)for(var d=0,e=b.length;e>d;d++){var f=b[d];if(c=y(f)?f(a)||a:a.replace(f[0],f[1]),c!==a)break}return c}function l(a,b){var c,d=a.charAt(0);if(I.test(a))c=a;else if("."===d)c=f((b?e(b):u.cwd)+a);else if("/"===d){var g=u.cwd.match(J);c=g?g[0]+a.substring(1):a}else c=u.base+a;return 0===c.indexOf("//")&&(c=location.protocol+c),c}function m(a,b){if(!a)return"";a=h(a),a=i(a),a=j(a),a=g(a);var c=l(a,b);return c=k(c)}function n(a){return a.hasAttribute?a.src:a.getAttribute("src",4)}function o(a,b,c){var d=K.createElement("script");if(c){var e=y(c)?c(a):c;e&&(d.charset=e)}p(d,b,a),d.async=!0,d.src=a,R=d,Q?P.insertBefore(d,Q):P.appendChild(d),R=null}function p(a,b,c){function d(){a.onload=a.onerror=a.onreadystatechange=null,u.debug||P.removeChild(a),a=null,b()}var e="onload"in a;e?(a.onload=d,a.onerror=function(){B("error",{uri:c,node:a}),d()}):a.onreadystatechange=function(){/loaded|complete/.test(a.readyState)&&d()}}function q(){if(R)return R;if(S&&"interactive"===S.readyState)return S;for(var a=P.getElementsByTagName("script"),b=a.length-1;b>=0;b--){var c=a[b];if("interactive"===c.readyState)return S=c}}function r(a){var b=[];return a.replace(U,"").replace(T,function(a,c,d){d&&b.push(d)}),b}function s(a,b){this.uri=a,this.dependencies=b||[],this.exports=null,this.status=0,this._waitings={},this._remain=0}if(!a.seajs){var t=a.seajs={version:"2.3.0"},u=t.data={},v=c("Object"),w=c("String"),x=Array.isArray||c("Array"),y=c("Function"),z=0,A=u.events={};t.on=function(a,b){var c=A[a]||(A[a]=[]);return c.push(b),t},t.off=function(a,b){if(!a&&!b)return A=u.events={},t;var c=A[a];if(c)if(b)for(var d=c.length-1;d>=0;d--)c[d]===b&&c.splice(d,1);else delete A[a];return t};var B=t.emit=function(a,b){var c=A[a],d;if(c){c=c.slice();for(var e=0,f=c.length;f>e;e++)c[e](b)}return t},C=/[^?#]*\//,D=/\/\.\//g,E=/\/[^/]+\/\.\.\//,F=/([^:/])\/+\//g,G=/^([^/:]+)(\/.+)$/,H=/{([^{]+)}/g,I=/^\/\/.|:\//,J=/^.*?\/\/.*?\//,K=document,L=location.href&&0!==location.href.indexOf("about:")?e(location.href):"",M=K.scripts,N=K.getElementById("seajsnode")||M[M.length-1],O=e(n(N)||L);t.resolve=m;var P=K.head||K.getElementsByTagName("head")[0]||K.documentElement,Q=P.getElementsByTagName("base")[0],R,S;t.request=o;var T=/"(?:\\"|[^"])*"|'(?:\\'|[^'])*'|\/\*[\S\s]*?\*\/|\/(?:\\\/|[^\/\r\n])+\/(?=[^\/])|\/\/.*|\.\s*require|(?:^|[^$])\brequire\s*\(\s*(["'])(.+?)\1\s*\)/g,U=/\\\\/g,V=t.cache={},W,X={},Y={},Z={},$=s.STATUS={FETCHING:1,SAVED:2,LOADING:3,LOADED:4,EXECUTING:5,EXECUTED:6};s.prototype.resolve=function(){for(var a=this,b=a.dependencies,c=[],d=0,e=b.length;e>d;d++)c[d]=s.resolve(b[d],a.uri);return c},s.prototype.load=function(){var a=this;if(!(a.status>=$.LOADING)){a.status=$.LOADING;var c=a.resolve();B("load",c);for(var d=a._remain=c.length,e,f=0;d>f;f++)e=s.get(c[f]),e.status<$.LOADED?e._waitings[a.uri]=(e._waitings[a.uri]||0)+1:a._remain--;if(0===a._remain)return a.onload(),b;var g={};for(f=0;d>f;f++)e=V[c[f]],e.status<$.FETCHING?e.fetch(g):e.status===$.SAVED&&e.load();for(var h in g)g.hasOwnProperty(h)&&g[h]()}},s.prototype.onload=function(){var a=this;a.status=$.LOADED,a.callback&&a.callback();var b=a._waitings,c,d;for(c in b)b.hasOwnProperty(c)&&(d=V[c],d._remain-=b[c],0===d._remain&&d.onload());delete a._waitings,delete a._remain},s.prototype.fetch=function(a){function c(){t.request(g.requestUri,g.onRequest,g.charset)}function d(){delete X[h],Y[h]=!0,W&&(s.save(f,W),W=null);var a,b=Z[h];for(delete Z[h];a=b.shift();)a.load()}var e=this,f=e.uri;e.status=$.FETCHING;var g={uri:f};B("fetch",g);var h=g.requestUri||f;return!h||Y[h]?(e.load(),b):X[h]?(Z[h].push(e),b):(X[h]=!0,Z[h]=[e],B("request",g={uri:f,requestUri:h,onRequest:d,charset:u.charset}),g.requested||(a?a[g.requestUri]=c:c()),b)},s.prototype.exec=function(){function a(b){return s.get(a.resolve(b)).exec()}var c=this;if(c.status>=$.EXECUTING)return c.exports;c.status=$.EXECUTING;var e=c.uri;a.resolve=function(a){return s.resolve(a,e)},a.async=function(b,c){return s.use(b,c,e+"_async_"+d()),a};var f=c.factory,g=y(f)?f(a,c.exports={},c):f;return g===b&&(g=c.exports),delete c.factory,c.exports=g,c.status=$.EXECUTED,B("exec",c),g},s.resolve=function(a,b){var c={id:a,refUri:b};return B("resolve",c),c.uri||t.resolve(c.id,b)},s.define=function(a,c,d){var e=arguments.length;1===e?(d=a,a=b):2===e&&(d=c,x(a)?(c=a,a=b):c=b),!x(c)&&y(d)&&(c=r(""+d));var f={id:a,uri:s.resolve(a),deps:c,factory:d};if(!f.uri&&K.attachEvent){var g=q();g&&(f.uri=g.src)}B("define",f),f.uri?s.save(f.uri,f):W=f},s.save=function(a,b){var c=s.get(a);c.status<$.SAVED&&(c.id=b.id||a,c.dependencies=b.deps||[],c.factory=b.factory,c.status=$.SAVED,B("save",c))},s.get=function(a,b){return V[a]||(V[a]=new s(a,b))},s.use=function(b,c,d){var e=s.get(d,x(b)?b:[b]);e.callback=function(){for(var b=[],d=e.resolve(),f=0,g=d.length;g>f;f++)b[f]=V[d[f]].exec();c&&c.apply(a,b),delete e.callback},e.load()},t.use=function(a,b){return s.use(a,b,u.cwd+"_use_"+d()),t},s.define.cmd={},a.define=s.define,t.Module=s,u.fetchedList=Y,u.cid=d,t.require=function(a){var b=s.get(s.resolve(a));return b.status<$.EXECUTING&&(b.onload(),b.exec()),b.exports},u.base=O,u.dir=O,u.cwd=L,u.charset="utf-8",t.config=function(a){for(var b in a){var c=a[b],d=u[b];if(d&&v(d))for(var e in c)d[e]=c[e];else x(d)?c=d.concat(c):"base"===b&&("/"!==c.slice(-1)&&(c+="/"),c=l(c)),u[b]=c}return B("config",a),t}}}(this);

!function(){function a(a){return function(b){return{}.toString.call(b)=="[object "+a+"]"}}function b(a){return"[object Function]"=={}.toString.call(a)}function c(a,c,e,f){var g=u.test(a),h=r.createElement(g?"link":"script");if(e){var i=b(e)?e(a):e;i&&(h.charset=i)}void 0!==f&&h.setAttribute("crossorigin",f),d(h,c,g,a),g?(h.rel="stylesheet",h.href=a):(h.async=!0,h.src=a),p=h,t?s.insertBefore(h,t):s.appendChild(h),p=null}function d(a,b,c,d){function f(){a.onload=a.onerror=a.onreadystatechange=null,c||seajs.data.debug||s.removeChild(a),a=null,b()}var g="onload"in a;return!c||!v&&g?(g?(a.onload=f,a.onerror=function(){seajs.emit("error",{uri:d,node:a}),f()}):a.onreadystatechange=function(){/loaded|complete/.test(a.readyState)&&f()},void 0):(setTimeout(function(){e(a,b)},1),void 0)}function e(a,b){var c,d=a.sheet;if(v)d&&(c=!0);else if(d)try{d.cssRules&&(c=!0)}catch(f){"NS_ERROR_DOM_SECURITY_ERR"===f.name&&(c=!0)}setTimeout(function(){c?b():e(a,b)},20)}function f(a){return a.match(x)[0]}function g(a){for(a=a.replace(y,"/"),a=a.replace(A,"$1/");a.match(z);)a=a.replace(z,"/");return a}function h(a){var b=a.length-1,c=a.charAt(b);return"#"===c?a.substring(0,b):".js"===a.substring(b-2)||a.indexOf("?")>0||".css"===a.substring(b-3)||"/"===c?a:a+".js"}function i(a){var b=w.alias;return b&&q(b[a])?b[a]:a}function j(a){var b,c=w.paths;return c&&(b=a.match(B))&&q(c[b[1]])&&(a=c[b[1]]+b[2]),a}function k(a){var b=w.vars;return b&&a.indexOf("{")>-1&&(a=a.replace(C,function(a,c){return q(b[c])?b[c]:a})),a}function l(a){var c=w.map,d=a;if(c)for(var e=0,f=c.length;f>e;e++){var g=c[e];if(d=b(g)?g(a)||a:a.replace(g[0],g[1]),d!==a)break}return d}function m(a,b){var c,d=a.charAt(0);if(D.test(a))c=a;else if("."===d)c=g((b?f(b):w.cwd)+a);else if("/"===d){var e=w.cwd.match(E);c=e?e[0]+a.substring(1):a}else c=w.base+a;return 0===c.indexOf("//")&&(c=location.protocol+c),c}function n(a,b){if(!a)return"";a=i(a),a=j(a),a=k(a),a=h(a);var c=m(a,b);return c=l(c)}function o(a){return a.hasAttribute?a.src:a.getAttribute("src",4)}var p,q=a("String"),r=document,s=r.head||r.getElementsByTagName("head")[0]||r.documentElement,t=s.getElementsByTagName("base")[0],u=/\.css(?:\?|$)/i,v=+navigator.userAgent.replace(/.*(?:AppleWebKit|AndroidWebKit)\/?(\d+).*/i,"$1")<536;seajs.request=c;var w=seajs.data,x=/[^?#]*\//,y=/\/\.\//g,z=/\/[^/]+\/\.\.\//,A=/([^:/])\/+\//g,B=/^([^/:]+)(\/.+)$/,C=/{([^{]+)}/g,D=/^\/\/.|:\//,E=/^.*?\/\/.*?\//,r=document,F=location.href&&0!==location.href.indexOf("about:")?f(location.href):"",G=r.scripts,H=r.getElementById("seajsnode")||G[G.length-1];f(o(H)||F),seajs.resolve=n,define("seajs/seajs-css/1.0.5/seajs-css",[],{})}();

!function(){function a(a){h[a.name]=a}function b(a){return a&&h.hasOwnProperty(a)}function c(a){for(var c in h)if(b(c)){var d=","+h[c].ext.join(",")+",";if(d.indexOf(","+a+",")>-1)return c}}function d(a,b){var c=g.XMLHttpRequest?new g.XMLHttpRequest:new g.ActiveXObject("Microsoft.XMLHTTP");return c.open("GET",a,!0),c.onreadystatechange=function(){if(4===c.readyState){if(c.status>399&&c.status<600)throw new Error("Could not load: "+a+", status = "+c.status);b(c.responseText)}},c.send(null)}function e(a){a&&/\S/.test(a)&&(g.execScript||function(a){(g.eval||eval).call(g,a)})(a)}function f(a){return a.replace(/(["\\])/g,"\\$1").replace(/[\f]/g,"\\f").replace(/[\b]/g,"\\b").replace(/[\n]/g,"\\n").replace(/[\t]/g,"\\t").replace(/[\r]/g,"\\r").replace(/[\u2028]/g,"\\u2028").replace(/[\u2029]/g,"\\u2029")}var g=window,h={},i={};a({name:"text",ext:[".tpl",".html"],exec:function(a,b){e('define("'+a+'#", [], "'+f(b)+'")')}}),a({name:"json",ext:[".json"],exec:function(a,b){e('define("'+a+'#", [], '+b+")")}}),a({name:"handlebars",ext:[".handlebars"],exec:function(a,b){var c=['define("'+a+'#", ["handlebars"], function(require, exports, module) {','  var source = "'+f(b)+'"','  var Handlebars = require("handlebars")["default"]',"  module.exports = function(data, options) {","    options || (options = {})","    options.helpers || (options.helpers = {})","    for (var key in Handlebars.helpers) {","      options.helpers[key] = options.helpers[key] || Handlebars.helpers[key]","    }","    return Handlebars.compile(source)(data, options)","  }","})"].join("\n");e(c)}}),seajs.on("resolve",function(a){var d=a.id;if(!d)return"";var e,f;(f=d.match(/^(\w+)!(.+)$/))&&b(f[1])?(e=f[1],d=f[2]):(f=d.match(/[^?]+(\.\w+)(?:\?|#|$)/))&&(e=c(f[1])),e&&-1===d.indexOf("#")&&(d+="#");var g=seajs.resolve(d,a.refUri);e&&(i[g]=e),a.uri=g}),seajs.on("request",function(a){var b=i[a.uri];b&&(d(a.requestUri,function(c){h[b].exec(a.uri,c),a.onRequest()}),a.requested=!0)}),define("seajs/seajs-text/1.1.1/seajs-text",[],{})}();

现在的效果就是点击按钮之后,加载的CSS跟HTML都是正常的,JS貌似也是正常的,但就是没办法让加进来的HTML变成有效的ANGULAR局部应用。

@subchen
Copy link
Owner

subchen commented Aug 18, 2016

你的代码中有一段如下:

angular.element(document.body).append(html)

这种方式加入的 html 没有经过 angular 处理,所以正确无法识别里面的 ng directive.

你需要用 $compile 对 html进行编译,连接才行, 然后在加入到 dom tree。

var html = '<div ng-model="xxx" />';
var dom = angular.element(document.body);
var parentScope = dom.scope();
var newElem = $compile(html)(parentScope);
dom.append(newElem);

上面的代码不一定能工作,只是提供一种思路和范例。

参考:

  1. https://segmentfault.com/q/1010000002593982
  2. http://www.gsgundam.com/2014-12-13-angularjs-compile-to-show-dymanic-html-content/

@vrbvillor
Copy link
Author

vrbvillor commented Aug 18, 2016

我试过,在JS.JS里边加入$compile(html)($scope)但是不行。而且我的没有directive,只是controller。

@subchen
Copy link
Owner

subchen commented Aug 18, 2016

有controller也可以的,只要能拿到 $compile service 就可以了。

@vrbvillor
Copy link
Author

vrbvillor commented Aug 18, 2016

这是我的第二种写法 https://github.com/CHIheart/CHIanimate/blob/master/async2.rar
它报错,报我要编译的那段HTML上的控制器不存在。

@vrbvillor
Copy link
Author

vrbvillor commented Aug 18, 2016

这是我的第三种写法 https://github.com/CHIheart/CHIanimate/blob/master/async3.rar
因为我刚才想到,作用域不应该是原来的作用域,应该是新加进去的那个元素上的作用域,所以我把作用域写成它了,但是依然报控制器不存在。
就算是先把HTML加进去,再编译也不行,只要链接到作用域就会报错,光编译时不会报错。

@subchen
Copy link
Owner

subchen commented Aug 18, 2016

$scope.load=function() {
    require.async(['./try.css','./try.html','./try.js'],function(css,html,js){
        $compile(html)($scope);
        angular.element(document.body).append(html)
    });
}

你的代码有 2 个问题:

  1. 需要把 try.js 动态注入到 angular.module 里面去(动态注入你就必须用到 angular-async-loader)
  2. 不能 append 原始的 html, 而是应该 append 编译后的 dom 对象

新的范例代码如下:

js.js

angular.module('AppMain',['AppLogin'])
.controller('CtrlMain',['$scope','$compile',function($scope,$compile){
    $scope.load=function() {
       require.async(['./try.css','./try.html','./try.js'],function(css,html,js) {
          var dom = $compile(html)($scope);
          var body = angular.element(document.body);
          body.append(dom)
          body.append('<style>\n' + css + '\n</style>')
       });
    }
}

try.js

define(function(require,exports,module){
    var asyncLoader = require('angular-async-loader');

    var app = angular.module('AppMain');
    asyncLoader.configure(app);
    app.controller('CtrlTry', ['$scope','$timeout','LoginInfo' , function ($scope,$timeout,LoginInfo) {
        $scope.message="This is the message!";
        $scope.login=function(){
            $timeout(function(){
                $scope.LoginInfo.username="已登录用户";
                alert(1)
            });
        }
    }]);
});

@vrbvillor
Copy link
Author

vrbvillor commented Aug 18, 2016

话说,大侠,怎么把你这插件,改成CMD格式的?

我改了好多地方,最后还是不好使,大侠能来一个完整版的代码么?谢谢啦,这个地方我已经卡住两个月了。

仍然是在$compile()()第二个括号,就是链接到作用域那个地方报错。而且try.js里边的控制器仍然没有执行到。

@subchen
Copy link
Owner

subchen commented Aug 18, 2016

angular-async-loader 已经支持 AMD/CMD 加载,可以直接使用

@vrbvillor
Copy link
Author

大侠能来一个完整版的代码么?谢谢啦,这个地方我已经卡住两个月了。

仍然是在$compile()()第二个括号,就是链接到作用域那个地方报错。而且try.js里边的控制器仍然没有执行到。

@subchen
Copy link
Owner

subchen commented Aug 18, 2016

是因为你在 try.js 里面的 controller 是动态加载的。
angular 不能在 angular.bootstrap() 之后,再通过 app.controller(...) 注册任何的 controller。
所以你的原始代码在 $compile(html)(scope) 的时候会找不到 controller。

虽然可以通过 angular-async-loader + $compile 来解决你的问题,不过还是建议你用
ui-router + angular-async-loader + require.js 来做。

可以参考我的 demo 代码:https://github.com/subchen/angular-async-loader/tree/master/demo

@vrbvillor
Copy link
Author

可是这是本页异步调用小插件,没有涉及到路由啊?而且我是CMD的,不会用require,用的是sea。既然能通过angular-async-loader+$compile来完成,求你帮我写一个完整版的代码呗,谢谢啦。我卡在这里卡好久了。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants