Skip to content

Vue Learning Notes

This blog records some notes when I am learning vue. The frontend framework performs quite different from the backend system which contains a lot of implicit conventions , and I try to highlight these differences to understand the vue better for frontend development.

Template Accesses Data from Component Instance

Template defines the page view, and it could access the data from the corresponding instance. It provides a convenient way for page rendering as you needn't replace the placeholder inside the page template after you getting data. The way of data accessing is called text interpolation. The important part to understand is the source of data, instead of template syntax which you should refer to the docs.

After knowing the template could access the data from component instance, we need to consider how to define data inside the component. Here, vue provides Composition API or Options API for you to define components, ref. They're equivalent semantically and good at solving different problems. For now, I won't continue further to differentiate them.

With Options API, we define a component's logic using an object of options such as data, methods, and mounted.

<template>
  <h1>{{ msg }}</h1>
</template>
<script>
export default {
  data() {
    return {
      msg: "helloworld"
    };
  }
}
</script>

With Composition API, we define a component's logic using imported API functions.

<template>
  <h1>{{ msg }} </h1>
</template>

<script>
import { ref } from 'vue';

export default {
  setup() {
    const msg = ref("helloworld");
    return {
      msg
    };
  },
}
</script>

Initialization Order of Template and Component Instance

Knowing the template could access the data from component instance is not enough, and we need dive deeper to learn about the interaction between template and instance via renderer.

Vue provides a lifecycle diagram for reference purpose. For us, we focus on the renderer which starts to stages from the start to created, as the below image shows:

vue-lifecycle_until_created.png

The renderer does the following jobs:

  1. initializes component instance: data and hooks(such as created)
  2. compiles template: the template is converted to a render function
  3. render: create a virtual dom by the compiled function from template
  4. mounting: using virtual dom as blueprint to create a real dom

If we map the jobs to the stages shown above, the job1 contains stage setup(Composition API) and Init Options API, job2 and job3 doesn't show in the diagram because it aims to highlight the lifecycle hooks. Then the job4 maps to the mounted hook in the diagram.

In conclusion, vue manages a lot of work and asks developer to provide the template and instance only. It doesn't ask the developers to call a function from framework to provide his business logic. This schema confused me quite a lot because I always want to figure out the call stack relationship.

Two-Way Data Binding

The v-model allows to bind variable with inputs, for example the radio button. Here we define two ratio buttons for the same variable toggle to make only one of them could be selected.

Two Radio Toggles
<template>
  <h1>{{ toggle }} </h1>
  <label>Radio Button1</label>
  <input type="radio"
    value="button 1"
    id ="b1"
    v-model="toggle"
  >
  <p></p>
  <label>Radio Button2</label>
  <input type="radio"
    id ="b2"
    value="button 2"
    v-model="toggle"
  >
</template>

<script>
import { ref } from 'vue';

export default {
  data() {
    return {
      toggle : "Please select a button"
    }
  }
}
</script>

This was a bit confusing when I first learned it, so I listed all points that confused me before.

Flow of Interactivity for v-model

When the button is clicked, there're the following steps:

  1. A dom event(a signal from browser) is created
  2. Vue gets the dom event and update the respective data
  3. Vue re-renders the virtual DOM and patches the DOM

(TODO): I'm not sure when the dom event is created, the view will be updated first before vue patches the dom. I don't delve it much because it's too deep knowledge.

Why Buttons Are Exclusive

When I bind one variable toggle with two radio buttons, I found vue allows me to select one button only, and will un-select the old button if I select another button.

At that time, I already know the select will update the data but have no idea that why the button is un-selected. This un-selection is actually done by the vue when it renders the dom.

First of all, v-model finds the corresponding radio button to render via value. For example, if the value of toggle equals button 2, this radio button will be selected, otherwise it won't. As a result, this enables you to set the default selection among multiple radio buttons.

  <input type="radio"
    value="button 2"
    v-model="toggle"
  >

Because vue uses v-model bound variable to decide whether a radio button is selected, after the data is updated and vue starts to re-render the dom, it will find the input with the same value to render the selected status.

If you two buttons share the same name with each other, they will be marked as selected together even though you only click one of them.

Browser Rendering Process

It's nice to learn the procedures of browser rendering, which starts from the source code, so you can understand the frontend framework better. I listed the good passages that help me to understand the procedures. The second blog introduced in more details and covered the compiling steps.

For a frontend newbie, the general procedures are: 1.parsing -> 2. render#style -> 3. render#layout -> 4. render#paint. In parsing stage, different parsers are applied to their respective contents, such as html, css and javascript. They will be parsed into the AST presentations for the further steps to process. The output of html is so-called DOM(document object model) and the css is CSSOM(CSS Object Model).

Parsing

HTML parsing usually mixes with javascript execution in a blocking mode, if the scripts are inline(not decorated by async or defer). For example, one stackoverflow question asked why the html parsing includes the javascript parsing.

<!-- synchronized script and will block html parsing until it's executed-->
<script src="foo.js"></script>

<!-- asynchronized script-->
<script src="foo.js" async></script>

It implies when an inline javascript is executed but the HTML parser doesn't complete to construct DOM, the javascript may fail to manipulate DOM. By this mean, the inline js usually initialization global variables, binding events or logging/debugging.

The async script will be executed when it's ready, so it usually doesn't interact with DOM because it don't know whether DOM is fully constructed. By contrast, defer scripts are always executed after the HTML is fully parsed so we can manipulate DOM safely.

CSSOM is parsed parallel with DOM parsing in the same process. As a result, when the defer script is executed after the DOM is constructed, CSSOM isn't guaranteed itself is ready to manipulate. By the way, the javascript runtime is maintained per page, the DOM, CSSOM and javascript runtime is 1-1 mapping.

Note the defer execution actual is a part of rendering, but to understand the interaction between DOM and scripts, and the CSSOM, I explained here in parsing topic.

Render#Style

After DOM is completed to parse, the browser starts to execute defer scripts which is available to manipulate DOM. Then, it tries to create a render tree(computed style tree) by merging the DOM and CSSOM together, while the non-visual DOM elements won't be inserted in the render tree.

Layout and Painting in Render Stage

After getting the render tree, the browser starts to process the render tree by calculating all geolocations of all elements of render tree for the future painting. The first turn of calculation is called layout while when the render tree is changed and the calculation is triggered, it's called reflow.

Then, the GUI APIs are used to draw the UIs for the rendering tree. During re-flow, the browser optimizes a lot so only the changed parts of render tree will be re-flow and re-painted.