A small trick to refresh components in Vue, and the principle behind it

Straight to the point

As shown below, what should I do if I want to refresh the child component table-template in Vue?

For example, I changed the value of the list list, and the child component needs to be refreshed.

<template>
  <div class="wrapper">
    <table-template
      ref="table"
      :columnData="fieldDetail.column"
      :listData="fieldDetail.list"
    />
  </div>
</template>
复制代码

general method

method 1:

Define a reload method in the child component table-template to refresh the data

this.$refs['table'].reload()
复制代码

In fact, I want to reload the entire subcomponent and go through the life cycle again. Well, try the v-if directive.

Method 2:

v-if directive, element and its data bindings/components are destroyed and rebuilt on toggle

<template>
  <div class="wrapper">
    <table-template
      v-if="showFlag"
      ref="table"
      :columnData="fieldDetail.column"
      :listData="fieldDetail.list"
    />
  </div>
</template>
复制代码
this.showFlag = false;
this.$nextTick(()=>{
  this.showFlag = true;
})
复制代码

Tips

Refresh the component through the bound key value

Completely trigger component lifecycle hooks

<template>
  <div class="wrapper">
    <table-template
      :key="fieldDetail.timer"
      :columnData="fieldDetail.column"
      :listData="fieldDetail.list"
    />
  </div>
</template>
复制代码
this.fieldDetail.list = res.data
this.fieldDetail.timer = new Date().getTime();
复制代码

Tips:

The special attribute of key is mainly used in Vue's virtual DOM algorithm to identify VNodes when comparing old and new nodes.

Without keys, Vue uses an algorithm that minimizes dynamic elements and tries to modify/reuse elements of the same type in-place as much as possible .

When using key, it will rearrange the order of elements based on the change of the key , and will remove the elements whose key does not exist.

Child elements with the same parent element must have unique keys. Duplicate keys will cause rendering errors.

The most common use case is to combine v-for

<ul>
  <li v-for="item in items" :key="item.id">...</li>
</ul>
复制代码

It can also be used to force an element/component to be replaced instead of reusing it. It may be useful when you encounter the following scenarios:

1. Completely trigger the lifecycle hooks of components

2. Trigger the transition

E.g:

<transition>
  <span :key="text">{{ text }}</span>
</transition>
复制代码

When the text changes, it is always replaced rather than modified, thus triggering the transition.

The rationale behind

The principle behind it needs to start with the diff algorithm of Vue's virtual DOM.

The purpose of the virtual DOM's diff algorithm is to render each change to the browser's page as quickly as possible.

For example, a house renovation.

Two options:

1. Dismantled and rebuilt;

2. Refine the comparison, and change where you need to change.

diff means refined comparison.

virtual DOM

React和Vue都采用虚拟DOM,当数据改变时,不用整体重新渲染,局部刷新变化即可。

简短解说,两句话:

1.通过JavaScript创建虚拟的DOM树结构,呈现至页面。

2.数据改变时,引发DOM树结构改变,生成新的虚拟DOM树,和之前的DOM对比,将变化的部分应用到真实的DOM树中,渲染至页面。

那么,虚拟dom与key值的关系是怎样的呢?

虚拟DOM与key值的关系

首先,我们来看看Vue中的虚拟DOM长啥样,源码如下:

export default class VNode {
  constructor (
    tag?: string,
    data?: VNodeData,
    children?: ?Array<VNode>,
    text?: string,
    elm?: Node,
    context?: Component,
    componentOptions?: VNodeComponentOptions,
    asyncFactory?: Function
  ) {
    this.tag = tag                                /*当前节点的标签名*/
    this.data = data        /*当前节点对应的对象,包含了具体的一些数据信息,是一个VNodeData类型,可以参考VNodeData类型中的数据信息*/
    this.children = children  /*当前节点的子节点,是一个数组*/
    this.text = text     /*当前节点的文本*/
    this.elm = elm       /*当前虚拟节点对应的真实dom节点*/
    this.ns = undefined            /*当前节点的名字空间*/
    this.context = context          /*当前组件节点对应的Vue实例*/
    this.fnContext = undefined       /*函数式组件对应的Vue实例*/
    this.fnOptions = undefined
    this.fnScopeId = undefined
    this.key = data && data.key           /*节点的key属性,被当作节点的标志,用以优化*/
    this.componentOptions = componentOptions   /*组件的option选项*/
    this.componentInstance = undefined       /*当前节点对应的组件的实例*/
    this.parent = undefined           /*当前节点的父节点*/
    this.raw = false         /*简而言之就是是否为原生HTML或只是普通文本,innerHTML的时候为true,textContent的时候为false*/
    this.isStatic = false         /*静态节点标志*/
    this.isRootInsert = true      /*是否作为跟节点插入*/
    this.isComment = false             /*是否为注释节点*/
    this.isCloned = false           /*是否为克隆节点*/
    this.isOnce = false                /*是否有v-once指令*/
    this.asyncFactory = asyncFactory
    this.asyncMeta = undefined
    this.isAsyncPlaceholder = false
  }

  get child (): Component | void {
    return this.componentInstance
  }
}
复制代码
this.key = data && data.key           
/*节点的key属性,被当作节点的标志,用以优化*/
复制代码

key的作用: 辅助判断新旧vdom节点在逻辑上是不是同一个对象。

使用key来给每个节点做一个唯一标识,diff算法就可以正确的识别此节点。

key的作用主要是为了高效的更新虚拟DOM。

接着提问,为什么要使用虚拟DOM呢?

Vue采用虚拟DOM的目的是什么?

这就要从早期的前端开发说起了。

HTML是结构化的文本文档,每一个元素(element)对应HTML中的一段结构化文本,DOM(Document Object Model,文档对象模型)可以理解为这段结构化文本的抽象。

DOM储存于内存中,提供了操作和修改HTML元素的一系列API。

DOM操作是前端开发的核心,最早流行的一些前端框架、工具库大都以优秀的DOM操作闻名,比如prototype.js和jQuery.js。

与JavaScript逻辑相比,DOM操作的性能消耗非常高,在以静态内容为主的WebPage时代,少量DOM操作的性能损耗基本可以忽略不计。然而对于存在丰富动态内容的WebApp而言,大量、频繁的DOM操作逐渐成为性能瓶颈

对于JavaScript而言,虚拟DOM仅仅是一个拥有丰富属性的对象,所有针对DOM的操作被映射为对JavaScript对象的修改,性能上自然大幅优于直接对DOM的操作。

引入虚拟DOM还带来了以下好处:

1.组件高度抽象化。

2.跨平台能力:可以渲染到 DOM 以外的平台。

参考书籍

《深入实战Vue开发》殷荣桧

《前端技术架构与工程》周俊鹏

Guess you like

Origin juejin.im/post/7084058976110772238