前端要给力 — 平凡之路

一直想总结下本身摸打滚爬的前端经历,3年,从一个极讨厌前端的人,变成一个吃前端饭碗的人。没有人带过我,跌跌撞撞的缓慢前进,但我很喜欢分享,喜欢一块儿进步,这会是我之后一直乐意作的事情。javascript

综述

娃娃学步

  • w3cschool上的 html / css / javascript / 以及jquery教程,万事开头的第一步css

Say hello to the world!html

小跑上路

赶上平衡木

在小跑上路的过程当中,作出来的东西看起来很专业,注意是“看起来”。若是不理解真正的前端技能,那只能是看起来专业,内部结构仍是乱糟糟的,或者是遇到bug不知道怎么调,东一句西一句,拆了东墙补西墙。这过程就像走在平衡木上,稍不留神就会摔下去。github

首先要了解css的布局原理

  • 盒模型web

  • 定位模型面试

  • 有了布局的基本理论后,尝试去理解Boostrap里的栅格系统 row col span2 背后的style

js最重要的三点: 闭包、原型、做用域

关于js的原型和做用域,我没专门写过文章,建议去博客园搜下。若是想要完整的理解js语言机制,能够去看《Javascript模式》这本书,或者看我整理的读书笔记

华丽跳跃谢幕

只有把平衡木上的技能磨熟练后,咱们才能真正的游刃有余,保证不从平衡木上摔下来的前提下,再有余力去设计如何华丽的跳跃和谢幕。

组件封装

还没了解js对类(或模块)的封装前,咱们的代码多是这样的

var getData = function(){
    // ......
};

function editFunc(){
    // ......
};

$('.refresh-btn').on('click', function(){
    var data = getData();
    var $target = $($(this).attr('data-target'));
    $target.empty();

    for(var i=0; i<data.length; i++){
        var $child = $('<tr></tr>');
        $child.append('<td>' + data[i]['name'] + '</td>');
        // ......
        $child.append('<td><a class="edit-link">编辑</a></td>');
        $target.append($child);
    }

    $target.find('.edit-link').on('click', editFunc);
});

一个点击就获取数据,而后刷新表格的功能。若是一个页面中有多个相似的异步刷新的表格,且每一个表格的字段又各不相同,那么最偷懒的作法就是拷贝大段代码,而后再调整<td>的字段。这样的代码简直了,太难维护了!

var table1 = new AjaxTable({
    el: '#dataTable',
    dataUrl: '/path/to/action/'
});

table1.refresh();

若是代码变成这样,那就爽多了,获取数据和刷新表格的过程都封在了AjaxTable中,各个使用之处只须要传个参数调用下refresh()便可,减小了大量重复(类似的)代码。这就是对UI组件/功能组件的封装。

之前为了准备面试时的“手撕代码”,写过一个简单的轮播组件,不用jquery(面试常常不容许使用任何库)

还写过下面一些文章

模块化开发

若是要在页面上引入外部的js库,最初学习的时候是这样引入的

<script type="text/javascript" src="jquery-1.7.2.min.js"></script>
<script type="text/javascript" src="jquery-ui/jquery-ui-1.8.24.min.js"></script>
<script type="text/javascript" src="jquery-ui/jquery-ui-datepicker-zh-CN.js"></script>
<script type="text/javascript" src="bootstrap-2.3.2.min.js"></script>

因为浏览器中js的执行(非加载)过程是在单线程中的,而各js文件又会存在依赖关系,好比 jquery-ui 依赖 jquery,bootstrap 也依赖 jquery,因此<script>标签的引入得知足依赖顺序。当一个项目越作页面越多时,这么多页面中会存在一堆<script>标签,若是要将某个js文件升级版本,或者修改script的依赖关系时,这就会成为一个很繁琐的工做,特别是<script>分散在项目的各个文件中时。

RequireJS就是出来解决这个问题的(简单来讲就是用js去管理js),还有SeaJS,它们分别表明着AMDCMD两种风格,关于模块化和二者的区别能够看这篇文章

实战案例

页面继承

页面继承 这块跟上面的各类具体的技术没太大关系,页面继承主要是用来组织项目文件结构(或页面结构)的一些经验规则。假设在一个系统里,每一个页面都有相同的头和尾,还有nav,那根据上面封装和分离的思想,咱们可能会这样写

<html>
<body>
    %{ include header.html }%

    <div class="container">
        <div class="left">
            %{ include nav.html }%
        </div>
        <div class="main">
            <!-- 具体业务... -->
        </div>
    </div>
    
    %{ include footer.html }%

    <script src="require.min.js"></script>
    <script type="text/javascript">
    requirejs.config({
        // 全局配置...
    });
    </script>

    <script type="text/javascript">
    require(['jquery'], function($){
        // 具体业务...
    });
    </script>
</body>
</html>

咱们能够把这一段做为一个base的父页面,命名为base.html,每一个“具体业务”的页面都继承自它。

%{ extends 'base.html' }%

%{ block styles }%
<style type="text/css">

</style>
%{ endblock }%

%{ block content }%
<div>具体业务...</div>
%{ endblock }%

%{ block scripts }%
<script type="text/javascript"
require(['jquery'], function($){
    // 具体业务...
});
</script>
%{ endblock }%

把这个页面叫作func1.html,具体业务的页面中只会包含自身业务功能须要关心(用到)的东西,不去多管base页面的闲事。能够看到子页面中有不少block之类的锚点,会将与endblock之间的内容插入到父页面中的相应位置,因此要先在base.html中“挖好坑”。

%{ block styles }% %{ endblock }%
%{ block content }% %{ endblock }%
%{ block scripts }% %{ endblock }%

具体作法能够去看常见的模板系统,本例中参考的是Django中的模板定义。

页面组件化

页面组件化 也是和具体技术没有关系,它是顺着 页面继承 的思路,把页面或文件结构作更小粒度的拆分,页面由一个个页面组件构成。

%{ include sectionA.css }%
%{ include sectionB.css }%

<div class="row">
    %{ include sectionA.tpl }%
</div>
<div class="row">
    %{ include sectionB.tpl }%
</div>

<script type="text/javascript">
require(['sectionA', 'sectionB'], function(A, B){
    var App = Base.extend({
        _init: function(){
            var that = this;
            var mods = [A, B];
            this.modules = [];
            
            mods.forEach(function(Module){
                that.modules.push(new Module(App));
            });
        }
    });
});
</script>

上面至关于一个业务页面,它由sectionAsectionB两个页面组件组成,sectionA.tplsectionB.tpl是html模板。在应用层(即业务)页面中初始化两个js模块AB,而且把自身的App变量传递给模块(new Module(App)),能够实现子模块与应用层页面的通讯,甚至是模块之间的通讯。

这样把页面拆成粒度更细的结构,好处是页面模块能够复用,也便于管理,改动页面中的一小块时只需在所处的模块中,缩小改动的影响范围。

还看过一种思想是,把css文件也当作资源由requireJS动态加载,这样上面示例中的include xxx.css都不须要了,页面模块的css资源做为该模块的依赖,写在js模块的define的依赖中。

define(['jquery', 'sectionA.css'], function($){
    // 业务模块...
});

这样把css和js都抽象成“资源”,至关于

组件 = 模板 + 资源

一个页面总体的模板,至关于多个页面组件的拼装而成。更进一步,若是能让页面组件作到异步渲染的话(便可以由js去解析模板语法和变量,而不是交给web框架),才能真正作到页面渲染的本质:

呈现给用户的页面 = 页面模板 (包括组件的模板) + 数据

“渲染”就是将带数据变量的页面模板输出成标准的html,同步渲染是指在服务端解析模板并输出完整html到浏览器中,而异步渲染指直接在浏览器中经过javascript 根据传入的数据将模板输出成标准html。

同一模板若是既能在服务端同步渲染,又能在浏览器端异步渲染的话,咱们就不须要关心“数据”是后端框架直接输出到页面的,仍是ajax动态取来的。对模板来讲,数据就是个“接口”,而 模板 + 数据 = 渲染。这样咱们做为前端,才能把更多精力放在模板和交互上,不用管数据的传递方式。

平凡之路

前端发展了十几年,如今几乎到达顶峰的速度了,近两年推出的框架层出不穷,jquery早已不是一统江湖了。每一个人的精力都有限,不可能一个个都学过来,可是必须认可,前端是一个完整的体系(我以前整理的知识体系),有它独特和魅力之处。不只是框架,还有更多的工程化问题,框架都是为了解决某类相通的问题而生。模板和数据分离也好,“状态”和“表现”分离也好,我愈来愈体会到

“分”是为了“合”

这条平凡之路,还会“频繁”的发展和融合下去。

本文最先发表在个人我的博客上,转载请保留出处 http://jsorz.cn/blog/2015/12/twisted-way-to-awesome-fe.html

相关文章
相关标签/搜索