vue3.0 支持组件中使用多个根节点,可以减少节点层级深度,也希望开发者能够明确语义
vue3.0 删除了过滤器(filters),将不在支持,官方建议使用计算属性(computed)替换过滤器
vue3.0 暴露出很多 API 供开发者使用,可以根据需求,将所需要的 API 从 Vue 中导入。考虑到 tree-shaking,利用了 import 和 export 的语法,实现了按需打包模块的功能
vue3.0 中新增了一个新的全局 API createApp
,调用 createApp 返回一个应用实例,该应用实例暴露出来全局 API(vue3.0 将可以全局改变 Vue 行为的 API 从原来的 Vue 构造函数上转移到了实例上了)
//vue2.0创建
import Vue from 'vue'
import App from './App.vue'
Vue.config.productionTip = false
new Vue({
render: h => h(App),
}).$mount('#app')
//vue3.0创建
import { createApp } from 'vue'
import App from './App.vue'
createApp(App).mount('#app');
Object.defineProperty 只能监听到属性的读写,而 Proxy 除读写外还可以监听属性的删除,方法的调用等
vue2.0
数据响应式的原理是通过遍历 data 属性,利用 Object.definePrototype
将其转化成 setter/getter,在数据变动时发布消息给订阅者,触发相应的监听回调,由于 js 的限制,vue 不能检测数组和对象属性的添加和删除vue3.0
基于 Proxy
来做数据的劫持代理,可以原生支持到数组的响应式,不需要重写数组的原型,还可以直接检测数组和对象属性的新增和删除(解决了 vue2.0 不能检测数组和对象属性的添加和删除的问题)Vue 组合式 API:https://composition-api.vuejs.org/zh/api.html#setup
setup
setup 函数是一个新的组件选项,作为在组件内使用 Composition API 的入口函数,变量、方法都定义在该函数中
props
和 context
:
return
暴露出去,供 template 中使用<template>
<div>
{{ count }}
{{ obj.count }}
</div>
</template>
<script>
//引入需要的API
import { ref, reactive } from 'vue'
export default {
name: 'home',
setup() {
const count = ref(0)
export let obj = reactive({ count: 0 })
//通过return暴露出去,供template中使用
return {
count,
obj
}
}
}
</script>
<style scoped>
</style>
使用
export
暴露出去,供 template 中使用<template>
<div>
{{ count }}
{{ obj.count }}
</div>
</template>
<script setup>
//引入需要的API
import { ref, reactive } from 'vue'
//通过export暴露出去,供template中使用
export let num = ref(0)
export let obj = reactive({ count: 0 })
</script>
<style scoped>
</style>
reactive
reactive 接收一个普通对象然后返回该普通对象的响应式代理,创建一个响应式的数据对象
<template>
<div>
{{ obj.count }}
</div>
</template>
<script>
//引入需要的API
import { reactive } from 'vue'
export default {
name: 'home',
setup() {
//通过reactive定义响应式对象
const obj = reactive({ count: 0 })
//通过return暴露出去,供template中使用
return {
obj
}
}
}
</script>
ref
ref 接受一个参数值并返回一个响应式且可改变的 ref 对象。ref 对象拥有一个指向内部值的单一属性 .value
<template>
<div>
{{ count }}
</div>
</template>
<script>
//引入需要的API
import { ref } from 'vue'
export default {
name: 'home',
setup() {
//通过ref定义响应式对象
const count = ref(0)
//通过value属性访问值
console.log(count.value) //0
//通过return暴露出去,供template中使用
return {
count
}
}
}
</script>
toRef
toRef 可以用来为一个 reactive 对象的属性创建一个 ref,这个 ref 可以被传递并且能够保持响应性(将 reactive 对象中的某个值转化为响应式数据)
<script>
//引入需要的API
import { reactive, toRef } from 'vue'
export default {
name: 'home',
setup() {
//通过reactive定义响应式对象
const obj = reactive({ count: 0, name: '廊坊吴彦祖' })
//通过toRef将obj中的count属性创建为ref
const count = toRef(obj, 'count')
//通过return暴露出去,供template中使用
return {
obj,
count
}
}
}
</script>
与 ref 的区别:
<script>
//引入需要的API
import { toRef } from 'vue'
export default {
name: 'home',
setup() {
const obj = { count: 0, name: '廊坊吴彦祖' }
//通过toRef将obj中的count属性创建为ref
const count = toRef(obj, 'count')
setTimeout(() => {
//改变count的值
count.value = 1
//obj中的count和count都变成了1,但是视图还是显示0,没有变化
console.log(obj.count, count) //1, 1
}, 2000);
//通过return暴露出去,供template中使用
return {
obj,
count
}
}
}
</script>
toRefs
toRefs 把一个响应式对象转换成普通对象,该普通对象的每个属性都是一个 ref ,和响应式对象属性一一对应(将 reactive 对象中的所有值转化为响应式数据)
<script>
//引入需要的API
import { reactive, toRefs } from 'vue'
export default {
name: 'home',
setup() {
//通过reactive定义响应式对象
const obj = reactive({ count: 0, name: '廊坊吴彦祖' })
//通过toRefs将obj中的所有属性创建为ref
const refObj = toRefs(obj)
console.log(refObj)
//通过return暴露出去,供template中使用
return {
obj,
refObj
}
}
}
</script>
readonly
readonly 传入一个对象(响应式或普通)或 ref,返回一个原始对象的只读代理(无法修改)
<template>
<div>
{{ count }}
</div>
</template>
<script>
//引入需要的API
import { readonly } from 'vue'
export default {
name: 'home',
setup() {
//通过readonly定义只读对象
const count = readonly(0)
count.value++ //修改报错!Cannot create property 'value' on number '0'
//通过return暴露出去,供template中使用
return {
count
}
}
}
</script>
computed
computed(计算属性)传入一个 getter 函数,返回一个默认不可手动修改的 ref 对象,使用和 vue 2.0 区别不大
<template>
<div>
{{ count }}
{{ addCount }}
</div>
</template>
<script>
//引入需要的API
import { ref, computed } from 'vue'
export default {
name: 'home',
setup() {
//通过ref定义响应式对象
const count = ref(0)
//通过computed方法实现计算属性
const addCount = computed(() => count.value + 1)
console.log(addCount.value) //1
//通过return暴露出去,供template中使用
return {
count,
addCount
}
}
}
</script>
watch
watch(侦听器)需要侦听特定的数据源,并在回调函数中执行副作用,使用和 vue 2.0 区别不大
<script>
//引入需要的API
import { ref, reactive, watch } from 'vue'
export default {
name: 'home',
setup() {
//通过ref定义响应式对象
const count = ref(0)
//通过watch方法实现对count的数据侦听
watch(count, (newVal, oldVal) => {
console.log('newVal:' + newVal)
console.log('oldVal:' + oldVal)
})
//通过reactive定义响应式对象
const obj = reactive({ count: 0 })
//通过watch方法实现对obj.count的数据侦听
watch(() => obj.count, (newVal, oldVal) => {
console.log('newVal:' + newVal)
console.log('oldVal:' + oldVal)
})
//通过watch方法实现同时对count和obj.count的数据侦听
watch([count, () => obj.count], ([newVal1, oldVal1], [newVal2, oldVal2]) => {
console.log('newVal1:' + newVal1)
console.log('oldVal1:' + oldVal1)
console.log('newVal2:' + newVal2)
console.log('oldVal3:' + oldVal2)
})
//通过return暴露出去,供template中使用
return {
count,
obj
}
}
}
</script>
watchEffect
watchEffect 立即执行传入的一个函数,并响应式追踪其依赖,并在其依赖变更时重新运行该函数
//watchEffect方法返回stop方法,执行该方法停止侦听
const stop = watchEffect(() => {
......
})
//停止侦听
stop()
与 watch 的区别:
<script>
//引入需要的API
import { ref, reactive, watchEffect } from 'vue'
export default {
name: 'home',
setup() {
//通过ref定义响应式对象
const count = ref(0)
//通过reactive定义响应式对象
const obj = reactive({ count: 0 })
//通过watchEffect方法实现数据侦听(只能得到变化后的值)
watchEffect(() => {
console.log(count.value)
console.log(obj.name)
})
//通过return暴露出去,供template中使用
return {
count,
obj
}
}
}
</script>
模板 Refs
使用组合式 API 时,reactive refs 和 template refs 的概念已经是统一的。为了获得对模板内元素或组件实例的引用,需要在 setup() 中声明一个值为 null 的 ref 并返回它
<template>
<div ref="box"></div>
</template>
<script>
//引入需要的API
import { ref, onMounted } from 'vue'
export default {
name: 'home',
setup() {
//通过ref(null)获取指定元素
const box = ref(null)
onMounted(() => {
console.log(box.value) //
})
//通过return暴露出去,供template中使用
return {
box
}
}
}
</script>
vue3.0 生命周期部分有所变化(setup 函数代替了 beforeCreate 和 created 两个生命周期函数,在生命周期 beforeCreate 之前被调用)
vue 2.0 | vue3.0 |
---|---|
beforeCreate | setup |
created | setup |
beforeMount | onBeforeMount |
mounted | onMounted |
beforeUpdate | onBeforeUpdate |
updated | onUpdated |
beforeDestory | onBeforeUnmount |
destoryed | onUnmounted |
使用 vue3.0 的生命周期,同样需要先从 vue 中导入,再在 setup 函数中使用
<script>
//引入生命周期
import { onBeforeMount, onMounted, onBeforeUpdate, onUpdated, onBeforeUnmount, unMounted } from 'vue'
export default {
name: 'home',
setup() {
//组件挂载前
onBeforeMount(() => {
......
})
//组件挂载前后
onMounted(() => {
......
})
//组件更新前
onBeforeUpdate(() => {
......
})
//组件更新后
onUpdated(() => {
......
})
//组件销毁前
onBeforeUnmount(() => {
......
})
//组件销毁后
unMounted(() => {
......
})
return {
......
}
}
}
</script>
npm install @vue/composition-api --save
import Vue from 'vue'
import App from './App.vue'
//引入@vue/composition-api
import VueCompositionAPI from '@vue/composition-api'
Vue.use(VueCompositionAPI)
Vue.config.productionTip = false
new Vue({
render: h => h(App),
}).$mount('#app')
脚手架要求:vue-cli4.0 以上
npm install -g @vue/cli
vue create vue3.0-demo
vue3.0 下 vue-router4.0
相关 API:
//引入路由相关API
import { createRouter, createWebHashHistory } from 'vue-router'
import Home from '../views/home/index.vue'
import About from '../views/about/index.vue'
//创建hash路由模式
const routerHashHistory = createWebHashHistory()
//创建路由实例
const router = createRouter({
history: routerHashHistory,
routes: [
{
name: 'home',
path: '/',
component: Home
},
{
name: 'about',
path: '/about',
component: About
}
]
})
export default router
import { createApp } from 'vue'
import App from './App.vue'
//引入路由实例
import router from './router'
//将路由实例注入到vue根实例中
createApp(App).use(router).mount('#app')