Reactivity in the Wild

2020-09-03  本文已影响0人  7dbe8fdb929f

If you begin to understand what you are without trying to change it, then what you are undergoes a transformation.
-- Jiddu Krishnamurti

In this article, we want to achieve something like Vue, to perform dependency-tracking and change-notification when properties are accessed or modified, by adding getter/setters which are invisible to the user.

<template>
  <div>Clicked {{count}} times!</div>
  <button type="button" id="counter-button">Click me!</button>
</template>
<div id="app"></div>
const data = {
  message: "a",
  count: 0,
}
function render() {
  const template = document.querySelector("template")
  let content = template.innerHTML
  content = content.replace(/{{(\w+)}}/g, (all, key) => {
    return data[key]
  })
  document.getElementById("app").innerHTML = content
  document.getElementById("counter-button").addEventListener("click", () => {
    data.count++
  })
}

We will walk through all of properties and convert them to getter/setters using Object.defineProperty, this is an ES5-only and un-shimmable feature.

function defineReactive(obj, key, val) {
  const property = Object.getOwnPropertyDescriptor(obj, key)
  if (property && property.configurable === false) {
    return
  }

  // cater for pre-defined getter/setters
  const getter = property && property.get
  const setter = property && property.set

  Object.defineProperty(obj, key, {
    get: function reactiveGetter () {
      const value = getter ? getter.call(obj) : val
      return value
    },
    set: function reactiveSetter (newVal) {
      const value = getter ? getter.call(obj) : val
      if (newVal === value) {
        return
      }
      if (setter) {
        setter.call(obj, newVal)
      } else {
        val = newVal
      }
      // update dom
      render()
    },
  })
}
Object.keys(data).forEach(key => {
  defineReactive(data, key, data[key])
})
render()
上一篇下一篇

猜你喜欢

热点阅读