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  原文链接

  • 相关阅读:
    jenkins构建时报错
    linux查看系统信息
    去掉jenkins的首页警告
    zabbix_server 报警
    OSI七层模型
    linux时间格式总结
    linux系统 lsof命令详解
    SharePoint 2010 用户权限和权限级别
    Error occurred in deployment step 'Activate Features': Unable to locate the workflow's association data.
    使用 Response.Write 向页面body中输出指定html
  • 原文地址:https://www.cnblogs.com/idche/p/2041334.html
Copyright © 2011-2022 走看看