zoukankan      html  css  js  c++  java
  • vue 双向绑定

    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    <title>vue双向绑定原理分析</title>
    </head>
    <style>
    body{
    margin: 0;
    padding: 0;
    }
    </style>
    <body>
    <div id="app">
    {{name}}
    </div>
    </body>
    <script>
    //vue类
    class Vue {
    constructor(options={}) {
    this.data = options.data
    this.el = options.el
    // 数据劫持
    observe(this.data)
    // 模版编译
    compile(this.el || document.body,this)
    }
    }
    class Ovserver {
    constructor(data) {
    this.data = data
    this.walk(this.data)
    }
    walk(data) {
    Object.keys(data).forEach(key=>objectDefinedDate(data,key,data[key]))
    }
    }

    observe=(data)=>{
    if (!data || typeof data !=='object') {
    return
    }
    return new Ovserver(data)
    //Object.keys(data).forEach(key=>objectDefinedDate(data,key,data[key]))
    }
    objectDefinedDate = (data,key,val)=> {

    let dep = new Dep()
    Object.defineProperty(data,key,{
    enumberable:true,
    configurable:true,
    get:()=>{
    // 添加订阅者
    if (Dep.target) {
    dep.addSub(Dep.target) // Dep.target为一个全局的对象,是Watcher的实例,拥有Watcher的一切属性和方法
    }
    return val
    },
    set:(newVal)=>{
    if (newVal === val) {
    return
    }
    val = newVal
    // 通知更新
    dep.notify()
    }
    })
    }
    class Dep {
    constructor() {
    this.subs = [] // 存放订阅者 订阅者就是观察者,即观察者实例
    }
    addSub(sub){
    this.subs.push(sub)
    }
    notify() {
    this.subs.forEach(sub=>sub.update()) // 调用Watcher的实例的更新方法
    }

    }
    // 模版编译
    compile =(node,vm)=> {

    let reg = /{{(.*)}}/g
    // 节点类型为元素
    if (node.nodeType === 1) {
    if (reg.test(node.innerHTML)){
    let name = RegExp.$1
    node.textContent = vm.data[name]
    // 添加观察者
    new Watcher(vm,name,function (newVal) {
    node.textContent = newVal
    })
    }
    }
    }
    class Watcher {
    constructor(vm,node,fn) {
    this.vm = vm // vue实例
    this.node = node // 绑定的节点
    this.fn = fn // 更新视图的回调函数
    this.value = this.get() // 触发 Object.defineProperty的get方法,然后触发添加订阅者方法
    }
    update(){
    let value = this.vm.data[this.node]
    let oldVal = this.value
    if (value !== oldVal) {
    this.value = value
    this.fn.call(this.vm,value,oldVal)
    }
    }
    get(){
    Dep.target = this // this表示当前的Watcher的实例
    let value = this.vm.data[this.node] // 触发 Object.defineProperty的get方法
    Dep.target = null
    return value

    }

    }
    let el = document.getElementById('app')
    const vue = new Vue({
    data:{
    name:'vue'
    },
    el:el
    })
    setTimeout(()=>{
    vue.data.name='vue change'
    },2000)

    </script>
    </html>
    参考https://juejin.im/post/5acd0c8a6fb9a028da7cdfaf
  • 相关阅读:
    程序员学习方法差在哪里
    解析域名
    tomcat下的公共jar包配置
    Ubuntu 16.04 修改状态栏位置
    sqlite3 C语言 API 函数
    vim配置文件
    关于 ioctl 函数
    字符设备基础了解
    Ubuntu14.04搭建Boa服务
    gcc 交叉工具链中工具使用(arm-linux-xxx)
  • 原文地址:https://www.cnblogs.com/liangshuang/p/9008148.html
Copyright © 2011-2022 走看看