亚马逊站外deal网站,上海建设银行黄浦区营业网站,有哪些做兼职的设计网站,百度关键词优化送网站前言 在移动浪潮袭来的时候#xff0c;小钗有幸进入框架组做webapp框架开发#xff0c;过程中遇到了移动端的各种坑#xff0c;也产生了各种激情#xff0c;就我们公司的发展历程来说 第一阶段#xff1a;使用传统方式开发移动站点#xff0c;少量引入HTML5元素 第二阶段…前言 在移动浪潮袭来的时候小钗有幸进入框架组做webapp框架开发过程中遇到了移动端的各种坑也产生了各种激情就我们公司的发展历程来说 第一阶段使用传统方式开发移动站点少量引入HTML5元素 第二阶段框架化使用jquery mobile框架发现慢组件不好管理不好维护给搞掉了 第三阶段jqueryBackbone的组合最后为了瘦身将jquery换成了zepto 第四阶段框架适应Hybrid版本Hybrid相关频道与H5站点一套代码业务扩展遍地开花 第五阶段框架适应ipad版本/实现前端ABTesting由于不可控原因计划夭折 框架使用过程中需要快速适应业务需求框架中过多的掺杂了业务代码并且随之发展框架本身的耦合度、设计不合理的地方也体现了出来 小钗虽然知道哪里有问题但框架的代码不是想象那么好改一个API的改变会导致整个业务线的崩溃听之任之又很不爽 开发一套干净webapp框架的想法油然而生于是该框架便出现了 诚然此框架比不上Backbone、比不了anglarJS毕竟小钗的资历、水平有限所以框架本身可能都会有一些缺陷但作为初步接触前端的同学 或者想在前端看到一些设计思想的同学或者想在移动webapp试水的公司。此框架还是有一些他一些优势我们带着看看不吃亏的想法还是可以看看嘛 也希望各位多多支持代码写的不好也在提高因为小钗不是专业的重构其中的CSS及DOM结构全部由在线网站down下来了这里是抄袭我说清楚了哦。 ① 这次首先出一篇大体介绍性文章简单结束 ② 而后有1,2篇博客对其中的全局MVC相关做说明这里使用了hashChange与pushState两种方案 ③ 然后对其中的UI继承关系做梳理并拿其中比较复杂的几个UI组件说一下设计思路预计会有3-5篇 ④ 最后根据反馈对框架做一些调整效果好的话我也试试捐赠我们家的左小萌居然也在搞捐赠我觉得我也该搞个 框架主要用途还是自我学习交流以及框架思维整理BUG在所难免若是有BUG请给我留言 框架简介 快速浏览 想简单看看demo的朋友请到 http://yexiaochai.github.io/blade/ 对源码有兴趣的朋友请入https://github.com/yexiaochai/blade 若是PC端浏览请使用chrome浏览器不用谢我叫雷锋若是只有IE的同学请装chrome暂时抛弃IE 支持情况 由于做是个人框架并且是学习框架便抛弃了一些系统现在支持情况是 IOS6 android4 那些手机不过千的浏览器上渲染可能会有问题至于wp或者低版本兼容小钗便需要看后续精力与工作强度 框架发展 第一期-MVC 该框架第一期的目标是简单的webapp MVC的实现现在也基本实现了app支持hashChange与pushState两种方式做路由加载view 对此有兴趣的同学可以看看helloWord关于app与页面级View的关系如下 第二期-通用工具 框架第二期的想法是完善本身一些通用的东西比如UI组件或者简单的flip手势工具等 这里小钗不是专业的前端就直接从线上将公司的CSS Down下来了也用了他的Dom结构 但是 整个组件的扩展非常方便有兴趣的同学看看UI一块的代码UI的继承关系如下 第三期-ABTesting 框架第三期目标是实现前端ABTesting方案 第四期-ipad适配 框架第四期的目标是一套业务代码可以同时用于mobile与ipad 第五期-Hybrid 框架第五期目标是实现Hybrid交互适配由于小钗本身不懂native开发所以此方案要靠后 随机期-疑难杂症 框架还会单开一个频道做一些疑难杂症处理比如 ① fixed问题 ② 区域滚动问题 ③ app唤醒 ④ History路径问题等 目录简介 有些项目文件或者不相关的文件我们不予关注整个框架代码在blade文件目录中主要 demo在demo中...... dest为框架打包后的文件 doc用于存放一些文档暂时还未补齐我的想法是博客作为文档因为后期会源码解析并分析设计思维 grunt存放着打包文件 helloworld为最简单的入门代码教我们如何进入webapp开发 res存放资源样式文件这里是直接用的别人的 test用于存放测试用例当然现在很多用例未加上...... Helloworld 要进入webapp开发非常简单只需要将代码下载下来即可其中helloworld异常简单 blade框架每个页面为一个页面片一个页面片对应一个js文件并且可能会对应一个html模板文件 一个频道的运行只需要这些文件即可其实有点多的最外层的index.html是基本入口 1 !doctype html2 !--[if (gte IE 9)|(gt IEMobile 7)|!(IEMobile)|!(IE)]!--3 html classie4 !--![endif]--5 html6 head7 meta charsetutf-8 /8 titlehello world/title9 meta nameviewport contentwidthdevice-width,initial-scale1.0, minimum-scale1.0, maximum-scale1.0, user-scalableno
10 meta contenttelephoneno nameformat-detection /
11 meta nameapple-mobile-web-app-capable contentyes /
12 link href../res/style/style.css relstylesheet typetext/css /
13
14 /head
15 body onselectstartreturn false
16
17 script src../blade/libs/require.js typetext/javascript/script
18
19 script src../blade/libs/zepto.js typetext/javascript/script
20 script src../blade/libs/underscore.js typetext/javascript/script
21 script src../blade/libs/underscore.extend.js typetext/javascript/script
22 script src../blade/libs/fastclick.js typetext/javascript/script
23
24 script src../blade/common.js typetext/javascript/script
25 script typetext/javascript src./main.js/script
26 /body
27 /html 他这里引入了源码文件我这里未做任何处理实际使用请参考demo的dest.html 可以看到js入口为对应的main.js 1 (function () {2 3 window.getViewTemplatePath function (path) {4 return text!helloworld/templates/ path .html;5 }6 7 require.config({8 baseUrl: ../,9 paths: {
10 }
11 });
12
13 require([AbstractApp], function (App) {
14 //实例化App
15 var app new App({
16 defaultView: index,
17 viewRootPath: helloworld/views/
18 });
19
20 });
21 })(); 那里引入了我们全局抽象App并进行了实例化这个时候整个代码便开始运行了这里默认加载的是index View 1 define([AbstractView, getViewTemplatePath(index)], function (View, viewhtml) {2 return _.inherit(View, {3 onCreate: function () {4 this.$el.html(viewhtml);5 console.log(大家好我是omCreate事件我会执行并且只会执行一次);6 },7 8 events: {9 click h2: function (e) {
10 this.forward(list);
11 },
12 click .icon_home: function () {
13 window.location ../index.html;
14 }
15 },
16
17 onPreShow: function () {
18 console.log(大家好我是onPreShow事件我每次都会执行执行最后执行turning方法便可显示view);
19 this.turning();
20 },
21
22 onShow: function () {
23 console.log(大家好我是onShow事件我在onPreShow执行turning后会执行);
24
25 },
26
27 onHide: function () {
28 console.log(大家好我是onHide事件每次切换我将隐藏时候我会触发);
29 }
30
31 });
32 }); View Code 我们每个View皆是继承至MVC中的View对于业务层的View只需要关注上面四个事件点即可描述文字写的比较清楚了我这里便不多说了 这个时候直接运行index.html便会默认加载index.js的逻辑代码webapp卡片设计由此开始 demo 是否引入第三方组件 demo中会列举出框架中的一些UI组件与一些通用功能的API并做简单示例一个框架是否好用的一个标识便是其API是否丰富好用 blade这里还需要很多努力这里还望各位多多提点 稍微成熟点的公司一般不会使用什么第三方组件什么创业团队就最喜欢使用第三方的插件或者通用功能我原来就见过一个公司 ① 需要一个弹出层组件便引用国外的1000-2000行代码功能非常全面 ② 需要一个flip手势工具也引用一个第三方的代码500-2000行功能非常全面 但是一来程序员抓不住其中的关键一旦遇到不能适应项目的功能便完蛋了这个时候对程序员的水准要求便高了可能需要源码修改 往往完全读懂后却发现自己只是需要其中的一点点功能而已这个时候很有可能会重写或者寻找另外的库所以只有2B公司才会完全依赖什么第三方库 一般放出来的库文件都是十分全面会满足很多场景但是你只会用到一个或者你基本适用但是总有一个两个地方不适用那么怎么办呢再从新引入一个第三方库么 这样的话产品前端代码便会越发臃肿难以维护并且BUG无数又烂又慢。 demo简介 算了这里扯远了回到demo中来demo中的代码逻辑便稍微复杂一点了首先他存在着两个入口文件分别是 ① debug.html 用于调试其中的所有文件皆是源码形式 ② dest.html 这个文件稍有不同其使用的框架文件和控制器js文件全部被grunt打包好了我们这里不存在Ajax数据请求所以整个浏览不会发生请求延时按道理来说比较快 dest目录便是装的压缩后的文件我们其实将所有相关文件全部打包至了其中的dest/main.js包括模板文件这个多亏grunt与requireJS之功 整个demo的设计我们放到下一章节再说这里简单描述下其中比较关键的是ex_mvc中的文件顾名思义他代表对框架mvc的扩展 扩展的基石是继承业内前端面试一道必考提便是继承但是前端真正使用该技术的人感觉不多很多前端都喜欢堆代码还停留在面向过程。 blade这里便对js的继承做了一个很好的示例希望对js的继承、面向对象知识点有所了解的朋友不妨看看两个MVC中的代码有何不同 1 define([AbstractView, cHighlight], function (AbstractView, cHighlight) {2 3 var hljs new cHighlight();4 5 hljs.registerLanguage(javascript, function(a) {6 return {aliases: [js],k: {keyword: in if for while finally var new function do return void else break catch instanceof with throw case default try this switch continue typeof delete let yield const class,literal: true false null undefined NaN Infinity,built_in: eval isFinite isNaN parseFloat parseInt decodeURI decodeURIComponent encodeURI encodeURIComponent escape unescape Object Function Boolean Error EvalError InternalError RangeError ReferenceError StopIteration SyntaxError TypeError URIError Number Math Date String RegExp Array Float32Array Float64Array Int16Array Int32Array Int8Array Uint16Array Uint32Array Uint8Array Uint8ClampedArray ArrayBuffer DataView JSON Intl arguments require},c: [{cN: pi,b: /^\s*(|)use strict(|)/,r: 10}, a.ASM, a.QSM, a.CLCM, a.CBLCLM, a.CNM, {b: ( a.RSR |\\b(case|return|throw)\\b)\\s*,k: return throw case,c: [a.CLCM, a.CBLCLM, a.REGEXP_MODE, {b: //,e: /;/,r: 0,sL: xml}],r: 0}, {cN: function,bK: function,e: /\{/,c: [a.inherit(a.TM, {b: /[A-Za-z$_][0-9A-Za-z$_]*/}), {cN: params,b: /\(/,e: /\)/,c: [a.CLCM, a.CBLCLM],i: /[\(]/}],i: /\[|%/}, {b: /\$[(.]/}, {b: \\. a.IR,r: 0}]}7 });8 hljs.registerLanguage(xml, function(a) {9 var c [A-Za-z0-9\\._:-];
10 var d {b: /\?(php)?(?!\w)/,e: /\?/,sL: php,subLanguageMode: continuous};
11 var b {eW: true,i: //,r: 0,c: [d, {cN: attribute,b: c,r: 0}, {b: ,r: 0,c: [{cN: value,v: [{b: //,e: //}, {b: //,e: //}, {b: /[^\s\/]/}]}]}]};
12 return {aliases: [html],cI: true,c: [{cN: doctype,b: !DOCTYPE,e: ,r: 10,c: [{b: \\[,e: \\]}]}, {cN: comment,b: !--,e: --,r: 10}, {cN: cdata,b: \\!\\[CDATA\\[,e: \\]\\],r: 10}, {cN: tag,b: style(?\\s||$),e: ,k: {title: style},c: [b],starts: {e: /style,rE: true,sL: css}}, {cN: tag,b: script(?\\s||$),e: ,k: {title: script},c: [b],starts: {e: \/script,rE: true,sL: javascript}}, {b: %,e: %,sL: vbscript}, d, {cN: pi,b: /\?\w/,e: /\?/,r: 10}, {cN: tag,b: /?,e: /?,c: [{cN: title,b: [^ /],r: 0}, b]}]}
13 });
14 hljs.registerLanguage(markdown, function(a) {
15 return {c: [{cN: header,v: [{b: ^#{1,6},e: $}, {b: ^.?\\n[-]{2,}$}]}, {b: ,e: ,sL: xml,r: 0}, {cN: bullet,b: ^([*-]|(\\d\\.))\\s}, {cN: strong,b: [*_]{2}.?[*_]{2}}, {cN: emphasis,v: [{b: \\*.?\\*}, {b: _.?_,r: 0}]}, {cN: blockquote,b: ^\\s,e: $}, {cN: code,v: [{b: .?}, {b: ^( {4}|\t),e: $,r: 0}]}, {cN: horizontal_rule,b: ^[-\\*]{3,},e: $}, {b: \\[.?\\][\\(\\[].?[\\)\\]],rB: true,c: [{cN: link_label,b: \\[,e: \\],eB: true,rE: true,r: 0}, {cN: link_url,b: \\]\\(,e: \\),eB: true,eE: true}, {cN: link_reference,b: \\]\\[,e: \\],eB: true,eE: true,}],r: 10}, {b: ^\\[.\\]:,e: $,rB: true,c: [{cN: link_reference,b: \\[,e: \\],eB: true,eE: true}, {cN: link_url,b: \\s,e: $}]}]}
16 });
17 hljs.registerLanguage(css, function(a) {
18 var b [a-zA-Z-][a-zA-Z0-9_-]*;
19 var c {cN: function,b: b \\(,e: \\),c: [self, a.NM, a.ASM, a.QSM]};
20 return {cI: true,i: [/|],c: [a.CBLCLM, {cN: id,b: \\#[A-Za-z0-9_-]}, {cN: class,b: \\.[A-Za-z0-9_-],r: 0}, {cN: attr_selector,b: \\[,e: \\],i: $}, {cN: pseudo,b: :(:)?[a-zA-Z0-9\\_\\-\\\\(\\)\\\\\]}, {cN: at_rule,b: (font-face|page),l: [a-z-],k: font-face page}, {cN: at_rule,b: ,e: [{;],c: [{cN: keyword,b: /\S/}, {b: /\s/,eW: true,eE: true,r: 0,c: [c, a.ASM, a.QSM, a.NM]}]}, {cN: tag,b: b,r: 0}, {cN: rules,b: {,e: },i: [^\\s],r: 0,c: [a.CBLCLM, {cN: rule,b: [^\\s],rB: true,e: ;,eW: true,c: [{cN: attribute,b: [A-Z\\_\\.\\-],e: :,eE: true,i: [^\\s],starts: {cN: value,eW: true,eE: true,c: [c, a.NM, a.QSM, a.ASM, a.CBLCLM, {cN: hexcolor,b: #[0-9A-Fa-f]}, {cN: important,b: !important}]}}]}]}]}
21 });
22 hljs.registerLanguage(json, function(a) {
23 var e {literal: true false null};
24 var d [a.QSM, a.CNM];
25 var c {cN: value,e: ,,eW: true,eE: true,c: d,k: e};
26 var b {b: {,e: },c: [{cN: attribute,b: \\s*,e: \\s*:\\s*,eB: true,eE: true,c: [a.BE],i: \\n,starts: c}],i: \\S};
27 var f {b: \\[,e: \\],c: [a.inherit(c, {cN: null})],i: \\S};
28 d.splice(d.length, 0, b, f);
29 return {c: d,k: e,i: \\S}
30 });
31
32
33 return _.inherit(AbstractView, {
34
35 propertys: function ($super) {
36 $super();
37
38 },
39
40 _initHead: function () {
41
42 this.$(header).append($(i classreturnico i_bef/i));
43 },
44
45 events: {
46 click .returnico: function () {
47 this.back(index);
48 }
49 },
50
51 initialize: function ($super, app, id) {
52 $super(app, id);
53
54 this._initHead();
55 },
56
57 onPreShow: function ($super) {
58 $super();
59
60 },
61
62 show: function ($super) {
63 $super();
64
65 hljs.initHighlighting(this);
66
67 }
68
69
70 });
71
72 }); View Code 这里代码比较简单主要是继承至AbstractView然后做了demo项目的一些通用工作 其中有一大段代码是对代码高亮做处理的这里小钗可耻的引用了一个第三方库。。。。。。 实现继承的代码在underscore.extend中这段代码需要各位仔细研读是本项目的基石。 //继承相关逻辑
(function () {// 全局可能用到的变量var arr [];var slice arr.slice;/*** inherit方法js的继承默认为两个参数** param {function} origin 可选要继承的类* param {object} methods 被创建类的成员扩展的方法和属性* return {function} 继承之后的子类*/_.inherit function (origin, methods) {// 参数检测该继承方法只支持一个参数创建类或者两个参数继承类if (arguments.length 0 || arguments.length 2) throw 参数错误;var parent null;// 将参数转换为数组var properties slice.call(arguments);// 如果第一个参数为类function那么就将之取出if (typeof properties[0] function)parent properties.shift();properties properties[0];// 创建新类用于返回function klass() {if (_.isFunction(this.initialize))this.initialize.apply(this, arguments);}klass.superclass parent;// 父类的方法不做保留直接赋给子类// parent.subclasses [];if (parent) {// 中间过渡类防止parent的构造函数被执行var subclass function () { };subclass.prototype parent.prototype;klass.prototype new subclass();// 父类的方法不做保留直接赋给子类// parent.subclasses.push(klass);}var ancestor klass.superclass klass.superclass.prototype;for (var k in properties) {var value properties[k];//满足条件就重写if (ancestor typeof value function) {var argslist /^\s*function\s*\(([^\(\)]*?)\)\s*?\{/i.exec(value.toString())[1].replace(/\s/i, ).split(,);//只有在第一个参数为$super情况下才需要处理是否具有重复方法需要用户自己决定if (argslist[0] $super ancestor[k]) {value (function (methodName, fn) {return function () {var scope this;var args [function () {return ancestor[methodName].apply(scope, arguments);}];return fn.apply(this, args.concat(slice.call(arguments)));};})(k, value);}}//此处对对象进行扩展当前原型链已经存在该对象便进行扩展if (_.isObject(klass.prototype[k]) _.isObject(value) (typeof klass.prototype[k] ! function typeof value ! fuction)) {//原型链是共享的这里处理逻辑要改var temp {};_.extend(temp, klass.prototype[k]);_.extend(temp, value);klass.prototype[k] temp;} else {klass.prototype[k] value;}}if (!klass.prototype.initialize)klass.prototype.initialize function () { };klass.prototype.constructor klass;return klass;};})(); 继承基石 总的来说各个view页面卡片的代码存放与views里面对应的模板文件存放与templates中具体原理我们后面点说明 业务入口与全局控制器 这里入口的js文件为main.js这个是最为关键一个js我们将里面的动画相关逻辑去掉来看看主干代码 1 (function () {2 var project demo/;3 4 window.getViewTemplatePath function (path) {5 return text! project templates/ path .html;6 }7 8 require.config({9 baseUrl: ../,
10 paths: {
11 View: project ex_mvc/view
12 }
13 });
14
15 var animations {};
16
17 require([AbstractApp], function (App) {
18 //实例化App
19 var app new App({
20 //选择pushState还是hashChange
21 hasPushState: false,
22 defaultView: index,
23 viewRootPath: project views/,
24 animations: animations
25 });
26
27 $.bindFastClick $.bindFastClick();
28
29 });
30 })(); 核心代码是17-27行这里首先做了一些初始化变量定义然后使用requireJS引入了我们的全局控制器这个文件虽然不到400行却是整个框架的最大核心 全局控制器的工作 这里点一下便是后续我们会详解之这里简单介绍全局控制器app应该干的事情 ① 提供URL解析机制以便让控制器可以根据URL获得当前是要加载哪个view的实例比如 http://www.baidu.com/index.html#index http://www.baidu.com/index 若是使用hashChange实现浏览器跳转便直接取出index这个键值 若是使用pushState方案的话便需要业务同事给出取出URL键值的方法最终我们需要得到index这个键值 ② app应该保留各个view的实例并且维护一个队列关系 以现在博客园为例我们可能具有两个view页面片index-detail 我们首次便是加载index这个view点击其中一个项目便加载detail这个view这个时候app是应该同时保存两个view并且内部要维系一个访问顺序队列 这个队列最好可与浏览器保存一致若不能保存一致后期便可能会出现点击浏览器后退死循环的问题 ③ app应该提供view实例化的方法 所以的view实例若无特殊原因皆应该由app生成app应该具有实例化view的能力view一般使用AMD规范管理这里涉及异步加载 PS真实工作环境中view需要自建一套事件机制比如实例化时候要触发什么事件显示时候要触发什么事件皆需要有app只会负责 实例化-显示-隐藏 ④ app应该提供监控浏览器事件每次自动加载各个view 如上面所述app会注册一个hashChange事件或者popState事件以达到改变URL不刷新页面的功能这个功能主要用于用户点击浏览器原生后退键 可扩展性/共性与继承 blade的构想是高扩展性比如我们核心的MVC的代码即可被继承扩展 无论是AbstractView还是AbstractAPP或者AbstractModel皆是可继承扩展的 我们后面会根据需要以AbstractApp继承一个ipadAPP版本出来 我们也会根据AbstractModel继承至十月localstorage缓存请求数据的版本 AbstractView的继承扩展更是家常便饭 以上是MVC的扩展完了就是UI组件的扩展简单由日历组件的demo来看 我只需要提供简单的实现用户几行代码便可以实现假日日历很多公司会出现价格日历也仅仅是几行代码的事情 我们可以继承下来做单独实现也可在实例化时候传入数据解决总之这里的观点便是 UI需要寻找共性做抽象而不是重复编码 再以弹出层类为例 我们的alert、toast、bubble.layer冒泡层皆是继承至ui.layer这样做的好处是什么呢 简单来说他们具有以下共性 ① 都需要mask蒙版也可以不具有 ② 点击mask可关闭 ③ 居中排列 ④ 以绝对定位的形式出现 于是我们可以轻易实现这样的代码 1 return _.inherit(UIView, {2 3 //默认属性4 propertys: function ($super) {5 $super();6 this.mask new UIMask();7 8 //需要蒙版9 this.needMask true;
10
11 //需要点击蒙版删除
12 this.maskToHide true;
13
14 //需要居中定位
15 this.needReposition true;
16
17 },
18
19 initialize: function ($super, opts) {
20 $super(opts);
21
22 this.clearRes();
23 },
24
25 //资源清理
26 clearRes: function () {
27 // if (this.needMask false) this.mask null;
28 },
29
30 addEvent: function () {
31 this.on(onCreate, function () {
32 this.$el.addClass(cui-layer);
33 });
34
35 this.on(onPreShow, function () {
36 var scope this;
37
38 if (this.needMask) {
39 this.mask.show();
40 }
41
42 if (this.needMask this.maskToHide) {
43 //mask显示之前为mask绑定关闭事件一次执行便不予理睬了
44 this.mask.$el.on(click.uimask this.mask.id, function () {
45 scope.hide();
46 });
47 }
48
49 });
50
51 this.on(onShow, function () {
52 if (this.needReposition) this.reposition();
53 this.setzIndexTop();
54 });
55
56 this.on(onHide, function () {
57 this.mask.$el.off(.uimask this.mask.id);
58 this.mask.hide();
59
60 });
61
62 },
63
64 //弹出层类垂直居中使用
65 reposition: function () {
66 this.$el.css({
67 margin-left: -($(this.$el).width() / 2) px,
68 margin-top: -($(this.$el).height() / 2) px
69 });
70 }
71
72 }); View Code 至于气泡弹层当然不是居中的于是气泡弹层中只需要重写掉repositon接口罢了 前端经常会提到继承经常会提到闭包但是到底如何使用继承或者闭包是什么还是必须真正使用才能掌握 若是不使用就不会真正明白那么如何成为优秀的前端如何成为前端架构只是空想更何论站在顶端呢 PS当然小钗这里有点扯淡并不是说小钗是高手其实我在公司也只是小码农 结语 好了扯着扯着就扯多了今天暂时到此其实也没有什么好介绍的代码在那里各位自己看吧若是有什么问题请给位留言 最后各位若能点一下推荐或者在git中为我加一颗心便善莫大焉了 后面点小钗会对框架进行源码解读希望对入门级的前端朋友有所帮助也不知道各位是否感兴趣转载于:https://www.cnblogs.com/yexiaochai/p/3837713.html