zoukankan      html  css  js  c++  java
  • 【分享】浅谈 JavaScript 在多交互站点中的工作方式

    先看事例,根据下面的HTML和后端接口来更新界面。

    HTML:

    <ul>
    	<li>用户名:<span id="userName"></span></li>
    	<li>昵称:<span id="loveName"></span></li>
    	<li>生日:<span id="birthday"></span></li>
    </ul>
    <input type="button" value="更新" id="update" rel="123456789" />
    

    后端接口:http://www.xxx.com/getuserinfo.php

    参数:uid Number

    返回数据:{"userName":"lujun", "loveName":"鲁军", "birthday":"1989/02/02"};

    要求:当用户点击update 按钮,根据rel值从服务器取得用户的信息,并且显示到HTML对应的位置

    不用思考,你的代码应该是这样的(利用jQuery):

    $("#update").click(function(){
    var uid = $(this).attr("rel");
    $.get(
    "http://www.xxx.com/getuserinfo.php",{"uid":uid},
    function(data){
    //var data = {"userName":"lujun", "loveName":"lujun", "birthday":"1989/02/02"};// 模拟数据
    $("#userName").text(data.userName);
    $(
    "#loveName").text(data.loveName);
    $(
    "#birthday").text(data.birthday);
    }
    );
    });

    对于简单的页面更新这并没有任何问题,也是最佳方案。简单,易懂

    今天讨论复杂的WEB站点,页面上可能有10-20个这样的按钮。还采用这样的更新方式,你会发现

    1:对于后端API调用的代码无法复用

    2:页面代码javascript非常乱(逻辑更复杂了,返回数据正确定判断和提示,HTML模板解析,多级请求嵌套)

    3:多人维护同一站点,看不懂别人的代码(因为都采用了自己的方式)

    使用观察者模式

    我们把获取数据的ajax看作一个数据 “发布者”,把更新UI界面的看作一个 “数据订阅者”

    于是有了下面的基本代码

    ;(function(){
    // 发布者
    var Model = function(key){
    this.key = key;
    this.observers;
    }
    Model.prototype
    = {
    // 添加订阅者
    addObserver:function(a){
    if(!this.observers){this.observers = []};
    this.observers.push(a);
    },
    // 获取数据的通道
    loadData:function(){
    throw "undefined";
    },
    // 通知订阅者数据发生改变
    changeValue:function(data){
    var observers = this.observers;
    for(var i = 0; i<observers.length; i++){
    observers[i].update(data,
    this);
    }
    }
    }

    // 订阅者
    var Observer = function(model){
    this.models;
    }
    Observer.prototype
    = {
    update:
    function(){
    // 用来维护用户界面
    throw "undefined";
    },
    // 添加发布者
    addModel:function(a){
    if(!this.models){ this.models = []};
    this.models.push(a);
    },
    // 主动拉去信息
    pull:function(){
    var models = this.models;
    for(var i=0; i< models.length; i++){
    models[i].loadData.apply(models[i], arguments);
    }
    }
    }

    window.PAGE
    = {
    "Model":Model,
    "Observer":Observer,
    };

    })();

    使用 PAGE 这个命名空间保存这两个“类”。

    发布者

    Model {

        addObserver:添加订阅者

        loadData:获取服务器数据,需要重载的方法

        changeValue:通知界面更新

    订阅者

    Observer{

      update:更新界面,需要重载的方法

      addModel:添加发布者(主要用来实现拉去信息)

      pull:拉去信息(拉去信息一般都很少用)

    有了上面的代码,那么要完成上面的题目应该这样做

    // Model 关注数据传输
    function getUserInfoModel(){}
    getUserInfoModel.prototype
    = new PAGE.Model();
    getUserInfoModel.prototype.loadData
    = function(uid){
    var _this = this;
    $.get(
    "http://www.xxx.com/getuserinfo.php",{"uid":uid},
    function(data){
    //var data = {"userName":"lujun", "loveName":"鲁军", "birthday":"1989/02/02"};//模拟数据
    _this.changeValue(data);
    }
    );
    };


    // Observer 关注用户界面
    function updateUserInfo(){}
    updateUserInfo.prototype
    = new PAGE.Observer();
    updateUserInfo.prototype.update
    = function(data){
    $(
    "#userName").text(data.userName);
    $(
    "#loveName").text(data.loveName);
    $(
    "#birthday").text(data.birthday);
    }



    // 关注UI交互
    $("#update").click(function(){

    var uid = $(this).attr("rel");

    var model = new getUserInfoModel();
    var observer = new updateUserInfo();

    model.addObserver(observer);
    model.loadData(uid);

    });

    获取数据和页面更新 分离了,如果再有其他地方需要获取用户信息,可以直接 new getUserInfoModel().loadData(),不必要在写一次javascript请求(这很重要)。

    如果团队约定每次更新数据,都按照这样的方式来工作。无论你看谁的代码,逻辑始终那么清晰。他调用了一个API,更新了页面上的这些内容。

    工作也会变得傻瓜式,首先 new 出 发布者和观察者,添加关注并覆盖获取数据,和更新界面的方法。大功告成

    不难发现,上面的代码任然存在一些问题。比如他增加了 2 个全局变量 getUserInfoModel ,updateUserInfo。这样绝对不行,不可能每一个API的调用都添加两个全局变量。

    使用单体模式

    单体(singleton)模式是javascript中最基本最有用的模式之一,它可能比任何模式都常用。《javascript设计模式》 P65。(如果不太了解可以查阅下资料)

    单体可以用来划分命名空间,减少全局变量,使代码更容易阅读和维护。

    回到上面的代码,getUserInfoModel ,updateUserInfo 继承了 Model , Observer。他们的主要工作 覆盖 loadData,update。并且提供一个全局可访问的名字。

    使用单体可以这样做:

    //依然使用PAGE 这个命名空间。

    PAGE.loadDatas
    = {};// 存放所有数据更新的方法
    PAGE.updates = {};// 存放所有页面的更新方法

    PAGE.loadDatas.getUserInfo
    = function(uid){
    var _this = this;
    $.get(
    "http://www.xxx.com/getuserinfo.php",{"uid":uid},
    function(data){
    var data = {"userName":"lujun", "loveName":"鲁军", "birthday":"1989/02/02"};//模拟数据
    _this.changeValue(data);
    }
    );
    }

    PAGE.updates.updateUserInfo
    = function(data){
    $(
    "#userName").text(data.userName);
    $(
    "#loveName").text(data.loveName);
    $(
    "#birthday").text(data.birthday);
    }

    $("#update").click(function(){

    var uid = $(this).attr("rel");

    var model = new PAGE.Model();// 直接继承 Model
    var observer = new PAGE.Observer();// 直接继承 Observer

    model.loadData
    = PAGE.loadDatas.getUserInfo; // 重载(覆盖) loadData
    observer.update = PAGE.updates.updateUserInfo; // 重载(覆盖) update

    model.addObserver(observer);
    model.loadData(uid);

    });

    使用直接继承(原来是继承2次),loadData,update方法被覆盖,同时提供了全局可访问的名字。代码组织很好。出色完成。

    当你写过几次以后,会发现 click 方法体内的模式几乎万年不变,你可以尝试门面模式进行一个包装。

    最后:

    对于多人协作,必须要找一个大家都认同的编码方式(相信你也认同这一点)。

    对于javascript 使用单体 比 (function(){/**你的N多代码**/})()。好很多

    观察者应该有事件注册和派发(fire)的能力。这可以解决多级AJAX请求嵌套的问题

    上面讨论的方式,并不适合简单的站点(少交互)。

    本文来之博客园:idche  原文链接

  • 相关阅读:
    poj 2187 Beauty Contest(旋转卡壳)
    poj 2540 Hotter Colder(极角计算半平面交)
    poj 1279 Art Gallery(利用极角计算半平面交)
    poj 3384 Feng Shui(半平面交的联机算法)
    poj 1151 Atlantis(矩形面积并)
    zoj 1659 Mobile Phone Coverage(矩形面积并)
    uva 10213 How Many Pieces of Land (欧拉公式计算多面体)
    uva 190 Circle Through Three Points(三点求外心)
    zoj 1280 Intersecting Lines(两直线交点)
    poj 1041 John's trip(欧拉回路)
  • 原文地址:https://www.cnblogs.com/idche/p/2041334.html
Copyright © 2011-2022 走看看