Vue

手撸一个 MVVM 不是梦

在实现 VUE 中 MVVM 的系列文章的最后一篇文章中说道:我觉得可响应的数据结构作用很大,在整理了一段时间后,这是我们的最终产出:RD - Reactive Dataok 回到整理,这篇文章我们不研究 Vue 了,而是根据我们现在的研究成果来手撸一个 MVVM。简单介绍 RD先看看下我们的研究成果:一个例子let demo = new RD({ data(){ return { text: 'Hello', firstName: 'aco', lastName: 'yang' } }, watch:

  • aco Yang
    aco Yang
13 min read
Vue

VUE - MVVM - part13 - inject & 总结

看这篇之前,如果没有看过之前的文章,移步拉到文章末尾查看之前的文章。provide / inject在上一步我们实现了,父子组件,和 props 一样 provide / inject 也是基于父子组件实现的,相比于 props 它的实现还要更简单一点。我们先来看看官网上对 provide / inject 的描述。这对选项需要一起使用,以允许一个祖先组件向其所有子孙后代注入一个依赖,不论组件层次有多深,并在起上下游关系成立的时间里始终生效。首先,由官网的例子可知,provide 的值是静态的,并不会去绑定到 data 中的内容。so 静态的,简单~

  • aco Yang
    aco Yang
5 min read
Vue

VUE - MVVM - part12 - props

看这篇之前,如果没有看过之前的文章,移步拉到文章末尾查看之前的文章。前言在上一步,我们实现 extend 方法,用于扩展 Vue 类,而我们知道子组件需要通过 extend 方法来实现,我们从测试例子来入手,看看这一步我们需要实现什么:let test = new Vue({ data() { return { dataTest: { subTest: 1 } } }, components: { sub: { props: { propsStaticTest: { default: 'propsStaticTestDefault' }, propsDynamicTest: { default: 'propsDynamicTestDefault'

  • aco Yang
    aco Yang
6 min read
Vue

VUE - MVVM - part11 - Extend

看这篇之前,如果没有看过之前的文章,移步拉到文章末尾查看之前的文章。组件的扩展在 Vue 中有 extend 方法可以扩展 Vue 的实例,在上一步中,有一些实现是必须要通过子父组件才能实现,而子组件相当于一个特殊的 Vue 实例,所以这步,我们先把这个扩展实例的方法实现。我们先来看看官网对于 extend 方法的介绍:使用基础 Vue 构造器,创建一个“子类”。参数是一个包含组件选项的对象。从后面一句和具体的使用方法可以得出其实是我们创建实例时,对于传入参数的扩展。对于这个参入参数我们就叫它 options。我们接着往下想,既然这个 options

  • aco Yang
    aco Yang
4 min read
Vue

VUE - MVVM - part10 - Computed

看这篇之前,如果没有看过之前的文章,移步拉到文章末尾查看之前的文章。回顾先捋一下,之前我们实现的 Vue 类,主要有一下的功能:属性和方法的代理 proxy监听属性 watcher事件对于比与现在的 Vue 中的数据处理,我们还有一些东西没有实现:Computed、props、provied/inject。由于后两者和子父组件有关,先放一放,我们先来实现 Computed 。Computed在官方文档中有这么一句话:计算属性的结果会被缓存,除非依赖的响应式属性变化才会重新计算。这也是计算属性性能比使用方法来的好的原因所在。ok 现在我们来实现它,我们先规定一下一个计算属性的形式:{ get: Function, set: Function

  • aco Yang
    aco Yang
7 min read
Vue

VUE - MVVM - part9 - Vue

看这篇之前,如果没有看过之前的文章,可拉到文章末尾查看之前的文章。前言激动人心的时候即将来临,之前我们做的 8 步,其实都在为这一步打基础,这一步,我们来简单实现一个 Vue 对象,还没有看过之前代码的同学,请确认看过之前的文章。主要实现内容我们从测试代码入手,来看我们这个 Vue 实现了什么,然后在根据要实现的内容来编写这个 Vue 对象:let test = new Vue({ data() { return { baseTest: 'baseTest', objTest: { stringA: 'stringA', stringB:

  • aco Yang
    aco Yang
5 min read
Vue

VUE - MVVM - part8 - 优化Event

看这篇之前,如果没有看过之前的文章,可拉到文章末尾查看之前的文章。回顾在上一步我们实现了一个简易的事件管理的类,接下来我们把它给优化下,方便我们的使用。主要优化内容:方便为多个事件添加同一个函数方便为一个事件添加多个函数有针对性的取消事件的函数第一点和第二点都要修改 $on 函数,所以我们一起改:之前的代码$on(eventName, fn) { let ctx = this; if(!ctx._events[eventName]){ ctx._events[eventName] = [] } ctx._events[eventName].push(fn) return ctx } 优化之后的代码$

  • aco Yang
    aco Yang
5 min read
Vue

VUE - MVVM - part7 - Event

看这篇之前,如果没有看过之前的文章,可拉到文章末尾查看之前的文章。事件是什么?在标准浏览器中,我们经常使用:addEventListener 来为一个 DOM 添加一个事件(click、mousemove、tap等)。在我看来,一个事件是一种行为(或情况),当发生这种行为(或情况)时,我们要去做的事,比如今天下雨了,那我就得去找伞;闹钟响了,那我就得起床等等。仔细看这些情况,归结到代码中,无非就是一个行为(或情况)的名称,和一些列的动作,而在 js 中动作就是

  • aco Yang
    aco Yang
3 min read
Vue

VUE - MVVM - part6 - Array

看这篇之前,如果没有看过之前的文章,可拉到文章末尾查看之前的文章。回顾在前面的几个 step 中,我们实现对象的属性的监听,但是有关于数组的行为我们一直没有处理。我们先分析下导致数组有哪些行为:调用方法:arr.splice(1, 2, 'something1', 'someting2')直接赋值:arr[1] = 'something'解决行为一首先我们知道数组下的一些方法是会对原数组照成影响的,有以下几个:pushpopshiftunshiftsplicesortreverse这几个方法总的来说会照成几个影响:数组长度发生变化数组内元素顺序发生变化不像对象,如果对象的 key 值的顺序发生变化,是不会影响视图的变化,但数组的顺序如果发生变化,视图是要变化的。也就是说当着几个方法触发的时候,我们需要视图的更新,也就是要触发 Dep

  • aco Yang
    aco Yang
5 min read
Vue

VUE - MVVM - part5 - Observe

看这篇之前,如果没有看过之前的文章,可拉到文章末尾查看之前的文章。回顾在 step4 中,我们大致实现了一个 MVVM 的框架,由3个部分组成:defineReactive 控制了对象属性,使变为可监听结构Dep 收集管理依赖Watcher 一个抽象的依赖defineReactive 和 Dep 改造了对象下的某个属性,将目标变成了观察者模式中的目标,当目标发生变化时,会调用观察者;Watcher 就是一个具体的观察者,会注册到目标中。之前的代码实现了观察者模式,使得数据的变化得以响应,但是还是有两个需要优化的地方:如果我们想让对象的属性都得以响应,那我们必须对对象下的所有属性进行遍历,依次调用 defineReactive 这不是很方便代码都在一个文件中,不利于管理解决问题2先解决第二个问题,

  • aco Yang
    aco Yang
5 min read
Vue

VUE - MVVM - part4 - 优化Watcher

看这篇之前,如果没有看过之前的文章,可拉到文章末尾查看之前的文章。回顾首先我们思考一下截止当前,我们都做了什么通过 defineReactive 这个函数,实现了对于数据取值和设置的监听通过 Dep 类,实现了依赖的管理通过 Watcher 类,抽象出了对象下某个属性的依赖,以及属性变换的 callBack发现问题对比 Vue 的 MVVM(先把视图层的渲染抽象成一个函数),我们仅仅是实现了一些基础性的东西。还有很大的区别,比如我们的 Watcher 仅仅是抽象了对象下的单一属性,而一般视图层的渲染是涉及多个属性的,而这些属性的变化是同一个渲染函数(也就是 Vue 中编译模板字符串最终生成的函数)。通过第一点,我们可以得知,对象下的某几个属性是拥有同一个

  • aco Yang
    aco Yang
5 min read
Vue

VUE - MVVM - part3 - Watcher

看这篇之前,如果没有看过之前的文章,可拉到文章末尾查看之前的文章。前言在 step2 中,我们实现了一个管理依赖的 Dep ,但是仅仅使用这个类并不能完成我们想实现的功能,而且代码的解耦上也有点小问题。以下是在 step2 中最后说的几个问题:解耦不完全,需要传递参数没有地方可以移除依赖考虑问题第一个问题显示出来一个问题,由于我们的依赖是函数,为了函数的执行我们只能讲参数传进去,这个问题的根源在于我们的依赖是一个函数;第二个问题其实反映出当前的 dep 实例只有在 defineReactive 中使用,而没有暴露出来,只要在外部有这个实例的引用,那么我们就能顺利的调用移除依赖了(removeSub)。解决第一个问题很简单,我们把某个属性的值、对应值变化时需要执行的函数抽象成一个对象,然后把这个对象当成是依赖,推入依赖管理中。在第一个问题的基础上第二个问题就能解决了,

  • aco Yang
    aco Yang
4 min read
Vue

VUE - MVVM - part2 - Dep

看这篇之前,如果没看过 part1 先移步看 实现 VUE 中 MVVM - step1 - defineProperty。在上一篇我们大概实现了,Vue 中的依赖收集和触发,但我们仅仅是将依赖维护在一个内置数组中,这样做虽然容易理解,但毕竟不好维护,为了更容易的维护这些依赖,我们来实现一个维护依赖的类。确定功能首先我们可以先确定这个类下的属性,以及一些功能:类下属性:target                                 函数,用于存放需要添加的依赖实例下属性及方法:subs/Array                       用于存放依赖addSub/Function           用于添加依赖removeSub/Function    用于移除依赖notify/

  • aco Yang
    aco Yang
3 min read
javaScript

VUE - MVVM - part1 - defineProperty

在 VUE 中关于如何实现在网上可以搜出不少,在看了部分源码后,梳理一下内容。首先,我们需要了解一下 js 中的一个 API :Object.defineProperty(obj, prop, descriptor)一般情况下我们为一个对象添加一个属性一般都会这么写let object = {} object.test = 'test' Object.defineProperty 也能做到同样的效果let object = {}, test = 'test' Object.defineProperty(object, 'test', { configurable: true, // 描述该属性的描述符能否被改变,

  • aco Yang
    aco Yang
3 min read