先贴个官网,vue官网个人觉得比react易读点😂 vue3
相对vue2,vue3的一些不兼容改动:
被移除的 API
keyCode作为v-on修饰符的支持
比如<input v-on:keyup.enter="submit" />
改成了在 v-on 上使用按键修饰符
<input v-on:keyup.page-down="nextPage">
$on、$off和$once实例方法,主要是eventBus的使用- 过滤器 (
filter)用计算属性computed/方法method代替 $childrenproperty 已被移除,这里需要使用$refs$destroy实例方法。用户不应再手动管理单个 Vue 组件的生命周期。- 全局函数
set和delete以及实例方法$set和$delete。因为vue3用的绑定原理是Proxy
非兼容的变更 模板指令
- 组件上
v-model用法已更改,以替换v-bind.sync <template v-for>和非v-for节点上的key用法已更改- 在同一元素上使用的
v-if和v-for优先级已更改,vue3for优先,vue2if优先 v-bind="object"现在排序敏感,如下,vue2的id是red,vue3的排名是谁在后面就是谁
<div id="red" v-bind="{ id: 'blue' }"></div>
v-on:event.native修饰符已移除v-for中的ref不再注册 ref 数组
组件
- 只能使用普通函数创建函数式组件
functionalattribute 在单文件组件 (SFC) 的<template>和functional组件选项中被废弃- 异步组件现在需要使用
defineAsyncComponent方法来创建 - 组件事件现在需要在
emits选项中声明
渲染函数
- 渲染函数 API 更改.以前是形参h现在直接引入
import { h } from 'vue' $scopedSlotsproperty 已移除,所有插槽都通过$slots作为函数暴露$listeners被移除或整合到$attrs$attrs现在包含class和styleattribute
自定义元素
- 自定义元素检测现在在模板编译时执行
- 特殊的
isattribute 的使用被严格限制在被保留的<component>标签中
重点组合式API
在vue中创建名字为project项目通常有3种办法(cli4/5和vite还有vue ui图形化工具):
// vue cli创建,通常3的话不会用vli2,而是用4或者5
vue create project
// vite创建
npm init vite@latest project --template vue
yarn create vite project --template vue
pnpm create vite project -- --template vue
// vue-cli基于webpack构建,并且有一些默认的预设配置,在服务启动之前会把所有代码打包成bundle,
// 然后启动服务,提供给浏览器使用,所以vue-cli4在开发一些大型项目的时候,越到后面服务启动的越慢。
// vite为了解决服务器动慢的问题,使用的ESbuild预编译依赖,比JS编写的打包器构建依赖要快很多倍。
// 为了避免每次启动项目的时候要重建整个包,Vite把预构建的回来缓存到了node_modules/.vite。
组合式 API官网说法:将同一个逻辑关注点相关代码收集在一起,在setup中使用。
<template>
<!-- Teleport提供了一种允许我们控制在DOM中哪个父节点下渲染HTML,比如新手用户指导弹窗 -->
<teleport to="具体的元素上(dom,#id,.class)">
<view> 弹窗内容 </view>
</teleport>
<h1 ref="domref" class="props-color">{{ propsdata }}</h1>
<button class="count-color" @click="count++">count is: {{ count }}</button>
</template>
<script>
import { ref, reactive, onMounted, toRefs, computed, watch } from 'vue'
export default {
// // 父组件注册
// provide: {
// demo: 'haha'
// }
// // 或者main.js全局引入
// app.provide('guide', 'Vue3 guide') // 挂载前注入
// // 子组件拿到
// inject: {
// book: {
// from: 'guide'
// },
// demo: 'demo'
// },
props: {
propsdata: {
type: String,
required: true,
validator: value => {
return [
'syncing',
'synced',
'version-conflict',
'error'
].includes(value)
}
}
},
setup(props, context) {
// setup是在创建之前执行
// setup中除了没有beforeCreate和created生命周期,其他的生命周期都有
// 放在Vue2 created的数据交互请求一般会放在setup,这里执行完如果外层有beforeCreate,created就会去执行他们两个,再回来这里的onBeforeMount/onMounted然后再去执行外面的onBeforeMount/onMounted
// setup第一个参数是props,是响应式的,不能使用es6解构,否则消除prop的响应式
// setup中第二个参数是一个普通JS对象,暴露了其他可能在setup中有用的值,它是一个普通的JS对象,不是响应式的。可以使用es6解构
// 如果要解构prop,可以在setup函数中使用toRefs函数来完成操作
let { propsdata } = toRefs(props)
// ref()函数用来根据给定的值创建一个响应式的数据对象
// ref()函数调用的返回值是一个对象,这个对象上只包含一个value属性
const count = ref(1)
// 获取一个dom元素
const domref = ref(null)
const init = () => {
console.log('hello world init')
}
// 我们可以在setup里注册生命周期钩子函数,组合式API上的生命周期钩子函数不变,但是有前缀on,onMounted
onMounted(init)
// 独立的computed计算属性
// console.log(count.value)
const com = computed(() =>count.value * 2 )
// watch不用加on就可以使用,可以接收三个参数
watch(count, (newVal, oldVal) => {
console.log(count.value, newVal, oldVal)
})
// watch监听比较一个数组 或对象的值,这些值是响应式的,要求它有一个由值构成的副本,这里需要注意一下
const arr = reactive([1, 2, 3, 4])
watch(
() => [...arr],
(newValue, oldValue) => {
console.log(newValue, oldValue)
}
)
// 如果要为JS对象创建响应式状态,可以用reactive
const obj = reactive({ title: 'Vue3 Guide' })
// reactive用法与ref用法相似,也是将数据变成响应式数据,不同的是ref用于基本数据类型
// reactive用于复杂数据类型,reactive的转换是'深度转换',它会影响传递对象的所有嵌套property
// watch监听深度嵌套对象时,仍然需要使用deep选项设置为true
// deep监听的时候两个都是新值,没有旧值了
watch(
() => obj,
(newValue, oldValue) => {
console.log(newValue, oldValue)
},
{deep: true}
)
// 可以跟vue2中的data啊,method啊一起用
data() {
return {
color: 'red'
}
}
return {
count,
obj,
domref,
...
}
}
}
</script>
// 单文件组件组合式API语法糖 script setup,无需return
// 这里面的代码会在每次组件实例被创建的时候执行
// 任何在这声明的的顶层绑定(变量、函数,以及import引入的内容)都能在模板中直接使用
// <script setup>可以和<script>一起用
<script setup>
import { ref } from 'vue'
defineProps({
data: String// 这里接受参数
})
let theme = { color: 'green' }
// ref值在模板中使用会自动解构
const count = ref(0)
// defineExpose,父组件通过模板ref方式获取到当前组件的实例
defineExpose({
count
})
</script>
<style scoped>
/* 单文件组件状态驱动的 CSS 变量 (<style> 中的 v-bind) */
.props-color {
color: v-bind(color);
}
.count-color {
color: v-bind("theme.color");
}
</style>
vuex状态管理器从vuex3升级成了vuex4,不过推荐pinia
路由的修改:
创建从new Router()变成了createRouter
三个路由模式:
'history':createWebHistory()
'hash':createWebHashHistory()
'abstract':createMemoryHistory()
去掉*比如在router.push('/not/found/url')的时候
router.onReady()函数已被替换为router.isReady()不带任何参数并返回 Promise 的函数
transition现在keep-alive必须通过API在内部使用:RouterView v-slot
<router-view v-slot="{ Component }">
<transition>
<keep-alive>
<component :is="Component" />
</keep-alive>
</transition>
</router-view>
append to修改了
replace
<router-link to="child-route" append>to relative child</router-link>
with
<router-link :to="append($route.path, 'child-route')">
to relative child
</router-link>
mixin 中的导航守卫被忽略
router.match, 和router.resolve已合并在一起router.resolve
router.getMatchedComponents被删除,可以从以下位置检索匹配的组件router.currentRoute.value.matched
所有导航,包括第一个导航,现在都是异步的
parent删除,可以通过下面访问到
const parent = this.$route.matched[this.$route.matched.length - 2]
params如果定义了参数没有传参就会报错
// given the following route:
const routes = [{ path: '/users/:id', name: 'user', component: UserDetails }]
// Missing the `id` param will fail
router.push({ name: 'user' })
router.resolve({ name: 'user' })
具体路由变更可以参考官网