【Vue】Data monitoring & input binding

Hello, I am Xiao Suoqi. The carefully crafted Vue series is continuously released, covering a large number of experiences and examples. If necessary, you can collect it. This
chapter explains to you data monitoring. The previous chapters have been updated, and the following chapters will continue. Output, if you have any questions, you can leave a message or send a private message, let’s work together~

Data monitoring

The core of Vue's implementation of data monitoring is to hijack the getter & setter of the property through defineProperty(). When we obtain the data data, the bottom layer is implemented by calling the getter & setter. Additional operations can be performed when the property is read or modified. This is actually The data object is "proxyed" to form the so-called "responsive data"

To be more specific, when initializing a component, Vue will traverse all properties of the data object and use Object.defineProperty to convert them into getters/setters. This proxy allows Vue to track dependencies and notify changes when properties are accessed and modified (VM The data in is the data proxy from _data)

For example, we define a data attribute named message, and Vue will convert it into

Object.defineProperty(data, 'message', {
  get () {
    // ...进行依赖收集 
  },
  set (newValue) {
    // ...触发更新
  }
})

In this way, when reading or modifying the message, the getter and setter can be triggered to perform dependency collection and update triggering. These can be directly called data hijacking.

Data hijacking is the cornerstone of Vue's responsiveness. It can detect data changes and trigger callbacks to complete view updates, so that developers only need to focus on the data itself without manually manipulating the DOM.

Why is data hijacking mentioned here?

In one sentence: data hijacking is a means, data monitoring is the purpose (without data hijacking, data changes cannot be accurately monitored)

Let’s look down specifically. Here are the key points and combined with the following. If you don’t understand, then climb up again.

Simulate how a small responsive system works:

<div id="app">
  <!-- 视图渲染 -->
</div>

<script>
// 数据对象  
const data = {
  name: 'John',
  age: 20
};

function reactive(obj) {
// 汇总所有obj形成一个数组并进行遍历
  // 核心响应式转换代码
  Object.keys(obj).forEach(key => {
    
    let value = obj[key];

    const dep = new Set();

    Object.defineProperty(obj, key, {

      get() {
        // 收集依赖
        dep.add(updateView); 
        return value;
      },

      set(newVal) {
        // 更新值
        value = newVal;
        
        // 触发依赖更新
        dep.forEach(fn => fn());
      }

    });

  });

  return obj;
}

// 数据响应式处理
const reactiveData = reactive(data);

// 视图更新函数 
function updateView() {
  // ...渲染视图
}

// 初始化
updateView(); 

// 数据改变时触发视图更新
reactiveData.name = "Bob";
</script>

This responsive system can automatically update views

When the attribute value is obtained, the subscribers are collected; when the attribute value is set, the subscriber is notified to update the view.

Without get and set, there will be no responsive data and it will not be displayed on the page! (The parentheses in the debugging page prove that there are, and the directly defined ones without get or set will not respond to the page)

expand

Responsive conversion may not understand?

// 响应式转换
const reactiveData = reactive(data);

The reactive function is used to convert ordinary objects into responsive objects. It accepts a common object as a parameter, performs responsive processing on all properties of this object, and then returns the responsive object.

So here

const data = {
  name: 'John',
  age: 20
};

is to define a common object data

transfer:

const reactiveData = reactive(data);

The reactive function will traverse all properties of the data object and use Object.defineProperty() to convert these properties into getter/setter form

In this way, responsiveData becomes a responsive object. It has the same properties as the data object, but with the addition of responsive functions, we use responsiveData instead of data, so that the view can be automatically updated.

Simply put, the function of the reactive(data) line is to convert a normal object data into a responsive object reactiveData, and obtain a responsive data object that can implement data monitoring and view updates.

It should be noted that since the properties are directly monitored, when the hierarchical structure on the object is too deep, changes in the internal properties will not trigger a response. This requires a complete replacement of the object or manual setting of new values.

data: {
  user: {
    name: 'John',
    friend: {
      name: 'Chris' 
    }
  }
}

If friend.name is changed directly like this, Vue cannot detect it (direct modification of deep properties cannot be detected because Vue's responsiveness is achieved by hijacking the getters and setters of the properties, but it can only hijack the first-layer properties of the object~ )

this.user.friend.name = '小索奇'

Important : You must replace the entire user object, or use Vue.set | this.$set to change friend.name, so that it will be responsive data and it will take effect!

// 非响应式
this.user.name = '小索奇'
// 响应式
// Vue.set(target, key, value) | this.$set(target, key, value)
this.$set(this.user.friend, 'name', '小索奇')

The same goes for arrays. Remember that you cannot change the index value of the array (the array itself does not have get or set methods)

this.list[0] = 'A'
// 如果数组下有对象属性,可以更改
this.list[0].name = '小索奇'

You need to directly call Vue's global API to change the array, such as using Vue.set to change the index, or using the array's own push, pop, shift, unshift, splice, sort, reverse, and other APIs.

  • These methods are wrapped by Vue, so view updates can be performed

The above can be replaced with splice

this.list.splice(start, deleteCount, item1)

If the data is changed in the asynchronous function, the page will not be updated immediately. The new data will not be displayed on the page until the asynchronous function is completed.

setTimeout(() => {
  this.message = 'hello'
}, 1000)

Therefore, if you use timers, ajax, etc. to change data, the page will be refreshed later.

These are the points that need to be paid attention to in Vue data monitoring. In summary:

  • Deeply nested data needs to be replaced with Vue.set or completely.
  • The array index needs to be changed using Vue.set or the array method.
  • If the data is changed in the asynchronous function, the page update will be delayed.

expand

Vue.set(target,key,val)

// vm.$set()
Vue.set(vm._data.obj,'country','China')
// 为什么等同于下面的
Vue.set(vm.obj,'country','China')

This is because data broker-review

Vue.setMethod to add a property to a reactive object and ensure that the new property is also reactive

When Vue is initialized, it will dataproxy the object to the Vue instance, so vm.objit is equivalent to accessingvm._data.obj

That is, in the component instance VM, access vm.objis equivalent to access vm._data.obj, because it will be proxied to _datathe original data object in

proxyThis is achieved through Vue's method, roughly as follows:

function proxy(vm) {
  Object.keys(vm._data).forEach(key => {
    Object.defineProperty(vm, key, {
      get() { 
        return vm._data[key];
      }
    });
  });
}

Therefore, Vue.setthe method can accept either the original _dataobject or the proxied component instance object, and the effect is the same.

They all point to the same original data object

Notice

  • The target is not allowed to be a VM instance, nor is it allowed to be a direct root object, such as data

image-20230823005727583

form input binding

No nonsense here, let’s get straight to the point:

If: <input type="text"/>, then v-model collects value, and what the user inputs is value.

If: <input type="radio"/>, then v-model collects value values, and the value value must be configured for the label

if:<input type="checkbox"/>

  • If the value attribute of the input is not configured, then what is collected is checked (checked or unchecked, which is a Boolean value)

Configure the value attribute of input:

  1. The initial value of v-model is non-array, so what is collected is checked (checked or unchecked, which is a Boolean value)

  2. The initial value of v-model is an array, so what is collected is an array composed of values.

v-model collects value by default. You must write value to collect the set content in vue. Otherwise, the default value is collected (for example, the checkbox defaults to checked-boolean).

Common examples of binding default values ​​to form elements in Vue are as follows:

radio button binding string value

// 不设置value默认读取null
<input type="radio" v-model="picked" value="A">
<script>
data() {
  return {
    picked: 'A'
  }
}  
</script>

Checkbox binding boolean value:

// checkbox 必须设置value值,不设置的话默认为checked的状态(布尔值)
// 如果有多组值,需要把绑定的数据设置为数组,
睡觉<input type="checkbox" v-model="hobby" value="sleep">
玩<input type="checkbox" v-model="hobby" value="play">
吃<input type="checkbox" v-model="hobby" value="eat">

<script>
data() {
  hobby:[]
}
</script>

Select box binding string:

<select v-model="selected">
  <option>A</option>
  <option>B</option>
  <option>C</option>
</select>

<script>
data() {
  return {
    selected: 'A'
  }  
}  
</script>

Text input binding string:

<input v-model="message">

<script>
data() {
  return {
    message: ''
  }
}
</script>

In addition, there are more practical functions waiting for us to learn, such as:

  • Use calculated properties to process form input values ​​and perform some data preprocessing or formatting.
  • v-modelModifiers used , such as .numberand .trim, can automatically convert or modify the input when needed.

Keep up the good work in the next section~

Guess you like

Origin blog.csdn.net/m0_64880608/article/details/133430645