zoukankan      html  css  js  c++  java
  • 用纯JS实现双向数据绑定

    双向数据绑定指的就是,绑定对象属性的改变到用户界面的变化的能力,反之亦然。

    换种说法,如果我们有一个user对象和一个name属性,一旦我们赋了一个新值给user.name,在UI上就会显示新的姓名了。同样地,如果UI包含了一个输入用户姓名的输入框,输入一个新值就应该会使user对象的name属性做出相应的改变。

    1. 我们需要一个UI元素和属性相互绑定的方法
    2. 我们需要监视属性和UI元素的变化
    3. 我们需要让所有绑定的对象和元素都能感知到变化

    还是有很多方法能够实现上面的想法,有一个简单有效的方法就是使用PubSub模式。

    这个思路很简单:我们使用数据特性来为HTML代码(UI元素)进行绑定,所有被绑定在一起的JavaScript对象和DOM元素都会订阅一个PubSub对象。只要JavaScript对象或者一个HTML输入元素监听到数据的变化时,就会触发绑定到PubSub对象上的事件,从而其他绑定的对象和元素都会做出相应的变化。

    <h1>原生js双向绑定及其应用</h1>
    <div class="js-2-1section2 col-sm-10 col-xs-10">
    <div><input type="text" data-bind-1="peopleName" id="text1"/>
    <!--data-bind-1="peopleName" 原生js双向绑定的格式-->
    </div>
    <div><input type="text" data-bind-2="killName" id="text2" />
    <button class="btn btn-primary" onclick="randomGroup()">随机词组</button>
    </div>
    <p data-bind-1="peopleName"></p>
    <p data-bind-2="killName"></p>
    </div>
    var DBind1 = new DBind( 1 );
    var DBind2 = new DBind( 2 );//前面是变量,括号里面的是html那里填的数字
    DBind1.set( "peopleName", '第一个' );
    DBind2.set( "killName", '第二个' );//第一个是刚才html格式那里的变量名,第二个方框是赋值
     
    function DataBinder( object_id ) {
    // 创建一个简单的pubSub对象
    var pubSub = {
    callbacks: {},
     
    on: function( msg, callback ) {
    this.callbacks[ msg ] = this.callbacks[ msg ] || [];
    this.callbacks[ msg ].push( callback );
    },
    publish: function( msg ) {
    this.callbacks[ msg ] = this.callbacks[ msg ] || [];
    for ( var i = 0, len = this.callbacks[ msg ].length; i < len; i++ ) {
    this.callbacks[ msg ][ i ].apply( this, arguments );
    }
    }
    },
    data_attr = "data-bind-" + object_id,
    message = object_id + ":input",
    timeIn;
     
    changeHandler = function( evt ) {
    var target = evt.target || evt.srcElement, // IE8兼容
    prop_name = target.getAttribute( data_attr );
     
    if ( prop_name && prop_name !== "" ) {
    clearTimeout(timeIn);
    timeIn = setTimeout(function(){
    pubSub.publish( message, prop_name, target.value );
    },50);
     
    }
    };
     
    // 监听事件变化,并代理到pubSub
    if ( document.addEventListener ) {
    document.addEventListener( "input", changeHandler, false );
    } else {
    // IE8使用attachEvent而不是addEventListenter
    document.attachEvent( "oninput", changeHandler );
    }
     
    // pubSub将变化传播到所有绑定元素
    pubSub.on( message, function( evt, prop_name, new_val ) {
    var elements = document.querySelectorAll("[" + data_attr + "=" + prop_name + "]"),
    tag_name;
     
    for ( var i = 0, len = elements.length; i < len; i++ ) {
    tag_name = elements[ i ].tagName.toLowerCase();
     
    if ( tag_name === "input" || tag_name === "textarea" || tag_name === "select" ) {
    elements[ i ].value = new_val;
    } else {
    elements[ i ].innerHTML = new_val;
    }
    }
    });
     
    return pubSub;
    }
    function DBind( uid ) {
    var binder = new DataBinder( uid ),
     
    user = {
    // 属性设置器使用数据绑定器pubSub来发布
    attributes: {},
    set: function( attr_name, val ) {
    this.attributes[ attr_name ] = val;
    // Use the `publish` method
    binder.publish( uid + ":input", attr_name, val, this );
    },
    get: function( attr_name ) {
    return this.attributes[ attr_name ];
    },
     
    _binder: binder
    };
     
    // Subscribe to the PubSub
    binder.on( uid + ":input", function( evt, attr_name, new_val, initiator ) {
    if ( initiator !== user ) {
    user.set( attr_name, new_val );
    }
    });
     
    return user;
    }

    双向绑定应用实例

    function randomGroup() {
    var oGroup=[];//存放所有词汇的词组、
    for(var i=0;i<20;i++){
    oGroup[i]={};//设置数组中的每个元素都是一个对象
    }
    //一个一个定义他们状态的字符串,然后在下面赋值
    oGroup[0].people="降龙十八掌";
    oGroup[0].killer="九阴白骨爪";
    oGroup[1].people="快乐大本营";
    oGroup[1].killer="天天向上";
    oGroup[2].people="零花钱";
    oGroup[2].killer="生活费";
    oGroup[3].people="爷爷";
    oGroup[3].killer="姥爷";
    oGroup[4].people="同学";
    oGroup[4].killer="同桌";
    oGroup[5].people="小沈阳";
    oGroup[5].killer="宋小宝";
    oGroup[6].people="成吉思汗";
    oGroup[6].killer="努尔哈赤";
    oGroup[7].people="谢娜张杰";
    oGroup[7].killer="邓超孙俪";
    oGroup[8].people="新年";
    oGroup[8].killer="跨年";
    oGroup[9].people="保安";
    oGroup[9].killer="保镖";
    oGroup[10].people="眉毛";
    oGroup[10].killer="胡须";
    oGroup[11].people="端午节";
    oGroup[11].killer="中秋节";
    oGroup[12].people="摩托车";
    oGroup[12].killer="电动车";
    oGroup[13].people="高跟鞋";
    oGroup[13].killer="增高鞋";
    oGroup[14].people="汉堡包";
    oGroup[14].killer="肉夹馍";
    oGroup[15].people="牛奶";
    oGroup[15].killer="豆浆";
    oGroup[16].people="唇膏";
    oGroup[16].killer="口红";
    oGroup[17].people="公交";
    oGroup[17].killer="地铁";
    oGroup[18].people="结婚";
    oGroup[18].killer="订婚";
    oGroup[19].people="面包";
    oGroup[19].killer="蛋糕";
    //词汇出自——————谁是卧底的词汇大全
    var oGroupNum=Math.floor(Math.random()*20);//抽取一个随机数,随机数范围跟上面数组的长度是一致的
    oPeople=oGroup[oGroupNum].people;
    okiller=oGroup[oGroupNum].killer;//随机数的对应下标的状态字符串赋值给这个变量。
    console.log(oPeople,okiller);
    DBind1.set( "peopleName", oPeople );//将上面的状态字符串赋值给input框,。这一步将在界面中直接显示出来
    DBind2.set( "killName", okiller );
    }
  • 相关阅读:
    HashMap源码分析
    静态代理和装饰模式的区别
    自动内存管理
    ReentrantReadWriteLock
    ReentranLock
    对象的内存布局
    对象的创建
    [P2495][SDOI2011]消耗战——虚树
    [HDU2966]In case of failure——KD树
    [Gym-101158J]Coverthe Polygon with Your Disk——梯度下降,模拟退火
  • 原文地址:https://www.cnblogs.com/sarah-wen/p/10837860.html
Copyright © 2011-2022 走看看