当前位置: 首页 > Web前端 > vue.js

Vue3.0升级及一些新特性

时间:2023-03-31 23:59:54 vue.js

相关库版本需要脚手架VueCLIv4.5orViteVueRouterv4.0Vuexv4.0ElementPlus地址:https://element-plus.gitee.io...AntDesignv2.0地址:https://2x.antdv.com/可能需要手动安装的插件@vue/compiler-sfc^3.0.7...buildnpmi-g@vue/clivuecreate//安装配置完成后选择Complete//或者使用可视化构建方式vueuimigration将所有库更新为支持Vue3的版本,执行npmi安装依赖,然后需要手动更改各种API调用和插件安装方式。全局API的替换入口文件main.js://Vue2.x,vue实例方法是使用Vue构造器实例化importVuefrom'vue'importAppfrom'./App.vue'importrouterfrom'@/router'newVue({router,render:h=>h(App)}).$mount('#app')//Vue3.0,调用createApp方法创建实例import{createApp}from"视图”;//从vue模块引入的不再是构造函数,而是一个对象importAppfrom'./App.vue'importrouterfrom"@/router";constapp=createApp(App);app.use(router).mount("#app");路由@/router/index//结合Vue2.x版本的路由器创建方法是基于构造器Router的实例化,而importVuefrom'vue'importRouterfrom'vue-router'Vue.use(Router)//需要调用Vue安装一次的静态方法use的构造函数,将router提供的方法和属性挂载到Vue原型上constrouter=newRouter({...})//Vue3.0,类似中这样,vue-router模块就被暴露为一个对象而不是构造函数。需要调用里面的createRouter方法createrouterimport{createRouter}from"vue-router";//不需要调用Vue.use安装插件constrouter=createRouter({routes:[...]})Vuex@/store/index.js//Vue2.x安装方法importVuefrom'vue'importVuexfrom'vuex'Vue.use(Vuex)conststore=newVuex.Store({...})//Vue3.0安装方法import{createStore}from"vuex";conststore=createStore({...});Vue.prototype=>app.config.globalPropertiesVue2.x最常用的全局变量设置是通过挂在构造函数的原型上Vue属性和方法让someProps='somethings'Vue.prototype.$someProps=someProps//访问组件中的console.log(this.$someProps);//'somethings'//通过原型访问importVuefrom'vue'console.log(Vue.prototype.$someProps);//'somethings'vs.Vue3.0useapp.config.globalPropertiesmain.jsimport{createApp}from'vue'constapp=createApp()letsomeProps='somethings'app.config.globalPropertis.$someProps=someProps...导出默认应用;//需要暴露app实例//通过调用API访问全局属性import{getCurrentInstance}from"vue"获取当前实例;constcurrentInstance=getCurrentInstance();//获取当前实例console.log(currentInstance.appContext.config.globalProperties)//在组件中通过this访问全局属性//SomeComp.vueconsole.log(this.$someProps)//'somethings'//通过导入Instanceaccessimportappfrom'@/main.js'console.log(app.config.globalProperties.$someProps);//'一些事情'注意:通过引入实例访问,需要与项目的app根实例建立连接,而不是重新创建app实例,所以app应该在main.js入口文件处对外暴露Provide/Inject跨层组件传值一般不需要使用全局属性,可以考虑provide/inject//Provide.vueimport{provide}from"vue";setup(){letstr="providestr";provide("str",str);}//Inject.vueimport{inject}from"vue";setup(){letinjectStr=inject("str");console.log(injectStr);//'providestr'}组件注册//Vue2.x注册importVuefrom'vue'importsomeCompfrom'./someComp.vue'Vue.component('SomeComp',someComp)//Vue3.x注册import{createApp}from'vue'importsomeCompfrom'./someComp.vue'constapp=createApp()app.component('SomeComp',someComp)自定义插件安装//somePlugin.jsexportdefault{install(Vue,config){...Vue.prototype.$pluginHandler=()=>{...}}}//main.jsimportVuefrom'vue'importsomePluginfrom'./somePlugin.js'Vue.use(somePlugin)vs.Vue3.0//somePlugin.jsexportdefault{install(app){//通过参数传递实例的引用app...app.config.globalProperties.$pluginHandler=()=>{...}}}//main.jsimport{createApp}from'vueimportsomePluginfrom'./somePlugin.js'constapp=createApp()app.use(somePlugin)总结了重构全局API组织的好处(从原型上的共享变为以模块的形式暴露):结合Treeshaking和便利的打包工具来确定依赖关系和去除无用的内容,按需输入,并获得更小的生产包。在需要不同的独立Vue实例的场景下,对原型的操作仍然会让不同实例的内容相关联,所以新的替换方式就实现了这一点。一种孤立。新功能复合APIsetupVue2.x组件结构可能如下所示://src/components/SomeComp.vueexportdefault{data:()=>({res1:[],res2:[],res3:[]}),methods:{handler1(){//...//处理数据并将其分配给res1},handler2(){//...//处理数据并将其分配给res2},handler3(){//...//处理数据赋值给res3}},}官方图解:Vue3.0使用setup将相关逻辑组织在一起,便于解释和维护。exportdefault{setup(props,context){//----------业务逻辑1------------constres1=ref([])consthandler1=()=>{//...//处理数据并赋值给res1}//----------业务逻辑2------------constres2=ref([])consthandler2=()=>{//...//处理数据并赋值给res2}//----------业务逻辑3-------------constres3=ref([])consthandler3=()=>{//...//处理数据并将其分配给res3}//-------将属性暴露给组件--------return{res1,handler1,res2,handler2,res3,handler3}}}在setup中注册生命周期钩子,在相应的钩子注册方法中通过回调来注册某个生命周期内需要执行的方法Passedin,到时候会在相应的生命周期中触发。import{onBeforeMount,onMounted}from'vue'exportdefault{setup(){onBeforeMount(()=>{conosle.log('onBeforeMount')})onMounted(()=>{conosle.log('onMounted1')})onMounted(()=>{conosle.log('onMounted2')})}}watch,computednewusageimport{watch,computed}from'vue'exportdefault{props:{someProp:{default:()=>0,类型:Number,},},setup(props){const{someProp}=toRefs(props);watch(someProp,(newValue)=>{console.log(newValue);});letcomputedVal=computed(()=>someProp.value*10);返回{计算值,};}};ReactiveAPIreactivecreateareactiveobjectwithreferencetypedata,即用组件data()返回的对象创建反应对象的原理。ref从底层数据类型创建一个反应对象,并将原始值包装在对象的value属性中。(测试发现也可以根据引用类型创建,但是响应性不高)toRefs将响应式对象转为普通对象(方便解构获取值),result中的每个属性维护一个指向响应对象的指针。如果不使用此方法进行转换,则获取的值将不会响应,也不会成为ref。import{reactive,ref}from"vue";exportdefault{setup(){//让num=0;//视图没有更新letnum=ref(0);//视图更新setInterval(()=>{num.value++},500);//让obj={num:0};//视图不更新letobj=reactive({num:0});//查看更新setInterval(()=>{obj.num++;console.log(obj);//数据更新},500);//让{时间}=foo;//视图未更新let{time}=toRefs(foo);setInterval(()=>{time.value=Date.now();console.log(time.value===foo.time);//true},1000);返回{num,obj};}};当异步更改反应对象以进行视图更新时,注意:将暴露的属性指向新的响应对象是无效操作。要响应,您需要直接对设置阶段暴露的反应对象进行操作。import{reactive,ref}from"vue";exportdefault{setup(){letarr=reactive([])setInterval(()=>{//arr=[1,2,3]//不要更新//arr=reactive([1,2,3])//不更新arr.push(1,2,3)//update},1000)//或者在外面包一层,把对象放在属性上node重新指向的方式letobj=reactive({arr:[]})setInterval(()=>{obj.arr=[1,2,3]//update},1000)//但是在第二个方式,虽然以结构方式访问属性没有问题,但是不要对解构赋值的变量进行同样的错误操作。例如:let{arr}=objsetInterval(()=>{arr=reactive([1,2,3])//模板上的{{arr}}是obj.arr,指向新的反应对象,所以它不会被更新},1000)export{arr,obj}}}