Summary of vue3 and its differences from vue2 (part)

1. Changes in life cycle: 3 X (upper) 2 X (bottom)


It's not hard to see, vue3 0 and vue2 The life cycle function between 0 changes during destruction:

beforeDestroy --> beforeUnmount
destroyed --> unmounted


Other differences mainly lie in the language used in writing
 stay ts Used in class Class component writing can refer to vue-class-component perhaps vue-property-decorator
 Writing style and vue2.0 There is little difference between options.
If used js The code should be written in combination.

The problems caused by specific changes will be explained in the following combinatorial writing.

2. Method change of defining global variables

// Before (Vue 2.x)
Vue.prototype.$http = () => {}
Vue.prototype.url= 'http://123'
// After (Vue 3.x)
const app = createApp({})
app.config.globalProperties.$http = () => {}
app.config.globalProperties.url= 'http://123'

3. Create vue instance changes

//=======vue3.x
//Use the createApp function to instantiate vue,
//This function takes a root component option object as the first parameter
//Using the second parameter, we can pass the root prop to the application
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
createApp(App,{ userName: "blackLieo" })
.use(store)
.use(router)
.mount('#app')  
//Since the createApp method returns the application instance itself, you can chain call other methods after it. These methods can be found in the following sections.

//=======vue2.x
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
 Vue({
  router,
  store,
  render: h => h(App)
}).$mount('#app')

4. Slot usage change

//================vue2.0 basically uses slot to operate directly
//Including vue2 0 has undergone two changes, and the slot of version 2.6.0 is upgraded to v-slot
<div>
    <slot :current="toolTipData" name="test"></slot> // Named scope slot
    <slot></slot> //Default slot
</div>
//The parent component calls the component
<test>
    <template>
       <div>Default slot</div>
    </template>
    // Scope slot
    <template slot-scope="{ current }" slot="test">
       <el-form label-width="80px" :model="current">
         <el-form-item label="id: ">
           <el-link type="info">{{ current.id }}</el-link>
         </el-form-item>
         <el-form-item label="name: ">
           <el-link type="info">{{ current.name }}</el-link>
         </el-form-item>
         <el-form-item label="label: ">
           <el-link type="info">{{ current.label }}</el-link>
         </el-form-item>
         <el-form-item label="group: ">
           <el-link type="info">{{ current.group }}</el-link>
         </el-form-item>
         <el-form-item label="runtime: ">
           <el-link type="info">{{ current.runtime }}</el-link>
         </el-form-item>
         <el-form-item label="category: ">
           <el-link type="info">{{ current.category }}</el-link>
         </el-form-item>
       </el-form>
     </template>
 </test>

 
 //==============vue3.0 use slot
//In vue3 0, the slot is abbreviated as v-slot#
<div>	
   <slot name="test" :newData="slotsData"></slot>
   <slot></slot>
</div>
<HelloWorld msg="Welcome to Your Vue.js + TypeScript App">
    <template #default> // It can be written as v-slot:default # followed by the slot name
       <div>Default slot</div>
    </template>
    //Scope slot
    <template #Test = "{newdata}" > / / can be written as v-slot:test="newData"
      <p>{{ newData.aa }}</p>
      <p>{{ newData.bb }}</p>
    </template>
</HelloWorld>
//When there are multiple slots in a component, you must bring the name, otherwise the scope may be disordered

5. User defined instructions

Implement a custom instruction in Vue 2:

// Customize a global instruction ` v-focus`
Vue.directive('focus', {
  // When the bound element is inserted into the DOM
  inserted: function (el) {
    // Focus element
    el.focus()
  }
})

In Vue 2, custom instructions are created through the following optional hooks:

  • bind: called only once, when the instruction is bound to the element for the first time. One time initialization settings can be made here.
  • Inserted: called when the bound element is inserted into the parent node (only the parent node is guaranteed to exist, but it may not have been inserted into the document).
  • Update: called when the VNode of the component is updated, but it may occur before its child VNode is updated. The value of the instruction may or may not have changed. However, you can ignore unnecessary template updates by comparing the values before and after the update (see the following for detailed hook function parameters).
  • componentUpdated: the VNode and its sub VNode of the instruction component are updated after all updates.
  • unbind: called only once when the instruction is unbound from the element.

In Vue 3, the API of user-defined instructions is modified more semantically, just like the change of component life cycle, in order to better semantically. The changes are as follows:

Therefore, in Vue3, you can customize instructions in this way:

const { createApp } from "vue"

const app = createApp({})
app.directive('focus', {
    mounted(el) {
        el.focus()
    }
})

You can then use the new v-focus directive on any element in the template, as follows:

<input v-focus />

6.v-model upgrade

Great changes have taken place in v-model in Vue 3:

Change: use on custom components v-model The default names of properties and events change
 Change: v-bind of.sync Modifier in Vue 3 It was removed again, Merged into v-model in
 Add: multiple can be set for the same component at the same time v-model
 New: developers can customize v-model Modifier 

Let's take a detailed look and compare the use of v-model on components between vue2 and vue3,
For example:
The bidirectional binding of the input box of vue2 is actually equivalent to passing the value attribute and triggering the input event:

<!-- Vue 2 -->
<input v-model="searchValue"><input>

<!-- amount to -->
<input :value="searchValue" @input="searchValue=$event"><input>

At this time, v-model can only be bound to the value attribute of the component. If we want to use an individual attribute for our component, and we don't want to update the value by triggering input.

However, in the actual development, we may need to evaluate one in some scenarios prop For "two-way binding", here take the most common dialog For example: dialog It's quite suitable for two-way binding of attributes,
External control of components visible Show or hide, internal closing of components can be controlled visible Property is hidden, and visible Properties are synchronously transferred to the outside. Inside the assembly, 
When we close dialog Time, In subcomponents update:PropName Mode trigger event.

Event is

this.$emit('update:visible', false)

Then, the parent component can listen to this event and update the data:

<el-dialog :visible="isVisible" @update:visible="isVisible = $event"></el-dialog>

In the development of vue2, we will actually find a new thing sync, so we can also use v-bind Sync to simplify implementation:

<el-dialog :visible.sync="isVisible"></el-dialog>

The above describes the v-model implementation in Vue2 and the bidirectional binding of component attributes. How should it be implemented in Vue 3?
In Vue3, using v-model on custom components is equivalent to passing a modelValue attribute and triggering an update:modelValue event:

<el-dialog v-model="isVisible"></el-dialog>
<!-- amount to -->
<el-dialog :modelValue="isVisible" @update:modelValue="isVisible = $event"></el-dialog>

If you want to bind the attribute name, you only need to pass a parameter to the v-model. You can bind multiple v-models at the same time:

<el-dialog v-model:visible="isVisible" v-model:content="content"></el-dialog>

<!-- amount to -->
<el-dialog
    :visible="isVisible"
    :content="content"
    @update:visible="isVisible"
    @update:content="content"
></el-dialog>

There is no such thing as this What happened to sync? It was abandoned in Vue 3 Sync writing, unified use of v-model.

7. Use of asynchronous components

In Vue3, define asynchronous components with defineAsyncComponent, and replace the configuration option component with loader. The loader function itself no longer receives the resolve and reject parameters, and must return a Promise. The usage is as follows:

<template>
  <!-- Use of asynchronous components -->
  <AsyncPage />
</tempate>

<script>
import { defineAsyncComponent } from "vue";

export default {
  components: {
    // Asynchronous component without configuration item
    AsyncPage: defineAsyncComponent(() => import("./NextPage.vue")),

    // Asynchronous component with configuration item
    AsyncPageWithOptions: defineAsyncComponent({
   loader: () => import("./NextPage.vue"),
   delay: 200,
   timeout: 3000,
   errorComponent: () => import("./ErrorComponent.vue"),
   loadingComponent: () => import("./LoadingComponent.vue"),
 })
  },
}
</script>

8.Composition API

   use Composition API Solve the problem that when we complete the function data,methods,computed as well as mounted After repeated jumps, he will be scattered
   Logic is maintained together, and separate logic can be subdivided into separate files

If you want to know the < script setup > < / script > syntax, please move to vue3 setup syntax sugar (Part summary)

Let's first understand the API of Composition

  • setup

setup is vue3 X is a new option. It is the entry to use the Composition API in the component.

setup execution timing
Through a piece of code, we can know:

<script>
import { defineComponent, reactive } from "vue";
export default defineComponent({
  beforeCreate() {
    console.log("----beforeCreate----");
  },
  created() {
    console.log("----created----");
  },
  setup() {
    const state = reactive({ count: 0 });
    console.log("----setup----");
    return {
      state,
    };
  },
});
</script>

The following output results will appear:

The setup execution time is before beforeCreate. For details, please refer to the life cycle explanation later.

  1. setup parameters

When using setup, it accepts two parameters:

  • props: properties passed in by the component
  • context

Props accepted in setup are responsive. When new props are passed in, they will be updated in time.
Because it is responsive, ES6 deconstruction cannot be used. Deconstruction will eliminate its responsiveness.
Error code example, this code will make props no longer support responsive:

setup(props) {
    const { name } = props;
    console.log(name);
    const state = reactive({ count: 0 });
    return {
      state,
    };
  },

For the above problems, we can explain them in the following toRefs.
Now let's talk about:

  1. reactive,ref,toRefs,readonly

In vue2 In X, the definition data is in data.
But vue3 X can use reactive and ref for data definition.
So what's the difference between ref and reactive

reactive Used to handle two-way binding of objects, ref handle js Bidirectional binding of basic type or processing object.
be careful refs
 It accepts an internal value and returns a responsive and variable value ref Object. ref Object has a single that points to an internal value property.value. 


<template>
  <div>
    <p>Count:{{ num }}s</p>
    <p>Master age:{{ person.age }}</p>
    <p>Owner's name:{{ person.name }}</p>
    <p>Animal category:{{ animal.type }}</p>
    <p>Animal name:{{ animal.name }}</p>
    <p>Animal age:{{ animal.age }}</p>
  </div>
</template>
<script>
import { defineComponent, reactive, ref } from "vue";
export default defineComponent({
  setup() {
    //Declare basic types using ref
    const num = ref(0);
    //Declare objects using ref
    const person = ref({ age: 20, name: "Zhang San" });
    //Declare objects using reactive
    const animal = reactive({ type: "cat", name: "floret", age: 5 });
    setTimeout(() => {
      person.value.age = person.value.age + 1;
      person.value.name = "Li Si";
      animal.age++;
    }, 1000);
    setInterval(() => {
      num.value++;
    }, 1000);
    return {
      num,
      animal,
      person,
    };
  },
});
</script>

We bind to the page through user name,user. ageļ¼› It feels cumbersome to write in this way. Can we directly deconstruct the attributes in user for use
The answer is that you can't structure the user directly, which will eliminate its response. Here we say that props can't be deconstructed directly with ES6.
Then we want to use the deconstructed data. The solution is to use toRefs.
toRefs is used to convert a reactive object into a normal object whose attributes are all ref objects. The specific usage is as follows:

<template>
  <div>
    <p>Count:{{ num }}s</p>
    <p>Master age:{{ person.age }}</p>
    <p>Owner's name:{{ person.name }}</p>
    <p>Animal category:{{ atype }}</p>
    <p>Animal name:{{ aname }}</p>
    <p>Animal age:{{ aage }}</p>
  </div>
</template>
<script>
import { defineComponent, reactive, ref, toRefs } from "vue";
export default defineComponent({
  setup() {
    //Declare basic types using ref
    const num = ref(0);
    //Declare objects using ref
    const person = ref({ age: 20, name: "Zhang San" });
    //Declare objects using reactive
    const animal = reactive({ atype: "cat", aname: "floret", aage: 5 });
    setTimeout(() => {
      person.value.age = person.value.age + 1;
      person.value.name = "Li Si";
      animal.aage++;
    }, 1000);
    setInterval(() => {
      num.value++;
    }, 1000);
    return {
      num,
      person,
      ...toRefs(animal),
    };
  },
});
</script>

Sometimes we want to track the changes of a responsive object (ref or reactive), but we also want to prevent it from changing somewhere in the application. At this time, we need readonly.
For example, when we have a responsive object that is passed, we don't want it to be changed when it is passed. To this end, we can create a read-only proxy object based on the original object:

import { reactive, readonly } from 'vue'

const original = reactive({ count: 0 })

const copy = readonly(original)

// Modifying count through original will trigger the listener that depends on copy

original.count++

// Modifying count through copy will result in failure and warning
copy.count++ // Warning: "Set operation on key 'count' failed: target is readonly."
  • Life cycle hook

At the beginning, we saw two pictures, and we can summarize the changes

We can see that beforeCreate and created are replaced by setup (but you can still use Vue3 because Vue3 is downward compatible, that is, you actually use vue2).
Secondly, on is added to the naming of hooks; Vue3. X also added hook functions onrendertrigged and onRenderTricked for debugging
Let's briefly use a few hooks to facilitate you to learn how to use vue3 The hooks in X need to be imported from Vue:

import {
  defineComponent,
  onBeforeMount,
  onMounted,
  onBeforeUpdate,
  onUpdated,
  onBeforeUnmount,
  onUnmounted,
  onErrorCaptured,
  onRenderTracked,
  onRenderTriggered,
} from "vue";
export default defineComponent({
  //beforeCreate and created are vue2
  beforeCreate() {
    console.log("------beforeCreate-----");
  },
  created() {
    console.log("------created-----");
  },
  setup() {
    console.log("------setup-----");
    // vue3. The X life cycle is written in setup
    onBeforeMount(() => {
      console.log("------onBeforeMount-----");
    });
    onMounted(() => {
      console.log("------onMounted-----");
    });
    onBeforeUpdate(() => {
      console.log("------onBeforeUpdate-----");
    });
    onUpdated(() => {
      console.log("------onUpdated-----");
    });
    onBeforeUnmount(() => {
      console.log("------onBeforeUnmount-----");
    });
    onUnmounted(() => {
      console.log("------onUnmounted-----");
    });
    onErrorCaptured(() => {
      console.log("------onErrorCaptured-----");
    });
    onRenderTracked(() => {
      console.log("------onRenderTracked-----");
    });
    // Debug what data has changed
    onRenderTriggered((event) => {
      console.log("------onRenderTriggered-----", event);
    });
  },
});

Please refer to the official documents for details on how to use and what to do, which will not be repeated here.

  • Usage of watch and watchEffect

The watch function is used to listen to a specific data source and perform side effects in the callback function. The default is lazy, which means that callbacks are executed only when the listening source data changes.

watch(source, callback, [options])

Parameter Description:

  1. source: can support string,Object,Function,Array;
  2. Used to specify the responsive variable callback to listen on:
  3. Options of callback function executed: support deep, immediate and flush options.

In fact, the whole is the same as the original vue2 0 has certain similarity, and the basic parameters have not changed greatly.

Next, I will introduce how to use these three parameters respectively. If you don't understand the use of watch, please look down:

//Listen for reactive objects:
watch(
      () => animal.aage,
      (curAge, preAge) => {
        console.log("New value:", curAge, "Old value:", preAge);
      }
    );

//Listen for ref variables
 watch(num, (newVal, oldVal) => {
      console.log("New value:", newVal, "Old value:", oldVal);
    });
    
//Listening for multiple values
 watch([() => animal.aage, num], ([curAge, newVal], [preAge, oldVal]) => {
      console.log("New value:", curAge, "Old value:", preAge);
      console.log("New value:", newVal, "Old value:", oldVal);
    });
    
//When the listening object is complex, please use deep listening to make the third parameter of the function deep: true
watch(
      () => state.animal,
      (newType, oldType) => {
        console.log("New value:", newType, "Old value:", oldType);
      },
      { deep: true }
    );

By default, watch is inert. Under what circumstances is it not inert and the callback function can be executed immediately? In fact, the use is also very simple. Set it in the third parameter
immediate: true.

//Stop listening function
   const stopWatchRoom = watch(
      () => state.animal,
      (newType, oldType) => {
        console.log("New value:", newType, "Old value:", oldType);
      },
      { deep: true }
    );
    setTimeout(() => {
      // Stop listening
      stopWatchRoom();
    }, 3000);

There is also a monitoring function watchEffect. Let's introduce watchEffect and see how its use is different from watch. On the basis of the above code, let's write it.

watchEffect(() => {
      console.log(num);
    });

The execution result first prints the num value; Then print the num value every second.
As can be seen from the above code, there is no need to pass in dependencies like watch. watchEffect will automatically collect dependencies as long as a callback function is specified. During component initialization, it will be executed once to collect dependencies, and then when the data in the collected dependencies changes, the callback function will be executed again. Therefore, the summary and comparison are as follows:

  • watchEffect does not need to manually pass in dependencies
  • watchEffect is executed once to automatically collect dependencies
  • watchEffect cannot get the value before the change, but only the value after the change

9.Hooks

In the previous mixin used by Vue, the so-called mixin provides a very flexible way to distribute reusable functions in Vue components. A mixed object can contain any component option. When a component uses mixed objects, the options of all mixed objects will be "mixed" into the options of the component itself.
Now vue3 0 provides a new thing Vue hooks. For specific Vue hooks, please refer to the online tutorial

Why did hooks come into being?
Let's start with class component / Vue options:

  • Cross component code is difficult to reuse
  • Large components are difficult to maintain, and the granularity is not easy to control. In fine-grained division, the nesting level of components is too deep, which affects the performance
  • Class components, this is uncontrollable, logic is scattered, and it is not easy to understand
  • mixins have side effects, logic is nested with each other, data sources are unknown, and cannot be consumed with each other

When there are many problems in the development of mins and the naming of mins is not clear, and the attributes of mins are not dependent on each other, and they are easy to conflict with each other. These are very painful points in development.
hooks has the following advantages:

  • Allow hooks to pass values between them
  • Reuse state logic between components
  • Clearly point out where the logic comes from

Let's first encapsulate a hooks. If this hooks is a function to add and subtract age and get double age. Use a separate file to store bus / useage ts

import { ref, Ref, computed } from "vue";
type CountResultProps = {
  age: Ref<number>;
  doubleAge: Ref<number>;
  increase: (curAge?: number) => void;
  decrease: (curAge?: number) => void;
};
export default function useCount(initValue = 20): CountResultProps {
  const age = ref(initValue);
  const increase = (curAge?: number): void => {
    if (typeof curAge !== "undefined") {
      age.value += curAge;
    } else {
      age.value += 1;
    }
  };
  const doubleAge = computed(() => age.value * 2);
  const decrease = (curAge?: number): void => {
    if (typeof curAge !== "undefined") {
      age.value -= curAge;
    } else {
      age.value -= 1;
    }
  };
  return {
    age,
    doubleAge,
    increase,
    decrease,
  };
}

Call the hooks in the component

<template>
  <div>
    <p>Count:{{ num }}s</p>
    <p>Master age:{{ person.age }}</p>
    <p>Owner's name:{{ person.name }}</p>
    <p>Animal category:{{ atype }}</p>
    <p>Animal name:{{ aname }}</p>
    <p>Animal age:{{ aage }}</p>
    <p>count: {{ age }}</p>
    <p>Double age: {{ doubleAge }}</p>
    <div>
      <button @click="increase()">Plus 1</button>
      <button @click="decrease()">Minus one</button>
    </div>
  </div>
</template>
<script>
import {
  defineComponent,
  reactive,
  ref,
  toRefs,
  watch,
  watchEffect,
} from "vue";
import useAge from "../bus/useAge.ts";
export default defineComponent({
  setup() {
    //Declare basic types using ref
    const num = ref(0);
    //Declare objects using ref
    const person = ref({ age: 20, name: "Zhang San" });
    //Declare objects using reactive
    const animal = reactive({ atype: "cat", aname: "floret", aage: 5 });
    setTimeout(() => {
      person.value.age = person.value.age + 1;
      person.value.name = "Li Si";
      animal.aage++;
      animal.aname = "Little orange";
    }, 1000);
    setInterval(() => {
      num.value++;
    }, 1000);
    const { age, doubleAge, increase, decrease } = useAge(22);
    return {
      num,
      person,
      ...toRefs(animal),
      age,
      doubleAge,
      increase,
      decrease,
    };
  },
});
</script>

10.vue2.x and vue3 Responsive data comparison of X

In vue2 In 0, many people should have used $set.
When the data is updated, why doesn't the page change? When do we use $forceUpdate to force updates?
In vue2 In X, object is used to realize data listening defineProperty. And vue3 X uses Proxy

  1. Object.defineProperty can only hijack the properties of an object, while Proxy is a direct Proxy object

Due to object Defineproperty can only hijack object properties. It needs to traverse every property of the object. If the property value is also an object, it needs to traverse deeply recursively.
However, Proxy directly proxies objects and does not require traversal

  1. Object.defineProperty needs to Observe the new property manually

Because object Defineproperty hijacks the properties of the object, so when adding a property, you need to traverse the object again,
Use object again for its new attribute Defineproperty is hijacked. Vue2 x
When adding attributes to arrays and objects in, you need to use $set to ensure that the added attributes are also responsive,
$set also calls object Defineproperty.

  1. Proxy has many interception methods, such as apply, deleteProperty and so on. It is object Defineproperty() does not have.
  2. Proxy is an object whose return value can be operated directly, while defineProperty() must traverse all object property values before operation.
    But relatively speaking, object Defineproperty () is more compatible.

11.Teleport

Report is vue3 X new features

What is Teleport?

Teleport is like the "arbitrary door" in Dora's dream. The function of any door is to instantly transfer people to another place. With this understanding, let's take A look at why we need to use the feature of teleport. Take A small example:

For example, when we use Dialog components, we often use Dialog in actual development. At this time, Dialog is rendered into one layer of sub components, and it becomes difficult to deal with the positioning, z-index and style of nested components. However, the component wants to be located at the top of the page. At this time, it is best to mount the Dialog component on the body. We can well control the location of the Dialog through zIndex. It is not so easy when it is nested in templat. To put it simply, you want to continue using Dialog inside the component, and you want the rendered DOM structure not to be nested in the DOM inside the component.

At this time, we need Teleport to play. We can wrap Dialog with < Teleport >, and a portal is established to transfer the content rendered by Dialog to any specified place.

<template>
  <div>
    <p>Count:{{ num }}s</p>
    <p>Master age:{{ person.age }}</p>
    <p>Owner's name:{{ person.name }}</p>
    <p>Animal category:{{ atype }}</p>
    <p>Animal name:{{ aname }}</p>
    <p>Animal age:{{ aage }}</p>
    <p>count: {{ age }}</p>
    <p>multiple: {{ doubleAge }}</p>
    <div>
      <button @click="increase()">Plus 1</button>
      <button @click="decrease()">Minus one</button>
    </div>
    <el-button type="text" @click="dialogVisible = true"
      >Click Open Dialog</el-button
    >
    <teleport to="#dialogLL">
      <el-dialog title="Tips" v-model="dialogVisible" width="30%">
        <span>This is a message</span>
        <template #footer>
          <span class="dialog-footer">
            <el-button @click="dialogVisible = false">Cancel</el-button>
            <el-button type="primary" @click="dialogVisible = false"
              >determine</el-button
            >
          </span>
        </template>
      </el-dialog>
    </teleport>
  </div>
</template>
<script>
import {
  defineComponent,
  reactive,
  ref,
  toRefs,
} from "vue";
export default defineComponent({
  setup() {
    //Declare basic types using ref
    const num = ref(0);
    const dialogVisible = ref(false);
    //Declare objects using ref
    const person = ref({ age: 20, name: "Zhang San" });
    //Declare objects using reactive
    const animal = reactive({ atype: "cat", aname: "floret", aage: 5 });
    setTimeout(() => {
      person.value.age = person.value.age + 1;
      person.value.name = "Li Si";
      animal.aage++;
      animal.aname = "Little orange";
    }, 1000);
    setInterval(() => {
      num.value++;
    }, 1000);

    return {
      dialogVisible,
      num,
      person,
      ...toRefs(animal),
    };
  },
});
</script>

We can clearly see that there is a to attribute on the report. This attribute tells the current node to transfer to the specified location. Where should the location be transmitted?
The answer is in index HTML above
The following is our home page. You will see that there is a div ID named dialogLL, and the node is attached here by teleport

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <link rel="icon" href="/favicon.ico" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Vite App</title>
  </head>
  <body>
    <div id="app"></div>
    <div id="dialogLL"></div>
    <script type="module" src="/src/main.js"></script>
  </body>
</html>

As shown in the figure:

12.Suspense

Suspend is vue3 What's the use of the new feature in X? We passed vue2 Some scenes in X to understand its role. Vue2. You should often encounter such scenarios in X:

<template>
  <div>
    <div v-if="!loading">...</div>
    <div v-if="loading">Loading...</div>
  </div>
</template>

It is an asynchronous process when the front and back ends interact to obtain data. Generally, we will provide an animation in loading, and cooperate with v-if to control the data display when the data is returned.
It provides two template slot s. At the beginning, it will render the content in a fallback state, and will not render the formal content in the default state until a certain condition is reached
Asynchronous rendering is easier when the suspend component is used for presentation.
The specific use can be represented by the following examples:
This is the component that needs to wait for the value to complete:

<template>
  <h1>{{ getData.result }}</h1>
</template>
<script>
export default {
  name: "NewModel",
  async setup() {
    let getData = await new Promise((resolve) => {
      setTimeout(() => {
        return resolve({ result: "OK" });
      }, 3000);
    });
    return {
      getData,
    };
  },
};
</script>

Call it in other components. When the component waiting for value taking is completed, the loading state will change to OK state

<template>
  <div>
    <suspense>
      <template #default>
        <NewSuspense></NewSuspense>
      </template>
      <template #fallback>
        <h1>Loadding...</h1>
      </template>
    </suspense>
  </div>
</template>
<script>
import NewSuspense from "./suspens.vue";
export default {
  name: "AppMain",
  components: {
    NewSuspense,
  },
};
</script>
<style>
</style>

The effect is shown in the figure:

13. Fragment

In vue2 In X, only one root node is allowed in the template:

<template>
    <div>
        <span></span>
        <span></span>
    </div>
</template>

But in vue3 In X, you can write multiple root nodes directly:

<template>
    <span></span>
    <span></span>
</template>

14. Tree shaking change

Vue3.x reconstructs the global and internal APIs on the basis of considering tree shaking. The result is that the current global API needs to be referenced by name through the reference mode of ES Module, such as vue2 In X, we use nextTick:

// vue2.x
import Vue from "vue"

Vue.nextTick(()=>{
    ...
})
perhaps 
this.nextTick(()=>{
    ...
})

Vue.nextTick() is a global API directly exposed from Vue objects. In fact, $nextTick() is just Vue nextTick() is a simple wrapper that binds this of the callback function of the latter to the current instance for convenience.
In vue3 X is rewritten as follows:

import { nextTick } from "vue"

nextTick(() =>{
    ...
})

Affected API s

This is a big change, because the previous global API can only be imported by name. This change will affect the following APIs:

  1. Vue.nextTick
  2. Vue.observable (replace with Vue.reactive)
  3. Vue.version
  4. Vue.compile (available for full version only)
  5. Vue.set (available only in 2.x compatible versions)
  6. Vue.delete (same as above)

16. Remove the filter

In 2 In version x, filter is used

<template>
  <p>{{ time | currencyUSD }}</p>
</template>

<script>
  export default {
    data(){
        return{
            time:new Date()        
        }    
    }
    filters: {
      currencyUSD(value) {
        return time
      }
    }
  }
</script>

In vue3 In X, the use of filter1 has been canceled. The official suggestion is to replace them with method calls or calculated attributes
Global filter
If the filter is globally registered in the application, it may not be so convenient to replace it with calculated properties or method calls in each component.
Instead, you can use global properties to make it available to all components:

// main.js
const app = createApp(App)

app.config.globalProperties.$filters = {
  currencyUSD(value) {
    return '$' + value
  }
}

Then, you can modify all templates through this $filters object, as follows:

<template>
  <h1>Bank Account Balance</h1>
  <p>{{ $filters.currencyUSD(accountBalance) }}</p>
</template>

Note that this approach applies only to methods, not to calculated properties, which make sense only when defined in the context of a single component.

17. Remove $children

In 2 X, developers can use this$ Children access the direct sub components of the current instance
In 3 In X, $children property has been removed and is no longer supported. If you need to access sub component instances, $refs is recommended.

18. Remove $listeners

In Vue 2, you can use this$ Attribs accesses the attribute passed to the component and through this$ The event passed to listeners by the component. Combined with inheritattributes: false, developers can apply these attributes and listeners to elements other than the root element:

<template>
  <label>
    <input type="text" v-bind="$attrs" v-on="$listeners" />
  </label>
</template>
<script>
  export default {
    inheritAttrs: false
  }
</script>
stay vue3 In, removed $listeners And merge it into $attrs in
<template>
  <label>
    <input type="text" v-bind="$attrs" />
  </label>
</template>
<script>
export default {
  inheritAttrs: false
}
</script>

The $attribute - on listener will now receive an attribute as follows:

{
  name: 'Component value transfer',
  onClose: () => console.log('close Event triggered')
}

19. Priority adjustment of V-IF and v-for

In version 2.x, when v-if and v-for are used simultaneously on an element, v-for takes precedence.
In version 3.x, v-if always takes precedence over v-for.

20. Remove the modifier native

By default, event listeners passed to components with v-on can only pass through this$ Emit trigger. To add a native DOM listener to the root element of a child component, you can use Native modifier:

<my-component
  v-on:close="close"
  v-on:click.native="handleNativeClickEvent"
/>

The new emits option in vue3 allows subcomponents to define events that will actually be triggered.
Therefore, Vue will now add all event listeners in the subcomponent that are not defined as triggered by the component as native event listeners to the root element of the subcomponent (unless inheritattrs: false is set in the options of the subcomponent).

<my-component
  v-on:close="close"
  v-on:click="handleNativeClickEvent"
/>


//MyComponent.vue
<script>
  export default {
    emits: ['close']
  }
</script>

Keywords: Javascript Front-end TypeScript Vue.js html

Added by jaymc on Wed, 09 Mar 2022 04:56:54 +0200