• Backbone前端开发流程及规范


    定好View

    首先,根据页面切分View,切分View的规则是将重复利用的视图或者功能相近的视图归于一个View,对于Backbone,每一个model都要对应一个View。父层View负责布局,并将model发给子层View,让子层view负责渲染model数据。View并不是越多越好,要合理设计,View过多将会导致View资源管理成为负担;另外,View过于精简,可能会造成View的不必要的渲染工作。页面切分很有讲究,所以这一部分工作建议进行统一设计。

    以下图作为例子进行View设计:

    View设计如下:

    这里一共有7个View(实际还有几个潜在view,比如弹窗,上传图片页面等,原理是一样的):

    MyMainView负责全局布局,并将子View的渲染内容填充到页面中;

    TopView负责渲染页面头,包括网站图标,工具栏,关于我们等;

    ContentView负责渲染页面主要内容;

    FooterView负责渲染页面底部信息,包括©copyright等;

    ContentView 里面还可以继续划分:

    ContentTopView负责内容管理工具条,包括相册的选择,管理相册按钮;

    ContentListView负责贴图的主要页面部分,里面是一个个的ContentListItemView , ContentListView负责为每一个ContentListItemView的位置进行布局,每一个ContentListItemView只负责将本view的内容进行渲染;

    结构如下:

    -MyMainView

        -TopView

        -ContentView

             -ContentTopView

             -ContentListView

                  -ContentListItemView

        -FooterView

    为了简要说明, 以下没说明样式,请自行加入。

    MyMainView.js:

     1 define(["backbone","TopView" ,"ContentView","FooterView] ,
     2     function(Backbone , TopView , ContentView , FooterView){
     3 
     4     var myMainView = Backbone.View.extend({
     5         initialize :{
     6             this.childrenView = [];
     7         },
     8         render:{
     9             this.$el.html("<div id='topview'></div>");
    10             this.$el.append("<div id='contentview'></div>");
    11             this.$el.append("<div id='footerview'></div>");
    12 
    13             var topView = new TopView({el:"#topview"});
    14             this.childrenView.push(topview);
    15             topview.render();
    16 
    17             var contentView = new ContentView({el:"#contentview"});
    18             this.childrenView.push(contentView);
    19             contentView.render();
    20 
    21             var footerView = new FooterView({el:"#footerview"});
    22             this.childrenView.push(footerView);
    23             footerView.render();
    24 
    25 
    26         }    ,
    27 
    28 
    29     dispose : function(onlyDisposeChildren) {
    30         // 1
    31         if (!this.childrenViews
    32                 || this.childrenViews.length == 0) {
    33             if (!onlyDisposeChildren) {
    34                 this.remove();
    35             }
    36             return;
    37         }
    38         // 2
    39         _.each(this.childrenViews, function(childView) {
    40             if (childView.dispose) {
    41                 childView.dispose();
    42             } else {
    43                 childView.remove();
    44             }
    45         });
    46         // 3
    47         this.childrenViews = [];
    48         // 4
    49         if (!onlyDisposeChildren) {
    50             this.remove();
    51         }
    52     }
    53     });
    54 
    55     return myMainView;
    56 });
    MyMainView.js

    利用Backbone划分View的好处就是,上层View只负责子层view的布局,而不需要关心子view的内容,具体的渲染工作交给子view去做,这样一个页面就可以划分为一个个的view,每一层view只关心本view的渲染和负责子view的布局。这样整个的页面开发更加有层次,并且打破常规的前端网页的开发模式,对于一个页面,可以多人进行开发,大大加快了效率。 

    定义好每一个View所需的参数

    上面说到父view负责子view的布局,并且负责生成子view,所以子view需要的参数,也是由父view传给它;比如对于ContentListView:

     1 var contentListView = Backbone.View.extend({
     2 initialize :function(data){
     3     this.collection = data.collection;
     4     this.COUNTPERROW = 5;
     5 },
     6 
     7 render :function(){
     8 
     9 var self =this;
    10 this.collection.each(function(aModel,index){
    11 
    12     var row = null;
    13 
    14     // 每行设计5张图片
    15     if (index % self.COUNTPERROW == 0) {
    16 
    17         row = $("<div class='row'></div>");
    18         self .append(row);
    19     }
    20 
    21     // 父view负责布局
    22     var itemDiv= $("<div id='" + aModel.get("id)' + "></div>);
    23     row.append(itemDiv);
    24 
    25     // 子view负责渲染
    26     var itemView = new ContentListItemView({
    27         el : itemDiv,
    28         model :aModel
    29     });
    30     self.childrenView.push(itemView);
    31     itemView.render();
    32 
    33 });
    34 
    35 },
    36 });
    contentListView

    View之间独立开发

    把整个页面的View划分好,并且将每一个的View的参数定义好后,就可以分配工作了,一个人负责几个View进行独立开发。

    每一个View 要做的就三件事:

    1、从上层取得渲染归属的dom节点 (this.$el) , 和所需参数;

    2、本层负责在该dom节点中进行渲染;

    3、为下层view布局,并传递数据

    -前端开发注意事项

    dom结构

    网页是由一个个的Dom节点组成的,对于动态网页,需要动态对dom进行操作,在操作的过程尤其需要注意的是,在dom结构append到当前页面dom结构之前,该dom节点很有可能获取不到:

    var div = $("<div id='test'></div>");
    $("#test").html("ad");
    
    this.$el.append(div);

    在append到dom结构之前,就使用了id或class去查找dom接口,结果是没用的。
    以上的方法可改为:

    var div = $("<div id='test'></div>");
    $(div).html("ad");
    
    this.$el.append(div);

    jquery提供给了很多的方法:

    节点的操作

    查找节点

    var $var_1=$("htmltype");   //这句话就是获取所有htmltype节点

    如:var ul1=ul1=(“ul”);

    创建并追加节点

    var $var_1=$("<htmltype>");//这句话是创建一个节点
    
    $("htmltype2").append($var_1) ; //这句话是把节点插入所有htmltype2节点中

    例子:

    var $li_1=$("<li  title="title1">香蕉</li>");
    
         $("ul").append($li_1);

    其中插入方法有以下几种:

    append() 把B追加到A内部(所有的A元素,以下类似)
    appendTo() 把A追加到B内部
    prepend() 把B追加到A内部的内容前
    prependTo() 把A追加到B的内容前
    after() 在A后追加B
    insertAfter() 在A前追加B
    before() 在A前追加B
    insertBefore()在A后追加B 

    例子:

    $("ul").append("<li>你好</li>");//在ul内部追加li
     $("<li>你好</li>").appendTo("ul");//在ul内部追加li

    删除节点

    remove() 删除该元素
    empty() 清空节点,包括后代节点 

    例子:

    $("ul  li:eq[1]").remove(); //获取ul中的第二个li并删除
    $("ul  li").remove(“li[title="菠萝"]”);//删除ul中li元素属性title="菠萝"的元素

    复制节点

    clone();//复制本节点 

    例子:

    $("ul  li:eq[1]").clone().appenTo("ul");//复制并追加到ul中,只复制是不会显示出来的

    替换节点

    replaceWith();//将B替换所有A
    replaceAll();//将A替换所有B 

    包裹节点

    warpAll();//用B包裹A
    warpInner();//用B包裹A的内容 

    属性操作

    获取和设置属性

    var $var_1=$("p");//这句话是获取节点P
    var $p_1=$var_1.attr("title");//获取节点P的title属性
    var $p_2=$var_1.attr("title","你好");//设置节点P的title属性为"你好"

    删除属性

    $("p").removeAttr("title");//删除节点P的Title属性

    样式操作

    获取和设置样式

    var $var_class=$("p").attr("class");//获取节点P的class属性
    $("p").attr("class","class1");设置节点P的class属性为样式表类class1

    追加样式

    addClass() 添加样式到A 

    例子:

    $("p").addClass("another");添加样式表类another类到P

    移除样式

    removeClass() 移除类 

    切换样式

    toggleClass() 切换clss属性类为新的类 

    判断某个样式是否存在

    hasClass() 

    内容的操作

    html() 该方法获取html元素的内容,如:var var1=$("p").html();//获取P元素内的内容
    text() 获取或设置某个html元素的内容
    val() 获取元素的Value值
    children() 获取html元素的所有子节点
    next()  获取html元素后紧邻的同辈节点
    prev() 获取html元素前紧邻的同辈节点
    siblings() 获取html元素前后紧邻的同辈节点  

    CSS-DOM技术

    css("属性","值") 设置元素css某个属性的值,如:$("p").css("color","red");//设置P的css属性{color:red;}

    View手动销毁

    由于Backbone 没有提供view的销毁机制, 所以在不使用的时候要手动将view清理掉,否则view始终存在于内存中,更糟糕的是这个view所有的绑定和监听事件都是有效的;如果没有手动清理view的习惯,那么一个请求很有可能就会被多次发送,而你却始终找不到问题的所在,这样不仅浪费网页内存,让你的网页由于存在大量view而奇卡无比 , 而且还会造成网络资源的浪费,服务器压力的倍增。
    销毁函数可采用以下:

     1 dispose : function(onlyDisposeChildren) {
     2        // 1
     3        if (!this.childrenViews
     4                || this.childrenViews.length == 0) {
     5            if (!onlyDisposeChildren) {
     6                this.remove();
     7            }
     8            return;
     9        }
    10        // 2
    11        _.each(this.childrenViews, function(childView) {
    12            if (childView.dispose) {
    13                childView.dispose();
    14            } else {
    15                childView.remove();
    16            }
    17        });
    18        // 3
    19        this.childrenViews = [];
    20        // 4
    21        if (!onlyDisposeChildren) {
    22            this.remove();
    23        }
    24    }
    View手动销毁

    谨慎使用全局事件

    在某些情况下,为了使得事件能够在全局范围内传播,可以将事件绑定在全局变量Backbone中。

    this.listenTo(Backbone , "Event:Test" , this.HandleTest);

    使用全局的确使得我们在事件触发和监听上获得了方便,但是需要特别谨慎的是,事件在view销毁之前会一直存在,如果该view没有调用remove方法,那么这个view和这个绑定事件就会一直存在的,由于是全局的事件,所以隐患很大。在切分View的时候,可能会分出几级的View视图出来,每一层View都可能会有事件监听,所以上一点说到的View销毁至关重要。另外在监听事件之前,最好先将当前事件进行解绑,让原有监听该事件的所有方法都失效,这样控制全局事件更加有效。

    Backbone.off("Event:Test");

    谨防js命名空间和css样式冲突

    对于js命名空间冲突问题 , 可以使用requireJS来解决命名空间冲突问题,对于requireJs的使用可以参考文章:使用RequireJS实现异步加载脚本。

    至于样式冲突问题,目前还没有很好地方式可以避免,我们在开发的过程中,每个人负责一部分模块,在开发的过程中,会共用到很多样式文件,尤其对于SIP开发,所以在样式问题上冲突时常发生,这个需要开发人员商定好统一的格式进行定义, 比如可以在模块的样式前加上模块名进行限定。比如对于bootstrap的 col-md-x样式 , 可能有些开发人员需要的栅栏布局的样式需要调整,就自己在css中添加了样式:

    .col-md-12 {
        margin : 0px 0px;
    }

    这样的整个系统中所有的col-md-12样式都会照着这个样式进行,而其他的需要的就是bootstrap 默然的样式,这样的错误非常容易出现,所在大家养成模块限定的好习惯:

    #schedules .col-md-12 {
        margin : 0px 0px;
    }

    以上的样式只覆盖了 schedules 下的所有col-md-12的样式,这样可以有效解决样式冲突问题,前提是需要每个开发人员进行有效预防。

  • 相关阅读:
    jQuery 对象 等操作
    根据文件大小自动判断单位B,KB,MB,GB
    PHP 根据子ID递归获取父级ID,实现逐级分类导航效果
    JQuery 目录树jsTree插件用法
    关于循环列表中包含递归函数的问题
    PHP文件上传大小限制问题
    UEditor+七牛,实现图片直连上传
    修改Ueditor的图片上传地址
    Thinkphp3.2.3加载外部类并调用类里面的方法 获取token
    七牛云--开发笔记
  • 原文地址:https://www.cnblogs.com/wangyongsong/p/8276510.html
Copyright © 2020-2023  润新知