登录
首页 >  数据库 >  MySQL

实现一个简单的双向绑定

来源:SegmentFault

时间:2023-01-10 20:56:15 323浏览 收藏

怎么入门数据库编程?需要学习哪些知识点?这是新手们刚接触编程时常见的问题;下面golang学习网就来给大家整理分享一些知识点,希望能够给初学者一些帮助。本篇文章就来介绍《实现一个简单的双向绑定》,涉及到MySQL、javascript,有需要的可以收藏一下

接触Vue有一段时间了,但是对于其双向绑定的实现一直是似懂非懂,今天看到一篇写的比较好的文章 传送门1 根据原作者的指导自己也去实现了一遍简单的 demo (本文的demo均基于Object.defineProperty 实现数据劫持,利用了对Vue.js实现双向绑定的思想)

[注]本文所有图片均来自于:传送门2

通过对比数据是否有变更,来决定是否更新视图。最简单的可以通过定时轮询去检测数据的变动。当然Google不会这么low, Angular 只有在指定事件触发时进入脏值检测:

  • DOM事件,比如用户输入文本点击按钮等(ng-click)
  • XHR响应事件
  • 浏览器 Location 变更
  • Timer事件
  • 执行 $digidt() 或 $apply()

3.数据劫持
Vue.js 采用的是

//将传入 node 的子节点进行劫持,经过处理后重新挂载回目标节点
function convertNode(node,vm){
    var fragment = document.createDocumentFragment(),
        child
    while(child = node.firstChild){
        //将原生节点拷贝到 fragment,并删除之前的child节点
        fragment.appendChild(child)
    }
    return fragment
}

var dom = convertNode(document.getElementById('app'))
document.getElmentById('app').appendChild(dom)

实现Complie解析模板指令

图片描述

Complie 主要做的事情就是解析模板指令,将模板中的变量替换为数据。所以要遍历整个DOM树,进行扫描解析编译,调用对应的指令渲染函数进行渲染,并调用对应的指令更新函数进行绑定

function convertNode(node,vm){
    //...
    while(child = node.firstChild){
        Compile(child,vm)
        fragment.appendChild(child)
    }
    return fragment
}
function Compile(node,vm){
    var reg = /\{\{(.*)\}\}/
    if(node.nodeType===1){  
        var attr = node.attributes  //对所有属性进行解析
        for(var i=0;i

ViewModel 层向 View 层的数据绑定

接下来实现一个

function Xin(options){
    this.data = options.data
    Observer(this.data,this)
    var id = options.el
    var dom = convertNode(document.getElementById(id),this)
    document.getElementById(id).appendChild(dom)
}

新建一个 vm 实例来测试一下

var vm = new Xin({
    el:'app',
    data:{
        text:'Hello MVVM'
    }
})

View 层向 viewModel 层的数据绑定

实际上,在 Observer 中我们已经通过

function Dep(){
    this.subs=[]    //订阅者队列
}
Dep.prototype={
    addSub:function(sub){
        this.subs.push(sub)
    },
    notify:function(){
        this.subs.forEach(function(sub){
            sub.update()
        })
    }
}

funcion Watcher(vm,node,bindName){
    //将全局Dep.target设置为当前页面元素node
    Dep.target = this
    //完成watcher的初始化
    this.name = bindName
    this.node = node
    this.vm = vm

    this.update()    //初次绑定时进行更新
    Dep.target = null    //保证Dep.target唯一
}

Watcher.prototype = {
    get:function(){
        this.value = this.vm.data[this.name]
    },
    update:function(){
        this.get()
        this.node.nodeValue = this.value
    }
}

function Observer(obj,vm){
    //...
    Object.defineProperty(obj,prop,{
        get:function(){...},
        set:function(newVal){
            if(val == newVal) return
            val = newVal
            //data属性被修改,由dep触发view层更新
            dep.notify()
        }
    })
}

考虑这样一个问题,什么时候会有双向绑定?

function Compile(node,vm){
    //...
    if(node.nodeType ===3){    //文本节点类型
        if(reg.test(node.nodeValue)){
            var bindName = RegExp.$1.trim()
            new Watcher = (vm,node,bindName)    //为该页面元素node生产watcher
        }
    }
}

更新

本文中实现模板渲染的方法借鉴了

Vue 1.x
中实现模板渲染的方法。
Vue 2.x
模板渲染 方法借鉴React 中的 VirtualDOM,基于 VirtualDOM。 Vue 2.x 还支持服务端渲染SSR

资料参考

1.https://github.com/DMQ/mvvm#_2

今天关于《实现一个简单的双向绑定》的内容介绍就到此结束,如果有什么疑问或者建议,可以在golang学习网公众号下多多回复交流;文中若有不正之处,也希望回复留言以告知!

声明:本文转载于:SegmentFault 如有侵犯,请联系study_golang@163.com删除
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>
评论列表