1. Detailed description of the difference between Vue3 and Vue2
1. Life cycle
For the life cycle, the overall change is not much, but most life cycle hooks have + "on" in the name, which is similar in function. However, one thing to note is that Vue3 needs to be introduced first when using lifecycle hooks in the Composition API (Composition API, expanded below), while Vue2 can directly call lifecycle hooks in the Options API (Options API), as shown below.
// vue3 <script setup> import { onMounted } from 'vue'; // Lifecycle hooks need to be introduced before useonMounted(() => { // ... }); // Different logic can be split into multiple onMounted, and still executed in order, and will not be overwritten.onMounted(() => { // ... }); </script> // vue2 <script> export default { mounted() { // Directly call the life cycle hook // ... }, } </script>
Commonly used life cycle pairs are shown in the table below.
vue2 | vue3 |
---|---|
beforeCreate | |
created | |
beforeMount | onBeforeMount |
mounted | onMounted |
beforeUpdate | onBeforeUpdate |
updated | onUpdated |
beforeDestroy | onBeforeUnmount |
destroyed | onUnmounted |
Tips: setup runs around beforeCreate and created life cycle hooks, so it does not need to be explicitly defined.
2. Multiple nodes
Friends who are familiar with Vue2 should be clear that if multiple root nodes are used in the template, an error will be reported, as shown below.
// There are multiple root nodes in template in vue2 and will report an error<template> <header></header> <main></main> <footer></footer> </template> // There can only be one root node, and it needs to be wrapped with a <div><template> <div> <header></header> <main></main> <footer></footer> </div> </template>
However, Vue3 supports multiple root nodes, that is, fragments. That is, the following multiple nodes are written to be allowed.
<template> <header></header> <main></main> <footer></footer> </template>
3. Composition API
Vue2 is an option API (Options API). A logic will be scattered in different locations of the file (data, props, computed, watch, life cycle hook, etc.), causing the code to be poorly readable. When a certain logic needs to be modified, it is necessary to jump up and down to jump back to the file location.
Vue3 Composition API (Composition API) solves this problem well, and can write the contents of the same logic together, enhancing the readability and cohesion of the code, and also provides a relatively perfect logical reusability solution.
4. Asynchronous Components (Suspense)
Vue3 provides Suspense component, allowing programs to render the content that is guaranteed before waiting for the asynchronous component to be loaded, making the user's experience smoother. Using it, it needs to be declared in the template and includes two named slots: default and fallback. Suspense ensures that the default slot is displayed when asynchronous content is loaded and uses the fallback slot as the loading state.
<tempalte> <suspense> <template #default> <List /> </template> <template #fallback> <div> Loading... </div> </template> </suspense> </template>
Before the List component (which may be an asynchronous component, or the component's internal processing logic or too much search operation caused by too slow loading, etc.) is loaded, display Loading... (i.e. fallback slot content), and display itself (i.e. default slot content) when loading is completed.
5. Teleport
Vue3 provides Teleport components to move some DOMs outside of Vue apps. For example, the common Dialog pop-up window in the project. refer to:Detailed answers to front-end vue interview questions
<button @click="dialogVisible = true">Show pop-up window</button> <teleport to="body"> <div class="dialog" v-if="dialogVisible"> I'm a pop-up window,I moved directly tobodyUnder the tag </div> </teleport>
6. Responsive Principle
The basis of Vue2's responsive principle is; the basis of Vue3's responsive principle is Proxy.
Basic usage: Define new properties directly on an object or modify existing properties and return the object.
let obj = {}; let name = 'leo'; (obj, 'name', { enumerable: true, // Enumerable (whether it can be accessed through for...in or ()) configurable: true, // Configurable (can be deleted with delete, can the properties be set again) // value: '', // Value of any type, undefined by default // writable: true, // rewritable get() { return name; }, set(value) { name = value; } });
Tips: writable
andvalue
andgetter
andsetter
No coexistence.
Move the Vue2 core source code and slightly deleted.
function defineReactive(obj, key, val) { // A key one dep const dep = new Dep() // Get the attribute descriptor of the key and find that it is an unconfigurable object and directly return it const property = (obj, key) if (property && === false) { return } // Get getter and setter and get val value const getter = property && const setter = property && if((!getter || setter) && === 2) { val = obj[key] } // Recursive processing to ensure that all keys in the object are observed let childOb = observe(val) (obj, key, { enumerable: true, configurable: true, // get hijacking obj[key] for dependency collection get: function reactiveGetter() { const value = getter ? (obj) : val if() { // Dependency collection () if(childOb) { // For nested objects, dependency collection () // Trigger array responsiveness if((value)) { dependArray(value) } } } } return value }) // set distribute update obj[key] set: function reactiveSetter(newVal) { ... if(setter) { (obj, newVal) } else { val = newVal } // Set the responsive form for new values childOb = observe(val) // Dependency notification update () } }
Then why did Vue3 abandon it? That must be because of some limitations.
Main reason: Unable to listen for newly added or deleted elements of objects or arrays.
Vue2 corresponding solution: hacked for common array prototype methods push, pop, shift, unshift, splice, sort, and reverse; new attributes added to the listening object/array are provided. The new/delete response of the object can also be new new objects. If the new one is added, the new attributes and the old object will be merged; if the deleted attributes are deleted, the object after the deleted attributes will be deeply copied to the new object.
- Proxy
Proxy is a new feature of ES6, which intercepts the behavior of the target object through the second parameter handler. Compared to providing full-range responsiveness in languages, it eliminates limitations.
limitation:
(1) Add or delete objects/arrays
(2) Monitoring .length modification
(3) Support for Map, Set, WeakMap, WeakSet
Basic usage: Create an agent for the object to implement the interception and customization of basic operations.
let handler = { get(obj, prop) { return prop in obj ? obj[prop] : ''; }, set() { // ... }, ... };
Move vue3's source code file.
function createReactiveObject(target, isReadOnly, baseHandlers, collectionHandlers, proxyMap) { ... // collectionHandlers: handle Map, Set, WeakMap, WeakSet // baseHandlers: handle arrays and objects const proxy = new Proxy( target, targetType === ? collectionHandlers : baseHandlers ) (target, proxy) return proxy }
7. Virtual DOM
Vue3 Compared with Vue2, patchFlag field is added on the virtual DOM. We use the helpVue3 Template ExplorerCome and see。
<div > <h1>vue3virtualDOMexplain</h1> <p>The weather is really good today</p> <div>{{name}}</div> </div>
The rendering function is shown below.
import { createElementVNode as _createElementVNode, toDisplayString as _toDisplayString, openBlock as _openBlock, createElementBlock as _createElementBlock, pushScopeId as _pushScopeId, popScopeId as _popScopeId } from vue const _withScopeId = n => (_pushScopeId(scope-id),n=n(),_popScopeId(),n) const _hoisted_1 = { id: app } const _hoisted_2 = /*#__PURE__*/ _withScopeId(() => /*#__PURE__*/_createElementVNode(h1, null, vue3 virtual DOM explanation, -1 /* HOISTED */))const _hoisted_3 = /*#__PURE__*/ _withScopeId(() => /*#__PURE__*/_createElementVNode(p, null, the weather is really good today, -1 /* HOISTED */))export function render(_ctx, _cache, $props, $setup, $data, $options) { return (_openBlock(), _createElementBlock(div, _hoisted_1, [ _hoisted_2, _hoisted_3, _createElementVNode(div, null, _toDisplayString(_ctx.name), 1 /* TEXT */) ])) }
Note that the fourth parameter of the third _createElementVNode is the patchFlag field type.
Field type situation: 1 represents the node as a dynamic text node. In the diff process, you only need to compare the text content without paying attention to class, style, etc. In addition, all static nodes (HOISTED is -1) were found to be saved as a variable for static promotion, and can be directly referenced when re-rendering without re-creating.
// patchFlags field type listexport const enum PatchFlags { TEXT = 1, // Dynamic text content CLASS = 1 << 1, // Dynamic class name STYLE = 1 << 2, // Dynamic style PROPS = 1 << 3, // Dynamic attributes, not including class names and styles FULL_PROPS = 1 << 4, // Has a dynamic key attribute. When the key changes, a complete diff comparison is required. HYDRATE_EVENTS = 1 << 5, // Node with listening events STABLE_FRAGMENT = 1 << 6, // fragment that will not change the order of child nodes KEYED_FRAGMENT = 1 << 7, // fragment or part of child nodes with key attribute UNKEYED_FRAGMENT = 1 << 8, // The child node does not have a fragment with key NEED_PATCH = 1 << 9, // Only non-props comparisons will be performed DYNAMIC_SLOTS = 1 << 10, // Dynamic slots HOISTED = -1, // Static node, the diff stage ignores its child nodes BAIL = -2 // means diff should end}
8. Event Cache
Vue3'scacheHandler
Our events can be cached after the first rendering. Compared to Vue2, there is no need to pass a new function every time it renders. Add a click event.
<div > <h1>vue3Event Cache Explanation</h1> <p>The weather is really good today</p> <div>{{name}}</div> <span onCLick=() => {}><span> </div>
The rendering function is shown below.
import { createElementVNode as _createElementVNode, toDisplayString as _toDisplayString, openBlock as _openBlock, createElementBlock as _createElementBlock, pushScopeId as _pushScopeId, popScopeId as _popScopeId } from vue const _withScopeId = n => (_pushScopeId(scope-id),n=n(),_popScopeId(),n) const _hoisted_1 = { id: app } const _hoisted_2 = /*#__PURE__*/ _withScopeId(() => /*#__PURE__*/_createElementVNode(h1, null, vue3 event cache explanation, -1 /* HOISTED */))const _hoisted_3 = /*#__PURE__*/ _withScopeId(() => /*#__PURE__*/_createElementVNode(p, null, the weather is really good today, -1 /* HOISTED */))const _hoisted_4 = /*#__PURE__*/ _withScopeId(() => /*#__PURE__*/_createElementVNode(span, { onCLick: () => {} }, [ /*#__PURE__*/_createElementVNode(span) ], -1 /* HOISTED */)) export function render(_ctx, _cache, $props, $setup, $data, $options) { return (_openBlock(), _createElementBlock(div, _hoisted_1, [ _hoisted_2, _hoisted_3, _createElementVNode(div, null, _toDisplayString(_ctx.name), 1 /* TEXT */), _hoisted_4 ])) }
Observe the above rendering function and you will find that the click event node is a static node (HOISTED is -1), which means that you do not need to re-render each time.
9. Diff algorithm optimization
Move the Vue3 patchChildren source code. Combining the above and source code, patchFlag helps diff distinguish between static nodes and different types of dynamic nodes. Reduce the comparison of nodes themselves and their attributes to a certain extent.
function patchChildren(n1, n2, container, parentAnchor, parentComponent, parentSuspense, isSVG, optimized) { // Get new and old children's nodes const c1 = n1 && const c2 = const prevShapeFlag = n1 ? : 0 const { patchFlag, shapeFlag } = n2 // Process patchFlag greater than 0 if(patchFlag > 0) { if(patchFlag && PatchFlags.KEYED_FRAGMENT) { // Existence key patchKeyedChildren() return } els if(patchFlag && PatchFlags.UNKEYED_FRAGMENT) { // No key patchUnkeyedChildren() return } } // Match is a text node (static): remove old nodes and set text nodes if(shapeFlag && ShapeFlags.TEXT_CHILDREN) { if (prevShapeFlag & ShapeFlags.ARRAY_CHILDREN) { unmountChildren(c1 as VNode[], parentComponent, parentSuspense) } if (c2 !== c1) { hostSetElementText(container, c2 as string) } } else { // Match the old and new Vnodes as arrays, then compare them all; otherwise, remove all current nodes if (prevShapeFlag & ShapeFlags.ARRAY_CHILDREN) { if (shapeFlag & ShapeFlags.ARRAY_CHILDREN) { patchKeyedChildren(c1, c2, container, anchor, parentComponent, parentSuspense,...) } else { unmountChildren(c1 as VNode[], parentComponent, parentSuspense, true) } } else { if(prevShapeFlag & ShapeFlags.TEXT_CHILDREN) { hostSetElementText(container, '') } if (shapeFlag & ShapeFlags.ARRAY_CHILDREN) { mountChildren(c2 as VNodeArrayChildren, container,anchor,parentComponent,...) } } } }
patchUnkeyedChildren The source code is as follows.
function patchUnkeyedChildren(c1, c2, container, parentAnchor, parentComponent, parentSuspense, isSVG, optimized) { c1 = c1 || EMPTY_ARR c2 = c2 || EMPTY_ARR const oldLength = const newLength = const commonLength = (oldLength, newLength) let i for(i = 0; i < commonLength; i++) { // If the new Vnode is already mounted, then clone it directly, otherwise create a new node const nextChild = (c2[i] = optimized ? cloneIfMounted(c2[i] as Vnode)) : normalizeVnode(c2[i]) patch() } if(oldLength > newLength) { // Remove excess nodes unmountedChildren() } else { // Create a new node mountChildren() } }
10. Packaging optimization
Tree-shaking: Concepts in module packaging webpack, rollup, etc. Removes unreferenced code in the JavaScript context. It mainly relies on import and export statements to detect whether the code module is exported, imported, and used by JavaScript files.
Taking nextTick as an example, in Vue2, the global API is exposed to the Vue instance and cannot be eliminated through tree-shaking even if it is not used.
import Vue from 'vue'; (() => { // Some things related to DOM});
Vue3 has been refactored for global and internal APIs, taking into account tree-shaking support. Therefore, the global API is now accessible only as a named export built by ES modules.
import { nextTick } from 'vue'; // Explicit importnextTick(() => { // Some things related to DOM});
With this change, as long as the module binder supports tree-shaking, unused apis in the Vue application will be eliminated from the final bundle, achieving the best file size.
The global API affected by this change is shown below.
- (Replace with
- (Full build only)
- (Compatible for builds only)
- (Compatible for builds only)
Internal APIs also have tags or instructions such as transition, v-model, etc. that are named and exported. Only when the program is actually used will it be bundled and packaged. Vue3 packages all running functions only about 22.5kb, which is much lighter than Vue2.
11. TypeScript Support
Vue3 is rewritten by TypeScript and has better TypeScript support compared to Vue2.
- In the Vue2 Options API, option is a simple object, while TypeScript is a type system with object-oriented syntax and does not have a special match.
- Vue2 requires vue-class-component to strengthen vue native components, and also requires vue-property-decorator to add more decorators that combine Vue characteristics, which is more cumbersome.
2. Options API and Composition API
Vue components can be written in two different API styles: the Options API and the Composition API.
1. Options API
Using the Options API, we use option objects to define the logic of components, such as data, methods, and mounted. The properties defined by the options are exposed in this internal function, pointing to the component instance, as shown below.
<template> <button @click="increment">count is: {{ count }}</button> </template> <script> export default { data() { return { count: 0 } }, methods: { increment() { ++; } }, mounted() { (`The initial count is ${}.`); }} </script>
2. Composition API
Using the Composition API, we use the imported API functions to define the logic of the component. In SFC, the Composition API is usually used
<template> <button @click="increment">Count is: {{ count }}</button> </template> <script setup> import { ref, onMounted } from 'vue'; const count = ref(0); function increment() { ++;} onMounted(() => { (`The initial count is ${}.`);}) </script>
The above is the detailed content of the difference between vue2 and vue3 in front-end interview. For more information on the difference between vue2 and vue3 in front-end interview, please pay attention to my other related articles!