从17年的12月,到现在18年的4月,历时5个月,spirte框架从一开始的一个简单雏形,慢慢变得强大起来。

从简单的require+Vue+VueRouter实现了框架的整体骨架,到后来和公司的前端部门一起配合实现了今日校园和微信的SDK初始化,再到跟公司的权限体系结合后实现的页面授权和按钮授权,再到游客模式,再到可配置的页面按需加载的实现,最后又实现了可配置的多入口应用实现,还支持了关于公司的对于移动应用的合并式二开扩展模式。

在这5个月的过程中,我踩了不计其数的坑,框架代码也改的面目全非,我想现在的sprite框架代码基本就代表了我现如今最高的前端水平了。

今天就在这里展示一下这五个月来我们部门用sprite框架做出来的成果,一些校园应用,然后在分享出耗费我“无数心血”写出来的sprite框架的“完全体”代码。


基于sprite框架开发的应用展示

5个月来,我们部门基于sprite框架开发了二三十个移动应用,我从里面挑了一些功能齐全,“颜值”高的应用截图展示:

1.宿舍考勤(学生在规定的时间在宿舍内使用手机进行考勤,管理老师查看考勤情况,并对考勤异常的学生进行处理):

2.迎新系统(学生利用迎新系统进行秒级扫码报到,免去了到处奔波的麻烦,并且集成了很多便捷迎新服务,管理老师实时监控全校新生的报到情况,还可以根据到站统计信息合理安排学生的站点接送):

3.离校系统 (学生利用离校系统线上办理离校手续,管理老师实时监控全校学生的离校办理情况):

4.奖学金系统 (学生在线申请奖学金,系统自动推送符合条件的奖种列表,管理老师一键审核)

5.学生请销假系统:(学生在线进行请假,管理老师进行审核以及销假等操作):

sprite框架的“完全体”代码

我一直号称我有代码洁癖,而且是一个注释狂魔。

这是因为我在写代码的时候,会强迫症一般的反反复复的查看之前写过的代码,然后看着看着就想去重构它们,为的就是能让我在一个月两个月以后重新回来看我的代码,不需要思考就能直接看懂,也是为了让接手我代码的人能够更容易的进行维护。

可能会有人觉得这样写代码太麻烦,没必要,但是这样的人可能也体会不到当我再次阅读我重构调优后的代码时,那种赏心悦目的成就感,那是支撑着我不断前进的最大动力。

Talk is cheap,show you the Code!

spriteFrame.js:被我精简到极致的框架主体

requireConfig中有不少js文件都是我们公司提供的公共组件js文件,这些可以忽略,专注看代码逻辑即可。

(function(require) {
    //require路径配置
    var requireConfig = {
        paths: {
            vue: SERVER_PATH + '/bower_components/vue2/vue.min',
            vueRouter: SERVER_PATH + '/bower_components/vue2/vue-router.min',
            text: SERVER_PATH + '/bower_components/text/text',
            util: 'public/util/util',
            MINT: SERVER_PATH + '/fe_components/mobile/MINT/index',
            jquery: SERVER_PATH + '/bower_components/jquery/dist/jquery.min',
            axios: SERVER_PATH + '/bower_components/vue2/axios.min',
            'emap-mobile': SERVER_PATH + '/fe_components/mobile/emap-mobile.min',
            BH_MOBILE: SERVER_PATH + '/fe_components/mobile/BH_MIXIN_SDK',
            WEIXIN: 'http://res.wx.qq.com/open/js/jweixin-1.2.0',
            selectRoleIndex: '../../swpubapp/public/mob/component/selectrole/selectrole',
            home: '../../swpubapp/public/mob/component/home/home',
            spriteUtils: '../../swpubapp/public/mob/js/spriteUtil',
            publicVueComponent: '../../swpubapp/public/mob/component',
            'draggable': SERVER_PATH + "/bower_components/vuedraggable/vuedraggable",
            'sortable': SERVER_PATH + "/bower_components/sortable/1.5.1/Sortable.min",
            qrcode: SERVER_PATH + '/bower_components/qrcode.js/qrcode',
            bhFillStyle: SERVER_PATH + '/fe_components/mobile/bh_utils_mobile',
            emapMin: '../../swpubapp/public/mob/js/emapMin'
        },
        shim: {
            'qrcode': {
                exports: 'QRCode'
            },
            'bhFillStyle': {
                exports: 'bhFillStyle'
            },
            'emapMin': {
                deps: ['jquery'],
            }
        }
    };

    /**
     * appLoadAsync用于控制app页面的加载方式
     * true: app的所有页面为异步加载,只在使用到时加载
     * false: app的所有页面在应用初始化时一次性加载
     */
    window.appLoadAsync = false;

    //默认的组件库和公共方法以及公共页面
    var requir_default_arr = ['vue', 'vueRouter', 'MINT', 'emap-mobile', 'jquery', 'axios', 'spriteUtils', 'draggable', 'qrcode', 'bhFillStyle', 'emapMin'];

    //封装的公共vue组件
    var default_component_arr = [{
        name: 'auditProcess',
        jsPath: 'publicVueComponent/auditprocess/auditProcess'
    }, {
        name: 'noneDatas',
        jsPath: 'publicVueComponent/nonedatas/nonedatas'
    }];

    /**
     * 用于保存所有模块的全局对象:
     * defaultModules:默认的组件库和公共方法以及公共页面
     * pageModules:当前应用的所有页面模块
     * defaultComponents:封装的公共vue组件
     */
    window.REQUIRE_MODULES_ARR = {
        defaultModules: requir_default_arr,
        pageModules: [],
        defaultComponents: default_component_arr
    };

    //配置require
    require.config(requireConfig);

    //加载框架所需的库和公共页面
    require(requir_default_arr, function(Vue, VueRouter, mintUI, EMAP_MOBILE, $, axios, sprite, draggable, QRCode, bhFillStyle, emapMin) {

        //设置拖拽组件
        Vue.component('draggable', draggable);

        //将各个组件库输出到全局作用域
        window.axios = axios;
        window.Vue = Vue;
        window.VueRouter = VueRouter;
        window.mintUI = mintUI;
        window.EMAP_MOBILE = EMAP_MOBILE;
        window.WIS_EMAP_SERV = emapMin;

        //vue路由组件
        Vue.use(VueRouter);
        //饿了么移动端组件mint-ui
        Vue.use(mintUI);
        //EMAP相关vue组件
        Vue.use(EMAP_MOBILE);

        //ids认证
        if (userId != null && userId != undefined) {
            //获取角色配置相关参数 --> 获取用户授权功能 --> 初始化应用
            sprite.getSelRoleConfig().then(sprite.getAuthConfig).then(sprite.initApp);
        }
        //游客
        else {
            // 初始化应用--游客模式
            sprite.initApp_visitor();
        }

    });

}(require));

spriteUtil.js:基于AMD规范开发的框架工具库

这个工具库的内容包括了应用初始化的回调机制实现,游客模式,基于正则扫描的按钮权限,可配置的页面按需加载以及微信SDK的初始化等等功能的实现:

define(function(require) {
    var spriteUtils = {
        /**
         * 初始化应用
         */
        initApp: function(callBack) {
            addCallback(callBack);
            requireAndInit();
        },
        /**
         * 初始化应用--游客模式
         */
        initApp_visitor: function(callBack) {
            addCallback(callBack);
            // 游客模式依赖 VISITOR_CONFIG 对象
            if (!window.VISITOR_CONFIG || !(window.VISITOR_CONFIG.PAGES instanceof Array)) {
                console.error("the VISITOR_CONFIG is not defined , whitch is required in the visitor mode !");
                return;
            }
            //将页面注册到全局对象中
            window.REQUIRE_MODULES_ARR.pageModules = window.VISITOR_CONFIG.PAGES;
            //游客模式无需选择角色
            window.IS_NEED_SELECTROLE = "0";
            requireAndInit();
        },
        /**
         * 加载组件
         */
        loadComponent: function(path) {
            return function() {
                var dfd = $.Deferred();
                require([path], function(componentInit) {
                    var component = componentInit();
                    component.template = compileTpl(component.template);
                    dfd.resolve(component);
                });
                return dfd;
            };
        },
        /**
         * 判断是否进入角色选择页
         * 如果用户有且只有一个角色,直接渲染该角色有权限的页面,否则进入角色选择页面
         */
        getSelRoleConfig: function() {
            var dfd = $.Deferred();
            MOB_UTIL.doPost({
                url: WIS_CONFIG.ROOT_PATH + '/sys/swpubapp/MobileCommon/getSelRoleConfig.do',
                params: {
                    APPID: WIS_CONFIG.APPID,
                    APPNAME: WIS_CONFIG.APPNAME
                }
            }).done(function(result) {
                window.IS_NEED_SELECTROLE = result.data.IS_NEED_SELECTROLE;
                //无需选择角色
                if (IS_NEED_SELECTROLE === "0") {
                    roleId = result.data.DEFAULT_ROLEID;
                }
                dfd.resolve();
            });
            return dfd;
        },
        /**
         * 获取用户授权的页面、按钮
         */
        getAuthConfig: function(fromSelectRole) {
            var dfd = $.Deferred();
            // IS_NEED_SELECTROLE为1,即需要先选择角色
            if (!fromSelectRole && window.IS_NEED_SELECTROLE == "1") {
                window.REQUIRE_MODULES_ARR.pageModules = [{
                    vueJsPath: 'selectRoleIndex'
                }];
                dfd.resolve();
            } else {
                MOB_UTIL.doPost({
                    url: WIS_CONFIG.ROOT_PATH + '/sys/swpubapp/MobileCommon/getMenuInfo.do',
                    params: {
                        APPID: WIS_CONFIG.APPID,
                        APPNAME: WIS_CONFIG.APPNAME
                    }
                }).done(function(result) {
                    //授权按钮列表
                    window.MOBILE_BUTTONAUTH_LIST = result.data.BUTTON;
                    //授权页面列表
                    window.REQUIRE_MODULES_ARR.pageModules = result.data.PAGES;
                    dfd.resolve();
                });
            }
            return dfd;
        }
    };

    var firstInit = true; //应用首次初始化(需要选角色时存在第二次初始化)
    var callbacks = [defaultCallback]; //回调集合

    /**
     * 应用初始化完成的默认回调函数
     */
    function defaultCallback() {
        if (firstInit) {
            console.log('|---sprite---|  App init finished,have fun!  |---sprite---|');
            firstInit = false;
        }
    }

    /**
     * 新增回调
     */
    function addCallback(callback) {
        if (callback) {
            if (callback instanceof Function) {
                callbacks.push(callback)
            }
            if (callback instanceof Array) {
                var allIsFunc = callback.every(function(c) {
                    return c instanceof Function;
                });
                if (allIsFunc) {
                    callbacks = callbacks.concat(callback);
                }
            }
        }
    }

    /**
     * 执行回调
     */
    function finishedCallback() {
        callbacks.forEach(function(callback) {
            callback();
        });
    }

    /** 
     * 加载组件与页面进行初始化
     */
    function requireAndInit() {
        var require_page_path = []; //页面模块js路径
        var require_component_path = []; //公共组件js路径
        setJsPath(require_page_path, require_component_path);

        //需要选择角色
        var needSelectRole = window.IS_NEED_SELECTROLE == "1" && require_page_path[0] == "selectRoleIndex";

        //加载公共组件
        require(require_component_path, function() {
            //注册公共组件
            window.REQUIRE_MODULES_ARR.defaultComponents.forEach(function(defaultComponent) {
                Vue.component(defaultComponent.name, spriteUtils.loadComponent(defaultComponent.jsPath));
            });
            //异步按需加载
            if (window.appLoadAsync) {
                var needSDK = true;
                init(needSDK, needSelectRole);
            }
            //全部加载
            else {
                require(require_page_path, function() {
                    var needSDK = true;
                    init(needSDK, needSelectRole);
                });
            }
        });
    }

    /**
     * 设置页面与组件的js文件路径
     */
    function setJsPath(require_page_path, require_component_path) {
        if (window.REQUIRE_MODULES_ARR.pageModules instanceof Array) {
            //页面模块js路径
            window.REQUIRE_MODULES_ARR.pageModules.forEach(function(pageModule) {
                require_page_path.push(pageModule.vueJsPath);
            });
        }
        if (window.REQUIRE_MODULES_ARR.defaultComponents instanceof Array) {
            //公共组件js路径
            window.REQUIRE_MODULES_ARR.defaultComponents.forEach(function(defaultComponent) {
                require_component_path.push(defaultComponent.jsPath);
            });
        }
    }

    /**
     * 应用初始化
     */
    function init(needSDK, needSelectRole) {
        var routes = [];

        var rootDiv = '#app';
        //初始化角色选择页面
        if (needSelectRole) {
            rootDiv = '#selectrole';
            routes = [{
                path: '/',
                name: 'selectrole',
                component: spriteUtils.loadComponent('selectRoleIndex')
            }];
        }
        //初始化当前用户有权限访问的页面
        else {
            routes = getVueRoute();
        }

        //生成VueRouter对象
        var router = new VueRouter({
            routes: routes
        });

        var hasAuth = checkAuth(routes);
        //无权限hash置空
        if (!hasAuth) {
            location.hash = '#/';
        }

        //路由切换完成后执行的操作
        router.afterEach(function(to, from, next) {
            //页面离开时,关闭messagebox
            mintUI.MessageBox.close();
            /**
             * 在切换路由后自动执行一个轻微滑动
             * 这样写的原因:ios在页面的高度比较高时,从其他页面返回该页面将会出现页面空白的现象
             * 需要轻触屏幕进行滑动才能恢复原页面
             */
            if (!to.meta.keepAlive && !from.meta.keepAlive) {
                document.body.scrollTop = 1;
                setTimeout(function() {
                    document.body.scrollTop = 0;
                }, 0);
            }
        });

        if (needSDK) {
            initSDKandApp(rootDiv, router);
        } else {
            //挂载主vue对象
            app = new Vue({
                el: '#app',
                router: router
            });
            finishedCallback()
        }
    }

    /**
     * 校验当前hash是否属于用户权限范围内
     */
    function checkAuth(routes) {
        return routes.some(function(route) {
            if (!route.children || route.children.length < 1) {
                return location.hash.indexOf(route.name) > 0;
            } else {
                return checkAuth(route.children);
            }
        });
    }

    /**
     * 根据加载的页面列表获取Vue路由数组
     */
    function getVueRoute() {
        var routes = [];
        //获取页面vue对象以及子节点列表
        var childrenIdList = [];
        window.REQUIRE_MODULES_ARR.pageModules.forEach(function(page, pageIndex) {
            page.index = pageIndex;
            page.component = loadPage(page.vueJsPath, page.components);
            if (page.childrenIds && page.childrenIds instanceof Array) {
                childrenIdList = childrenIdList.concat(page.childrenIds);
            }
        });

        //构建子节点映射,通id可以获取到这个子节点,并且在原数组中标记子节点的isChild为true
        var childrenObjs = {};
        childrenIdList.forEach(function(childId, index) {
            window.REQUIRE_MODULES_ARR.pageModules.forEach(function(page, index) {
                if (page.id === childId) {
                    page.isChild = true;
                    childrenObjs[page.id] = page;
                }
            });
        });

        var indexPages = []; //首页集合
        //把REQUIRE_MODULES_ARR.pageModules解析为vue的路由数组
        window.REQUIRE_MODULES_ARR.pageModules.forEach(function(page, index) {
            if (!page.isChild) {
                var pageComponent = page.component; //vue组件对象
                var pageName = page.vueRouteName; //路由跳转名称
                var pagePath = page.vueRoute; //路由路径
                var isIndex = page.isIndex === "true"; //是否首页
                var needCache = page.keepAlive === "true"; //是否缓存

                var routeObj = {};
                routeObj.path = pagePath;
                routeObj.component = pageComponent;
                routeObj.name = pageName;
                routeObj.meta = {
                    keepAlive: needCache
                };
                addChildrenRoute(page, routeObj, childrenObjs);

                if (isIndex) {
                    //配置为多首页时使用
                    routeObj.meta.index = page.vueRouteName; //首页标识
                    routeObj.meta.indexIcon = page.indexIcon; //首页图表
                    routeObj.meta.indexName = page.indexName; //首页中文名
                    indexPages.push(routeObj);
                } else {
                    routes.push(routeObj);
                }
            }
        });

        return homePageProcess(routes, indexPages);
    }

    /**
     * 加载页面
     */
    function loadPage(path, components) {
        return function() {
            var dfd = $.Deferred();
            spriteUtils.loadComponent(path)().then(function(page) {
                //注册应用自定义组件
                if (!page.components) {
                    page.components = {};
                }
                if (components && components instanceof Array) {
                    components.forEach(function(component) {
                        page.components[component.name] = spriteUtils.loadComponent(component.jsPath);
                    });
                }
                dfd.resolve(page);
            });

            return dfd;
        };
    }

    /**
     * 递归添加子路由
     */
    function addChildrenRoute(page, routeObj, childrenObjsMap) {
        //如果当前页面存在子页面,则将子页面加入当前页面的子路由
        if (page.childrenIds && page.childrenIds instanceof Array) {
            routeObj.children = [];
            page.childrenIds.map(function(childId, index) {
                var child = childrenObjsMap[childId];
                var needCache = child.keepAlive === "true";
                var childrouteObj = {};
                childrouteObj.component = child.component;
                childrouteObj.name = child.vueRouteName;
                childrouteObj.path = child.vueRoute.substr(child.vueRoute.indexOf('/') + 1);
                childrouteObj.meta = {};
                childrouteObj.meta.keepAlive = needCache;
                //递归添加子页面的子页面
                addChildrenRoute(child, childrouteObj, childrenObjsMap);
                routeObj.children.push(childrouteObj);
            });
        }
    }

    /**
     * 处理首页
     */
    function homePageProcess(routes, indexPages) {
        window.REQUIRE_MODULES_ARR.indexPages = indexPages;
        //至少需要一个首页
        if (indexPages.length == 0) {
            throw new Error("need at least one home page!");
        }
        //单首页
        if (indexPages.length == 1) {
            routes.push(indexPages[0]);
            routes.push({
                path: '/',
                component: indexPages[0].component,
                children: indexPages[0].children || [],
                meta: {
                    keepAlive: indexPages[0].meta.keepAlive
                }
            });
        }
        //多首页
        if (indexPages.length > 1) {
            var home = {
                path: '/',
                component: spriteUtils.loadComponent('home'),
                children: indexPages,
                redirect: indexPages[0].path
            };
            routes.push(home);
        }
        return routes;
    }

    /**
     * 初始化SDK与应用
     */
    function initSDKandApp(rootDiv, router) {
        getWechatSign().then(function(signData) {
            var config = {
                //微信jdk初始化参数
                wx: {
                    uploadImgsToEmapUrl: WIS_CONFIG.ROOT_PATH + '/sys/swpubapp/MobileCommon/saveFileFromWechat.do'
                },
                //钉钉jdk初始化参数
                dd: {}
            };
            //如果获取到了微信签名,则用该签名对象初始化微信jssdk
            if ('{}' !== JSON.stringify(signData)) {
                config.wx.signData = signData;
            }

            /**
             * 判断父窗口中是否加载了SDK,如果加载了则直接使用父窗口的SDK
             * 这样写的原因:微信SDK在同一页面初始化两次会造成第二次初始化失败
             *               即使是iframe嵌套的页面也不行
             */
            if (window.parent && window.parent.SDK) {
                window.SDK = window.parent.SDK;
                //挂载主vue对象
                app = new Vue({
                    el: rootDiv,
                    router: router
                });
                finishedCallback();
                return;
            }

            //使用BH_MOBILE提供的方法进行SDK的注册
            require(['BH_MOBILE'], function(BH_MOBILE) {
                window.BH_MOBILE = BH_MOBILE;
                //初始化sdk
                BH_MOBILE.default(function(res) {
                    window.SDK = res.sdk;
                    //挂载主vue对象
                    app = new Vue({
                        el: rootDiv,
                        router: router
                    });
                    finishedCallback();
                }, config);
            });

        });
    }

    /**
     * 获取微信签名信息
     */
    function getWechatSign() {
        var dfd = $.Deferred();
        var url = WIS_CONFIG.ROOT_PATH + '/sys/swpubapp/MobileCommon/getWechatSign.do';
        if (window.VISITOR_CONFIG && VISITOR_CONFIG.WECHAT_API.getWechatSign) {
            url = WIS_CONFIG.ROOT_PATH + VISITOR_CONFIG.WECHAT_API.getWechatSign;
        }
        //如果在微信环境,则请求微信签名用于加载微信jssdk
        if (/micromessenger/.test(navigator.userAgent.toLowerCase())) {
            /**
             * 请求微信js全局对象
             * 由于戚雨提供的BH_MOBILE需要依赖微信的js文件
             * 因此在加载BH_MOBILE前,先保证微信的js文件已加载
             */
            require(['WEIXIN'], function(WEIXIN) {
                require(['BH_MOBILE'], function(BH_MOBILE) {
                    window.BH_MOBILE = BH_MOBILE;
                    window.wx = WEIXIN;
                    //请求当前页面的微信签名
                    MOB_UTIL.doPost({
                        url: url,
                        params: {
                            url: window.location.href.replace(/#(\S+)?/, '')
                        }
                    }).done(function(result) {
                        dfd.resolve(result.data);
                    });
                });
            });
        }
        //不在微信环境直接返回 
        else {
            dfd.resolve();
        }
        return dfd;
    }

    /**
     * 正则扫描模板文件,实现按钮权限
     */
    function compileTpl(tpl) {
        if (!window.MOBILE_BUTTONAUTH_LIST) {
            window.MOBILE_BUTTONAUTH_LIST = [];
        }
        //获取tpl中所有权限id
        var tplIds = [];
        var result;
        var pattern = new RegExp('auth-id=[\'|\"]{1}[^\'^\"]+[\'|\"]{1}', 'gm');
        while ((result = pattern.exec(tpl)) != null) {
            tplIds.push(result[0].substring(9, result[0].length - 1));
        };
        if (tplIds.length == 0) {
            return tpl;
        }

        //删除所有无权限的dom
        tplIds.forEach(function(id, index) {
            if (window.MOBILE_BUTTONAUTH_LIST.indexOf(id) < 0) {
                var regExp = new RegExp('<[^/].*(auth.*?auth-id=[\'|\"]{1}' + id + '[\'|\"]{1}).*>[\\s\\S]*?</.*auth.*>', 'gm');
                tpl = tpl.replace(regExp, "");
            }
        });

        return tpl;
    }

    return spriteUtils;
});

mobutil.js封装的基于axios的异步Ajax请求工具:

对原有的axios方法进行了进一步的封装,并且使用mint-ui的组件进行统一的异常提示(这是基于我们所有api的统一返回格式)。

;
var MOB_UTIL = {};
(function(MOB_UTIL) {
    /**
     * get方式请求,尽量少用
     * @param params  {url:"http://www.baidu.com",params:{}}
     * @returns
     */
    MOB_UTIL.doGet = function getData(params) {
        var dfd = $.Deferred();
        mintUI.Indicator.open();
        axios({
            method: 'get',
            params: {
                "data": encodeURI(JSON.stringify(params.params ? params.params : {}))
            },
            url: params.url
        }).then(function(res) {
            mintUI.Indicator.close();
            var result = res.data;
            if (result.code === '0') {
                dfd.resolve(result);
            } else {
                result.msg = result.msg || '系统内部错误,请联系管理员';
                mintUI.MessageBox('提示', result.msg);
                dfd.reject(result);
            }
        }).catch(function(err) {
            //打印堆栈
            console.error(err);
            mintUI.Indicator.close();
            if (err.response) {
                mintUI.MessageBox('网络错误(' + err.response.status + ')', err.message);
            } else {
                err.message = err.message == 'Network Error' ? '网络连接不可用' : err.message;
                mintUI.MessageBox('错误', err.message);
            }
            dfd.reject(err);
        });
        return dfd;
    };
    /**
     * 异步数据请求,主要使用方式
     * @param params
     * @returns
     */
    MOB_UTIL.doPost = function getData(params) {
        var dfd = $.Deferred();
        mintUI.Indicator.open();
        axios({
            method: 'post',
            data: params.params ? params.params : {},
            url: params.url,
            transformRequest: [function(data) {
                return "data=" + encodeURIComponent(JSON.stringify(data));
            }]
        }).then(function(res) {
            mintUI.Indicator.close();
            var result = res.data;
            if (result.code === '0') {
                dfd.resolve(result);
            } else {
                result.msg = result.msg || '系统内部错误,请联系管理员';
                mintUI.MessageBox('提示', result.msg);
                dfd.reject(result);
            }
        }).catch(function(err) {
            //打印堆栈
            console.error(err);
            mintUI.Indicator.close();
            if (err.response) {
                mintUI.MessageBox('网络错误(' + err.response.status + ')', err.message);
            } else {
                err.message = err.message == 'Network Error' ? '网络连接不可用' : err.message;
                mintUI.MessageBox('错误', err.message);
            }
            dfd.reject(err);
        });
        return dfd;
    };
})(window.MOB_UTIL = MOB_UTIL);

head.jsp:所有移动应用index.jsp中的的公共head

除了一些必要的外部js文件和css样式以及我们公司提供的一些组件和公共样式之外,框架只需要引入三个js文件即可,一个是require.js,一个是spriteFrame.js,还有就是mobutils.js(这个文件也可以替换为别的ajax实现)

<%@ page language="java" contentType="text/html; charset=UTF-8" session="false" %>
<%@ page import="java.util.*" %>
<%@ taglib uri="/WEB-INF/etags/emap.tld" prefix="e" %>
<e:call id="PreLoadData" method="loadData" params="SERVER_PATH" var="server_data"/>
<% 
    String path = request.getContextPath();
    String appId = com.wisedu.emap.pedestal.core.AppManager.currentApp().getId();
    String appname= com.wisedu.emap.pedestal.core.AppManager.currentApp().getName();
    List resLs = (List<Map<String,String>>)request.getAttribute("server_data");
    Map resMap = (Map<String,String>)resLs.get(0);
    String SERVER_PATH = resMap.get("CSZ").toString();//路径名
%>
<meta charset="UTF-8">
<meta name="renderer" content="webkit">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<!-- 用来禁止浏览器缓存,使得每次请求test.html都从服务器下载最新版本 -->
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate" />
<meta http-equiv="Pragma" content="no-cache" />
<meta http-equiv="Expires" content="0" />
<meta name="format-detection" content="telephone=yes">

<script>
        var SERVER_PATH = "<%=SERVER_PATH%>";
        var pageMeta = <e:page/> ;
        var contextPath = "<%= request.getContextPath() %>";
        var rootPath = "<%=path%>";
        rootPath = rootPath.replace("http:", window.location.protocol);
        rootPath = rootPath.replace(":80/", "/");
        window.WIS_CONFIG = {
            ROOT_PATH: rootPath,
            PATH: "<%=path%>",
            APPID: "<%=appId%>",
            APPNAME: "<%=appname%>",
            RES_SERVER: "<%=SERVER_PATH%>"
        }
        window.WIS_CONFIG.STATIC_TIMESTAMP = "v";
        var userId = pageMeta.params.userId;
        var roleId = pageMeta.params.roleId;
</script>

<link rel="stylesheet" href="<%=SERVER_PATH%>/bh_components/mobile/1.0.0/bh-lib.min.css">
<link rel="stylesheet" href="<%=SERVER_PATH%>/fe_components/iconfont_mobile/iconfont.css">
<link rel="stylesheet" href="public/css/style.css">
<link rel="stylesheet" href="../../swpubapp/public/mob/css/mob.css">
<link rel="stylesheet" href="<%=SERVER_PATH%>/fe_components/skins/mint2.0/skin.css">
<link rel="stylesheet" href="<%=SERVER_PATH%>/fe_components/mobile/MINT/style.min.css">

<!-- spirte框架所需js文件 -->
<script src="<%=SERVER_PATH%>/bower_components/requirejs/require.js"></script>
<script src="../../swpubapp/public/mob/js/mobutil.js"></script>
<script src="../../swpubapp/public/mob/js/spriteFrame.js"></script>

body.jsp:所有移动应用的公共body

<%@ page language="java" contentType="text/html; charset=UTF-8" session="false" %>
<div id="selectrole">
    <!-- 路由出口 -->
    <!-- 路由匹配到的组件将渲染在这里 -->
    <router-view></router-view>
</div>
<div id="app" style="position:relative;z-index:0">
    <!-- 路由出口 -->
    <!-- 路由匹配到的组件将渲染在这里 -->
    <keep-alive>
        <router-view v-if="$route.meta.keepAlive"></router-view>
    </keep-alive>
    <router-view v-if="!$route.meta.keepAlive"></router-view>
</div>

基于head.jsp和body.jsp,可以大大的精简每个应用的index.jsp文件,如下图:

这些就是sprite框架目前主要的代码了,当然很多代码时和我们公司的特有的代码结合起来生效的,所以看起来可能会有些不明白,不过没关系,我把sprite框架的主要代码帖在这里的目的只是想要展示一下我关于框架代码的优化和重构的思路和方法,所以不需要注重具体的实现,关注代码思想就好了~

发表评论

电子邮件地址不会被公开。 必填项已用*标注