发布订阅模式实现双向绑定

2018-06-13 admin

看了一些关于双向绑定的文章,现在来整理一下思路。 首先实现双向绑定有三个步骤:

  1. 需要一个方法来识别哪一个的view被绑定了相应的数据
  2. 需要监视数据和view的变化
  3. 需要将所有变化传播到绑定的对象和对应的view

为了解决第一个问题,要在对应的dom上添加相应的data-bind-<prop_name>属性,比如:

  num: <input type="number" data-bind-num>
  <div data-bind-num></div>

为了解决第二个问题,一方面监听数据改变,需要这样添加一个set()方法进行监听:

const Vue = {
  data: {
    num: 0
  },
  set(key, val) {
    this.data[key] = val
  }
}

规定通过set(key, val)的方式来修改数据。 另一边监听对应视图改变就直接监听input事件。

为了解决第三个问题就需要用发布订阅模式实现一个事件枢纽:

const eventHub = {
  callbacks: {},

  on(eventName, callback){
    this.callbacks[eventName] = this.callbacks[eventName] || [];
    this.callbacks[eventName].push(callback);
  },

  emit(eventName, ...rest){
    this.callbacks[eventName] = this.callbacks[eventName] || [];
    for(let i = 0; i < this.callbacks[eventName].length; i++){
      this.callbacks[eventName][i].call(this,...rest);
    }
  }
}

一方面将数据层的变化传播到视图,需要用特定名称与dom上的属性对应:

//触发事件就修改视图
eventHub.on('num:change', (val) => {
  $(`input[data-bind-num]`).val(val)
  $(`div[data-bind-num]`).text(val)
})
//通过set()修改data来触发对应的change事件
set(key, val) {
  this.data[key] = val
  eventHub.emit('num:change', val)
}

将视图层的变化传播到数据:

$(`input[data-bind-num]`).on('input', function() {
  let val = $(this).val() === '' ? 0 : parseInt($(this).val())
  Vue.set(key, val)
})

至此双向绑定就实现完成!但是这样一个个写事件名和属性名有点蠢,优化一下

const fn = (prop_name) => {     
  return {
    dataBind: `data-bind-${prop_name}`,//对应dom的data属性名
    eventName: `${prop_name}:change`//对应数据的change事件名称
  }      
}

//给所有data绑定change事件,给所有data对应的view绑定input事件
for(let key in Vue.data){
  //data修改改变view
  eventHub.on(fn(key).eventName, (val) => {

    $(`input[${fn(key).dataBind}]`).val(val)
    $(`div[${fn(key).dataBind}]`).text(val)

  })

  //view改变data
  $(`input[${fn(key).dataBind}]`).on('input', function() {

    let val = $(this).val() === '' ? 0 : parseInt($(this).val())
    Vue.set(key, val)

  })
}

set()改变数据效果: clipboard.png

修改input效果:

clipboard.png

文章相关代码已经同步到Github,欢迎查阅~

原文链接:https://segmentfault.com/a/1190000015278446

本站文章除注明转载外,均为本站原创或编译。欢迎任何形式的转载,但请务必注明出处。

转载请注明:文章转载自 JavaScript中文网 [https://www.javascriptcn.com]

本文地址:https://www.javascriptcn.com/read-33988.html

文章标题:发布订阅模式实现双向绑定

相关文章
vue.js实现请求数据的方法示例
vue2.0示例代码如下: var vm = new Vue({ el:&quot;#list&quot;, data:{ gridData: &quot;&quot;, }, ...
2017-03-20
IO.js 1.0.0 正式发布,支持 ES6 语言特性!
IO.js 是为 V8 引擎编写的基于事件 IO 的实现。Node.js中一群不满Joyent公司控制的信徒发起了另外一个项目io.js,即另外一个支持服务器端JavaScript的变种,称为io.js或iojs 。 IO.js 1.0.0...
2015-11-12
vuejs通过filterBy、orderBy实现搜索筛选、降序排序数据
直接贴代码了: 先上输入前的样子: &lt;style&gt; #example{margin:100px auto;width:600px;} .show{margin:10px;} #searchText{display: block...
2017-03-17
js实现鼠标左右移动,图片也跟着移动效果
效果:鼠标往左移,图片对应右移,鼠标往右移,图片就左移动。图片距离越远偏移距离越大。 思路:首先获取图片原先的距离。设置一个变化值,图片的最终距离等于原先的距离加上变化值 布局:大盒子里面是图片,大盒子position:relative;图...
2017-02-17
js实现文字向上轮播功能
话不多说,请看实现代码: &lt;!DOCTYPE html&gt; &lt;html lang=&quot;en&quot;&gt; &lt;head&gt; &lt;meta charset=&quot;UTF-8&quot;&gt;...
2017-03-10
纯css实现窗户玻璃雨滴逼真效果
这里仅是用CSS技术来演示这样的一个场景,可能并不太实用。然而这是一个探索CSS新功能的最佳机会。可以让你尝试使用一些新特性和新工具。并且逐渐将在工作中实践。在制作窗口雨滴效果,将使用到HAML和Sass。 案例效果 看到上面的效果是不是...
2017-03-29
Node.js v0.11.16 开发版发布
Node.js v0.11.16 开发版发布了,改进记录包括: openssl: Upgrade to 1.0.1l npm: Upgrade to 2.3.0 url: revert support of path for url.fo...
2015-11-12
JavaScript中文网:即将发布JavaSCript原创教程
JavaScript中文网:即将发布JavaSCript原创教程 ...
2015-11-12
canvas实现流星雨的背景效果
看到一个很棒的流星雨效果。修改一下样式就可以作为网页背景了。。! &lt;!DOCTYPE html&gt; &lt;html&gt; &lt;head&gt; &lt;meta charset=&quot;utf-8&quot...
2017-03-09
js实现的tab标签切换效果代码分享
这是一款基于js实现的tab标签切换效果,是一款无需jQuery,原生javascript制作的tab切换效果源码。点击上面的标题即可实现对应页面的切换功能,非常具有实用价值。 为大家分享的js实现的tab标签切换效果代码如下 &lt;!...
2017-03-31
回到顶部