Preface:

Never to contact Vue3, before summer vacation time, just take this opportunity to learn well, this article is my learning before Vue3 notes, make notes on the one hand, let oneself more understanding and grasp the new features of these knowledge, on the other hand also hope to be able to let everybody introduction Vue3, their learned is made, References are indicated in the conclusion

Vue3 profile

The problem: As features grew and the code for complex components became harder to maintain, Vue3 came along and TypeScript became more and more popular. Vue3 was written by TS so it supports TypeScript better

That’s all there is to it

Most of the features of VUE2 are available in Vue3 as Vue is, after all, incremental

Reactive principle to use Proxy implementation, V-model can pass parameters and other new features

Basic work

With Vue3, you must create a Vue3 project using the build tool

Install the vue – cli

# npm
npm install -g @vue/cli
# yarn
yarn global add @vue/cli
Copy the code

Create a project

Create using the create command line or visually with the UI

Everyone has been using Vue for so long that I won’t go into how to create it

# createVue create Project name# visualization
vue ui
Copy the code

Of course, you can also choose Vite, which is a bit faster to create than the above method

NPM init vite-app project namecdProject name NPM install NPM run devCopy the code

Introduction to Vue3

Composition API

Vue3 introduces the Composition API

In Vue2.X we use OptionAPI with familiar data, computed, methods, watch…

In Vue3, we can still use OptionAPI but we don’t recommend mixing it with Vue3

In Vue2, we implement a function score in different places, put the data in data,computed methods in methods, it’s too messy, a few functions are ok, dozens or hundreds, that’s a bit…

Therefore, Vue3 proposed Composition API, which can collect a logical code together and write a hook separately, and then introduce it, so that it is not distributed everywhere and looks messy

Fragment

You no longer need a root element wrapped around the template

<template>
  <img alt="Vue logo" src="./assets/logo.png" />
  <HelloWorld msg="Welcome to Your Vue.js + TypeScript App" />
</template>
Copy the code

There are actually multiple tags internally contained within a Fragment virtual element

Benefits: Reduced label hierarchy and memory footprint

scriptdifferences

Let’s look at the difference between Script and Vue2

<script lang="ts">
import { defineComponent} from 'vue'

export default defineComponent({
  name: 'App'.setup() {
    return {
        // The attributes and methods are merged into the data function and methods object
    }
  },
})
</script>
Copy the code
  • Can againscriptusetsJust set uplangCan be
  • defineComponentMethod to create a component
  • export defaultExport a component directly

setup

Setup is the entry point to the Composition API

setupExecution order

It will execute once before the beforeCreate hook. The beforeCreate hook is used for initialization, so this is not initialized. This = undefined so that methods and properties cannot be called through this

setupThe return value

Setup returns an object whose properties are merged with the object returned by the data function in the component, and the methods returned by the data function are merged with the methods, which can be used directly in the template. If the same name exists, the same properties and methods are used. Methods and data should be merged into setup, whereas setup cannot get their properties and methods because this = undefined

Suspensecomponent

The setup using async/await

We need setup to return data so it definitely can’t use async modifiers. In this case we don’t want to see the situation. If we insist on async modifiers, we need to nest a built-in component in suspense around its parent. Put some indeterminate operations in it, for example we can put asynchronous components in it

1. The child component
<template>
  {{ res }}
</template>

<script lang="ts">
import { defineComponent } from 'vue'
export default defineComponent({
  name: 'Son'.async setup() {
    const res = await axios.get('address')
    return {
      res,
    }
  },
})
</script>
Copy the code
2. The parent component
<template>
    <Suspense>
        <! -- Subcomponent -->
        <Son></Son>
    </Suspense>
</template>
Copy the code

setupparameter

setup(props, context)

The first argument in the setup function is props. It receives the props for passing information from the parent component

The second parameter is context, which contains 3 attributes {attrs, slots, emit}. This.$attrs, this.$slots, this

  • attrs: in addition to thepropsAdditional attributes in
  • slots: Object to which the parent passes the contents of the slot
  • emit: and for parent-child component communication

ref

Define/convert to reactive

None of the data that setup writes above is responsive, and if you change the data, the view does not update

Vue3 provides two ways to define reactive data, starting with ref

Import ref method

import { defineComponent, ref } from 'vue'
Copy the code
  • You can declare one firstBasic types ofI’m going to take the variablerefThe parameter to the
  • Or directly in therefThe incoming
  setup() {
    / / way
    let number1 = ref(10)
    let num = 0
    2 / / way
    let number2 = ref(num)
    return{}},Copy the code

So let’s see what number one is

So what you can see is number1 is a Ref object, and the value 10 that we set is on the value property of this object

So what we have to change is number1.value

Data hijacking is implemented by adding getters/setters to the value property

However, when using the template, you can write number1 instead of number1.value

Value is automatically added when the template is compiled

<template>
  {{ number1 }}
  <button @click="updateNum">+</button>
</template>

<script lang="ts">
import { defineComponent, ref } from 'vue'
export default defineComponent({
  name: 'Son'.setup() {
    let number1 = ref(10)

    / / modify the number1
    function updateNum() {
      number1.value++
    }
    return {
      number1,
      updateNum,
    }
  },
})
</script>
Copy the code

No problem in use

Can a REF accept complex types, object types, etc.

Passing a complex type to ref is implemented by calling Reactive

Reactive is mentioned below

refAccess to elements

A ref can also be used to fetch elements

Ref =’XXX’ and this.$refs.XXX

Getting elements on Vue3 is a little different

1. If ref=’XXX’ on the template element, do not use v-bind

<template>
  <div id="haha" ref="haha"></div>
</template>
Copy the code

2. In the setup

You have to give the ref type HTMLElement

setup() {
  let haha = ref<HTMLElement|null> (null)
  console.log(haha)
    
  return {
    haha,
  }
},
Copy the code

If you need to use HAHA in components, you must export haha Return and merge data

Let’s see what it prints. Okay

And what you can see is that haha is a Ref object, and the value is the element that we want to get

Then we can operate on the HAHA DOM element, like this one

haha.style.fontSize = '20px'
Copy the code

reactive

Reactive receives a common object and returns a reactive proxy object for that common object

Yes, the bottom of it is to use Proxy for Proxy

Write a simple Vue3 responsive Proxy example

new Proxy(target, handler)

  • target: to useProxyWrapped target object (can be any type of object, including a native array, a function, or even another proxy)
  • handler: an object that usually has functions as attributes, and the functions in each attribute define the agents that perform the various operationsp
// Simulate Vue data
let data = {
    msg: ' '.age: ' ',}// Simulate an instance of Vue
// Proxy first
let vm = new Proxy(data, {
    // get() gets the value
    // target indicates the object to be propped up
    // key is the key of the object
    get(target, key) {
        return target[key]
    },
    / / set the value
    // newValue is the set value
    set(target, key, newValue) {
        // Also determine if it saves as much performance as the previous value
        if (target[key] === newValue) return
        // Set the value
        target[key] = newValue
        document.querySelector('#app').textContent = target[key]
    },
})
Copy the code

Reactive

Import, of course, vscode will automatically import it for you when you write

import { defineComponent, reactive } from 'vue'
Copy the code

Simple to use

setup() {
    let obj = reactive({
        name: 'the little waves'.age: 21,})return {
        obj,
    }
}
Copy the code

Take a look at the returned Proxy object

The data is all in Target,

Use {{obj.name}} directly in the template

Obj [name] = ‘XXX’

Manipulating proxy objects also changes the data in OBJ, and if you want to update the rendering of the interface while manipulating the data, then manipulating proxy objects as well

Responsive data is deep (recursive deep responsive)

It is also responsive to multiple layers of nested data

setup() {
    let obj = reactive({
        name: 'the little waves'.age: 21.phone: {
            p_name: 'millet'.p_apps: {
                app_name: 'Xiaomi Campaign',}}})function upadateName() {
        obj.phone.p_apps.app_name = 'the nuggets'
    }
    console.log(obj)

    return {
        obj,
        upadateName,
    }
},
Copy the code

shallowReactive

It is a simple reactive that changes only the first-layer objects to reactive, but I won’t talk about it here

The object is passed in using ref

setup() {
    let obj = ref({
        name: 'the little waves'.age: 21,})console.log(obj)

    return {
        obj,
    }
}
Copy the code

Ref actually uses Reactive to do that

toRefs

In this way, every attribute of reactive object is a Ref object. In this way, every attribute of Reactive object is still reactive. We can also decompose each attribute, so that the component does not need obJ. Code load lightened, YYDS

setup() {
  const user = reactive({
    name: 'the little waves'.age: 21,})let userObj = toRefs(user)
  console.log(userObj)

  return{}}Copy the code

You can see that name and age have become Ref objects

We can deconstruct the name and age separately

setup() {
  const user = reactive({
    name: 'the little waves'.age: 21,})let userObj = toRefs(user)

  return {
    ...userObj,
  }
}
Copy the code

toRef

There is also a toRef method that does much the same as toRefs, but it can only change one of the properties of a reactive object/normal object into a Ref object

You can use it to create a REF for a property on a source reactive object. You can then pass the REF out, preserving a reactive connection to its source property.

export default {
  setup(props) {
    useSomeFeature(toRef(props, 'foo'))}}function useSomeFeature(foo: Ref) {
  // ...
}
Copy the code

Copy a new data value to operate separately, update does not affect each other

ToRef is useful when you want to pass a PROP ref to a composite function

The function useSomeFeature receives an argument foo of type Ref, which can be converted using toRef

Judgment response

A few ways to determine what kind of reactive creation you are

1. IsRef: Checks whether a value is a ref object

let ref1 = ref(1)
console.log(isRef(ref1))  // true
Copy the code

2. IsReactive: Checks whether an object is a reactive agent created by Reactive

let ref2 = reactive({name: 'the little waves'})
console.log(isReactive(ref2))  // true
Copy the code

3. IsReadonly: Checks whether an object is a read-only proxy created by readOnly

let ref3 = readonly({name: 'the little waves'})
console.log(isReadonly(ref3))  // true
Copy the code

4. IsProxy: Checks whether an object is a proxy created by reactive or Readonly

let ref2 = reactive({name: 'the little waves'})
console.log(isProxy(ref2))  // true
let ref3 = readonly({name: 'the little waves'})
console.log(isProxy(ref3))  // true
Copy the code

customRef

As mentioned above, so many refs are built in by Vue,

We can implement our own Ref through customRef

Create a custom REF with explicit control over its dependency trace and update trigger. It requires a factory function that takes track and trigger functions as arguments and should return an object with get and set.

The official documentation gives an example of anti-shaking, so let’s write one

<template>
  <h2>App</h2>
  <input v-model="keyword"/>
  <p>{{keyword}}</p>
</template>

<script lang="ts">
import {
  customRef
} from 'vue'

// The type is not certain, so we use generics here
function useDebouncedRef<T> (value: T, delay = 200) {
  / / timer
  let timeout: number
  return customRef((track, trigger) = > {
    return {
      get() {
        // Tell Vue the trace data
        track()
        return value
      },
      set(newValue: T) {
        clearTimeout(timeout)
        timeout = setTimeout(() = > {
          value = newValue
          // Tell Vue to trigger interface update
          trigger()
        }, delay)
      }
    }
  })
}

export default {
  setup () {
    const keyword = useDebouncedRef(' ')
    return {
      keyword
    }
  },
}
</script>
Copy the code

shallowRefshallowReactive

Shallow response is generally not used much, and ref and Reactive are often used

shallowReactive

The object structure is nested in multiple layers, but we only need to modify the outermost layer of data, instead of changing the nested structure inside to responsive, so that the shallow response is used to improve performance, only the outermost layer is responsive

It’s easier to understand, and I’m not going to give you any examples

shallowRef

As we mentioned earlier, ref can also pass in an object. In fact, we call Reactive to return the Proxy object, and if there are objects in the inner layer, we still use Reactive to process them

ref({ name: 'Ming' })
// Call reactive (ref value = key,value = key,value = key
reactive({ value: { name: 'Ming'}})Copy the code

In the same way that shallowRef handles object types, shallowReactive does that

shallowRef({ name: 'Ming' })
// Call reactive (ref value = key,value = key,value = key
shallowReactive({ value: { name: 'Ming'}})Copy the code

Reactive: Value reactive: value reactive: value reactive: Value reactive: Value reactive

[Note] : shallowRef creates a ref that tracks its value changes, but does not perform a reactive proxy conversion to the changed value

setup() {
  let info1 = ref({
    name: 'the little waves'.notebook: {
      name: 'Mi Notebook',}})let info2 = shallowRef({
    name: 'Ming'.notebook: {
      name: 'Mi Notebook',}})console.log(info1, info2)
  return {
    info1,
    info2,
  }
},
Copy the code

Let’s print the next two objects

You can see that the value of Ref is a Proxy object returned by Reactive.

The value of shallowRef is a normal object

readonlyshallowReadonly

Readonly Depth read-only

If you set a normal object or a reactive object to be read-only, you can’t change it, you can’t change it, you can’t change it, you can’t change it, you can’t change it, you can’t change it, you can’t change it, you can’t change it

Basic use:

Import what you use

import { defineComponent, readonly } from 'vue'
Copy the code

Error: “name” cannot be assigned because it is read-only

Both the inner and outer layers are read only and are depth checked

ShallowReadonly Shallow read-only

If it’s shallow, it only applies to the outermost layer and doesn’t care about the inner layer

In the following example, only the name of the outer layer is in error, and there is no error in modifying the inner layer

toRawmarkRaw

These two are still used sparingly

I’m just going to go through this very briefly

ToRaw: Turns a reactive object into a normal object

Simple use:

setup() {
  let info1 = reactive({
    name: 'the little waves'.notebook: {
      name: 'Mi Notebook',}})const rawInfo = toRaw(info1) // Return a normal object
  console.log(info1)
  console.log(rawInfo)

  return{}},Copy the code

Two are printed out, and one is a reactive object, which becomes a normal object through toRaw

MarkRaw: Marks an object so that it is never turned into a responsive object and returns its own value

For example: some unchanged data dead data, there are some third-party class instances, do not need to turn into responsive objects, improve performance

Simple use:

Here we use two identical objects, one with markRaw processing and one without markRaw processing

And then also use Reactive to go reactive

setup() {
  let obj = {
    name: 'the little waves'.notebook: {
      name: 'Mi Notebook',}}// Make a tag
  let markRawObj = markRaw(obj)
  // Try to become responsive
  let reactObj = reactive(markRawObj)

  let obj2 = {
    name: 'the little waves'.notebook: {
      name: 'Mi Notebook',}}// Change to responsive
  let reactObj2 = reactive(obj2)

  console.log(reactObj)
  console.log(reactObj2)

  return{}}Copy the code

Notice that the printed, marked OBJ is not converted to a Proxy responsive Proxy object

computedCalculate attribute

Using computed in Vue3 is a little different from using computed in vue2. X, where computed is a method

First, you have to import computed methods

import { defineComponent, computed } from 'vue'
Copy the code

The argument is a callback and the default is GET

<template>
  <div class="box">
    <input type="text" v-model="name" />
    <br />
    <input type="text" v-model="age" />
    <br />
    <input type="text" v-model="getInfo" />
  </div>
</template>
Copy the code
setup() {
    let name = ref('the little waves')
    let age = ref(21)
	
    // Calculate attributes
    let getInfo = computed(() = > {
        return 'My name:${name.value}This year,${age.value}Please give me more advice
    })
    return {
        name,
        age,
        getInfo,
    }
}
Copy the code

The set method is not implemented here, so the following changes are useless

The argument is an object and I’ll say get set here

The template is the same as above

setup() {
    let name = ref('the little waves')
    let age = ref(21)

    let getInfo = computed({
        / / get methods
        get() {
            return `${name.value}.${age.value}`
        },
        / / set methods
        set(val: string) {
            let arr = val.split(', ')
            name.value = arr[0]
            age.value = parseInt(arr[1])}})return {
        name,
        age,
        getInfo,
    }
Copy the code

watchThe listener

The use method of Vue2.X Watch is similar

introduce

watch(data,handler,object)

  1. data: can be returnedgetterDelta function, or delta functionref
  2. handler: callback function
  3. object: Optional configuration item{ immediate: true }

The introduction of

import { defineComponent, watch } from 'vue'
Copy the code

Data is a ref

The callback takes (new value, old value)

setup() {
    let name = ref('the little waves')
    let age = ref(21)

    let watchName = ref(' ')
    watch(name, (newName, oldName) = > {
        watchName.value = 'My name is new${newName}My name is old${oldName}`
    })
    return {
        name,
        age,
        watchName,
    }
},
Copy the code

The third parameter of watch is the configuration object, which can be set to execute {immediate: true} immediately.

I’m going to execute it once and of course oldName is undefined

watch(
  name,
  (newName, oldName) = > {
    watchName.value = 'My name is new${newName}My name is old${oldName}`
  },
  { immediate: true})Copy the code

Data is a getter

watch(() = >haha,(newName, oldName) = >{
  / / processing...
})
Copy the code

()=> Haha returns a value, which is equivalent to the shorthand for getter. Haha may not be reactive data

Data is multiple refs

The template is the same as before

<template>
  <div class="box">
    <input type="text" v-model="name" />
    <br />
    <input type="text" v-model="age" />
    <br />
    <input type="text" v-model="getInfo" />
  </div>
</template>
Copy the code

We can put multiple Refs in an array

NewNameAndAge, oldNameAndAge is an array that holds new and old [name,age]

setup() {
    let name = ref('the little waves')
    let age = ref(21)

    let watchName = ref(' ')
    watch(
      [name, age],
      (newNameAndAge, oldNameAndAge) = > {
        watchName.value = `new: ${newNameAndAge}
        old: ${oldNameAndAge}`
      },
      { immediate: true})return {
        name,
        age,
        watchName,
    }
},
Copy the code

The data for reactive

setup() {
  let user = reactive({
    name: 'the little waves'.age: 21,})let watchInfo = ref(' ')
  watch(
    user,
    (newInfo, oldInfo) = > {
      console.log(newInfo === oldInfo)  // true})}Copy the code

This is where the object will have a problem, and immediately after execution,

If added immediately except for the first time newInfo is {name: ‘small wave ‘,age: 21}

OldInfo is undefined, after which the current value of the object is always returned

So newInfo = oldInfo

To solve this problem, we need to add the configuration object {deep: true} for depth detection

Deep detection can also determine multiple nesting

watch(
  user,
  (newInfo, oldInfo) = > {
    console.log(newInfo === oldInfo) // false
  },
  { deep: true})Copy the code

watchEffect

This is also used to listen for data changes, it’s done once by default so you don’t have to configure it, and you don’t have to specify data, you listen for what reactive data is used

let user = reactive({
    name: 'the little waves'.age: 21,})// This will be executed if user.name changes
watchEffect(() = > {
    console.log(user.name)
});
Copy the code

provide / inject

Provision and injection are simple to understand

Realize communication between components (grandparent and grandchild) across hierarchies

Used in multi-tier nested components without the need to pass data down layer by layer

Communication between components can be achieved across hierarchies

In the parent component

setup() {
    const info = reactive({
        title: 'Vue3 learning'
        date: '2021/7/23'
    })
    // Provide data provide data name, data value
    provide('info', info)
    
    return {
        info
    }
}
Copy the code

This is obtained using injection in the descendant level component

setup() {
    // Get the value of the corresponding data
    const color = inject('info')

    return {
        info
    }
}
Copy the code

TeleportTransmission components

This component is particularly interesting in that you can transfer components

<teleport v-if="flag" to=".test">
    <div class="dog">The dog son</div>
</teleport>
Copy the code

To is the address of the target body, #XXX,.xxx these are all CSS selectors

So let’s write an example to make it clear

The template

<template>
  <ul>
    <li class="li_1"></li>
    <li class="li_2"></li>
    <li class="li_3"></li>
  </ul>
  <teleport :to="target">
    <img src="Https://img0.baidu.com/it/u=3077713857, 1222307962 & FM = 26 & FMT = auto&gp = 0. JPG" />
  </teleport>
  <div class="btnGroup">
    <button @click="target = '.li_1'">Send 1</button>
    <button @click="target = '.li_2'">Send 2</button>
    <button @click="target = '.li_3'">Send three</button>
  </div>
</template>
Copy the code

setup

setup() {
  // target
  let target = ref('.li_1')
  return {
    target,
  }
},
Copy the code

Use button click to control whether teleport displays, teleport will run below Li as soon as it renders

Vue3The life cycle

Vue2.X corresponds to the Vue3 composite API

Vue2.X Vue3
beforeCreate —> setup()
created —> setup()
beforeMount —> onBeforeMount
mounted —> onMounted
beforeUpdate —> onBeforeUpdate
updated —> onUpdated
beforeDestroy —> onBeforeUnmount
destroyed —> onUnmounted
activated —> onActivated
deactivated —> onDeactivated
errorCaptured —> onErrorCaptured
onRenderTriggered
onRenderTracked

It can be seen that

BeforeCreate and Created work fine in Vu3, we can use better and faster setup instead in Vue3

Life cycles starting with ON need to be imported via import and used in the setup function

The life cycle of Vue3 is faster than that of Vue2.X

For example: onBeforeMount is faster than beforeMount and so on

There are two more hooks:

  • onRenderTriggeredCalled when tracking the virtual DOM is re-rendered
  • onRenderTrackedCalled when the virtual DOM rerendering is triggered

globalAPI transfer

The global API on the Vue in Vue2.X, such as the custom directive vuue. Directive, and the global component Vue.com Ponent have been changed in Vue3 to provide app instead of Vue

See the changes below

Vue2.X Vue3
Vue.config app.config
Vue.config.productionTip remove
Vue.config.ignoredElements app.config.isCustomElement
Vue.component app.component
Vue.directive app.directive
Vue.mixin app.mixin
Vue.use app.use
Vue.prototype app.config.globalProperties
new Vue().$mount(‘#app’) createApp(App).mount(‘#app’)

conclusion

At this point, we’re pretty much familiar with some of Vue3’s features

  • New scaffolding toolsvite
  • inVue3Still supportVue2Most of the features in
  • VuecombinationAPiInstead of aVue2In theoption APIWhen the same logic is centralized, the reusability is stronger
  • Vue3useTSWrite better support for TS
  • Vue3useProxyInstead of aVue2In theObject.defineProperty()Realize the responsive principle
  • New components are introduced:Fragment Teleport Suspense

Vue3, which has not been mentioned here, rewrites the virtual DOM to improve performance

I hope this note can help you, if I write not clear, specific have to see the official document YYDS, the school has recently started, there are many things in the school…

8゜ – ゜

References:

Vue3 official website document

B station data