Today, after watching the new generation of rap, it was 12 o ‘clock. Anyway, it was so late that I stayed up and wrote a document. Please bear with me

Cut the crap and just turn it on

You can use either of these methods

I personally use scaffolding

Upgrade (i.e. reload)

npm install -g @vue/cli # OR yarn global add @vue/cli
vue create hello-vue3
Copy the code

The following is different from the original is more than a choice of version, choose VUE3 to start

A, key

Take the most obvious ones listed on the official website below (ignore the last three)

1.1. composition API

Instead of comparing the Options API to the Composition API, let’s get started with the Composition API

Composition API entry point setup function

Create responsive datarefwithreactive

ref

The ref function returns a reactive ref object with one argument

Go straight to the chestnuts

<template>
  <div>
      {{num}}
  </div>
</template>
<script>
import { ref } from "vue";
export default {
  setup() {
    const num = ref(1);
    return{ num }; }};</script>
Copy the code

In other words, it is the same as the notation in vue2. X

data(){
    return {
        num:1}}Copy the code

It is worth noting that ref returns an object and needs to retrieve its value through its value attribute

Also the num. Value. However, it will solve automatically when used in templates. In the template above, num is used directly, and there is another case that can be solved automatically

In addition, you can now understand that the REF is used to reactalize simple types of data

reactive

Ref is responsible for simple data data, and Reactive is reactive to reference type data

Go straight to the chestnuts

<template>
  <div>{{num}}{{obj.name}}</div>
</template>
<script>
import { ref, reactive } from "vue";
export default {
  setup() {
    const num = ref(1);
    const obj = reactive({
      name: "gxb".age: 18});return{ num, obj }; }};</script>
Copy the code

Another case where the ref object above is automatically unnested is where it is used as a property of the reactive parameter object

That is:

 const num = ref(1);
const obj = reactive({
      name: "gxb".age: 18,
      num
    });
Copy the code

Note: Do not use it casually here… Syntax or deconstruction, otherwise you lose responsivity, and the last utility functions will be described

readonly

The argument to this function can be a response or a normal object or a ref. Returns a read-only proxy (deep)

chestnuts

Computed with the watch

computed

Computed is a function that requires passing a getter function. The return value is a ref object that cannot be manually modified

chestnuts

<template>
  <div>{{num2}}</div>
</template>
<script>
import { ref, reactive, computed } from "vue";
export default {
  setup() {
    const num = ref(1);
    const obj = reactive({
      name: "gxb".age: 18,
      num,
    });
    const num2 = computed(() = > num.value + 1);
    return{ num, obj, num2 }; }};</script>
Copy the code

Note It cannot be modified.

Such as

 const num2=computed(() = >num.value+1)
    num2.value++
Copy the code

If you want one that can be modified, you pass an object with get and set functions

<template>
  <div>{{num2.value}}</div>
</template>
<script>
import { ref, reactive, computed } from "vue";
export default {
  setup() {
    const num = ref(1);
    const obj = reactive({
      name: "gxb".age: 18,
      num,
    });
    const num2 = computed({
        get:() = >num,
        set:value= >num.value=value
    });
    
    num2.value=3
    return{ num, obj, num2 }; }};</script>
Copy the code

Note that num2 is no longer automatically unpacked

watch

Listen to a

<template>
  <div>{{num2.value}}</div>
</template>
<script>
import { ref, reactive, computed, watch } from "vue";
export default {
  setup() {
    const obj = reactive({
      name: "gxb".age: 18,
      num,
    });

    watch(
      () = > obj.name,
      (name, preName) = > {
        console.log(`new ${name}---old ${preName}`); });setTimeout(() = > {
      obj.name = "zhangsan";
    }, 1000);

    return{ obj }; }};</script>
Copy the code

The first argument can be either a getter function like the one above that returns a value, or a ref object

namely

<template>
  <div></div>
</template>
<script>
import { ref, reactive, computed, watch } from "vue";
export default {
  setup() {
    const obj = reactive({
      name: "gxb".age: 18,
      num,
    });
    const num = ref(0);
    watch(num, (name, preName) = > {
      console.log(`new ${name}---old ${preName}`);
    });
    setTimeout(() = > {
      num.value = 2;
    }, 1000);

    return{ obj }; }};</script>
Copy the code

Listen more

A change in either num or obj.name triggers the listener to handle the callback

<template>
  <div></div>
</template>
<script>
import { ref, reactive, computed, watch } from "vue";
export default {
  setup() {
    const obj = reactive({
      name: "gxb".age: 18,
      num,
    });
    const num = ref(0);
    watch([num, () = >obj.name], ([newNum, newName], [oldNum, oldName]) = > {
      console.log(`new ${(newNum)}.${(newName)}---old ${(oldNum)}.${oldName}`);
    });
    setTimeout(() = > {
      num.value = 6;
    // obj.name = "zhangsan";
    }, 1000);

    return{ obj }; }};</script>
Copy the code

Lifecycle hook

chestnuts

import { onMounted, onUpdated, onUnmounted } from 'vue'

const MyComponent = {
  setup() {
    onMounted(() = > {
      console.log('mounted! ')
    })
    onUpdated(() = > {
      console.log('updated! ')
    })
    onUnmounted(() = > {
      console.log('unmounted! ')})}},Copy the code

Corresponding to 2.x hooks

Props and this

props

The setup entry function receives props as the first argument

chestnuts

You have to be careful not to deconstruct it

The graph save trouble

  props: {
    data: String,},setup({ data }) {
    console.log(data);
  }
Copy the code

Deconstruction makes it unresponsive

this

2.x component instances are easy to pick up, usually just this, but setup is different.

However, there are many apis on component instances that we will use

So the second argument to setup is a context object

Chestnut: dispatch a custom event

Note that the context only selectively exposes a few attributes, such as emit and attrs and slots above

Dependency injection and Refs

Dependency injection

Provide and inject the same as those of vue2.x

chestnuts

An example of a component I used for diagram simplicity

Their responses need to be worked out by themselves (e.g. Ref)

Refs

So let’s take this node down here

<template>
  <div ref="test">test</div>
</template>
<script>
import {
  ref,
  reactive,
  computed,
  watch,
  provide,
  inject,
  onMounted,
} from "vue";
export default {
  setup() {
    const test = ref(null);
    onMounted(() = > {
      console.log(test.value);
    });

    return{ test }; }};</script>
Copy the code

Some utility functions

Let’s start by writing down what breaks the response object proxy generated by Reactive

So let’s write it the normal way

<template>
  <div ref="test">
    {{obj.age}}
    <button @click="obj.age++">add</button>
  </div>
</template>
<script>
import { ref, reactive, computed, watch, provide, inject, readonly } from "vue";
export default {
  props: {
    data: String,},setup(props, context) {
    console.log(props.data);
    context.emit("test");
    const obj = reactive({
      name: "gxb".age: 18});return{ obj }; }};</script>
Copy the code

Use extended syntax

<template>
  <div ref="test">
    {{age}}
    <button @click="age++">add</button>
  </div>
</template>
<script>
import { ref, reactive, computed, watch, provide, inject, readonly } from "vue";
export default {
  props: {
    data: String,},setup(props, context) {
    console.log(props.data);
    context.emit("test");
    const obj = reactive({
      name: "gxb".age: 18});return{... obj }; }};</script>
Copy the code

Deconstructed ones don’t work either

<template>
  <div ref="test">
    {{age}}
    <button @click="age++">add</button>
  </div>
</template>
<script>
import { ref, reactive, computed, watch, provide, inject, readonly } from "vue";
export default {
  props: {
    data: String,},setup(props, context) {
    console.log(props.data);
    context.emit("test");
    const obj = reactive({
      name: "gxb".age: 18});const { age } = obj;
    return{ age }; }};</script>
Copy the code

The principle of reactive is very simple. The internal principle of Reactive is Proxy, which operates on the returned Proxy instance

Let’s start with a few utility functions

  1. Unref, if the argument is a ref, returns the value attribute of the ref, otherwise returns itself
  2. ToRef, which creates a ref for the properties of a Reactive object
  3. ToRefs, which converts a reactive object into a normal object where each property is a ref
  4. IsRef, to determine if a value isRef
  5. IsProxy, which determines whether an object is created byreactiveorreadonlyMethod to create an agent.
  6. IsReactive: checks whether an object is created byreactiveCreate a responsive proxy
  7. IsReadonly: checks whether an object is created byreadonlyThe read-only agent created.

Let’s just write an example for 2 and 3

ToRef, which changes a property on a Reactive object to a REF

What does that mean, or is it the chestnut that broke the response

Fix (you can pull out one of its attributes to make a reactive ref, and they are still related to each other)

<template>
  <div ref="test">
    {{age}}
    <button @click="age++">add</button>
  </div>
</template>
<script>
import {
  ref,
  reactive,
  computed,
  watch,
  provide,
  inject,
  readonly,
  toRef,
} from "vue";
export default {
  props: {
    data: String,},setup(props, context) {
    const obj = reactive({
      name: "gxb".age: 18});const age=toRef(obj, "age");
    watch(() = >obj.age,(newAge,oldAge) = >{
        console.log(newAge);
    })
    return{ age }; }};</script>
Copy the code

ToRefs consolidates all attributes in the object into refs, which is a much simpler fix

<template>
  <div ref="test">
    {{age}}
    <button @click="age++">add</button>
  </div>
</template>
<script>
import {
  ref,
  reactive,
  computed,
  watch,
  provide,
  inject,
  readonly,
  toRef,
  toRefs
} from "vue";
export default {
  props: {
    data: String,},setup(props, context) {
    const obj = reactive({
      name: "gxb".age: 18});const obj02=toRefs(obj);
    
    return{... obj02 }; }};</script>
Copy the code

1.2. Teleport

The portal, as the name suggests

Scenario: We may need a modal box function in some components, but although the modal box logically belongs to the component, the actual operation usually requires the box to be attached to the body. The Teleport component helps us with this problem

To see chestnuts

Suppose you need a modal box in your component

<template>
    <div>
        <model></model>
    </div>
</template>
<script>
import Model from './model'
export default {
    components:{Model}
}
</script>
Copy the code

Modal box components

<template> <div> < button@click ="flag=true"> Click </button> <teleport to="body"> <div> </teleport> </div> </template> <script> import { ref } from "vue"; export default { setup() { const flag = ref(false); return { flag }; }}; </script>Copy the code

The purpose of the Teleport component is to pass elements from the Teleport tag to the body

Look at the hierarchy

1.3. Fragments could

This is a little bit easier to understand

It turns out that only one outermost parent div is allowed

<template>
  <div>
    ...
  </div>
</template>
Copy the code

Now you can have multiple

<template>
  <div>
    ...
  </div>
  <div>
    ...
  </div>
	...
</template>
Copy the code

1.4. Emits Component Option

1.4.1 Custom Event Dispatch

The important point here is that there is an option to dispatch events emits

When we send an event using emit, we need to include the event name in the option

Chestnut:

<template> <div> < button@click ="$emit('test')"> click </button> </div> </template> <script> export default {emits: ["test"], }; </script>Copy the code

Note: If you send a native event and don’t put it in the emits option, the parent component’s listening will be triggered twice

<template> <div> < button@click ="$emit('click')"> click </button> </div> </template> <script> export default {// emits: ["click"], }; </script>Copy the code

1.4.2 v – model

The v-model in VUe3 uses the attribute modelValue and the event update:modelValue (with sync removed from 3)

chestnuts

The parent component

<template> <div id="nav"> {{data}} <test05 v-model="data"></test05> </div> </template> <script> import { ref } from "vue"; import Test05 from "./components/test05"; export default { components: { Test05 }, setup() { const data=ref('gxb') return {data}; }}; </script>Copy the code

Child components

<template>
  <div>
    <input type="text" :value="modelValue" @input="$emit('update:modelValue',$event.target.value)" />
  </div>
</template>
<script>
export default {
    props:{
        modelValue:String
    },
    emits:['update:modelValue']
}
</script>
Copy the code

Custom attribute name. In ve2. X, the model option can be used to specify the attribute name and the event to be used by the V-Model. Attributes can also be customized in VUe3

chestnuts

Parent component (that is, specify binding after V-Model)

<test05 v-model:foo="data"></test05>
Copy the code

Child components

<template>
  <div>
    <input type="text" :value="foo" @input="$emit('update:foo',$event.target.value)" />
  </div>
</template>
<script>
export default {
    props:{
        foo:String
    },
    emits:['update:foo']
}
</script>
Copy the code

Multiple V-Model instructions can be written to a component

Chestnut:

The parent component

 <test01 v-model:foo="a" v-model:bar="b"></test01>
Copy the code

Child components

<template> <div> <input type="text" :value="foo" @input="$emit('update:foo',$event.target.value)" /> <input type="text" :value="bar" @input="$emit('update:bar',$event.target.value)" /> </div> </template> <script> export default { props: { foo: String, bar: String, }, emits: ["update:foo", "update:bar"], setup(props) { return {}; }}; </script>Copy the code

1.5. createRendererAPI

Custom renderer as its name says, its main function is that we can customize the way the Virtual DOM to DOM, see good 3 or 4 big guys are using canvas to draw pictures. Can’t think of any chestnuts here

Second, the other

2.1 Global API

There is no concept of application in ve2. X, and the so-called “app” in VE2. X is just an instance constructed through Vue. But some of the global apis in 2.x (mixins, use, Component, etc.) are directly in the Vue constructor

That is, if there are “applications” underneath that use New Vue, these global apis can easily become contaminated

Take a look at the entry file for VUe3

import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'

createApp(App).use(store).use(router).mount('#app')
Copy the code

Now that you have a createApp, this method returns an instance of the application

Write component for chestnuts

import { createApp, h } from 'vue' import App from './App.vue' import router from './router' import store from './store' createApp(App) Component (' test06 '{render () {return h (' div', {}, 'global components')}}). Use (store). Use (router). The mount (' # app)Copy the code

Other apis will change accordingly, such as the official website

Global API Treeshaking

The official website uses vue.nexttick (), a global API, as an example

What the hell is this tree shaking thing?

These apis are written indiscriminately in the vue constructor if they are not used in the application. So is it a waste of performance and an increase in packaging volume to include these things in the packaging

Therefore, the use of nextTick in VUe3 also needs to be imported from VUE

import { nextTick } from 'vue'

nextTick(() = >{... })Copy the code

Other affected apis

2.2 the Template Directives

v-model

V-model has been written on it, and sync has been deleted. V-model has been used for unification

V-if, V-for priority problem

In 2.x, v-for has a high priority, and in 3.0, V-if has a high priority

2.3 the Components

Functional component

Since functional components now offer negligible performance gains in VUE3, the use of state components is recommended.

And functional components can only be declared by pure functions and can only accept props and context (also emit, slots, attrs).

Let’s do a quick example

Let’s be lazy here. Get the chestnuts from the website

vue2.x

// Vue 2 Functional Component Example
export default {
  functional: true.props: ['level'].render(h, { props, data, children }) {
    return h(`h${props.level}`, data, children)
  }
}
Copy the code

Vue3, the difference between h function: true, and the argument problem mentioned above, another change is removed.

import { h } from 'vue'

const DynamicHeading = (props, context) = > {
  return h(`h${props.level}`, context.attrs, context.slots)
}

DynamicHeading.props = ['level']

export default DynamicHeading
Copy the code

Single file comparison

2.x

// Vue 2 Functional Component Example with <template>
<template functional>
  <component
    :is="`h${props.level}`"
    v-bind="attrs"
    v-on="listeners"
  />
</template>

<script>
export default {
  props: ['level']}</script>
Copy the code

3.0, functional is removed, listeners are put in $attrs and can be removed

<template>
  <component
    v-bind:is="`h${props.level}`"
    v-bind="$attrs"
  />
</template>

<script>
export default {
  props: ['level']}</script>
Copy the code

Asynchronous components

What about asynchronous components

const asyncPage = () = > import('./NextPage.vue')
Copy the code

Or with a choice

const asyncPage = {
  component: () = > import('./NextPage.vue'),
  delay: 200.timeout: 3000.error: ErrorComponent,
  loading: LoadingComponent
}
Copy the code

Vue3, however, has a new API defineAsyncComponent that shows how to define asynchronous components

That is

const asyncPage = defineAsyncComponent(() = > import('./NextPage.vue'))
Copy the code

or

const asyncPageWithOptions = defineAsyncComponent({
  loader: () = > import('./NextPage.vue'),
  delay: 200.timeout: 3000.errorComponent: ErrorComponent,
  loadingComponent: LoadingComponent
})
Copy the code

Component is loader

Resolve,reject, and 3.0 are accepted as arguments, but must return a Promise

2.4 Render Function

Render function changes

So the original function of h looks like this

export default {
  render(h) {
    return h('div')
  }
}
Copy the code

Now the h function needs to be imported from vue

I actually have one chestnut on top that I’ve already used, so bring it back again

import { createApp, h } from 'vue' import App from './App.vue' import router from './router' import store from './store' createApp(App) Component (' test06 '{render () {return h (' div', {}, 'global components')}}). Use (store). Use (router). The mount (' # app)Copy the code

There is also a property change, directly take the official website chestnut

2. Format of node attributes in x

{
  class: ['button'.'is-outlined'].style: { color: '#34495E' },
  attrs: { id: 'submit' },
  domProps: { innerHTML: ' ' },
  on: { click: submitForm },
  key: 'submit-button'
}
Copy the code

In 3.0, these attributes are no longer nested and flattened (this looks more like DOM node stuff).

{
  class: ['button'.'is-outlined'].style: { color: '#34495E' },
  id: 'submit'.innerHTML: ' '.onClick: submitForm,
  key: 'submit-button'
}
Copy the code

Slot in

$scopedSlots is deprecated and $slots is used

In vue2. X, a component uses a render function to take slots like this

<script>
export default {
    render(h) {
        return h('div',{},this.$scopedSlots.default)
    },
}
</script>
Copy the code

This is true in vue3. X

<script>
import {h} from 'vue'
export default {
    props:{
        data:String
    },
    render() {
        return h('div',{},this.$slots.default())
    },
}
</script>
Copy the code

2.5 the Custom Elements

Custom element whitelist

Like some special components, we want special uses of vue to be ignored by the compiler

chestnuts

Put a registered component directly into the component

 <test08></test08>
Copy the code

If you don’t want this error, put it on the whitelist

Use build tool versions

rules: [
  {
    test: /\.vue$/,
    use: 'vue-loader'.options: {
      compilerOptions: {
        isCustomElement: tag= > tag === 'test08'}}}// ...
]
Copy the code

Runtime compilation version

const app = Vue.createApp({})
app.config.isCustomElement = tag= > tag === 'test08'
Copy the code

Is can only be used when<component>on

< Component :is=”componentId”>

Hence the INTRODUCTION of the V-IS instruction in VUe3

That’s it. That’s pretty much it. Can’t hold… Good night, good dream