VUE3.0笔记2

Global API改为应用程序实例调用

vue2中有很多全局api可以改变vue的行为,比如vue.compenent等。这导致一些问题:

  • vue2中没有app概念,new Vue()得到的根实例被作为app,这样的话所有创建的根实例是共享相同的全局配置,这在测试时会污染其他测试用例,导致测试变得困难。
  • 全局配置也导致没有办法再单页面创建不同全局配置的多个app实例。
    vue3中使用createApp返回app实例,由它暴露一些列全局api
    main.js
createApp(App)
.component('comp',{
    render(){
        return h('div','I am comp')
    }
})
.mount('#app')

然后helloapp.vue添加该组件

<comp></comp>
2.x Global API3.x Instance API(app)
Vue.configapp.config
Vue.config.productionTipremove
Vue.config.ignoredElementsapp.config.isCustomElement
Vue.componentapp.component
Vue.directiveapp.directive
Vue.mixinapp.mixin
Vue.useapp.use
Vue.filterremoved

Global and internal APIs重构为可做摇树优化

vue2中不少global-api是作为静态函数直接挂在构造函数上的,例如vue.nextTick(),如果我们从未在代码中用过它们,就会形成所谓的dead code,这类global-api造成的dead code无法使用webpack的tree-shaking排除掉。

import Vue from 'vue'
Vue.nextTick(() =>{
})

vue3中做了相应的变化,将他们抽取成为独立函数,这样打包工具的摇树优化可以将这些dead code排除掉。

import {nextTick} from 'vue'
nextTick(() =>{
})

受影响api:

  • vue.nextTick
  • vue.observable(replaced by vue.reactive)
  • vue.version
  • vue.compile(only in full builds)
  • vue.set(兼容版本)
  • vue.delete(兼容版本)

model选项和v-bind的sync修饰修饰符被移除,统一为v-model参数形式

vue2.0中.sync和v-model功能有重叠,容易混淆,vue3做了统一。
HelloWorld.vue

<template>
  <h1>{{ msg }}</h1>
  <button @click="count++">count is: {{ count }}</button>
  <p>
    Edit <code>components/HelloWorld.vue</code> to test hot module replacement.
  </p>
  <p>Hello,vite!!!</p>
  <!-- Composition -->
<Composition></Composition>
<!-- Teleport:ModalButton -->

<ModelButton></ModelButton>
<EmitsComponent @my-click="onClick"></EmitsComponent>
<!-- 实例方法组件定义 -->
<comp></comp>
<!-- v-model的使用 -->
<VmodelTest v-model:counter="counter"></VmodelTest>
<!-- v-model等效于 -->
<!-- <VmodelTest :counter="counter" @update:counter="counter=$event"></VmodelTest> -->
</template>

<script>
import {
  computed,
  reactive,
  onMounted,
  onUnmounted,
  ref,
  toRefs,
  watch,
} from "vue";
import Composition from './Composition.vue';
import ModelButton from './ModelButton.vue';
import EmitsComponent from './EmitsComponent.vue'
import VmodelTest from './VmodelTest.vue'
export default {
  components: { Composition,ModelButton,EmitsComponent,VmodelTest},
  name: "HelloWorld",
  props: {
    msg: String,
  },
  data(){
    return {
      counter:1
    }
  },
  methods:{
    onClick(){
      console.log('click me!');
    }
  }
  
};

</script>

VmodelTest.vue

<template>
    <div @click="$emit('update:counter',counter+1)">
         counter:{{counter}}
    </div>
</template>

<script>
export default {
   props: {
       counter: {
           type: Number,
           default: 0
       },
   },
}
</script>

<style lang="scss" scoped>

</style>

渲染函数API修改

变简单,主要修改有以下几点
不再传入h函数,需要我们手动导入;拍平的props结构。scopedSlots删掉了,统一到slots

<template>
  <h1>{{ msg }}</h1>
  <button @click="count++">count is: {{ count }}</button>
  <p>
    Edit <code>components/HelloWorld.vue</code> to test hot module replacement.
  </p>
  <p>Hello,vite!!!</p>
  <!-- Composition -->
<Composition></Composition>
<!-- Teleport:ModalButton -->

<ModelButton></ModelButton>
<EmitsComponent @my-click="onClick"></EmitsComponent>
<!-- 实例方法组件定义 -->
<comp></comp>
<!-- v-model的使用 -->
<VmodelTest v-model:counter="counter"></VmodelTest>
<!-- v-model等效于 -->
<!-- <VmodelTest :counter="counter" @update:counter="counter=$event"></VmodelTest> -->

<!-- render api发生变化 -->
<RenderTest v-model:counter="counter">
  <template v-slot:default>title</template>
  <template v-slot:content>content...</template>

</RenderTest>
</template>

<script>
import {
  computed,
  reactive,
  onMounted,
  onUnmounted,
  ref,
  toRefs,
  watch,
  h
} from "vue";
import Composition from './Composition.vue';
import ModelButton from './ModelButton.vue';
import EmitsComponent from './EmitsComponent.vue'
import VmodelTest from './VmodelTest.vue'
export default {
  components: { Composition,ModelButton,EmitsComponent,VmodelTest,
  RenderTest:{
    props: {
      counter: {
        type: Number,
        default: 0
      },
    },
    render(){
      // 以前写法 ,现在作用域插槽被废除
      // this.$scopedSlots.content()
      this.$slots.default();
      this.$slots.content();
      return h('div',[
        h('div',{onClick:this.onClick},[
          `I am RenderTest: ${this.counter}`,
          this.$slots.default(),
          this.$slots.content()
        ]),
      ]);
    },
    methods:{
      onClick(){
         this.$emit('update:counter',this.counter+1)
      }
    }
  }},
  name: "HelloWorld",
  props: {
    msg: String,
  },
  data(){
    return {
      counter:1
    }
  },
  methods:{
    onClick(){
      console.log('click me!');
    }
  }
  
};

</script>

函数式组件仅通过简单函数方式创建,functional选项废弃

函数式组件变化较大,主要有以下几点

  • 性能提升在vue3中可忽略不计,所以vue3.0中推荐使用状态组件
  • 函数时仅能够通过纯函数形式声明,接受props和context两个参数
  • SFC中不能添加functional特性声明函数是组件
  • {functional:true}组件选项移除
    Functional.vue或者js

<script>
import { h } from '@vue/runtime-core'
// 也可以是js
// vue3中函数式组件只能用函数方式声明
// 到处function
function Heading(props,context){
    console.log(context);
    return h(`h${props.level}`,context.attrs,context.slots)
}
//验证或者声明还可以通过静态属性
Heading.props=["level"]
export default Heading
</script>

<style lang="scss" scoped>

</style>

插入以下到helloapp.vue标签下

<!-- 函数式组件 -->
<Functional level='3'>这是一个动态的h元素</Functional>

异步组件要求使用defineAsyncComponent方法创建

由于vue3中函数式组件必须定义为纯函数,异步组件定义时,异步组件定义时有如下变化:

  • 必须明确使用defineAsyncComponent包裹
  • component选项重命名为loader
  • Loader函数不在接收resolve and reject且必须返回一个Promise
  AsyncComp: defineAsyncComponent(()=> import('./NextPage.vue')),

带配置的异步组件,loader选项是以前的component(仅此一点变化)

组件data选项应该总是声明函数

vue3中的data选项统一为函数形式,返回响应式数据

createApp({
   data(){
   return{
     apiKey:'alb2c3'
     }
     }
     }).mount('#app')

自定义组件白名单

vue3中自定义元素检测发生在模板编译时,如果要添加一些vue之外的自定义元素,需要在编译器选项中设置isCustomElement选项
使用构建工具时,模板都会用到vue-loader预编译,设置它提供的compilerOptions即可
我们演示项目使用vite,在vite.config.js中配置vueCompilerOptions即可:
创建vite.config.js

module.exports={
    vueCompilerOptions:{
        isCustomElement:tag => tag ==='piechart'
    }
}

is属性仅限于用在component标签上

vue3设置动态组件时,is属性仅能用于component标签上

<Composition is="comp"></Composition>

dom内模板解析使用v-is代替

scopedSlots属性被移除,都用scopedSlots属性被移除,都用scopedSlotsslots代替

vue3中同意普通插槽和作用域插槽到$slots,具体变化如下

  • 插槽均以函数形式暴露
  • $scopedSlots移除
function Heading(props,context){
    console.log(context);
    return h(`h${props.level}`,context.attrs,context.slots)
}

自定义指令API和组件保持一致
vue3中指令api和组件保持一致,具体表现在:

  • bind-beforeMout
  • inserted - mounted
  • beforeUpdate:新的,元素自身更新前调用,和组件生命周期很像
  • componentUpdated->updated
  • beforeUnmount 新的和组件生命周期钩子相似,元素将要被移除之前调用。
  • unbind->unmounted
    (main.js)
createApp(App)
.component('comp',{
    render(){
        return h('div','I am comp')
    }
})
.directive('highlight',{
    beforeMount(el,binding,vnode){
        el.style.background=binding.value;
    }
})
.mount('#app')

(helloworld.vue)

<!-- 自定义指令 -->
<p v-highlight="'green'">highlight is here!!</p>

transition类名变更

  • v-enter -> v-enter-from
  • v-leave -> v-leave-from
<template>
    <div id="demo">
      <button @click="show=!show">Toggle</button>
      <transition name="fade">
          <p v-if="show">Hello</p>
      </transition>
    </div>
</template>

<script>
export default {
    data () {       
        return {
            show:true,
        }
    }
}
</script>

<style  scoped>
.fade-enter-active,
.fade-leave-active{
    transition: opacity 0.5s ease;
}
/* 淡入淡出 */
.fade-enter-from,
.fade-leave-to{
    opacity: 0;
}
</style>

组件watch选项和实例方法$watch不再支持点分隔符串路径

以.分割的表达式不再被watch支持,可以使用计算函数作为$watch参数实现

vue2.x中应用程序根容器outerHTML会被根组件替换(或被编译为template),vue3.x现在使用根容器的innerHTML取代

$on $off $once移除

上述3个方法被认为不应该由vue提供,可以使用第三方

<script src="https://unpkg.com/mitt/dist/mitt.umd.js"></script>

首先先安装mitt

npm i mitt -S
// 事件派发和监听
import mitt from 'mitt';

// 工厂函数  公用并且导出

export const emitter=mitt();

data里面的method

  methods:{  
    sendMsg(){
      emitter.emit('someEvent','foooo')
    }
  },

添加组件

<!--编程方式发送和监听事件  -->
<button @click="sendMsg">emit event</button>

同级的NextPage.vue接收事件

import {emitter} from './HelloWorld.vue'
export default {
   mounted(){
      emitter.on('someEvent',msg=>{
          console.log(msg);
      })
   }
  
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值