用原生 JS 实现双向绑定及应用实例

简介: 写在前面:所谓的双向绑定,无非是从界面的操作能实时反映到数据,数据的变更也能实时展现到界面。angular封装了双向绑定的方法,使双向绑定变得十分简单。但是在有些场景下(比如下面那个场景),不能使用angular来实现双向绑定,需要我们使用js来实现双向绑定。需求场景:写了一个点击事件,当点击的时候在后台赋值了,但是在页面视图上面没有显示出来,想到要使用双向绑定来实现这个功能。因为代码之前是用js和jq写的,引入angular的话,会导致之前的代码不能用。在网上参考了一篇文章之后做出来了这个功能

写在前面:

所谓的双向绑定,无非是从界面的操作能实时反映到数据,数据的变更也能实时展现到界面。angular封装了双向绑定的方法,使双向绑定变得十分简单。但是在有些场景下(比如下面那个场景),不能使用angular来实现双向绑定,需要我们使用js来实现双向绑定。


需求场景:

写了一个点击事件,当点击的时候在后台赋值了,但是在页面视图上面没有显示出来,想到要使用双向绑定来实现这个功能。因为代码之前是用js和jq写的,引入angular的话,会导致之前的代码不能用。在网上参考了一篇文章之后做出来了这个功能

ps零碎知识点:楼主踩过坑了,引用angular写的话,不能再使用JQ写代码,楼主上次代码都删的差不多了,还不能使用,最后才发现是angular和JQ冲突了,所以最好不要混着使用。

实现效果:

image.png

实现效果

点击按钮的时候,在后台赋值,然后直接在页面中显示出来,在方框里面输入值,也可以实时反映到数据

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地址


目录
相关文章
|
7天前
|
JavaScript API 数据库
深入理解Node.js事件循环及其在后端开发中的应用
【9月更文挑战第3天】本文将深入浅出地介绍Node.js的事件循环机制,探讨其非阻塞I/O模型和如何在后端开发中利用这一特性来处理高并发请求。通过实际的代码示例,我们将看到如何有效地使用异步操作来优化应用性能。文章旨在为读者揭示Node.js在后端开发中的核心优势和应用场景,帮助开发者更好地理解和运用事件循环来构建高性能的后端服务。
|
9天前
|
缓存 JavaScript 前端开发
JavaScript模块化开发:ES6模块与CommonJs的对比与应用
JavaScript模块化开发:ES6模块与CommonJs的对比与应用
15 2
|
13天前
|
JavaScript 前端开发 API
揭秘现代前端开发秘籍:Vue.js与ES6如何联手打造惊艳应用?
【8月更文挑战第30天】本文介绍如何从零开始使用Vue.js与ES6创建现代前端应用。首先,通过简要介绍Vue.js和ES6的新特性,使读者了解这两者为何能有效提升开发效率。接着,指导读者使用Vue CLI初始化项目,并展示如何运用ES6语法编写Vue组件。最后,通过运行项目验证组件功能,为后续开发打下基础。适用于希望快速入门Vue.js与ES6的前端开发者。
28 3
|
11天前
|
机器学习/深度学习 存储 前端开发
实战揭秘:如何借助TensorFlow.js的强大力量,轻松将高效能的机器学习模型无缝集成到Web浏览器中,从而打造智能化的前端应用并优化用户体验
【8月更文挑战第31天】将机器学习模型集成到Web应用中,可让用户在浏览器内体验智能化功能。TensorFlow.js作为在客户端浏览器中运行的库,提供了强大支持。本文通过问答形式详细介绍如何使用TensorFlow.js将机器学习模型带入Web浏览器,并通过具体示例代码展示最佳实践。首先,需在HTML文件中引入TensorFlow.js库;接着,可通过加载预训练模型如MobileNet实现图像分类;然后,编写代码处理图像识别并显示结果;此外,还介绍了如何训练自定义模型及优化模型性能的方法,包括模型量化、剪枝和压缩等。
22 1
|
11天前
|
JavaScript 前端开发 开发者
|
11天前
|
C# 开发者 测试技术
震惊!Xamarin 竟能如此构建跨平台应用程序,代码共享、界面设计与性能优化全攻略大揭秘!
【8月更文挑战第31天】在移动应用开发领域,跨平台工具日益受到青睐。Xamarin 是一款强大的工具,支持使用 C# 开发适用于 iOS、Android 和 Windows 的应用。通过安装 Visual Studio 或 Visual Studio for Mac,并创建 Xamarin 项目,开发者可以利用丰富的功能和工具进行开发。Xamarin 的主要优势在于代码共享,能够显著提高开发效率。
26 0
|
11天前
|
前端开发 Java UED
JSF 面向组件开发究竟藏着何种奥秘?带你探寻可复用 UI 组件设计的神秘之路
【8月更文挑战第31天】在现代软件开发中,高效与可维护性至关重要。JavaServer Faces(JSF)框架通过其面向组件的开发模式,提供了构建复杂用户界面的强大工具,特别适用于设计可复用的 UI 组件。通过合理设计组件的功能与外观,可以显著提高开发效率并降低维护成本。本文以一个具体的 `MessageComponent` 示例展示了如何创建可复用的 JSF 组件,并介绍了如何在 JSF 页面中使用这些组件。结合其他技术如 PrimeFaces 和 Bootstrap,可以进一步丰富组件库,提升用户体验。
21 0
|
11天前
|
JavaScript 开发者
深入理解Node.js事件循环及其在后端开发中的应用
【8月更文挑战第31天】 本文将带你走进Node.js的事件循环机制,通过浅显易懂的语言和实例代码,揭示其背后的工作原理。我们将一起探索如何高效利用事件循环进行异步编程,提升后端应用的性能和响应速度。无论你是Node.js新手还是有一定经验的开发者,这篇文章都能给你带来新的启发和思考。
|
11天前
|
Devops 持续交付 测试技术
JSF遇上DevOps:开发流程将迎巨变?一篇文章带你领略高效协同的魅力!
【8月更文挑战第31天】本文探讨了如何在JavaServer Faces(JSF)开发中融入DevOps文化,通过持续集成与部署、自动化测试、监控与日志记录及反馈机制,提升软件交付速度与质量。文中详细介绍了使用Jenkins进行自动化部署、JUnit与Selenium进行自动化测试、ELK Stack进行日志监控的具体方法,并强调了持续改进的重要性。
22 0
|
11天前
|
API UED 开发者
如何在Uno Platform中轻松实现流畅动画效果——从基础到优化,全方位打造用户友好的动态交互体验!
【8月更文挑战第31天】在开发跨平台应用时,确保用户界面流畅且具吸引力至关重要。Uno Platform 作为多端统一的开发框架,不仅支持跨系统应用开发,还能通过优化实现流畅动画,增强用户体验。本文探讨了Uno Platform中实现流畅动画的多个方面,包括动画基础、性能优化、实践技巧及问题排查,帮助开发者掌握具体优化策略,提升应用质量与用户满意度。通过合理利用故事板、减少布局复杂性、使用硬件加速等技术,结合异步方法与预设缓存技巧,开发者能够创建美观且流畅的动画效果。
34 0