使用es6的proxy实现vue的双向绑定

本文探讨了如何利用ES6的Proxy特性来实现Vue框架中的核心功能——双向数据绑定,详细解析了v-model、v-bind和v-click指令的实现过程,并提供了GitHub源码链接供读者深入研究。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

实现v-model v-bind v-click
github: https://github.com/myh6666/vvvue/blob/master/src/vue/vue.js

export default class Vue {
  constructor(option) {
    if (!option.el) return;
    this.$el = document.querySelector(option.el);
    this.data = option.data || {};
    this.$methods = option.methods || {};
    this.$binding = {};
    this.init()
  }

  init() {
    this.obs();
    this.complie(this.$el);
    Object.keys(this.$binding)
    .forEach(key => this.$binding[key]
    .forEach(b => b.update()));
  }

  obs() {
    let that = this;
    this.$data = new Proxy(this.data, { // 使用proxy在值发生变化时触发监听器
      set(target, key, value) {
        let val = Reflect.set(target, key, value);
        that.$binding[key].forEach(x => x.update());
        return val;
      }
    });
  }

  complie(node) {
    let nodes = Array.from(node.children);
    nodes.forEach(n => {
      if (n.children.length) this.complie(n);
      const vModel = n.getAttribute('v-model');
      if (vModel) {
        this.pushWatcher(new Watcher(n, 'value', this.$data, vModel));
        n.addEventListener('input', () => this.$data[vModel] = n.value);
      }
      const vBind = n.getAttribute('v-bind');
      if (vBind) {
        this.pushWatcher(new Watcher(n, 'innerHTML', this.$data, vBind));
      }
      const vClick = n.getAttribute('v-click');
      if (vClick) {
        n.addEventListener('click', () => this.$methods[vClick] && this.$methods[vClick].call(this.$data))
      }
    });
  }

  pushWatcher(watcher) {
    if (!this.$binding[watcher.key]) this.$binding[watcher.key] = [];
    this.$binding[watcher.key].push(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];
  }
}
<div id="app">
  <input type="text" v-model="ipt">
  <p v-bind="ipt"></p>
  <hr>
  <input type="text" v-model="ipt2">
  <p v-bind="ipt2"></p>
  <hr>
  <button v-click="switch">click</button>
</div>
import Vue from './vue/vue';
import './css/index.css';

new Vue({
  el: '#app',
  data: {
    ipt: '',
    ipt2: '234'
  },
  methods: {
    switch() {
      this.ipt = [this.ipt2, this.ipt2 = this.ipt][0]
    }
  }
});
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值