编程知识 cdmana.com

The changes of vue3

I'm reading through vue After the official website document of , I recorded the following as opposed to 2.x What's changed is .

1. Changes in creating application instances

It used to be like this :

let app = new Vue({
	// ... Some options 
	template: '',//  String template 
	render: h => h(App)//  In the case of a single file 
})
let vm = app.$mount('#app')
app === vm// true
 Copy code 

And now it's like this :

import { createApp } from 'vue'
import App from './App.vue'
let app = createApp({
    // ... Component options 
})
let app = createApp(App)//  In the case of a single file 
let vm = app.mount('#app')
app === vm // false
 Copy code 

The main reason for changing to this is to avoid to Vue The global configuration of affects every instance created .

2.data Options change

Previously, creating an instance without components can use objects , But now you can only use one function that returns the object .

3. Life cycle change

beforeDestroy=>beforeUnmount,destroyed=>unmounted, Two additional lifecycles have been added renderTracked and renderTriggered, Used to track virtual DOM To render .

4. Event monitoring supports multiple processing functions

stay 3.0 in v-on Instruction can bind multiple processing functions :

<button @click="one(),two(),three($event)"></button>
 Copy code 
export default {
    methods: {
        one(){},
        two(){},
        three(){}
    }
}
 Copy code 

When binding multiple functions, you must use the inline function call mode , That is, you cannot write only one function name .

5. The instance has one more data option :emits

The component can be explicitly declared to trigger , It's like props Same property , It can be a simple array of strings , It could be an object , alike , Object type can be used to define validation , How to use it is as follows :

export default {
    emits: ['change', 'select'],//  An array type 
    emits: {//  object type 
        change: null,//  There is no validation function 
        select: (arg) => {//  receive this.$emit('select', ..args) Of args Parameters 
            return true//  return true or false Represents whether the event parameter is valid , Can the verification event be triggered normally , But a warning message will pop up on the console 
        }
    },
    methods: {
        emit() {
            this.$emit('change')
            this.$emit('select', 1, 2, 3)
        }
    }
}
 Copy code 

The statement is optional .

6. Added v-is Instructions

This instruction is used to undertake 2.x Special in the version attributeis Part of the function of .

stay 2.x in is It can be used in two scenarios , One is for dynamic components component To switch the components to render , The second is used in the DOM Some of the template HTML The limitation of elements , such as ul Only in the elements li Elements , So when ul When using custom components in, the browser will consider it invalid , You can use is attribute :

<ul>
    <!--<my-component></my-component> x That's not good -->
    <li is="my-component"></li>
</ul>
 Copy code 

And in the 3.0 edition is Can only be used in component On , The above functions need to be used v-is Instead of :

<ul>
    <li v-is="'my-component'"></li>
</ul>
 Copy code 

Note that the single quotation marks above are required .

7. Undeclared emits

Because of the addition of similar props The option to emits, If some of the properties passed to the component are not in the props Statement , So you can go through $attrs Property to access , The same is true for event listeners :

<!-- Parent component -->
<sub-component @change="change" @select="select"></sub-component>
 Copy code 
//  Child components 
export default {
    emits: ['change'],
    created(){
        console.log(this.$attrs)// { onSelect: () => {}  }
    },
}
 Copy code 

in addition , stay 2.x These undeclared props or emits Will inherit directly to the root node of the component , such as :

<!-- Parent component -->
<sub-component class="warn"></sub-component>
 Copy code 
<!-- Child components -->
<div class="info"></div>
 Copy code 
<!-- Actual rendering results -->
<div class="info warn"></div>
 Copy code 

But in 3.x Components in support multiple root nodes , When multiple root nodes appear , Property will not be actively inherited , You need to manually bind components that need to inherit properties , If none of them are bound vue A warning will be given :

<template>
	<my-momponent class="bar" @change="change"></my-component>
</template>
 Copy code 
<template>
	<div v-bind="$attrs"></div>
	<div></div>
</template>
 Copy code 

8.v-model The change of

stay 2.x Custom for a component in v-model It's usually like this :

export default {
    model: {// v-model The default is to use the value Of prop And input event , You can use model Options to modify 
        prop: 'checked',
        event: 'change'
    },
    props: {
        checked: Boolean
    },
    methods: {
        emit() {
            this.$emit('change', true)
        }
    }
}
/*
<my-component v-model="checked"></my-component>
*/
 Copy code 

stay 3.x in v-model Command has one more parameter , such as :v-model:value="value", So there's no need to use model Options. ,vue It will be used directly value Property and event name update:value

export default {
    props: {
        checked: Boolean
    },
    methods: {
        emit() {
            this.$emit('update:checked', true)
        }
    }
}
/*
<my-component v-model:checked="checked"></my-component>
*/
 Copy code 

Of course, you can omit value, This defaults to binding to the modelValue Of prop On :

export default {
    props: {
        modelValue: Boolean
    },
    methods: {
        emit() {
            this.$emit('update:modelValue', true)
        }
    }
}
/*
<my-component v-model="checked"></my-component>
*/
 Copy code 

One advantage of this is that you can bind multiple v-model

export default {
    props: {
        modelValue: Number,
        checked: Boolean,
        value: String
    },
    methods: {
        emit() {
            this.$emit('update:modelValue', 1)
            this.$emit('update:checked', true)
            this.$emit('update:value', 'abc')
        }
    }
}
/*
<my-component v-model="count" v-model:checked="checked" v-model:value="value"></my-component>
*/
 Copy code 

The last point is 3.x Support customization v-model The embellishment of , Generally, the modifier can also be passed props Get , Then you can perform some corresponding data formatting operations according to whether the modifier exists or not :

/*
<my-component v-model.double="count" v-model:count2.double="count2"></my-component>
*/

export default {
    props: {
        modelValue: Number,
        count2: Number,
        modelModifiers: Object,//  Without parameters v-model Modifier data for , The name is modelModifiers, Object format :{double: true}, If the modifier does not exist; otherwise undefined
        count2Modifiers: Object//  Parameterized v-model The modifier data name for is : Parameters +"Modifiers", Object format :{double: true}, If the modifier does not exist; otherwise undefined
    },
    methods: {
        emit() {
            //  In this case, it can be based on modelModifiers and count2Modifiers To determine whether to do some data operations 
            this.$emit('update:modelValue', xxx)
            this.$emit('update:value', xxx)
        }
    }
}
 Copy code 

9. Response type provide/reject

provide/reject The default is not responsive , Parent component provide The value has changed. , Use of subcomponents reject Received values are not updated accordingly , stay 2.0 in , It's a lot of trouble to make it responsive , This is not the way to do it , Parent component count Changed the configuration of the subcomponents count It doesn't change :

<template>
	<div>{{count}}</div>
</template>
<script>
export default {
    inject: ['count']
}
</script>
 Copy code 
export default {
    provide() {
        return {
            count: this.count
        }
    },
    data: {
        count: 0
    }
}
 Copy code 

vue2.x There's a hint in the document :

Tips :provide and inject Binding is not responsive . This is intentional . However , If you pass in a listener object , So the object of property Still responsive .

The second half of the sentence I understand is if provide If the property value of the returned object is a responsive object , So it can be , such as :

export default {
    provide() {
        return {
            count: this.countObj
        }
    },
    data: {
        countObj: {
            value: 0
        }
    }
}
 Copy code 

If so, modify it countObj.value Value , The subcomponents are updated accordingly , But if you want to be as dependent as above count Value , Even if you use computed No way :

export default {
    provide() {
        return {
            count: this.countObj
        }
    },
    data: {
        count: 0
    },
    computed: {
        countObj() {
            return {
                value: this.count
            };
        }
    }
}
 Copy code 

Then you can only use watch and Vue.observable Method :

let countState = Vue.observable({ value: 0 });

export default {
    provide() {
        return {
            count: countState
        };
    },
    data: {
        count: 0
    },
    watch: {
        count(newVal) {
            countState.value = newVal
        }
    }
}
 Copy code 

But in 3.x It's relatively simple , You can use combination directly api Inside computed Method :

import {computed} from 'vue'

export default {
    provide() {
        return {
            count: computed(() => {
                return this.count
            })
        };
    },
    data: {
        count: 0
    }
}
 Copy code 

The latter ones need to be accessed when they are used in sub components count.value attribute .

10. Asynchronous component

stay 2.x in , Asynchronous components are generally defined as follows :

//  overall situation 
Vue.component('async-component', () => import('./my-async-component'))
//  Local 
{
    components: {
        'async-component': () => import('./my-async-component')
    }
}
 Copy code 

stay 3.x A new function is added in defineAsyncComponent To do this :

import { defineAsyncComponent } from 'vue'
const AsyncComp = defineAsyncComponent(() =>
  import('./components/AsyncComponent.vue')
)

//  overall situation 
app.component('async-component', AsyncComp)
//  In component 
{
    components: {
		'AsyncComponent': AsyncComp
    }
}
 Copy code 

11. transition class The change of

3.x and 2.x equally , There are still 6 individual class, The meaning is exactly the same , The only change is v-enter->v-enter-fromv-leave->v-leave-from Two names and enter-class->enter-from-classleave-class->leave-from-class Changes of two custom class names .

12. Custom instruction change

stay 2.x Provided in bindinsertedupdatecomponentUpdatedunbind Five instructions , stay 3.x There's a new , There are six in all :

beforeMount( The instruction is called when it is first bound to an element and has not yet been mounted on the parent component , Corresponding to bind, Used for some initialization operations )

mounted( Called when the parent component of a binding element is mounted , Corresponding inserted, however inserted Only the parent component is guaranteed to exist, but not necessarily be inserted into the document ,mounted It's not in the description )

beforeUpdate( Before the virtual node containing the component is updated, it is called. , Corresponding update

updated( The virtual nodes that contain the component and all the sub components of the component are updated after they are called , Corresponding componentUpdated

beforeUnmount( Call before unloading the parent component of the binding element. , Add hook for )

unmounted( Called when an instruction is unbound from an element and the parent component has been unloaded , Corresponding unbind

In general, the user-defined hook and vue Their life cycle hooks tend to be consistent .

13. newly added Teleport

stay 2.x There is a common pain point in the heart :

<div>
    <Dialog></Dialog>
    <Loading></Loading>
</div>
 Copy code 

There are two sub components in the above components , Like this pop-up window or loading Components generally want them DOM The node is directly attached to the body Under the element , In this way, it is easy to control the style, especially the level , But the actual rendering is here div Node under , Then you can only move these two components to the body Next , But logically, these two components belong to the component , That's why I'm not happy .

stay 3.x Added in teleport Components can be used to solve this problem :

<div>
    <teleport to="body">
    	<Dialog></Dialog>
    </teleport>
    <teleport to="#xxx">
    	<Loading></Loading>
    </teleport>
</div>
 Copy code 

Put the components that need to be mentioned to the outer layer directly into the teleport In the label , adopt to Property to specify the element to mount to ,to Can be a valid element query selector , such as id Selectors , Selectors, etc .

14. Changes in rendering functions

stay 2.x Use in render Function needs to use injection method to create virtual node , Examples are as follows :

Vue.component('my-component', {
    render(createElement) {
        return createElement('div', ' I am the text ')
    }
})
 Copy code 

stay 3.x Use in vue Object to implement the static method :

Vue.component('my-component', {
    render() {
        return Vue.h('div', ' I am the text ')
    }
})
 Copy code 

h Function to receive parameters and createElement Basic it is tagpropschildren, however props The structure has changed a lot , For example, event binding :

Vue.component('my-component', {
    render(createElement) {
        return createElement('div', {
            on: {
                'click': this.clickCallback
            }
        })
    }
})
Vue.component('my-component', {
    render() {
        return Vue.h('div', {
            onClick: this.clickCallback
        })
    }
})
 Copy code 

stay 2.x China does not support it. v-model,3.x China has already supported , Other changes have been significant , Readers need to understand it in detail , The official documentation for this section should be improved ,props We didn't see the specific description of , But the general change is more flattening , such as 2.x Structure :

{
  class: ['xxx', 'xxx'],
  style: { color: '#fff' },
  attrs: { id: 'xxx' },
  domProps: { innerHTML: 'xxx' },
  on: { click: onClick },
  key: 'xxx'
}
 Copy code 

stay 3.x It's like this :

{
    class: ['xxx', 'xxx'],
  	style: { color: '#fff' },
    id: 'xxx',
    innerHTML: 'xxx',
    onClick: onClick,
    key: 'xxx'
}
 Copy code 

15. Changes in plug-in development

stay 2.x To call a plug-in when it is registered in install Method Vue Objects and parameters , stay 3.x Because it will Vue The global properties and methods on are moved to the createApp Method app On , So you need to register plug-ins in the createApp After method execution , In addition, there will be some slight changes in the injection function .

16. Filter option removed

stay 3.x Methods can be used to implement this function in .

17. Change of response principle

as everyone knows , stay 2.x Is used in Object.defineProperty To achieve data response , stay 3.x By default ES6 Of Proxy To achieve , And in IE Use... On the browser Object.defineProperty To downgrade .

In addition to 3.x There are many ways to add response lines to data , such as :

//  Not the original value 
import {reactive} from 'vue'
//  Responsive state 
const state = reactive({
    count: 1
})

//  Original value 
import {ref} from 'vue'

//  Responsive state 
const count = ref(0)
console.log(count.value)
 Copy code 

In addition, it added computedwatch And so on , These methods are generally used in combination api In case of use .

18. New responsive and combined api

There are many articles about it in detail , You can search on the Nuggets or go to the official website , I won't go into details here .

19.ref The change of

stay 2.x in ref Is used to access component instances or DOM Attribute of element :

<div ref="div">
    <ul>
    	<li v-for="item in list" ref="liList"></li>
    </ul>
	<MyComponent ref="component"></MyComponent>
</div>
 Copy code 
export default {
    mounted() {
        console.log(this.$refs.div, this.$refs.component)
        console.log(this.$refs.liList)// liList It will automatically be an array 
    }
}
 Copy code 

When used in the loop ref It's not clear , In particular, there are nested loops , So in 3.x in ref Supports binding to a function :

<div ref="div">
    <ul>
    	<li v-for="item in list" :ref="setLiList"></li>
    </ul>
	<MyComponent ref="component"></MyComponent>
</div>
 Copy code 
export default {
    data() {
        return {
            liList: []
        }
    }
    mounted() {
        console.log(this.$refs.div, this.$refs.component)
        console.log(this.liList)
    },
    methods: {
        setLiList(el) {
            this.liList.push(el)
        }
    }
}
 Copy code 

20.Vue-Router change

vue-router Upgrade to a new version , The installation command is :npm install vue-router@4.

Let's take a look at a simple example 2.x and 3.x The difference between :

// 2.x
import Vue from 'vue'
import VueRouter from 'vue-router'
Vue.use(VueRouter)
const routes = [
    // ...
]
const router = new VueRouter({
    // ... Some options configuration 
    routes
})
const app = new Vue({
    router
}).$mount('#app')
 Copy code 
// 3.x
import Vue from 'vue'
import VueRouter from 'vue-router@4'
const routes = [
    // ...
]
const router = VueRouter.createRouter({
    // ... Some options configuration 
    routes
})
const app = Vue.createApp({})
app.use(router)
app.mount('#app')
 Copy code 

In addition to changes in the way routes are created , There are many other details , And how to use the api Use in , I haven't finished reading it , Please read by yourself vue-router file .

21.Vuex change

Except routing , Official state management library vuex The new version is also upgraded , install :npm install vuex@next --save.

Also take a very simple example to see the initialization changes :

// 2.x
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
const store = new Vuex.Store({
	state: {
        count: 0
    },
    mutations: {},
    actions: {},
    // ...
})
new Vue({
    store
})
 Copy code 
// 3.x
import {createApp} from 'vue'
import {createStore} from 'vuex'
const store = createStore({
    state() {
        return {
            count:0
        }
    },
    mutations: {},
    actions: {},
    // ...
})
const app = createApp({})
app.use(store)
 Copy code 

vuex Of api Basically no big change , You can learn more about how to work in combination api Use in .

22. List of other changes

  • $attrs It also includes class and style

  • Removed $children, To access the subcomponents, use the ref

  • Removed Vue Example of $on$emit$once Method , Before the common use of methods now need to implement their own or use other event Libraries :

    import Vue from 'vue'
    Vue.prototype.$bus = new Vue()
     Copy code 

    This common operation was completely wiped out , Because if you want to add global functions now, you need to use the globalProperties attribute :

    app.config.globalProperties.$bus = new OtherEvent()
     Copy code 
  • Support multiple root nodes :

    <template>
    	<div></div>
        <Header></Header>
    </template>
     Copy code 
  • some 2.x Overall situation api Use the export method instead , such as :import {nextTick} from 'vue', This can help build tools to get rid of useless code

  • Use template When the component is cycled ,key Property can be set directly in the template On the label :

    <template>
    	<template v-for="item in list" :key="item.id"></template>
    </template>
     Copy code 

Most of the above is in vue Also mentioned in the official upgrade guide , Those who are interested can also go directly to the official documents :v3.vuejs.org/guide/migra…, And the Chinese version :v3.cn.vuejs.org/guide/migra…, If there is any mistake, please point it out .

版权声明
本文为[Kobayashi on the street corner]所创,转载请带上原文链接,感谢
https://cdmana.com/2020/12/20201224152607747K.html

Scroll to Top