前言
最近校招要来了,很多大三的同学一定按捺不住心中的焦躁,其中有期待也有彷徨,或许更多的是些许担忧,最近在开始疯狂的复习了吧
这里小钗有几点建议给各位:
① 不要看得太重,关心则乱,太紧张反而表现不好
② 好的选择比坚持更重要
这点小钗便深有体会了,因为当年我是搞.net的,凭着这项技能想进bat简直就是妄想,于是当时我就非常机智的转了前端,另一个同学也非常机智的转了安卓
所以各位想进大公司,还需要提前关注各个公司最大的缺口是什么,找不准缺口基本无望进大公司的
③ 积累最重要/没有积累现在就专精
想进大公司除了运气,最重要的还是平时积累,若是大三之前没有5W行代码量的同学便需要专精一门,不要东搞西搞,最后什么都不会,那就完了
④ 不要扯设计模式
这里虽然有点偏激,但是就我的观察,我原来的leader、我身边的同事,我们公司的架构师,真的没有几个完全理解了设计模式,我们很多架构师甚至连个依赖图,时序图都搞不出来
所以各位面试的同学除非真的对设计模式有深入了解,或者代码量达到了10-20w行,除此之外不要在面试扯设计模式,肯定会中招的
PS:尼玛,这里差点忘了加之前,万一被leader看见了就完了!
最后,进得了大公司的同学一般之前大学时光没有怎么浪费,或者说天资本来就好,进不了的同学便先积累吧,搞不好哪天就中彩票不用工作了
好了,我们进入今天的正题,这是与blade框架有关的第三篇博客,第二篇是关于webapp seo难题的解决方案
由于该方案本身具有一定难度还在实现之中,所以这里就先出第三篇了......
PS:此文只是个人粗浅的认识,有误请指正
前端的发展
我原来常与leader讨论,javascript之前不适合做大规模应用的一个主要原因是其无法分模块,这个就带来了多人维护一个文件的难题
程序员往往都是2B,我们可能不会觉得自己的代码写得多好,但是一般会觉得别人的代码写得很烂!
于是你会看见一个有趣的现象便是两个有一定差距的程序员维护了一个js文件后,可能以后他们都不能愉快的玩耍了
让2个程序员维护一个文件都非常困难了,何况是多个?所以分模块、分文件是javascript或者说是前端一个极大的进步
他让前端合作变成了可能,由此才出现了几万甚至几十万代码量的前端应用,这里requireJS相关的模块库功不可没
这里我们先来回顾下之前我们是怎么写代码的
混杂编程
最初,我们的应用一般都不复杂,我们会这样写前端代码:
复制代码
<body>
<div>
<span οnclick="test()">测试</span>
</div>
<script type="text/javascript">
function test() {
alert('do something');
}
</script>
</body>
复制代码
慢慢的我们感觉好像不对,因为B同事好像也有个test方法,由于B同事比我们早来几年我们也不好喷他,于是只好寻求解决方案,于是出现了命名空间
复制代码
<div>
<span οnclick="yexiaochai.test()">测试</span>
</div>
<script type="text/javascript">
var yexiaochai = {
test: function () {
alert('do something');
}
};
</script>
复制代码
这里解决了B同事冲刷我代码的问题后,突然B同事便离职了,B同事的代码交给了我们,于是我们非常看不惯其以B开头的命名空间!
此类情况也出现与了最初的ASP、JSP甚至现今的PHP,他们有一些共同的特点便是:
① web中的asp代码与javascript代码交替,代码杂乱
② 界面设计与程序设计混杂,维护升级困难
一个经典的例子便是著名论坛框架discuz的源码(他js其实控制的比较好),看过其源码的同学想必对其印象极其深刻
动则一个文件成千上万,内中html php代码混杂,整个维护阅读成本非常之高
这个时候由于社会发展,越来越多的复杂需求层出不穷,为了满足社会的需要,各大框架分分求变,于是有了一些变化
UI分离
这一次的变化我认为集中体现在UI分离这块,里面做的最成功的当然是ASP.net,javascript有与之对应的struts2
这一次的革新两大巨头不在将逻辑操作以及数据库操作写在与HTML有关的文件中了,而是写在与之对应的后台文件中,这里最优雅的是.net的codebehind方案
这次的变化倒不是说程序本身发生了什么变化,事实上程序本身并没有发生变化,以小钗熟悉的.net为例
我们一次新建页面会具有两个文件:
① index.apsx
② index.aspx.cs
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="index.aspx.cs" Inherits="_00综合_11mvc_index" %>
复制代码
public partial class _00综合_10doc_write_index : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
}
}
复制代码
值得关注的是两个文件的这些代码,这里的内部实现我们不去深究,但是小钗可以告诉你,最终的编译会将这两个文件和到一起,以上的代码映射便是他们合并的凭据
因为他们最终会和到一起,所以index.apsx与其index.apsx.cs才会具有方法数据通信的能力,跨页面就不行了
UI分离带来的第二个好处便是经典的.net三层架构以及经典的Java SSH框架,在UI分离之前,这类分离是不好实现的
于是.net与java的代码可以基于此一再细分,各个领域的程序员专注点与擅长点完全分开了,所以很多复杂的软件出现了
前端模块化
最初.net的做法也带来了很多质疑,因为懂行的都会知道,这样的代码事实上效率低了,理解差了;这里便和现今javascript的一些特征惊人的一致
我们的代码存在着这样一种递进的关系:
① 最简单的代码
<span οnclick="test()">测试</span>
② 考虑方法重名问题后的代码
<span οnclick="yexiaochai.test()">测试</span>
③ 考虑一个标签具有多个事件的实现
复制代码
<body>
<div>
<span id="test">测试</span>
</div>
<script type="text/javascript">
var yexiaochai = {
test: function () {
alert('do something');
}
};
document.getElementById('test').addEventListener('click', yexiaochai.test);
</script>
</body>
复制代码
以上三种递进关系其实诠释了一客观因素:
业务需求变得复杂、业务复杂后处理业务的方法便多了,所以方法会重复,也是因为逻辑的复杂度导致一个标签可能具有多个事件
所以,现阶段前端代码复杂度的提升的根本原因便是原来的写法不满足需求了,我们需要这样写
以上三种递进关系只是一个开始,由于业务逻辑的膨胀,javascript代码爆炸性的膨胀起来了,于是我们做了一下事情:
① 将javascript文件放到一个文件里面
② 一个文件太多不好维护了,于是分成多个文件
③ 文件太多了,不好管理,于是开始适应模块化管理工具
以上是前端分模块的主要原因
前端MVC
前端做久了我们会发现,很多时候我们还是在操作html,无论是js事件操作,或者css操作,或者数据来了需要改变dom结构,总而言之我们总是在操作我们的UI
这个时候我们也会遇到一种现象是,这里需要一个信息提示框,那里也需要一个信息提示框,好像长得差不多
这样相似的需求积累,我们又不傻,当然会寻求统一的解决方案,于是便出现了UI组件,UI组件的出现是前端一大进步
这样前端便不只是写点小特效,小验证的码农了,摇身一变成为了高大上的交互设计师,而且还有很多妹子,工作环境好得不得了,想来的同学请给位私信,发简历,工资高,妹子多!!!
我们刚开始可能是这样做UI的:
复制代码
function showAlert(msg) {
//构架复杂dom结构,略
var el = $('<div class="msg">' + msg + '</div>')
//绑定复杂的事件,略
el.click(function () { });
$('body').append(el);
}
showAlert('史上最强孙组长!');
复制代码
这里面涉及到几个元素:
① 数据 => msg
② 界面 => el
③ 事件 => click
PS:此段虚构
逐渐的,我们发现这样写很不方便,原因是UED新来一个叫左盟主的抽风给我说什么语义化,要动我的dom结构!!!
尼玛,他当我傻啊!HTML有什么语义化可言嘛!我这边据理力争,因为他不懂嘛,他对不懂的事物便比较恐惧,所以我要把他说明白
但是史上最强、宇宙无敌孙组长带来了CSS天使小静mm给我语重心长的聊了一下小时代与后会无期的故事与渊源,最后还唱起了女儿情
于是我深深的理解了左盟主是正确的,前端确实应该考虑语义化,于是我决定修改我的DOM结构!!!
真正的修改下来,发现这里工作量不小:
首先是原来代码过程重来没有考虑过dom或者classname会变,这里一变的直接影响便是我那些可怜的事件绑定全部完蛋
于是我这里便考虑是不是应该将,表现与行为分离
这里的UI操作不应该影响我具体事件逻辑,而且UI样式的变化是家常便饭,就算UED不便,不同的业务场景总会要求一点不一样的东西,这里便引入了伟大的模板引擎
模板引擎
前端模板引擎的出现具有划时代的意义,他是实现表现与行为分离的基石,这里再配以zepto的事件机制,最后的结论就是左盟主的需求很简单
这里以blade的一个组件代码为例:
我们看到这里的alert组件的dom结构就是一个简单的html片段,于是我们要改某个dom结构便直接修改便是,不需要修改我们的js文件
当然这里的前提是这里的className映射不能丢,这个映射丢了,事件绑定一块仍然需要修改
到这里,我们是时候进入今天MVC的深入发掘了
理解MVC
正如.net引入Code Behind为了解决UI与业务分离一样,前端javascript也采用了MVC的方式分离UI与业务,前端MVC出现的主要原因其实便是:
职责分离!
其实小钗之前一直对MVC不太了解,不知道应该从哪个方案来了解MVC,以structs2为例,我好像就只看到几个配置向并没有看到控制器就完了
再以Backbone为例,其View的实现以及Model的实现基本处于分离状态,完全可以单独使用,Router一层看似扮演着控制器的角色但是我这里依旧觉得他仅仅是路由
再拿小钗最近写的Blade框架的app模块,他倒是有点像全局控制器了,控制着各个View的创建、销毁、通信,但是这里的Model好像由不在了
PS:传统的MVC的控制器是负责转发请求处理请求,生成View的,这点可以参考Blade的app
所以要想理解MVC还真不是一件容易的事情,当有人问起什么是MVC时往往我们都是一图打发:
事实上这个模型,在前端来说很少出现,他经常不上缺了一个Controller就是缺了一个Model,而每次问起级别较高的同事也只是将上图简单描述一下即只
好像MVC变成了一个玄之又玄的东西,处处透露着只可意会不可言传的神秘
PS:所以面试的同学小心了,一般问到什么设计模式或者MVC要么这个面试官很牛,要么狠喜欢装B,两者对你都不利
所谓MVC便是:
① View就只处理View的事情,其它神马都不要管
② 数据由Model处理,并且为View提供渲染需要的数据
③ 由于后端可能抽风可能将name变成Name坑前端所以会衍生出一套viewModel的东西作为Model与View的映射
④ 业务代码集中与viewController,提供事件让用户与View交互,入口点为View
所以一般逻辑是,Controller加载,初始化状态Model获得数据生成ViewModel,View生成,用户操作View触发事件由ViewController处理引起数据更新,然后Model通知view做更新
这里我认为实现最为优雅的是我与原leader的一个开源项目:
https://github.com/leewind/dalmatians
我觉得这个代码便很好的说明了MVC这个思想,各个模块只是关心了自己的职责,举个例子来说:
View Code
View Code
复制代码
<script type="text/underscore-template" id="template-ajax-init">
<div class="cui-alert" >
<div class="cui-pop-box">
<div class="cui-hd">
<%=title%>
</div>
<div class="cui-bd">
<div class="cui-error-tips">
</div>
<div class="cui-roller-btns" style="padding: 4px; "><input type="text" placeholder="设置最低价 {day: '', price: ''}" style="margin: 2px; width: 100%; " id="ajax_data" class="txt" value="{day: , price: }"></div>
<div class="cui-roller-btns">
<div class="cui-flexbd cui-btns-sure"><%=confirm%></div>
</div>
</div>
</div>
</div>
</script>
<script type="text/underscore-template" id="template-ajax-suc">
<ul>
<li>最低价:本月<%=ajaxData.day %>号,价格:<%=ajaxData.price %> 元</li>
</ul>
</script>
<script type="text/underscore-template" id="template-ajax-loading">
<span>loading....</span>
</script>
复制代码
复制代码
//模拟Ajax请求
function getAjaxData(callback, data) {
setTimeout(function () {
if (!data) {
data = {day: 3, price: 20};
}
callback(data);
}, 1000);
}
var AjaxView = _.inherit(Dalmatian.View, {
_initialize: function ($super) {
//设置默认属性
$super();
this.templateSet = {
init: $('#template-ajax-init').html(),
loading: $('#template-ajax-loading').html(),
ajaxSuc: $('#template-ajax-suc').html()
};
}
});
var AjaxAdapter = _.inherit(Dalmatian.Adapter, {
_initialize: function ($super) {
$super();
this.datamodel = {
title: '标题',
confirm: '刷新数据'
};
this.datamodel.ajaxData = {};
},
format: function (datamodel) {
//处理datamodel生成viewModel的逻辑
return datamodel;
},
ajaxLoading: function () {
this.notifyDataChanged();
},
ajaxSuc: function (data) {
this.datamodel.ajaxData = data;
this.notifyDataChanged();
}
});
var AjaxViewController = _.inherit(Dalmatian.ViewController, {
_initialize: function ($super) {
$super();
//设置基本的属性
this.view = new AjaxView();
this.adapter = new AjaxAdapter();
this.viewstatus = 'init';
this.container = '#container';
},
//处理datamodel变化引起的dom改变
render: function (data) {
//这里用户明确知道自己有没有viewdata
var viewdata = this.adapter.getViewModel();
var wrapperSet = {
loading: '.cui-error-tips',
ajaxSuc: '.cui-error-tips'
};
//view具有唯一包裹器
var root = this.view.root;
var selector = wrapperSet[this.viewstatus];
if (selector) {
root = root.find(selector);
}
this.view.render(this.viewstatus, this.adapter && this.adapter.getViewModel());
root.html(this.view.html);
},
//显示后Ajax请求数据
onViewAfterShow: function () {
this._handleAjax();
},
_handleAjax: function (data) {
this.setViewStatus('loading');
this.adapter.ajaxLoading();
getAjaxData($.proxy(function (data) {
this.setViewStatus('ajaxSuc');
this.adapter.ajaxSuc(data);
}, this), data);
},
events: {
'click .cui-btns-sure': function () {
var data = this.$el.find('#ajax_data').val();
data = eval('(' + data + ')');
this._handleAjax(data);
}
}
});
var a = new AjaxViewController();
a.show();
复制代码
程序的执行流程由控制器发起,控制器至少需要一个View的实例,可能需要一个Model的实例
事件业务全部被控制器负责了,每次View的操作会引起Model的Setter操作从而影响数据模型的变化便会通知其观察者View做出相应的改变
Blade UI中的MVC
但是,上述的实现在实际使用中发现并不是那么好用,为什么呢?
分层过细
分层思维应该大力倡导,但是层次的划分也有一个度,因为总的来说分层多了业务实现复杂度或者阅读门槛就会上来
以上述的方案如果去做UI的话是相当得不偿失的,一个UI的形成,便需要一个view的实例,一个Model的实例,再变态一点设置会被划分到不同的模块
这样的话维护成本以及代码编写成本便有所提高,总之分层有理,但也要适度!这个时候便需要改造,改造点集中表现为:
① 我的View不需要具有状态值,我就只有一个模块
② 我的Model不想与人共享,我就放在自己的内部属性即可
View Code
核心点变成了几个属性:
① template,根据他生成UI
② datamodel,根据他生成viewModel提供给template使用
③ eventArr,业务事件注册点
这里简单以alert组件做说明:
1 define(['UILayer', getAppUITemplatePath('ui.alert')], function (UILayer, template) {
3   return _.inherit(UILayer, {
4     propertys: function ($super) {
5       $super();
7       //数据模型
8       this.datamodel = {
9         title: 'alert',
10         content: 'content',
11         btns: [
12           { name: 'cancel', className: 'cui-btns-cancel' },
13           { name: 'ok', className: 'cui-btns-ok' }
14         ]
15       };
16 
17       //html模板
18       this.template = template;
19 
20       //事件机制
21       this.events = {
22         'click .cui-btns-ok': 'okAction',
23         'click .cui-btns-cancel': 'cancelAction'
24       };
25     },
26 
27     initialize: function ($super, opts) {
28       $super(opts);
29     },
30 
31     addEvent: function ($super) {
32       $super();
33       this.on('onCreate', function () {
34         this.$el.addClass('cui-alert');
35       });
36       this.maskToHide = false;
37     },
38 
39     okAction: function () {
40       this.hide();
41       console.log('ok');
42     },
43 
44     cancelAction: function () {
45       this.hide();
46       console.log('cancel');
47 
48     },
49 
50     setDatamodel: function (datamodel, okAction, cancelAction) {
51       if (!datamodel) datamodel = {};
52       _.extend(this.datamodel, datamodel);
53       this.okAction = okAction;
54       this.cancelAction = cancelAction;
55       this.refresh();
56     }
57 
58   });
59 
60 });
<div class="cui-pop-box">
<div class="cui-hd">
<%=title%>
</div>
<div class="cui-bd">
<div class="cui-error-tips">
<%=content%></div>
<div class="cui-roller-btns">
<% for(var i = 0, len = btns.length; i < len; i++ ) {%>
<div class="cui-flexbd <%=btns[i].className%>">
<%=btns[i].name%></div>
<% } %>
</div>
</div>
</div>
实例化时,alert组件会执行基类的方法,最终反正会执行AbstractView的程序逻辑
首先会根据datamodel以及template生成DOM结构,然后在使用事件代理的方式用eventArr绑定业务事件,具体实现请移步至:
https://github.com/yexiaochai/blade/tree/master/blade/ui
结语
今天又做了一回标题党,引面试党进来看了看,然后谈了自己对前端MVC、分成的一些理解,最后说了Blade UI一块的设计思路,希望对各位有帮助
有时候感觉知道了却写不出来,然后本来也想好好的解析下代码却感觉没什么说的,烦劳各位自己看看吧
最后微博求粉:http://weibo.com/yiquinian/home?wvr=5
本文转自叶小钗博客园博客,原文链接http://www.cnblogs.com/yexiaochai/p/3888373.html,如需转载请自行联系原作者

【blade的UI设计】理解前端MVC与分层思想相关推荐

  1. 目前UI设计和前端哪个行业更好,女生应该怎么抉择?

    对于大多数人来说,前端和U设计两个职业都算是转行互联网行业相对可行性较高的方向.那究竟是选择前端,还是选择UI设计呢?今天就来跟大家简单分析一下, 希望从以下内容中你可以更加了解这两个职业,从而根据自 ...

  2. 微信小程序--圣诞头像框UI设计及前端实现

    这周主要是在搞一个新项目,主要负责UI设计和前端页面实现,也是类似之前头像框的项目,主题不同,这次的主题是圣诞,所以在UI设计上就需要注意和圣诞节的搭配. (该项目最后取消了,所以就是记录一下过程) ...

  3. UI设计和前端开发的区别

    UI设计(或称界面设计)是指对软件的人机交互.操作逻辑.界面美观的整体设计.UI设计分为实体UI和虚拟UI,互联网说的UI设计是虚拟UI,UI即User Interface(用户界面)的简称.好的UI ...

  4. 目前UI设计和前端哪个行业更好?女生应该怎么抉择?

    UI设计有什么优点? 想了解UI设计,首先要知道什么是UI设计.指软件的人机交互.操作逻辑.界面美观的整体设计,它包含了交互设计和视觉设计2个方面.也就是说,UI设计负责产品的图形.色彩搭配等,让产品 ...

  5. 浅谈从UI设计转前端的坎坷历程

    大家好,我是一个程序员--资深CV工程师(狗头保命)!在此想和大家一起分享一下从UI转前端的坎坷历程,希望能够帮助一些想入坑的朋友们. 加入门派(如何走上UI设计之路) 我大学的专业是计算机科学与技术 ...

  6. 网页+微信小程序UI设计及前端开发(第二周)

    日期 工作内容 2020年8月12日 网页前端架构,素材查找,小程序前端架构 2020年8月13日 网页.小程序页面完善,提交网页与小程序前端文件 文章目录 一.网页 (一)页头 (1)logo及导航 ...

  7. UI设计摘要背景素材|简单分层PSD格式化模板,为项目增加背景

    任何提交过提案或尝试过设计项目的人都可能被要求提交或创建项目的设计简报. 这是一种相当标准的做法,但有时会令人生畏,尤其是如果你不习惯的话. 一个好的设计概要是一个工具,它可以帮助你和设计客户在项目上 ...

  8. html和ui有什么区别,前端设计和ui设计的区别是什么

    前端设计和ui设计的区别有研究方向不同,ui是用户研究.交互设计.界面设计,web前端是html.css.js等需要编写代码:职业机会不同,ui设计:前端开发工程师.资深前端开发工程师.前端架构师等, ...

  9. 众筹开班你说了算!UI设计+前端开发一站式打包学

    UI设计入门有几步?前端开发是开发些啥?实际工作中UI设计和前端开发是如何衔接在一起工作的?Word天,这期课程厉害了,听完干货都能直接上手参加工作了,快告诉我怎么听课! 这一回小码哥不走寻常路,干货 ...

最新文章

  1. java 用户登录token_Java,SpringBoot采用token方式实现登录认证
  2. android 第三方登录 --- QQ
  3. php 单选框选中事件,html中的checkbox和radio事件选择用法详解
  4. 苹果cmsv10自适应卡通动漫番剧模板
  5. android百度地图地址解析失败怎么办,【百度地图API】当地址解析失败时,如何调用search方法查找地址...
  6. Leetcode106 由中序序列和后序序列构建二叉树
  7. [转]C#中水晶报表实例
  8. 07_封装丶静态和工具类
  9. 数字图像处理理论课件(清华大学计算机科学与技术)
  10. 推荐克莱夫·汤普森《天才程序员》
  11. wps公式如何加序号_神器:AxMath数学公式编辑排版软件 输入公式、化学方程式从未如此简单...
  12. 向PDF写入签名日期
  13. mysql 统计七日留存率_1.七日留存率-SQL实现
  14. java实现手写签名_手写签字,保存笔迹到图片
  15. 性能测试流程-性能测试2
  16. S32K系列之ADC
  17. 大脑如何表征时间和情绪之间的关系?
  18. Python学习手册--第二部分(数据类型)
  19. Delaunay 三角网格学习
  20. 个人所得税及酬金计算公式

热门文章

  1. 中国大学MOOC音乐与健康试题及答案
  2. 【C进阶】之结构体类型( struct)
  3. 2019余额不足,技术人如何高效充电?
  4. 图像处理-opencv去水印(如有图片侵权,请及时联系)
  5. 理解子网掩码和如何计算子网掩码
  6. TCP/IP协议模型详解六数据传输过程
  7. 感悟:君子不立于危墙之下
  8. Python爬虫(一):简单小说爬取实例
  9. 开发企业架构的实用指南
  10. 基于Flask的文章内容管理系统(CMS)