current position:Home>Four step simple implementation of watch in Vue

Four step simple implementation of watch in Vue

2021-08-27 02:00:24 Old fish eat shrimp

watch Use

This article is mainly about watch( It can also be called observer mode ) The implementation of the , So how to use direct look at the code

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script>
  <title>Document</title>
</head>
<body>
  <div id="app">
    <p>{{msg}}</p>
    <p>{{count}}</p>
    <button @click="add">add</button>
  </div>
  <script> let app = new Vue({ el:'#app', data:{ msg:'Hello world', count: 0 }, methods: { add(){ this.count++ } }, // watch watch:{ //  The function name must be the same as data Only when the object names in the data source are consistent can you listen  count(newVal,oldVal){ //  If the latest value is greater than 10 The modified data Medium msg attribute  if(newVal>=10) this.msg = 'Hello Watch' } } }) </script>
</body>
</html>
 Copy code 

What we need to know is :

  1. watch The function name must be data Of objects in the data source key value , That's how it works data The data source corresponds to key Value object .
  2. watch The function in takes two arguments , The first parameter is the new value assigned to , The second parameter is the initial value .
  3. understand Object.defineProperty Characteristics of

Realization

First step , Clear requirements

demand : Implement a constructor , You can put data Data sources and watch Method ,watch The function name in corresponds to data Key name in , You can hear... In the corresponding function data The data of the corresponding object in ( The data was hijacked ).

let vm = new Watcher({
  data: {
    a: 0,
    n:'hello'
  },
  watch: {
    a(newValue, oldValue) {
      console.log(newValue,oldValue);
    }
  }
})
setTimeout(() => {
  vm.a = 1
}, 2000) 
//  Print out  1 0  The requirements are realized 
 Copy code 

Understand the needs , Next, let's implement it

The second step , Build constructor

First ,Watcher The constructor has one argument , The parameter should include data and watch, So we need to judge whether we can get... In the parameters data and watch, And you need to use a function to judge data and watch Is it an object

class Watcher{
  constructor(args) {
    //  Judge whether the passed in parameters meet the conditions 
    this.$data = this.getBaseType(args.data) === "Object" ? args.data : {}
    this.$watch = this.getBaseType(args.watch) === "Object" ? args.watch : {}
  }
  getBaseType(target) {
    const typeStr = Object.prototype.toString.call(target) // "[Object String]"
    //  Return type  
    return typeStr.slice(8, -1)
  }
}

 Copy code 

The third step , monitor data The object in

If the parameter is passed in data and watch All objects , Get started The data was hijacked , send data Every object in the is monitored .

class Watcher {
  constructor(args) {
    this.$data = this.getBaseType(args.data) === "Object" ? args.data : {}
    this.$watch = this.getBaseType(args.watch) === "Object" ? args.watch : {}
    //  Traverse data Each of them key,for in Can also be , It can traverse the... Of the object key
    Object.keys(args.data).forEach(key => {
      this.setData(key)
    })
  }
  getBaseType(target) {
    const typeStr = Object.prototype.toString.call(target)
    return typeStr.slice(8, -1)
  }
  setData(_key) {
    // Object.defineProperty(this) Will point the context to the current object 
    //  there this It's equivalent to... In the constructor this.$data
    Object.defineProperty(this, _key, {
      get: function () {

      },
      // //  Corresponding value _key A change in the value of will trigger set
      set: function (val) {
        // val Corresponding key The modified value of the object 
        console.log(val)
      }
    })
  }
}
 Copy code 

Be careful :defineProperty The first parameter is not this.$data It is this, Here is a puzzling point , See the notes for the specific reasons , You might say why not this.$data As the first parameter , But obviously , since defindProperty Inside this It's already equivalent to... In the constructor this.$data, that defindProperty Inside this.$data It's equivalent to... In the constructor this.$data.$data. I hope this explanation will dispel your doubts .

Step four , Realization

perfect defineProperty The structure in , Here's the key , Look at the code here to better understand

class Watcher {
  constructor(args) {
    this.$data = this.getBaseType(args.data) === "Object" ? args.data : {}
    this.$watch = this.getBaseType(args.watch) === "Object" ? args.watch : {}
    //  Traverse data Each of them key
    Object.keys(args.data).forEach(key => {
      this.setData(key)
    })
  }
  getBaseType(target) {
    const typeStr = Object.prototype.toString.call(target) // "[Object String]"
    //  Return type  
    return typeStr.slice(8, -1)
  }
  setData(_key) {
    // Object.defineProperty(this) Will point the context to the current object 
    //  there this It's equivalent to... In the constructor this.$data
    Object.defineProperty(this, _key, {
      get: function () {
        return this.$data[_key]
      },
      set: function (val) {
        //  Corresponding value _key A change in the value of will trigger set
        //  First get the value before modification 
        const oldVal = this.$data[_key]
        this.$data[_key] = val
        //  The definition here stipulates watch The format must be the same name , And be a function 
        this.$watch[_key] && this.getBaseType(this.$watch[_key]) === "Function" && (
          //  call watch Function in and pass parameters 
          this.$watch[_key].call(this, val, oldVal)
        )
      }
    })
  }
}
//  testing 
let vm = new Watcher({
  data: {
    a: 0,
    n: 'hello'
  },
  watch: {
    a(newValue, oldValue) {
      console.log(newValue, oldValue);
    }
  }
})


setTimeout(() => {
  vm.a = 1
}, 2000) 
//1 0
 Copy code 

It's easy to implement here , Actually vue in watch Much more complicated than this , But what we learn is an idea , Understand the requirements and then replace them with ideas , This is very helpful for learning the source code .

The above is the realization watch Four steps of , I hope it will help the readers . If there are any mistakes, please comment and discuss .

copyright notice
author[Old fish eat shrimp],Please bring the original link to reprint, thank you.
https://en.qdmana.com/2021/08/20210827020021365s.html

Random recommended