美文网首页Web前端之路让前端飞
亲自实现一个简单的类 Vue 框架 —— 简单的数据驱动视图

亲自实现一个简单的类 Vue 框架 —— 简单的数据驱动视图

作者: ac68882199a1 | 来源:发表于2017-05-14 23:23 被阅读352次

看过上一节的小伙伴肯定已经知道了这次的主要内容——实现数据更新驱动页面视图

数据驱动视图的基本构想

我们已经实现了数据的gettersetter,也实现了页面上数据的替换,那么怎样将两者结合呢?最简单的方法当然就是在数据的setter方法中实现视图的更新了

那么怎样结合呢?我们先来回想一下上一节的代码:在 实例l初始化时,就已经将数据替换到页面上了——但这是一次性的

通过 “指令” 将数据的变更与视图的更新关联

那如何使其摆脱一次性呢?我们可以在遍历到每一个需要填入数据的文本节点时,将这个节点的相关信息(填入的数据名、节点信息等)保存起来,是这些信息成为一个数组,当数据改变时,获取到数组中对应的信息,即可更新视图

如果给上面的这些信息起一个名字,我们可以叫它为“指令”,因为每一个信息都会对应页面上一个节点的更新,它负责给页面发送一条“指令”从而执行更新的任务

当然,“指令”中不仅仅可以存在文本数据的更新,我们知道 Vue 中的指令还有v-if v-bind 等等,这些都可以通过扩展“指令”的属性和方法来实现,但我们这一节仅讨论文本数据的更新,其他的如果有机会以后在讨论

设计一个“指令”类

在这里,我们将“指令”单独拎出来,作为一个独立的类存在,当然你也可以将它放在Lue

/** 声明一个 Directive 类
  * @param {String} name 指令的种类 当存在多种指令时用来区分是哪种指令 本文中的 name=text
  * @param {Object} el 与这条指令相关联的节点 node类型
  * @param {Object} vm 指令存在的 Lue 实例 可以方便地获取到该实例上的属性
  * @param {String} expression 表达式 本文中值属性名
  */
function Directive(name, el, vm, expression) {
    this.name = name
    this.el = el
    this.vm = vm
    this.expression = expression
    // 节点的值的属性名 此处写死 当需要扩展指令时可以通过传参确定值
    this.attr = 'nodeValue'

    this.update()
}

// 为 Directive 添加一个更新视图的方法 当指令类型增多时可以添加更多的方法
Directive.prototype.update = function() {
    this.el[this.attr] = this.vm.$data[this.expression]
}

为 Lue 添加指令的存储数组

首先为 Lue添加属性this.$directives=[]
重写_compileText方法

Lue.prototype._compileText: function (node) {
    var patt = /{{\w+}}/g
    var nodeValue = node.nodeValue
    var expressions = nodeValue.match(patt)
    if (!expressions) return
    
    var self = this
    expressions.forEach(function (expression) {
          // 这里删除了上一节中的创建节点后替换的代码 可以直接通过 nodeValue 来更新节点的值
        var property = expression.replace(/[{}]/g, '')
        // 向 $directives 添加一条指令
        self.$directives.push(new Directive('text', node, self, property))
        
    })
}

重写 setter 将数据的更新与指令关联

Lue.prototype._bindData = function (obj, key, val) {
    var directive, self = this
    // 遍历 $directives 中的所有指令,找出与当前数据的 key 相同的指令
    self.$directives.forEach(function (dir) {
            if (dir.expression === key) {
                directive = dir
            }
        })
    Object.defineProperty(obj, key, {
        enumerable: true, // 是否可枚举
        configurable: true, // 是否可删除
        get: function () {
            return val
        },
        set: function (newVal) {
            if (val !== newVal) {
                val = newVal
                  // 当新旧值不同且不为对象时 执行指令的页面更新
                  if (typeof newVal !== 'object') directive.update()
            }
            if (typeof newVal === 'object') self._each(newVal, newVal)
         }
    })
}

由于先执行节点指令的解析 所以需要在初始化完成后调用一下指令的 update() 方法,否则初始化时页面将不会显示数据

Lue框架还有很多不够完善的地方,但我们的目标不是重现实现一个 Vue,而是去学习它的长处,去了解怎样实现一个相似的功能,从而提升自己的能力。感谢所有支持我的小伙伴,感谢你们的赞、评论和关注!让我们一起进步

最后无耻的做个广告:

查看完整代码,可以关注公众号,回复 Lue 即可!

扫码关注前端周记公众号

相关文章

  • 亲自实现一个简单的类 Vue 框架 —— 简单的数据驱动视图

    看过上一节的小伙伴肯定已经知道了这次的主要内容——实现数据更新驱动页面视图 数据驱动视图的基本构想 我们已经实现了...

  • Vue.js是什么

    Vue.js不是一个框架——它只聚焦视图层,是一个构建数据驱动的Web界面库。Vue.js通过简单的API提供高效...

  • Vue基础和指令

    Vue框架介绍 Vue是一个构建数据驱动的web界面的渐进式框架。目标是通过尽可能简单的API实现响应式的数据绑定...

  • vue简介

    1.vue特性 vue框架有两个特性 数据驱动视图 双向数据绑定 1.1 数据驱动视图 在使用vue的页面中,vu...

  • vue面试题整理

    vue是什么? vue是构建数据驱动的web界面的渐进式框架。Vue.js 的目标是通过尽可能简单的 API 实现...

  • 2018最新web前端VUE面试题

    vue是什么? vue是构建数据驱动的web界面的渐进式框架。Vue.js 的目标是通过尽可能简单的 API 实现...

  • vue的非父子组件通信

    一 、前言 vue是一个视图层框架,不是一个数据层框架。对于非父子组件之间的通信,仅仅使用简单的父子组件间接实现,...

  • Vue快速上手

    Vue是一个前端框架,简单来说,其目标是通过尽可能简单的 API 实现响应的数据绑定和组合的视图组件。 国际惯例H...

  • 数据驱动视图简单实现

    前端框架日新月异,Angularjs的MVVM模式风靡全球,React的MV模式也被大家捧得火热。我不知道有多少人...

  • 史上最强vue总结,万字长文——面试开发全靠它了

    一、vue框架篇 vue的优点轻量级框架:只关注视图层,是一个构建数据的视图集合,大小只有几十kb;简单易学:国人...

网友评论

    本文标题:亲自实现一个简单的类 Vue 框架 —— 简单的数据驱动视图

    本文链接:https://www.haomeiwen.com/subject/uvjcxxtx.html