1、vue3变化
-
新增了三个组件:
Fragment
支持多个根节点、Suspense
可以在组件渲染之前的等待时间显示指定内容、Teleport
可以让子组件能够在视觉上跳出父组件(如父组件overflow:hidden)。 -
新增指令
v-memo
,可以缓存 html 模板,比如 v-for 列表不会变化的就缓存,简单说就是用内存换时间。 -
新增
Composition API
可以更好的逻辑复用和代码组织,同一功能的代码不至于像以前一样太分散,虽然 Vue2 中可以用 minxin 来实现复用代码,但也存在问题,比如方法或属性名会冲突,代码来源也不清楚等。 -
用
Proxy
代替 Object.defineProperty 重构了响应式系统,可以监听到数组下标变化,及对象新增属性,因为监听的不是对象属性,而是对象本身,还可拦截 apply、has 等13种方法。 -
重构了虚拟 DOM,在编译时会将事件缓存、将 slot 编译为 lazy 函数、保存静态节点直接复用(静态提升)、以及添加静态标记、Diff 算法使用 最长递增子序列 优化了对比流程,使得虚拟 DOM 生成速度提升
200%
。 -
支持在
<style></style>
里使用v-bind
,给 CSS 绑定 JS 变量(color: v-bind(str)
)。 -
用
setup
代替了 beforeCreate 和 created 这两个生命周期。 -
新增了开发环境的两个钩子函数,在组件更新时
onRenderTracked
会跟踪组件里所有变量和方法的变化、每次触发渲染时onRenderTriggered
会返回发生变化的新旧值,可以让我们进行有针对性调试。
2、入口文件main.js
vue2
import Vue from 'vue'
import App from './App'
import store from './store'
import routes from './router'
Vue.config.productionTip = false
new Vue({
router,
store,
render: (h) => h(App)
}).$mount('#app')
vue3
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
createApp(App).use(store).use(router).mount('#app')
区别:vue2引入的是vue构造函数,vue3是createApp
工厂函数。vue2的写法在vue3不能兼容
3、支持碎片
在组件可以拥有多个根节点。
<template>
<div id="nav">
<router-link to="/">home</router-link>
</div>
<router-view/>
</template>
区别:vue2只能在在div根标签里面写东西,vue3可以有多个根标签
4、生命周期
(图来自网络)
由于vue3是向下兼容的,所以vue3中仍可以使用beforeCreate和created
注意:vue3中的生命周期需要从 vue 中导入
setup() {
onBeforeMount(() => {
console.log('onBeforeMount')
})
},
因为 setup
是围绕 beforeCreate
和 created
生命周期钩子运行的,所以不需要显式地定义它们。换句话说,在这些钩子中编写的任何代码都应该直接在 setup
函数中编写。
5、Composition API
vue2中使用OptionAPI
Options API缺点:只能固定用 data
、computed
、methods
等选项组织代码,在组件越来越复杂的时候,一个功能相关的属性和方法就会在文件上中下到处都有,很分散,变越来越难维护。虽然可以用 minxin
来做逻辑的提取复用,但是 minxin 里的属性和方法名会和组件内部的命名冲突,还有当引入多个 minxin 的时候,我们使用的属性或方法是来于哪个 minxin 也不清楚。
vue3Composition API
官网介绍:通过创建 Vue 组件,我们可以将界面中重复的部分连同其功能一起提取为可重用的代码段。仅此一项就可以使我们的应用在可维护性和灵活性方面走得相当远。
(图来自网络)
5.1、setUp
-
新的
setup
选项在组件创建之前beforeCreat之前执行,就将作为组合式 API 的入口。setup 函数只会在组件初始化的时候执行一次。因为setUp在beforeCreate之前执行,实例还没生成,所以在setUp中无法使用this
setup(props, context) { ... }
setUp接受两个参数:
-
props: 组件传入的属性,setup 中接受的
props
是响应式的, 当传入新的 props 时,会及时被更新。由于是响应式的, 所以不可以使用es6解构赋值,解构会消除它的响应式。如果需要解构可使用toRefs函数
import { toRefs } from 'vue' setup(props) { const { title } = toRefs(props) console.log(title.value) }
-
context:context 是一个普通 JavaScript 对象,不是响应式的所以可以使用 ES6 解构。context 对象有四个属性:
attrs
(等同于 $attrs)、slot
(等同于 $slots) 、emit
(等同于 $emit),expose
(暴露公共 property (函数))
5.2、响应性API reactive与响应性API ref
5.2.1、reactive
返回对象的响应式副本
使用步骤
-
从vue框架中导入
reactive
函数 -
在setup函数中调用reactive函数并将想要变成响应式的对象数据当成参数传入
-
在setup函数中把reactive函数调用完毕之后的返回值以对象的形式返回出去
import { reactive } from '@vue/reactivity';
export default {
setup() {
const obj = reactive({ count: 0 })
return {
obj
}
}
}
5.2.2、ref
接受一个内部值并返回一个响应式且可变的 ref 对象。ref 对象仅有一个 .value
property,指向该内部值。
使用步骤
-
从vue框架中导出
ref
函数 -
在setup函数中调用
ref
函数并传入数据(简单类型或者复杂类型) -
在setup函数中把ref函数调用完毕的返回值以对象的形式返回出去。
注意:在setup函数中使用ref结果,需要通过.value
访问,模板中使用不需要加.value
import { ref } from '@vue/reactivity';
export default {
setup() {
let money = ref(100)
console.log(money.value)
return {
money
}
}
}
5.2.3、reactive 对比 ref
(reactive
用于处理对象的双向绑定,ref
则处理 js 基础类型的双向绑定) (掘金)
ref与reactive的区别
-
ref用来定义:基本类型数据(ref可以定义对象或数组的,它只是内部自动调用了reactive来转换。)。
-
ref通过
Object.defineProperty()
的get
与set
来实现响应式(数据劫持)。 -
ref定义的数据:操作数据需要
.value
,读取数据时模板中直接读取不需要.value
。 -
reactive用来定义:对象或数组类型数据。
-
reactive通过使用Proxy来实现响应式(数据劫持), 并通过Reflect操作源代码内部的数据。
-
reactive定义的数据:操作数据与读取数据:均不需要
.value
。
5.2.4 toRef()函数
toRef()函数用于将一个 reactive 对象转化为属性全部为 ref 对象的普通对象,简单说就是对reavtive()函数解构返回。
setup() {
const data = reactive({
name: ['张三', '李四', '王五'],
selectName: '',
selectFn: (index:number) => {
data.selectName = data.name[index]
}
});
return {
...toRefs(data),
}
}
6、watch和watchEffect()
6.1、watch
watch
作用是对传入的某个或多个值的变化进行监听;触发时会返回新值和老值;也就是说第一次不会执行,只有变化时才会重新执行。
vue3的watch监听单个值:
import {watch} from 'vue' // vue3使用watch必须先引用
watch(a, (newVal, oldVal) => {
console.log(newVal, '===', oldVal)
})
wacth函数接收两个参数,第一个参数是我们要检测的值,第二个是回调函数,和以前一样拥有新旧两个值。
vue3的watch同时监听多个值:
import {watch} from 'vue'
watch([a, b], ([newValA, newValB], [oldValA, oldValB]) => {
console.log(newValA, newValB, '===', oldValA, oldValB)
})
注意:watch只能监听,1:拥有getter/setter属性的值。2:一个ref属性,也就是通过ref()申明的数据。3:一个reactive()函数返回的对象。4:一个数组。 所以监听reactive()函数定义的将会直接报错。
如果想要监听reactive函数声明的值,可以通过一个函数直接return回来一个新值
const data = reactive({
name: '张三',
age: 1
})
watch(() => data.age, ([newValA, newValB], [oldValA, oldValB]) => {
console.log(newValA, newValB, '===', oldValA, oldValB)
})
6.2、watchEffect
官方解释:立即执行传入的一个函数,同时响应式追踪其依赖,并在其依赖变更时重新运行该函数。
const count = ref(0)
watchEffect(() => console.log(count.value))
setTimeout(() => {
count.value++
}, 100)
watchEffect
是传入一个立即执行函数,所以默认第一次也会执行一次;不需要传入监听内容,会自动收集函数内的数据源作为依赖,在依赖变化的时候又会重新执行该函数,如果没有依赖就不会执行;而且不会返回变化前后的新值和老值
6.3、watch和watchEffect共享的行为
watch与 watchEffect共享停止侦听,清除副作用 (相应地 onInvalidate
会作为回调的第三个参数传入)、副作用刷新时机和侦听器调试行为。