TP+angular+oc.lazyLoad 前端组件式开发构思
1.TP 负责Service 处理,静态页面处理,Api等。解决angular seo不友好部分。
2.angular+oc.lazyLoad负责前端组件化拆分调用等。
哪里需要哪里掉,哪个模板适合调用哪个模板思想。
3.目前构思是我之前的一个项目尝试,由于不想用sea,requirejs 需要js封装类型的异步加载方式,所以尝试了angular +oc独立组件方式载入。
目前项目已完成,特发布感想。有什么想法都可以留言讨论。
分享局部代码 只是局部功能展示
局部目录结构的:

1.脚本依赖,jquery,B3(有它最好),angularjs,angular 插件 oc.lazyload,其他个别插件,哪个组件用到组件内部注入。项目启动App.js入口
2.页面初始化基本js常量初始化操作等。
设置好模板目录静态文件目录等基本变量
<script type="text/javascript">
var HTTP_HOST = "__HTTP_HOST__";
var PUBLIC_URL = HTTP_HOST + "__PUBLIC__";
var SERVICE_HOST = "__SERVICE_HOST__";
var TEMPLATE_URL = "__TEMPLATE_URL__";
var MODULE_URL = "__MODULE_URL__";
var CDN_HOST='__CDN_HOST__';//图片,静态文件前缀
var _G=''//后台一些信息json传值至前台存入改变量
</script>
3.App.js 入口js初始化angular.module('common.ctrl', []);//控制器,组件等。
angular.module("common.directives", []);//公共指令等
angular.module('common', ['common.ctrl', 'common.directives']);//common 依赖相关js分层 自己决定
var routeApp = angular.module("app", ["oc.lazyLoad", "common"]);
//_G 全局变量。设置一些全局参数
//初始化服务
routeApp.config(['$ocLazyLoadProvider', function($ocLazyLoadProvider) {
$ocLazyLoadProvider.config({
debug: _G['debug'],
events: _G['debug'],
cssFilesInsertBefore: 'ng_load_plugins_before' // load the above css files before a LINK element with this ID. Dynamic CSS files must be loaded between core and theme css files
, modules: []
});
}]);
routeApp.run(["$rootScope", function($rootScope) {
$rootScope.pageLoaded = true;//载入状态控制
$rootScope._G = _G;
$rootScope.CDN_HOST = CDN_HOST;
//...更多全局变量存入$rootScope
$rootScope.SERVICE_HOST = SERVICE_HOST;
}]);
//最高Controller 一些全局操作
routeApp.controller('AppCtrl', ['$scope', 'uiTool', '$rootScope', 'BbsService','$element', function($scope, uiTool, $rootScope, BbsService, $element) {
if ($rootScope._G['debug']) {
console.info('$rootScope:');
console.info($rootScope);
}
$element.find('.fancybox').fancybox();
}]);
4.组件载入方式。4.1比如页面需要一个论坛发帖组件, 采用 oc-lazy-load 指令载入组件入口模板
<!--发帖组件-->
<div class="row" oc-lazy-load='{"template":MLMJS+"/tpl/ViewThreadCtrl.html"}'>
<section ng-include="'tpl/ViewThreadCtrl.html'"></section>
</div>
4.2论坛发帖组件入口模板 \js\tpl\ViewThreadCtrl.html模板key: tpl/ViewThreadCtrl.html
启动模板 包含相关js/css/等依赖信息
模板/css/img/js等这些都在启动模板内关联依赖。并且将这些资源自动加入缓存,那就是说这些依赖js/css都是载入一次的。
前台展示模板可以根据多种环境调用不同的模板key,控制器一个就可以了。
\js\tpl\ViewThreadCtrl.html
<!--ocLazyLoad 载入模板方式-->
<!--发帖帖子-->
<!-- The basic File Upload plugin -->
<script id="tpl/ViewThreadCtrl.html" type="text/ng-template">
<section oc-lazy-load='{"files": [MLMPLUG+"/bootbox/bootbox.min.js",MLMPLUG+"/fileupload/css/jquery.fileupload.css",MLMPLUG+"/fileupload/js/vendor/jquery.ui.widget.js",MLMPLUG+"/fileupload/js/jquery.iframe-transport.js",MLMPLUG+"/fileupload/js/jquery.fileupload.js",MLMPLUG+"/fancybox/source/jquery.fancybox.js",MLMPLUG+"/fancybox/source/jquery.fancybox.css",MLMJS+"/ctrl/ViewThreadCtrl.js"]}'>
<div ng-controller="NewViewThreadCtrl">
<section ng-include="'tpl/ViewThread/NewThreadBox.html'"></section>
</div>
</section>
</script>
<!--发帖框-->
<script id="tpl/ViewThread/NewThreadBox.html" type="text/ng-template">
<div class="item-horizontal bg-gray">
<div class="text-title">我想说两句</div>
<div>
<select ng-if="forumCategory" onchange="angular.element(this).scope().setForumCategory(this)">
<option value="" ng-click="setForumCategory(0)">请选择讨论分类</option>
<option value="{{key}}" ng-repeat="(key,value) in forumCategory">
{{value}}
</option>
</select>
<input style="width: 696px;" ng-model="post.subject" placeholder="一句话说清楚你的问题,比如“帮我看看户型图,我家的一居室能否改成两居室?”">
<textarea class="reply-box" placeholder="对问题进行补充,详细描述你的疑问或者经验。~" rows="3" ng-model="post.message"></textarea>
<!--aids:{{post.aids|json}}-->
<section ng-controller="UploadFilesCtrl">
<div class="reply-submit clearfix">
<div class="pull-left icon-smile" ng-click="selectImg()">
<div class="btn btn-success fileinput-button">
<i class="glyphicon glyphicon-plus"></i> <span>选择图片...</span>
<input type="file" name="Filedata" multiple/>
</div>
</div>
<div class="pull-right">
<button ng-disabled="newThreadLoading" type="button" ng-click="newThread(0)" class="btn btn-red" ng-bind="newThreadLoading?'提交中...':'提交'"></button>
</div>
</div>
<div class="file-list row">
<div class="topic-upload" ng-repeat="(key,item) in imgList" ng-if="!item.del">
<span class="up-info" ng-hide="1">{{item.file.name}}<br></span>
<span class="up-waiting">
<img ng-if="item.loading" ng-src="{{MLMIMG+'/loading5.gif'}}">
</span> <span class="up-process"></span>
<span class="up-photo">
<a ng-click="openFancyBox()" ng-if="item.result.obj.url||item.base64Img" class="fancybox-thumbs" data-fancybox-group="thumb" href="{{item.result.obj.url?item.result.obj.url:item.base64Img}}">
<img ng-if="item.result.obj.url||item.base64Img" ng-src="{{item.result.obj.url?item.result.obj.url:item.base64Img}}" style="display: inline;">
</a>
</span> <a ng-if="item.result.obj.aid" class="up-del" ng-click="delImg(item.result.obj.aid)">
<img ng-src="{{MLMIMG+'/upload-del-s.png'}}"> </a>
</div>
</div>
</section>
</div>
</div>
</script>
组件控制器\js\ctrl\ViewThreadCtrl.js
/**
* 发帖插件
* 插件引入
<div oc-lazy-load='{"template":MLMJS+"/tpl/ViewThreadCtrl.html"}'>
<section ng-include="'tpl/ViewThreadCtrl.html'"></section>
</div>
*/
angular.module('common.ctrl')
/**
* sub 图片上传操作
*/
.controller('UploadFilesCtrl', ['$scope', 'uiTool', '$rootScope', 'BbsService', '$element', function ($scope, uiTool, $rootScope, BbsService, $element) {
$scope.uploadInput = $element.find("input[type='file']");
var url = '';
imgexts = typeof imgexts == 'undefined' ? '.jpg, .jpeg, .gif, .png,.bmp' : imgexts;
var imgIndex = 1;
$scope.initInput = function () {
$scope.uploadInput.fileupload({
url: url,
dataType: 'json',
acceptFileTypes: /(\.|\/)(gif|jpe?g|png)$/i,
autoUpload: false,
formData: [
{name: 'uid', value: $rootScope._G['uid']},
{name: 'hash', value: $rootScope._G['uploadhash']}
]
}).on('fileuploadadd', function (e, data) {
if (uiTool.login()) {
data._index = imgIndex;
$scope.imgList[imgIndex] = {file: data.files[0], loading: true};
$scope.readerFile(imgIndex);
imgIndex++;
$scope.$apply();
data.submit();
}
}).on('fileuploadprocessalways', function (e, data) {
//console.info('fileuploadprocessalways');
//console.info(data);
}).on('fileuploadprogressall', function (e, data) {
}).on('fileuploaddone', function (e, data) {
$scope.imgList[data._index]['result'] = $scope.uploadBack(data.result.msg);
if ($scope.imgList[data._index].result.code != 200) {
uiTool.alert($scope.imgList[data._index].file.name + '<br>' + $scope.imgList[data._index].result.msg, 'error');
$scope.imgList[data._index]['del'] = true;
}
$scope.updateUsedAids();
$scope.imgList[data._index].loading = false;
$scope.$apply();
}).on('fileuploadfail', function (e, data) {
//console.info('fileuploadfail');
//console.info(data);
});
}
/**
* 删除图片
* @param aid
*/
$scope.delImg = function (aid) {
if (!uiTool.login()) {
return false;
}
var postData = {
uid: $rootScope._G['uid'] ? $rootScope._G['uid'] : 0,
pid: $rootScope._G['pid'] ? $rootScope._G['pid'] : 0,
tid: $rootScope._G['tid'] ? $rootScope._G['tid'] : 0,
aid: aid
};
if ($scope.loading.delloading[aid]) {
return;
}
$scope.loading.delloading[aid] = true;
BbsService.fetch(postData, 'deleteattach').success(function (data) {
BbsService.callback(data, function () {
if (data.obj > 0) {
for (var i in $scope.imgList) {
if ($scope.imgList[i].result && $scope.imgList[i].result.obj && $scope.imgList[i].result.obj.aid == aid) {
$scope.imgList[i]['del'] = true;
break;
}
}
$scope.updateUsedAids();
//$scope.$apply();
}
});
$scope.loading.delloading[aid] = false;
}).error(function () {
$scope.loading.delloading[aid] = false;
uiTool.alert('未知错误,请联系管理员');
})
};
/**
* html5 图片预读
* @param index
* @returns {boolean}
*/
$scope.readerFile = function (index) {
if (typeof FileReader == 'undefined') {
console.info('你的浏览器不支持FileReader接口!');
return false;
}
var file = $scope.imgList[index].file;
if (!/image\/\w+/.test(file.type)) {
console.info('格式错误');
return false;
}
var reader = new FileReader();
reader.readAsDataURL(file);
//reader.readAsBinaryString(file);
//reader.readAsText(file);
reader.onload = function (e) {
$scope.imgList[index]['base64Img'] = this.result;
}
};
/**
* 清理图片
*/
$scope.clearAttache = function () {
BbsService.fetch({}, 'clearattache');
};
/**
* 图片预览插件
*/
$scope.openFancyBox = function () {
$element.find('.fancybox-thumbs').fancybox();
};
/**
* 上传图片回调信息处理
* @param result
* @returns {{code: number, msg: string, obj: null}}
*/
$scope.uploadBack = function (result) {
return result;
};
$scope.updateUsedAids = function () {
$scope.aids = [];
angular.forEach($scope.imgList, function (value, key) {
if (value.result && value.result.code == 200 && !value.del) {
$scope.aids.push({aid: parseInt(value.result.obj.aid), description: value.result.obj.name});
}
});
$scope.eventParent($scope.aids);
}
//通知父类控制器更新图片上传id
$scope.eventParent = function (aids) {
$scope.$emit('eventAidsChanged', aids);
}
$scope.clearAttache();
$scope.initInput();
}])
/**
* parent 发帖操作
*/
.controller('NewViewThreadCtrl', ['$scope', 'uiTool', '$rootScope', 'BbsService', '$element', function ($scope, uiTool, $rootScope, BbsService, $element) {
$scope.post = {message: '', fid: $rootScope._G['fid'], subject: '', typeid: 0, aids: []};
$scope.list = [];
$scope.obj = {};
$scope.newThreadLoading = false;
$scope.forumCategory = [];
$scope.init = function () {
//获取版块分类
BbsService.fetch({fid: $scope.post.fid}, 'getForumCategory').success(function (data) {
$scope.forumCategory = data.list;
});
}
$scope.setForumCategory = function (i) {
if (i == 0) {
$scope.post.typeid = 0;
return;
}
$scope.post.typeid = angular.element(i).val();
}
//监听图片上传id
$scope.$on('eventAidsChanged', function (event, data) {
if (data && angular.isArray(data) && data.length > 0) {
$scope.post.aids = data;
}
});
$scope.newThread = function () {
if (!uiTool.login()) {
return false;
}
if ($scope.post.subject == '') {
uiTool.alert('请输入您想提的问题', 'warning');
return;
}
if ($scope.post.message == '') {
uiTool.alert('请输入问题描述', 'warning');
return;
}
$scope.newThreadLoading = true;
BbsService.newthread($scope.post).success(function (data) {
if (data.code == 200 && data.obj && data.obj.tid > 0) {
data.url = BbsService.fetchUrl({tid: data.obj.tid}, 'newThread');
} else {
$scope.newThreadLoading = false;
}
BbsService.callback(data, function () {
});
}).error(function () {
$scope.newThreadLoading = false;
uiTool.alert('未知错误,请联系管理员');
});
};
$scope.init();
}]);
基本上组件流程就完成。这样理论上所以不相关的seo 等操作都可做成组件。
单场景应用等也可参考这种插件引入方式。真正做到一个插件。完全独立哪需要引哪里。