热门标签 | HotTags
当前位置:  开发笔记 > 前端 > 正文

使用proxy实现一个更优雅的vue【推荐】

Proxy用于修改某些操作的默认行为,等同于在语言层面做出修改,所以属于一种“元编程”。这篇文章主要介绍了用proxy实现一个更优雅的vue,需要的朋友可以参考下

如果你有读过Vue的源码,或者有了解过Vue的响应原理,那么你一定知道Object.defineProperty(), 那么你也应该知道,Vue 2.x里,是通过 递归 + 遍历 data 对象来实现对数据的监控的, 你可能还会知道,我们使用的时候,直接通过数组的下标给数组设置值,不能实时响应,是因为Object.defineProperty() 无法监控到数组下标的变化,而我们平常所用的数组方法 push , pop , shift , unshift , splice , sort , reverse , 其实不是真正的数组方法,而是被修改过的,这些都是因为 Object.defineProperty() 提供的能力有限,无法做到完美。

网上看过很多关于Vue的源码解读或者实现一个简易版的Vue的教程,还都是用 Object.defineProperty (大概是为兼容性考虑吧), 而 Object.defineProperty() 确实存在诸多限制, 据说Vue的3.x版本会改用Proxy,那么今天我们就先来尝尝鲜,用Proxy实现一个简单版的Vue

proxy 介绍

Proxy 用于修改某些操作的默认行为,等同于在语言层面做出修改,所以属于一种“元编程”(meta programming),即对编程语言进行编程。

Proxy 可以理解成,在目标对象之前架设一层“拦截”,外界对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写。Proxy 这个词的原意是代理,用在这里表示由它来“代理”某些操作,可以译为“代理器”。

以上引用内容来自阮一峰的es6教程的Proxy章节 原文地址请戳这里。

我们来看看如何用Proxy去定义一个监听数据的函数

定义 observe

_observe (data){
 var that = this
 // 把代理器返回的对象存到 this.$data 里面
 this.$data = new Proxy(data, {
 set(target,key,value){
 // 利用 Reflect 还原默认的赋值操作
 let res = Reflect.set(target,key,value)
 // 这行就是监控代码了
 that.handles[key].map(item => {item.update()})
 return res
 }
 })
}

当触发set的时候,就会执行 that.handles[key].map(item => {item.update()}) ,这句代码的作用就是执行 该属性名下的所有 "监视器"

那么,监视器怎么来的呢? 请继续看以下代码

定义 compile

_compile (root){
 const nodes = Array.prototype.slice.call(root.children)
 let data = this.$data
 nodes.map(node => {
  // 如果不是末尾节点,就递归
  if(node.children.length > 0) this._complie(node)
  // 处理 v-bind 指令
  if(node.hasAttribute('v-bind')) {
  let key = node.getAttribute('v-bind')
  this._pushWatcher(new Watcher(node,'innerHTML',data,key))
  }
  // 处理 v-model 指令
  if(node.hasAttribute('v-model')) {
  let key = node.getAttribute('v-model')
  this._pushWatcher(new Watcher(node,'value',data,key))
  node.addEventListener('input',() => {data[key] = node.value})
  }
  // 处理 v-click 指令
  if(node.hasAttribute('v-click')) {
  let methodName = node.getAttribute('v-click')
  let mothod = this.$methods[methodName].bind(data)
  node.addEventListener('click',mothod)
  }
 })
 }

上面这段代码,看起来很长,可是实际上,只做了意见很简单的事情, 就是 "编译" html 模板 ,把有 v-bind 、 v-model 、 v-click 都给加上对应的 通知 和 监控

1.通知就是 this._pushWatcher(...) , 相当于是安装一个监听器,这样只要 this.$data 有发生 set 操作的话,就会执行 this._pushWatcher 括号里面传的函数,来通知节点更新数据

2.监控就是 node.addEventListener(...) 监听相应的事件,然后执行对应的 watcher 或者 methods

this._pushWatcher 又做了什么呢?

_pushWatcher (watcher) {
 if (!this._binding[watcher.key]) this._binding[watcher.key] = []
 this._binding[watcher.key].push(watcher)
 }

这个就更简单了,如果 this._binding[watcher.key] 为空,就初始化,然后向里面添加一个 监听器

最后,我们再来看看,监听器是怎么实现的

定义 Watcher

class Watcher {
 constructor (node,attr,data,key) {
 this.node = node
 this.attr = attr
 this.data = data
 this.key = key
 }
 update () {
 this.node[this.attr] = this.data[this.key]
 }
 }

Watcher 是一个类,只有一个方法,就是更新数据,怎么知道要更新哪个节点,更新为什么数据呢? 在实例化(new)的时候,传的参数就是定义这些的

这样,我们就实现初步的双向绑定了,整个代码大概只有50行。其实还可以更少, 但是更少的话,就是继续阉割功能了(虽然目前实现的也是严重阉割版的), 但是我觉得实现这些,刚好可以不多不少帮我我们理解vue的本质。

最后

本文最终实现代码已经放在 github 上,想要直接看效果的同学,可以上去直接copy,运行。

如果觉得本文对您有用,请给本文的github 加个star,万分感谢

另外, github 上还有其他一些关于前端的教程和组件,有兴趣的童鞋可以看看,你们的支持就是我最大的动力。

总结

以上所述是小编给大家介绍的使用proxy实现一个更优雅的vue,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对网站的支持!


推荐阅读
  • 页面预渲染适用于主要包含静态内容的页面。对于依赖大量API调用的动态页面,建议采用SSR(服务器端渲染),如Nuxt等框架。更多优化策略可参见:https://github.com/HaoChuan9421/vue-cli3-optimization ... [详细]
  • 实现Win10与Linux服务器的SSH无密码登录
    本文介绍了如何在Windows 10环境下使用Git工具,通过配置SSH密钥对,实现与Linux服务器的无密码登录。主要步骤包括生成本地公钥、上传至服务器以及配置服务器端的信任关系。 ... [详细]
  • 汇总了2023年7月7日最新的网络安全新闻和技术更新,包括最新的漏洞披露、工具发布及安全事件。 ... [详细]
  • 本文分享了作者在使用LaTeX过程中的几点心得,涵盖了从文档编辑、代码高亮、图形绘制到3D模型展示等多个方面的内容。适合希望深入了解LaTeX高级功能的用户。 ... [详细]
  • 本文提供了一个详尽的前端开发资源列表,涵盖了从基础入门到高级应用的各个方面,包括HTML5、CSS3、JavaScript框架及库、移动开发、API接口、工具与插件等。 ... [详细]
  • 本文详细介绍如何在SSM(Spring + Spring MVC + MyBatis)框架中实现分页功能。包括分页的基本概念、数据准备、前端分页栏的设计与实现、后端分页逻辑的编写以及最终的测试步骤。 ... [详细]
  • 本文回顾了作者在求职阿里和腾讯实习生过程中,从最初的迷茫到最后成功获得Offer的心路历程。文中不仅分享了个人的面试经历,还提供了宝贵的面试准备建议和技巧。 ... [详细]
  • Python3爬虫入门:pyspider的基本使用[python爬虫入门]
    Python学习网有大量免费的Python入门教程,欢迎大家来学习。本文主要通过爬取去哪儿网的旅游攻略来给大家介绍pyspid ... [详细]
  • HTML 表格与列表标签详解
    本文详细介绍了HTML中的表格标签和列表标签的使用方法,包括如何创建表格的不同部分(如标题、头部、主体和脚部),以及如何利用这些标签进行数据展示和布局设计。 ... [详细]
  • 深入理解iOS中的链式编程:以Masonry为例
    本文通过介绍Masonry这一轻量级布局框架,探讨链式编程在iOS开发中的应用。Masonry不仅简化了Auto Layout的使用,还提高了代码的可读性和维护性。 ... [详细]
  • WebBenchmark:强大的Web API性能测试工具
    本文介绍了一款名为WebBenchmark的Web API性能测试工具,该工具不仅支持HTTP和HTTPS服务的测试,还提供了丰富的功能来帮助开发者进行高效的性能评估。 ... [详细]
  • ArcBlock 发布 ABT 节点 1.0.31 版本更新
    2020年11月9日,ArcBlock 区块链基础平台发布了 ABT 节点开发平台的1.0.31版本更新,此次更新带来了多项功能增强与性能优化。 ... [详细]
  • 基于SSM框架的在线考试系统:随机组卷功能详解
    本文深入探讨了基于SSM(Spring, Spring MVC, MyBatis)框架构建的在线考试系统中,随机组卷功能的设计与实现方法。 ... [详细]
  • binlog2sql,你该知道的数据恢复工具
    binlog2sql,你该知道的数据恢复工具 ... [详细]
  • 在Android中实现黑客帝国风格的数字雨效果
    本文将详细介绍如何在Android平台上利用自定义View实现类似《黑客帝国》中的数字雨效果。通过实例代码,我们将探讨如何设置文字颜色、大小,以及如何控制数字下落的速度和间隔。 ... [详细]
author-avatar
天佑千行
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有