Giter VIP home page Giter VIP logo

mvvm's People

Contributors

chroota avatar dmq avatar jgchenu avatar prebra avatar scarboroughcoral avatar xsf0105 avatar zhangenming2821 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

mvvm's Issues

关于dep.target=null的问题

Watcher.js文件
get: function() {
        Dep.target = this;
        var value = this.getter.call(this.vm, this.vm);
        Dep.target = null;
        return value;
},

这里的Dep.target为什么要再次重置为null?

数据显示出现问题

demo中的例子:

<div id="mvvm-app">
    <input type="text" v-model="someStr">
    <input type="text" v-model="child.someStr">
    <!-- <p v-class="className" class="abc">
        {{someStr}}
        <span v-text="child.someStr"></span>
    </p> -->
    <p>{{getHelloWord}}</p>
    <p v-html="child.htmlStr"></p>
    <button v-on:click="clickBtn">change model</button>
    <br>
      {{getHelloWord}} {{getHelloWord}} <!-- 如果这样设置会出现错误, -->
    <br>

</div>

错误如下:

watcher.js:50 Uncaught TypeError: Cannot read property 'call' of undefined
    at Watcher.get (http://localhost:63342/mvvm/js/watcher.js:50:32)
    at Watcher (http://localhost:63342/mvvm/js/watcher.js:13:23)
    at Object.bind (http://localhost:63342/mvvm/js/compile.js:128:9)
    at Object.text (http://localhost:63342/mvvm/js/compile.js:96:14)
    at Compile.compileText (http://localhost:63342/mvvm/js/compile.js:73:21)
    at http://localhost:63342/mvvm/js/compile.js:41:20
    at Array.forEach (native)
    at Compile.compileElement (http://localhost:63342/mvvm/js/compile.js:33:35)
    at Compile.init (http://localhost:63342/mvvm/js/compile.js:26:14)
    at Compile (http://localhost:63342/mvvm/js/compile.js:7:14)

而且如果在 Element 是这样设置的
<div>Hello ,{{someStr}} </div>, 你的做法会将{{model}}填充整个节点,只留下<div>{{someStr}} </div>

call( )函数和dep问题

请问项目中的watcher.js和compile.js中的call函数是什么意思啊,没有找到call函数的实现啊。也看不懂。
还有一个问题就是为什么 child.name 是个新值,之前的 setter、dep 都已经失效?

关于 watcher 被重复订阅的问题

优化了一下,通过参数控制是否触发属性的get , 把订阅者(watcher)添加到订阅器(keyDep)中。这样会比较好理解, 另外个人觉得 在闭包中保存 dep 对新手不太好理解, 可以提取出来 用统一的发布订阅中心维护 订阅器和相应的订阅者

observer.js
 get: function () {
         KeyDep.current_watcher && keydep.addSub(KeyDep.current_watcher)
         return val;
 },

watcher.js
function Watcher(vm,attr_val,cb){ 
    this.vm = vm;
    this.attr_val = attr_val;
    this.cb = cb;
    this.value = this.get(this) //触发get 把 自己(订阅者)添加到 相应的订阅器中
}
Watcher.prototype = {
    contructor: Watcher,
    update(){
        var newValue = this.get(null); //再次触发get 不再往 相应的订阅器中 添加自己(订阅者)
        var oldValue = this.value;
        if(newValue !== oldValue){ 
            this.value = newValue;
            this.cb.call(this.vm,newValue,oldValue)
        }
    },
    get(_this){
        KeyDep.current_watcher = _this;
        var value = compileUtil._getVMVal(this.vm,this.attr_val);
        KeyDep.current_watcher = null;
        return value
    }
}

Dep.target干嘛的?

get里有 if (Dep.target) { dep.depend()} 这段,而后面又直接设置 Dep.target = null 这是为了以后用的吗?看不懂

关于多个watcher的探讨

看代码的时候发现 每一个动态node节点(携带指令、或者{{text}} 文本节点) 都会生成一个Watcher,这个Watcher 绑定了对应的节点和更新函数,当更新data中的数据时,调用dep.notify(), 触发Watcher里面的update方法,再触发绑定的更新函数,从而实现节点的更新。
但是今天看Vue2.0源码的时候发现,每个Vue实例只会绑定一个Watcher,当调用dep.notify(), Watcher做的事情是创建一个新的虚拟节点,再通过虚拟节点的diff来更新试图,和简易版的MVVM是有差别,不知道理解的对不对。

watcher和vue的watcher对应关系不一样吧

项目里的一个watcher对应一个指令,而vue源码里是一个watcher对应一个vm,依赖变化触发mountComponent,patch vdom,之所以不一样是因为vue完全使用vdom的原因吗

Watcher存在的问题

多谢提供的分享,但是Watcher存在一个问题

function Watcher(vm, exp, cb) {
    this.cb = cb;
    this.vm = vm;
    this.exp = exp;
    // 此处为了触发属性的getter,从而在dep添加自己,结合Observer更易理解
    this.value = this.get(); 
}
Watcher.prototype = {
    update: function() {
        this.run();	// 属性值变化收到通知
    },
    run: function() {
        var value = this.get(); // 取到最新值
        var oldVal = this.value;
        if (value !== oldVal) {
            this.value = value;
            this.cb.call(this.vm, value, oldVal); // 执行Compile中绑定的回调,更新视图
        }
    },
    get: function() {
        Dep.target = this;	// 将当前订阅者指向自己
        var value = this.vm[exp];	// 触发getter,添加自己到属性订阅器中
        Dep.target = null;	// 添加完毕,重置
        return value;
    }
};

如果每次触发更新,都会把Watcher加入观察者中,存在部分性能问题
可以这样

function Watcher(vm, exp, cb) {
    Dep.target = this;	// 将当前订阅者指向自己
    this.cb = cb;
    this.vm = vm;
    this.exp = exp;
    // 此处为了触发属性的getter,从而在dep添加自己,结合Observer更易理解
    this.value = this.get(); 
    Dep.target = null;	// 添加完毕,重置
}
Watcher.prototype = {
    update: function() {
        this.run();	// 属性值变化收到通知
    },
    run: function() {
        var value = this.get(); // 取到最新值
        var oldVal = this.value;
        if (value !== oldVal) {
            this.value = value;
            this.cb.call(this.vm, value, oldVal); // 执行Compile中绑定的回调,更新视图
        }
    },
    get: function() {
        var value = this.vm[exp];	// 触发getter,添加自己到属性订阅器中
        return value;
    }
};

只有每次初始化的时候才会加入观察者

watch原型中的exp写错了

image
如图应该没有找到exp,如果想在原型中拿到exp可以修改为this.exp,因为原型中的this指向watch实例,watch实例中保存过了exp
$O2B`T0MF (ZS{JOI8WU1

你好,mvvm如何作用于动态dom节点?

比如我在页面上

<script>

		new MVVM({
			el: '#todoist_app',
			data: {
				input_due_date: '00月00日'
			},
			methods: {
				
			}
		})
document.body.appendChild('<div>{{input_due_date}}</div>')

</script>

在这种情况下,没有渲染input_due_date

for循环操作属性赋值问题

data.index = 1
for(var i=0;i<10000;i++) {
vm.index = i;
}
//update=》run函数执行10000次,dom执行10000次,这个怎么解决?

想知道computed实现原理

大佬, 能解答一下,为什么 Object.defineProperty 劫持一下 computed 中的属性,就可以实现 computed 的功能呢,

computed: {
   fullname () {
       return this.firstname + this.lastname
   }
}

firstname 或 lastname 更新怎么触发的 fullname, 这一块不是很明白, 为什么 lastname 更新时 set 方法里的 dep.notify(); 这个 dep 是 跟 fullname 相关的。

大佬方便微信或其他聊天工具联系一下吗

关于constructor

发现了个不知算不算问题的小问题,就是如果直接将一个对象赋值给构造函数Functionprototype,导致Function.prototype.constructor指向Object了。
如:

function Dep() {
       .....
}

Dep.prototype = {
    ......
}

let dep = new Dep();
console.log(dep.constructor)   //Object

将原生节点拷贝到fragment的代码错误

// 将原生节点拷贝到fragment
        while (child = el.firstChild) {
            fragment.appendChild(child);
        }

这里是个无限循环,或许可以改为:

for (child = el.firstChild; child != null; child = child.nextSibling) {
      fragment.appendChild(child);
    }

关于watcher的问题

您好 , 您关于vue双向数据绑定的文章写得灰常好!!!
有小地方还不太理解,能具体讲讲compile初始化的时候watcher有什么用处以及修改input里value值时watcher的调用情况吗?
非常感谢!!!

issue: 对于嵌套的data属性,观察者的回调会同时绑定在父级,以及子级属性上

复现步骤

  1. 修改watcher中的run方法,不加任何验证判断,单纯只执行回调函数
run: function() {
    this.cb.call(this.vm);
}
  1. 打开mvvm.html文件,并打开控制台页面,执行以下代码
// 生成一个data对象
var data = { a: 'test', b: {c:'test2'} }
// 用data去实例化MVVM
var vm = new MVVM({ data })
// 生成一个观察者,去观察data.b.c的变化,并传入回调函数
new Watcher(vm, '_data.b.c', ()=>console.log('观察到数据c变化,开始执行操作'))
  1. 再输入以下代码,来验证观察者生效
vm._data.b.c = 'test3'    // 观察到数据c变化,开始执行操作
vm._data.b = {} // 观察到数据c变化,开始执行操作

给c赋值,监听到变化,这是正常的。
但是给b赋值,他也执行c的回调就不对了。原因是,在parseGetter中,我们想获得b.c,就会先执行b的get, 再执行c的get,但是他的watcher都是同一个。

有什么好的solution吗?我看vue的实现,也没看到怎么处理这个循环绑定watcher的

在observer.js中 您重写了默认的Observer.prototype 那么this.walk(data) 还能正确的找到walk这个方法吗

var Observer = function Observer (value) {
this.value = value;
this.dep = new Dep();
this.vmCount = 0;
def(value, 'ob', this);
if (Array.isArray(value)) {
var augment = hasProto
? protoAugment
: copyAugment;
augment(value, arrayMethods, arrayKeys);
this.observeArray(value);
} else {
this.walk(value);
}
};

Observer.prototype.walk = function walk (obj) {
    var keys = Object.keys(obj);
    for (var i = 0; i < keys.length; i++) {
        defineReactive(obj, keys[i]);
    }
};

这是尤大的写法
你是直接用字面量的方式进行重写
在学习你的代码的过程中发现按照你的写法显示walk 为定义

关于node2Fragment函数中的节点遍历

源代码如下:
node2Fragment: function (el) { var fragment = document.createDocumentFragment(), child; // 将原生节点拷贝到fragment while (child = el.firstChild) { fragment.appendChild(child); } }
上面代码中,el每次循环将第一个子节点赋值给child时,el不需要删除对应的子节点吗?

对表达式的支持有缺陷

例如:{{someStr+child.someStr}},这种直接报错,应该是挺常见的,computed可以解决。
如果我扩展了for指令,表达式里会用到局部的index变量,就没办法解析了。

你好,有个问题想请教一下

compile.js 里:

function Compile(el, vm) {
    this.$vm = vm;
    this.$el = this.isElementNode(el) ? el : document.querySelector(el);

    if (this.$el) {
        this.$fragment = this.node2Fragment(this.$el);
        // 上面的代码添加了一个this.$el 的文档碎片,
        this.init();
        this.$el.appendChild(this.$fragment);
        // 这里把文档碎片添加到了父元素上, 为什么父元素不会出现两个一样的子节点呀?
       // 因为 this.$el 本来就有一些子节点, 后面有添加了一份 文档碎片节点, 这里感觉很疑惑,希望你帮忙解答一下,谢谢~
    }
}

您好,我想问下关于watcher的问题

在Watcher函数中有一个判断
if (typeof expOrFn === 'function') { this.getter = expOrFn } else { this.getter = this.parseGetter(expOrFn) }
我看示例里并没有为function的类型啊,什么情况下这里会触发function的逻辑呢?非常感谢

关于watcher.js中的一行代码问题

Dep.target = watcherInstance标记订阅者是当前watcher实例,强行触发属性定义的getter方法
为什么通过获取watcher实例,会触发data里面的属性的getter方法呢?
希望有人帮我解答下呀。

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.