vue3新特性与Vue2对比

尤大大在今年春节时发布了Vite 2.0版本,为了紧跟尤大大的脚步,同时也是对前端主流框架之一的Vue.js的3.0版本的学习。
Vue3肯定是为了弥补上个版本的一些不足。但相比于Vue2,Vue3到底更新了什么呢?它有哪些新的特性?它相对于Vue2的优势是什么?Vue3如何进行使用?
本文就将带着大家提前体验一下Vue3,以上的问题也会一一得到解答,大家也可以从中感受一下Vue3的魅力。

新特性

Compossition API

setup 函数是 Compsition API 的入口函数,我们的变量、方法都是在该函数里定义的
<template>
  <p>{{ count }}</p>
  <p>{{msg}}-------{{doubuleConter}}</p>
  <p ref="desc"></p>
</template>

<script>
//从VUe中引入函数
import {ref, computed, onMounted, onUnmounted, reactive, toRefs, watch } from 'vue'

export default{
  setup(){
    //Count相关逻辑
    let {count,doubuleConter} = getCount()

    //ref声明单值响应式 
    const msg = ref('message')
    //ref也可对页面同值的ref元素引用
    const desc = ref(null)
    //监听
    watch(count,(val,oldval)=>{
      const p = desc.value
      p.textContent = `值从${oldval}to${val}`
    })
    return {
      count,
      doubuleConter,
      desc,
      msg
    }
  }
}
function getCount(){
  //reactive 可以创建响应式的对象
    const state = reactive({
      count: 0 ,
      //computed 计算属性
      doubuleConter:computed(()=>state.count * 2)
    })
    
    let timer
    onMounted(()=>{
      timer = setInterval(()=>{
        state.count++
      },1000)
    })
    onUnmounted(()=>{
      clearInterval(timer)
    })

    //toRefs可以对响应式的对象进行解构
    return toRefs(state) 
}

</script>

Teleport

传送门组件提供一种简洁的方式可以指定它里面内容的父元素。

<template>
  <div>
    <button @click="modalOpen = true">打开模态框</button>
    <teleport to="body">
      <div v-if="modalOpen" class="modal">
        <div>
          我是一个模态框 挂载在body下面
          <button @click="modalOpen = false">关闭</button>
        </div>
      </div>
    </teleport>
  </div>
</template>

<script>
import { ref } from "vue";
export default {
  setup() {
    const modalOpen = ref(false);
    return { modalOpen };
  },
};
</script>

<style scoped>
.modal {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  background-color: rgba(0, 0, 0, 0.5);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
}

.modal div {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  background-color: white;
  width: 300px;
  height: 300px;
  padding: 5px;
}
</style>

Fragments

vue3中组件可以拥有多个根

<template>
    <header>...</header>
    <main>...</main>
    <footer>...</footer>
</template>
  • Emits Compontent Option
    vue3中组件的发送的自定义事件需要在emits选项中:
    • 与原生事件重名会触发两次,比如click
    • 更好的指示组价工作方式
    • 对象形式事件校验
<template>
    <div @click="$emit('click')">
    	<p>自定义事件</P>
    </div>
</template>

<script>
export default{
  emits:['click']
}

</script>

自定义渲染器 Custom render

vue3中支持自定义渲染器(render):这个API可以用来自定义渲染逻辑。
createRender API用于创建自定义渲染器

破坏性变化

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

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

  • vue2中没有app概念,new Vue()得到的根实例被作为app,这样的话所有创建的根实例是共享相同的全局配置,这在测试时会污染其他测试用例,导致测试变得困难
  • 全局配置也导致没有办法在单页面创建不同全局配置的多个app实例。
    vue3使用createApp返回app实例,由它暴露一系列全局api
import { createApp }from "vue";
//实例方法自定义全局组件comp
const app = createApp({})
  .component("comp", { render: () => h("div", "i am comp") })
  .mount("#app");
2.x Global API3.x Instance API(app)
Vue.configapp.config
Vue.config.productionTip移除
Vue.config.ignoredElementsapp.config.isCustomElement
Vue.componentapp.component
Vue.directiveapp.directive
Vue.mixinapp.mixin
Vue.useapp.use
Vue.filter移除

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

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

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

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

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

受影响的api:

  • Vue.nextTick
  • Vue.observable
  • Vue.version
  • Vue.compile
  • Vue.set
  • Vue.delete

v-model使用变化

model选项和v-bind的sync修饰符被移除,统一为v-model参数形式。vue2中.sync和v-model功能有重叠,容易混淆,vue3做了统一.。

//父组件
<div>
	<p>{{ data }}</p>
	<comp v-model="data"></comp>
	<!-- 或者 -->
	<comp v-model:modelValue="data"></comp>
</div>

//子组件
<template>
  <div @click="$emit('update:modelValue', modelValue + 1)">
    data:{{ modelValue }}
  </div>
</template>
<script>
export default {
  props: {
    modelValue: {
      type: Number,
      default: 0,
    },
  },
};
</script>

子组件中的model选项移除

渲染函数API修改

渲染函数变得更简单好用了,主要有以下几点修改:

  • 不再传入h函数,需要手动导入
  • 拍平的props结构
  • scopedSlot删掉了,统一到slots

函数式组件仅能通过简单函数方式创建

函数式组件的变化主要有以下几点:

  • 性能提升在vue3中可忽略不计,所以vue3中推荐使用状态组件。
  • 函数时组件仅能通过纯函数形式声明,接受propscontext 两个参数。
  • SFC中 <template> 不能添加functional特性声明函数时组件。
  • {functional:true}组件选项移除。
<script>
import {h} from 'vue'
// 函数式组件
function Heading(props, context) {
  console.log(context);
  return h(`h${props.level}`, context.attrs, context.slots);
}
Heading.props = ["level"]
export default Heading
</script>

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

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

  • 必须明确使用defineAsyncComponent包裹
  • component选项重命名为loader
  • Loader函数不在接受resolve and reject 且必须返回一个Promise

定义一个异步组件,loader选项是以前的compontent

import { defineAsyncComponent } from 'vue'
const asyncPage = defineAsyncComponent({
    loader:()=>import('./NextPage.vue')),
    delay:200,
    timeout:3000,
    errorComponent:ErrorCompontent,
    loadingCompontent:LoadingCompontent
  }

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

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

createApp({
    data(){
        return {
            msg:'message'
        }
    }
}).mount('#app')

自定义组件白名单

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

export default defineConfig({
  vueCompilerOption:{
    isCustomElement:tag=>tag === 'plastic-button'
  }
})

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

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

<compentent is="comp"></compentent >

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

<table>
	<tr v-is="'comp'"></tr>
</table >

$scopedSlots属性被移除,都用¥slots代替

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

  • 插槽均以函数形式暴露
  • $scopedSlot移除

函数形式访问插槽内容:

<script>
import {h} from 'vue'
export default {
  props: {
    to: {
      type: String,
      required: true,
    },
  },
  render() {
    return h("a", { href: this.to }, this.$slots.default());
  },
};
</script>

注意修改$slots,xx 为 $slots.xx()

自定义指令API和组件一致

vue3中指令api和组件保持一致:

  • bind —> beforeMount
  • inserted —> mounted
  • beforeUpdate:new! 元素自身更新前调用,和组件生命周期钩子很像
  • update —> removed! 和update基本相同因此被移除,使用update代替。
  • componentUpdate —> undated
  • beforeUnmount new!和组件生命周期钩子相似,元素将要被移除之前调用。
  • unbind —> unmounted
<p v-highlight="'yellow'">自定义指令</p>
<script>
createApp(App).directive('highlight',{
    beforeMount(el,binding,vnode){
        el.style.background = binding.value
    }
}).mount('#app')
</script>

一些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不在支持 . 分隔符字符串表达式,使用计算属性作为其参数

this.$watch(() => this.foo.bar,(v1,v2) => {
	console.log(this.foo.bar)
})

其他小改变

  • 来自 mixin 的 data 选项现在为浅合并
  • <TransitionGroup> 不再默认渲染包裹元素
  • 当侦听一个数组时,只有当数组被替换时,回调才会触发,如果需要在变更时触发,则需要指定 deep 选项
  • 没有特殊指令的标记 (v-if/else-if/else、v-for 或 v-slot) 的 <template> 现在被视为普通元素,并将生成原生的 <template> 元素,而不是渲染其内部内容。
  • 在 Vue 2.x 中,应用根容器的 outerHTML 将替换为根组件模板 (如果根组件没有模板/渲染选项,则最终编译为模板)。Vue 3.x 现在使用应用容器的 innerHTML,这意味着容器本身不再被视为模板的一部分。

参考链接

移除API

  • 移除keyCode作为v-on修饰符
    vue2中可以使用keyCode指代某个按键,vue3不在支持
<!-- keycodee方式不再支持,可读性太差 -->
<input v-on:keyup.13="submit">
<!-- 只能使用alias方式 -->
<input v-on:keyup.enter="submit">
  • $on , $off and $once移除
    上述三个方法被移除,可以使用第三方库mitt实现
//创建emitter
const emitter = mitt()
//发送事件
emitter.emit('foo','fooooo')
//监听事件
emitter.on('foo',msg => console.log(msg))
  • Filter移除
  • 内联模板 attributes移除
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值