Js原生 双向数据绑定

时间:2021-04-18 22:47:04
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Demo</title>
    <script>
        function DataBinder( object_id ) {
            // Create a simple PubSub object
            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 compatibility
                                prop_name = target.getAttribute( data_attr );

                        if ( prop_name && prop_name !== "" ) {
                            clearTimeout(timeIn);
                            timeIn = setTimeout(function(){
                                pubSub.publish( message, prop_name, target.value );
                            },50);

                        }
                    };

            // Listen to change events and proxy to PubSub
            if ( document.addEventListener ) {
                document.addEventListener( "input", changeHandler, false );
            } else {
                // IE8 uses attachEvent instead of addEventListener
                document.attachEvent( "oninput", changeHandler );
            }

            // PubSub propagates changes to all bound elements
            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 = {
                // ...
                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;
        }


    </script>
</head>
<body>
<input type="text" data-bind-1="name" />
<span data-bind-1="name"></span>
<script>
    var DBind = new DBind( 1 );
    DBind.set( "name", "黄奇" );
</script>
</body>
</html>