相干库版本要求
- 脚手架 Vue CLI
v4.5
或 Vite - Vue Router
v4.0
- Vuex
v4.0
- Element Plus 地址:https://element-plus.gitee.io...
- Ant Design
v2.0
地址:https://2x.antdv.com/ 可能须要手动装置的插件
@vue/compiler-sfc
^3.0.7- ...
构建
npm i -g @vue/clivue create <Project Name> // 抉择装置配置后实现// 或者采纳可视化构建形式vue ui
迁徙
将所有库更新到反对 Vue3
的版本后,执行 npm i
装置依赖,接下须要手动更改各项 API 调用以及插件的装置形式。
全局 API 的更换
入口文件 main.js
:
// Vue2.x,vue实例形式为应用 Vue 构造函数实例化import Vue from 'vue'import App from './App.vue'import router from '@/router'new Vue({ router, render: h => h(App)}).$mount('#app')
// Vue3.0,调用 createApp 办法创立实例import { createApp } from "vue"; // 从vue模块引入的不再是一个构造函数,而是一个对象import App from './App.vue'import router from "@/router";const app = createApp(App);app .use(router) .mount("#app");
路由 @/router/index
// 联合 Vue2.x 版本的 router 创立形式是基于构造函数 Router 的实例化,并import Vue from 'vue'import Router from 'vue-router'Vue.use(Router) // 须要调用 构造函数Vue的静态方法use装置一次,将router提供的办法和属性挂载到 Vue 原型上const router = new Router({ ...})
// Vue3.0,同样相似的形式,vue-router 模块裸露进去的为一个对象而不再是一个构造函数,须要调用外面的 createRouter 办法创立 routerimport { createRouter } from "vue-router";// 无需再调用Vue.use 装置插件const router = createRouter({routes:[...]})
Vuex @/store/index.js
// Vue2.x 装置形式import Vue from 'vue'import Vuex from 'vuex'Vue.use(Vuex)const store = new Vuex.Store({...})
// Vue3.0 装置形式import { createStore } from "vuex";const store = createStore({...});
Vue.prototype
=> app.config.globalProperties
Vue2.x 最罕用的全局变量设置是通过在构造函数 Vue
的原型上挂上罕用的属性和办法
let someProps = 'some things'Vue.prototype.$someProps = someProps// 组件中拜访console.log(this.$someProps); // 'some things'// 通过原型拜访import Vue from 'vue'console.log(Vue.prototype.$someProps); // 'some things'
比照 Vue3.0 应用 app.config.globalProperties
main.js
import { createApp } from 'vue'const app = createApp()let someProps = 'some things'app.config.globalPropertis.$someProps =someProps...export defaul app; // 须要将 app 实例裸露进来
// 通过调用 API 获取以后实例拜访全局 propertyimport { getCurrentInstance } from "vue";const currentInstance = getCurrentInstance(); //获取以后实例console.log(currentInstance.appContext.config.globalProperties)// 组件中通过 this 拜访 全局 property// SomeComp.vueconsole.log(this.$someProps) // 'some things'// 通过引入实例拜访import app from '@/main.js'console.log(app.config.globalProperties.$someProps); // 'some things'
留神: 通过引入实例拜访是须要与我的项目的 app 根实例建立联系,而并非从新创立 app 实例,因而在 main.js
入口文件处要将 app 对外裸露。
Provide / Inject
跨层级组件传值个别不用用全局属性时,能够思考到 provide
/ inject
// Provide.vueimport { provide } from "vue";setup() { let str = "provide str"; provide("str", str);}
// Inject.vueimport { inject } from "vue";setup() { let injectStr = inject("str"); console.log(injectStr); // 'provide str' }
组件注册
// Vue2.x 注册形式import Vue from 'vue'import someComp from './someComp.vue'Vue.component('SomeComp',someComp)
//比照 Vue3.x 注册import { createApp } from 'vue'import someComp from './someComp.vue'const app = createApp()app.component('SomeComp',someComp)
自定义插件装置
// somePlugin.jsexport default { install(Vue,config){ ... Vue.prototype.$pluginHandler = ()=>{...} }}// main.jsimport Vue from 'vue'import somePlugin from './somePlugin.js'Vue.use(somePlugin)
比照 Vue3.0
// somePlugin.jsexport default { install(app){ //通过参数 app 传递实例的援用 ... app.config.globalProperties.$pluginHandler = ()=>{...} }}// main.jsimport { createApp } from 'vueimport somePlugin from './somePlugin.js'const app = createApp()app.use(somePlugin)
小结
全局 API 组织形式的重构(由从原型上共享改为以模块裸露)的益处:
- 联合 Treeshaking 和便于打包工具确定依赖关系,将无用的内容去除,按需输出,失去体积更小的生产包。
- 在须要不同的独立的 Vue 实例场景下,以在原型上操作的形式,仍然会使不同实例之间内容产生分割,因而取代的新形式将实现这种隔离。
新个性
组合式 API setup
Vue2.x 组件构造可能会相似如下:
// src/components/SomeComp.vueexport default { data:()=>({ res1:[], res2:[], res3:[] }) , methods: { handler1(){ // ... // 解决失去数据并赋值给 res1 }, handler2(){ // ... // 解决失去数据并赋值给 res2 }, handler3(){ // ... // 解决失去数据并赋值给 res3 } },}
官网给图:
Vue3.0 应用 setup
将相干逻辑组织在一块,便于解读、保护。
export default { setup(props,context){ // ----------业务逻辑1------------ const res1 = ref([]) const handler1 = ()=>{ // ... // 解决失去数据并赋值给 res1 } // ----------业务逻辑2------------ const res2 = ref([]) const handler2 = ()=>{ // ... // 解决失去数据并赋值给 res2 } // ----------业务逻辑3------------ const res3 = ref([]) const handler3 = ()=>{ // ... // 解决失去数据并赋值给 res3 } // -------将属性裸露给组件--------- return { res1, handler1, res2, handler2, res3, handler3 } }}
在 setup
中注册 生命周期钩子
可将须要在某个生命周期执行的办法,在对应的钩子注册办法通过回调传入,届时会在对应的生命周期所触发。
import { onBeforeMount, onMounted } from 'vue'export default { setup(){ onBeforeMount(()=>{ conosle.log('onBeforeMount') }) onMounted(()=>{ conosle.log('onMounted1') }) onMounted(()=>{ conosle.log('onMounted2') }) }}
watch
、computed
新的用法
import { watch , computed } from 'vue'export default { props: { someProp: { default: () => 0, type: Number, }, }, setup(props) { const { someProp } = toRefs(props); watch(someProp, (newValue) => { console.log(newValue); }); let computedVal = computed(() => someProp.value * 10); return { computedVal, }; }};
响应性 API
reactive
以援用类型的数据创立一个响应式对象,即以组件data()
返回的对象创立响应式的原理。ref
以根底类型的数据创立响应式对象,并会将原始值包裹在一个对象的value
属性下。(测试发现其实也能够依据援用类型创立,但响应性不高)toRefs
将响应式对象转换为一般对象(不便解构获取值),并且后果中的每个property
放弃对响应式对象的指向。若不必该办法转换,取到的值将不具备响应性,也不为ref
。
import { reactive, ref } from "vue";export default { setup() { // let num = 0; // 视图不更新 let num = ref(0); // 视图更新 setInterval(() => {num.value++ }, 500); // let obj = { num: 0 }; // 视图不更新 let obj = reactive({ num: 0 }); // 视图更新 setInterval(() => { obj.num++; console.log(obj); // 数据更新 }, 500); // let { time } = foo; // 视图不更新 let { time } = toRefs(foo); setInterval(() => { time.value = Date.now(); console.log(time.value === foo.time); // true }, 1000); return { num, obj }; }};
异步更改响应式对象进行视图更新时,须要留神:将 已裸露的属性 指向 新的响应式对象 是有效的操作,要响应则须要间接对 在 setup 阶段裸露的响应式对象 进行操作。
import { reactive, ref } from "vue";export default{ setup(){ let arr = reactive([]) setInterval(()=>{ // arr = [1,2,3] // 不更新 // arr = reactive([1,2,3]) // 不更新 arr.push(1,2,3) // 更新 },1000) // 或者外面包一层,并在该对象在属性节点上进行从新指向的形式 let obj = reactive({ arr:[] }) setInterval(()=>{ obj.arr = [1,2,3] // 更新 },1000) // 但在第二种形式下,以构造的形式拜访属性尽管没有问题,但勿在解构赋予的变量上做雷同的错误操作。例如: let { arr } = obj setInterval(()=>{ arr = reactive([1,2,3]) // 模板上的{{ arr }}是obj.arr,此时指向了新的响应式对象,因而不会更新 },1000) export { arr, obj } }}