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 dataref
withreactive
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
- Unref, if the argument is a ref, returns the value attribute of the ref, otherwise returns itself
- ToRef, which creates a ref for the properties of a Reactive object
- ToRefs, which converts a reactive object into a normal object where each property is a ref
- IsRef, to determine if a value isRef
- IsProxy, which determines whether an object is created by
reactive
orreadonly
Method to create an agent. - IsReactive: checks whether an object is created by
reactive
Create a responsive proxy - IsReadonly: checks whether an object is created by
readonly
The 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