用原生 JS 實現雙向繫結及應用例項

OBKoro1發表於2017-05-08

寫在前面:

所謂的雙向繫結,無非是從介面的操作能實時反映到資料,資料的變更也能實時展現到介面。angular封裝了雙向繫結的方法,使雙向繫結變得十分簡單。但是在有些場景下(比如下面那個場景),不能使用angular來實現雙向繫結,需要我們使用js來實現雙向繫結。

需求場景:

寫了一個點選事件,當點選的時候在後臺賦值了,但是在頁面檢視上面沒有顯示出來,想到要使用雙向繫結來實現這個功能。因為程式碼之前是用js和jq寫的,引入angular的話,會導致之前的程式碼不能用。在網上參考了一篇文章之後做出來了這個功能

ps零碎知識點:樓主踩過坑了,引用angular寫的話,不能再使用JQ寫程式碼,樓主上次程式碼都刪的差不多了,還不能使用,最後才發現是angular和JQ衝突了,所以最好不要混著使用。

實現效果:

用原生 JS 實現雙向繫結及應用例項

實現效果

點選按鈕的時候,在後臺賦值,然後直接在頁面中顯示出來,在方框裡面輸入值,也可以實時反映到資料

ps:文末有demo連結,可以直接複製到本地試一試

應用:

比如實現一個在後臺賦值,然後介面出現一個隨機的選項,誰是臥底、狼人殺這型別的。


實現原生js過程中的三個步驟:

1.需要一個UI元素和屬性相互繫結的方法(核心)

2.監視屬性和UI元素的變化

3.需要讓所有繫結的物件和元素都能感知到變化

實現思路:

我們使用資料特性來為HTML程式碼進行繫結,所有被繫結在一起的JavaScript物件和DOM元素都會訂閱一個PubSub物件。只要JavaScript物件或者一個HTML輸入元素監聽到資料的變化時,就會觸發繫結到PubSub物件上的事件,從而其他繫結的物件和元素都會做出相應的變化。

程式碼實現部分:

html程式碼部分:

<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>複製程式碼

上面程式碼中data-bind-1="peopleName" 比較重要,其他一些亂七八糟,用來實現效果的,可以不用管。

分析一下————data-bind-1="peopleName":

格式:data-bind-可以更改,只能是數字="可以更改,相當於變數名"

ps:第一個地方只能更改數字,因為建立的是物件。這裡的數字可以不按照順序,我試了999都可以。

js程式碼雙向繫結部分

js程式碼是封裝好了的一個方法,可以按照前面幾行的方式呼叫,程式碼裡面有註釋。

實際上以下這段程式碼已經實現了雙向繫結,下面還有一個應用例項,感興趣的可以看看。文末有demo連結,可以直接複製到本地試一試。

 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;
    }複製程式碼

原生js雙向繫結應用例項:

做了一個實現像誰是臥底中,隨機抽取詞彙,類似的功能。

    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 );
    }複製程式碼

demo地址

以上就是用原生js實現雙向繫結及其應用的所有內容了,本文主要是分享給之前不知道的小夥伴們看的,或者需要此類資料的小夥伴們。

最後:如需轉載,請放上原文連結並署名。碼字不易,感謝支援!因為我經常看不懂別人寫的分享,所以個人寫文比較偏小白,寫的不好之處,歡迎指點。然後就是希望看完的朋友點個喜歡,也可以關注一下我。
ps:目前待業,座標北京,本人適應網際網路快節奏,高強度,持續學習,持續成長,認真,嚴謹,學習積極性強。中小公司大佬求帶走,郵箱:1677593011@qq.com。
掘金個人主頁

參考連結:

JavaScript 實現簡單的雙向資料繫結

Javascript實現簡單的雙向繫結

用原生js實現資料雙向繫結

相關文章