vue 3.0新特性
参考: https://www.cnblogs.com/Highdoudou/p/9993870.html
https://www.cnblogs.com/ljx20180807/p/9987822.html
性能优化
观察者机制的变化:Proxy 替代 object.defineProperty
- Vue 2.x使用
Object.defineProperty的 getter 和 setter。 但是,Vue 3 将使用 ES2015 Proxy 作为其观察者机制。 这消除了以前存在的警告,使速度加倍,并节省了一半的内存开销。
- Vue 2.x使用
virtual DOM重构(比2.5快一倍) 【和模版大小有关 --> 和模版内的动态内容数量相关】
传统:组件 update时,整个vdom树需要重新创建,然后遍历进行diff, update
新的更新策略: block tree
区分动态节点和静态节点
基于动态节点指令(v-if, v-for, {{ name }}等)更新
编译时优化
slot默认编译为函数
vnode的创建函数保持参数一致化
编译时生成vnode的类型标记
新增composition-api,
https://composition-api.vuejs.org/
可以在vue2.x的项目中通过安装@vue/composition-api包来使用composition-api.
- reactive:reactive的作用是将对象包装成响应式对象——通过 Proxy代理后的对象。
- ref:由传入值返回一个响应式的、可变的且只有value一个属性的ref对象。
当ref被作为render context被返回,在template中使用该ref对象时,自动获取内部的值,不需要使用.value属性。
<template>
<div>{{ count }}</div>
</template> <script>
export default {
setup() {
return {
count: ref(0)
}
}
}
</script>
当ref对象被作为属性,传入响应式对象reactive时,会自动获取其内部的值(表现得像普通的属性值,而非对象)。
const count = ref(0)
const state = reactive({
count
}) console.log(state.count) // state.count = 1
console.log(count.value) //
reactive属性绑定新的ref对象后,原来ref的value不变(断开了)。
const otherCount = ref(2) state.count = otherCount
console.log(state.count) //
console.log(count.value) //
其他情况获取ref时需要带.value
const arr = reactive([ref(0)])
// need .value here
console.log(arr[0].value) const map = reactive(new Map([['foo', ref(0)]]))
// need .value here
console.log(map.get('foo').value)
- reactive对象与ref对象的区别
可以通过如何撰写标准的 JavaScript 逻辑来比较:
// 风格 1: 将变量分离
let x = 0
let y = 0 function updatePosition(e) {
x = e.pageX
y = e.pageY
} // 风格 2: 单个对象
const pos = {
x: 0,
y: 0,
} function updatePosition(e) {
pos.x = e.pageX
pos.y = e.pageY
}
可以将风格 (1) 转换为使用 ref写法 (为了让基础类型值具有响应性) 。
将风格 (2) 转换为使用
reactive对象的写法。
如果只使用 reactive 的问题是,使用组合函数时必须始终保持对这个所返回对象的引用以保持响应性。这个对象不能被解构或展开:
// 组合函数:
function useMousePosition() {
const pos = reactive({
x: 0,
y: 0,
}) // ...
return pos
} // 消费组件
export default {
setup() {
// 这里会丢失响应性!
const { x, y } = useMousePosition()
return {
x,
y,
} // 这里会丢失响应性!
return {
...useMousePosition(),
} // 这是保持响应性的唯一办法!
// 你必须返回 `pos` 本身,并按 `pos.x` 和 `pos.y` 的方式在模板中引用 x 和 y。
return {
pos: useMousePosition(),
}
},
}
toRefs API 用来提供解决此约束的办法——它将响应式对象的每个 property 都转成了相应的 ref。
function useMousePosition() {
const pos = reactive({
x: 0,
y: 0,
})
// ...
return toRefs(pos)
}
// x & y 现在是 ref 形式,可以i解构了!
const { x, y } = useMousePosition()
- computed:传入一个getter()函数,返回一个值不可变的响应式ref对象。
const count = ref(1)
const plusOne = computed(() => count.value + 1) console.log(plusOne.value) // 2 count值改变,plusOne的值相应的改变 plusOne.value++ // error
当传入的是一个具有get和set函数的对象时,返回的是一个可写的ref对象。
const count = ref(1)
const plusOne = computed({
get: () => count.value + 1,
set: val => {
count.value = val - 1
}
}) plusOne.value = 1
console.log(count.value) // 0 count值改变,plusOne的值随之改变;改变plusOne的值, count的值也相应的改变
- readonly:将接受到的对象(无论是响应式对象、ref对象或普通对象),转成通过Proxy代理的只读对象。
const original = reactive({ count: 0 })
const copy = readonly(original)
watchEffect(() => {
// works for reactivity tracking
console.log(copy.count)
})
// mutating original will trigger watchers relying on the copy
original.count++
// mutating the copy will fail and result in a warning
copy.count++ // warning!
- watchEffect:接受一个函数,当依赖改变时,重新调用该函数。
const count = ref(0)
watchEffect(() => console.log(count.value))
setTimeout(() => {
count.value++
}, 100)
当watchEffect()在setup()或生命周期钩子中被调用时,监听就始终存在该组件的生命周期中,直到组件unmount.
另一种卸载监听的情况是,watchEffect()返回一个stop handler,调用该handler即可停止监听。
const stop = watchEffect(() => {
/* ... */
})
// later
stop()
当向后台获取数据时,watchEffect()接受async回调函数。
const data = ref(null)
watchEffect(async () => {
data.value = await fetchData(props.id)
})
组件的update函数也有watch effect。用户定义的watchEffect会在组件update之后再去调用。
<template>
<div>{{ count }}</div>
</template> <script>
export default {
setup() {
const count = ref(0) watchEffect(() => {
console.log(count.value)
}) return {
count
}
}
}
</script>
上述代码,第一轮会同步打印count.value(在onmount生命周期前); 当count发生改变时,先执行组件更新,然后再去log.
如果想将watchEffect中的回调函数第一次执行,放在onmount后,
onMounted(() => {
watchEffect(() => {
// access the DOM or template refs
})
})
如果想让watchEffect()调用发生在组件update前,或re-run同步,需要传递一个带有flush属性(默认值为post)的option对象。
watchEffect(()=> {
//...
}, {
flush: 'sync' // 在更新前触发 flush: "pre"
})
此外,option对象还有ontrack和ontrigger两个函数属性,用于调试watcher的行为。
onTrackwill be called when a reactive property or ref is tracked as a dependencyonTriggerwill be called when the watcher callback is triggered by the mutation of a dependency
watchEffect(
() => {
/* side effect */
},
{
onTrigger(e) {
debugger // 进行交互式调试
}
}
)
- watch:等价于vue 2.x中的this.$watch.
相比于watchEffect(), watch()可帮我们实现:
- Perform the side effect lazily;
- Be more specific about what state should trigger the watcher to re-run;
- Access both the previous and current value of the watched state.
watch()的数据源可以是一个返回值的getter函数,或者是一个ref对象。
// watching a getter
const state = reactive({ count: 0 })
watch(
() => state.count,
(count, prevCount) => {
/* ... */
}
) // directly watching a ref
const count = ref(0)
watch(count, (count, prevCount) => {
/* ... */
})
对于多数据源的监听,可借助数组。
watch([fooRef, barRef], ([foo, bar], [prevFoo, prevBar]) => {
/* ... */
})
生命周期api调整

<template>
<div>{{count}} {{obj.foo}}</div>
</template>
<script>
import { ref, reactive, watchEffect } from '@vue/composition-api'
export default {
props: {
name: String
},
setup (props) {
const count = ref(0)
const obj = reactive({ foo: 'abc' })
watchEffect(() => {
console.log(props.name)
})
return {
count,
obj
}
}
}
</script>
setup()接受的第一个参数是props。props是响应式的。注意:传参时不能对其解构。上面的代码将props传入setup()后,并通过watchEffect()进行监听。
setup()还可接受第二个参数context(相当于vue2.x中的this, setup()不允许使用this),context作为参数时,可以进行解构。常用的有:
context.attrs, context.slots, context.emit
setup(props, {attrs}) {
function onClick() {
console.log(attrs.foo) // 可以保证是最新的值
}
}
其他生命周期函数可以在setup()中被同步注册。当同步执行生命周期hooks时,组件实例的renderContext,watcher和computed properties也同步建立。当组件卸载时,内部的生命周期hooks也会同步去掉。
setup() {
onMounted(() => {
console.log('mounted!')
})
onUpdated(() => {
console.log('updated!')
})
onUnmounted(() => {
console.log('unmounted!')
})
}
- <template>和之前一样,同样 vue-next也支持手写 render的写法。 template和 render同时存在的情况,优先 render。
- setup()是新增的主要变动。顾名思义, setup函数会在组件挂载前运行一次,类似组件初始化的作用, setup需要返回一个对象或者函数。返回对象会被赋值给组件实例的 renderContext,在组件的模板作用域可以被访问到,类似 data的返回值。返回函数会被当做是组件的 render。
基于逻辑关注点组织代码
在vue 2.x中,使用的是option api,要完成一个函数所用到的data或computed计算属性距离这个函数的定义可能有很多行(代码是分散的),这种碎片化使得代码维护变得困难。
这一问题在composition api中得到了解决。每个逻辑关注点的代码现在都被组合进了一个组合函数(命名以use开头)。这大大减少了在处理大型组件时不断“跳转”的需要。同时组合函数也可以在编辑器中折叠起来,使组件更容易浏览。
setup() {
// ...
},
}
function useCurrentFolderData(networkState) {
// ...
}
function useFolderNavigation({ networkState, currentFolderData }) {
// ...
}
function useFavoriteFolder(currentFolderData) {
// ...
}
function useHiddenFolders() {
// ...
}
function useCreateFolder(openFolder) {
// ...
}
setup() 函数现在只是简单地作为调用所有组合函数的入口。最后的 return 语句作为单一出口确认暴露给模板的内容。
export default {
setup() {
// 网络状态
const { networkState } = useNetworkState()
// 文件夹状态
const { folders, currentFolderData } = useCurrentFolderData(networkState)
const folderNavigation = useFolderNavigation({
networkState,
currentFolderData,
})
const { favoriteFolders, toggleFavorite } = useFavoriteFolders(
currentFolderData
)
const { showHiddenFolders } = useHiddenFolders()
const createFolder = useCreateFolder(folderNavigation.openFolder)
// 当前工作目录
resetCwdOnLeave()
const { updateOnCwdChanged } = useCwdUtils()
// 实用工具
const { slicePath } = usePathUtils()
return {
networkState,
folders,
currentFolderData,
folderNavigation,
favoriteFolders,
toggleFavorite,
showHiddenFolders,
createFolder,
updateOnCwdChanged,
slicePath,
}
},
}

逻辑提取和复用
一个组合函数仅依赖它的参数和 Vue 全局导出的 API,而不是依赖 this 上下文。你可以将组件内的任何一段逻辑导出为函数以复用。
import { ref, onMounted, onUnmounted } from 'vue'
export function useMousePosition() {
const x = ref(0)
const y = ref(0)
// 提取为函数
function update(e) {
x.value = e.pageX
y.value = e.pageY
}
onMounted(() => {
window.addEventListener('mousemove', update)
})
onUnmounted(() => {
window.removeEventListener('mousemove', update)
})
return { x, y }
}
在一个组件中调用上述组合函数
import { useMousePosition } from './mouse'
export default {
setup() {
const { x, y } = useMousePosition()
// 其他逻辑...
return { x, y }
},
}
与现有api配合
组合式 API 会在 2.x 的选项 (
data、computed和methods) 之前解析,并且不能提前访问这些选项中定义的 property。setup()函数返回的 property 将会被暴露给this。它们在 2.x 的选项中可以访问到。
vue3.0与react的比较:
同样的逻辑组合、复用能力
composition api 的 setup() 只会调用一次,相比与react hooks
符合js 直觉
没有闭包变量问题
不会在每次渲染时重复执行,降低垃圾回收的压力;
不存在内联回调导致子组件永远更新的问题
- 不存在忘记记录依赖的问题,也不需要“useEffect”和“useMemo”并传入依赖数组以捕获过时的变量。Vue 的自动依赖跟踪可以确保侦听器和计算值总是准确无误。
vue 3.0新特性的更多相关文章
- vue 3.0 体验,vue 3.0新特性
前言 昨天不是尤雨溪 不是刚在B站 直播玩了,分享了vue-next v3.0.0-beta.1 版本 哈哈, 不要太刺激哦 6大亮点 Performance:性能更比Vue 2.0强. Tree s ...
- vue3.0新特性以及进阶路线
Vue3.0新特性/改动 新手学习路线 ===> 起步 1. 扎实的 JavaScript / HTML / CSS 基本功.这是前置条件. 2. 通读官方教程 (guide) 的基础篇.不要 ...
- Vue3.0新特性
Vue3.0新特性 Vue3.0的设计目标可以概括为体积更小.速度更快.加强TypeScript支持.加强API设计一致性.提高自身可维护性.开放更多底层功能. 描述 从Vue2到Vue3在一些比较重 ...
- 浅谈Tuple之C#4.0新特性那些事儿你还记得多少?
来源:微信公众号CodeL 今天给大家分享的内容基于前几天收到的一条留言信息,留言内容是这样的: 看了这位网友的留言相信有不少刚接触开发的童鞋们也会有同样的困惑,除了用新建类作为桥梁之外还有什么好的办 ...
- Java基础和JDK5.0新特性
Java基础 JDK5.0新特性 PS: JDK:Java Development KitsJRE: Java Runtime EvironmentJRE = JVM + ClassLibary JV ...
- Visual Studio 2015速递(1)——C#6.0新特性怎么用
系列文章 Visual Studio 2015速递(1)——C#6.0新特性怎么用 Visual Studio 2015速递(2)——提升效率和质量(VS2015核心竞争力) Visual Studi ...
- atitit.Servlet2.5 Servlet 3.0 新特性 jsp2.0 jsp2.1 jsp2.2新特性
atitit.Servlet2.5 Servlet 3.0 新特性 jsp2.0 jsp2.1 jsp2.2新特性 1.1. Servlet和JSP规范版本对应关系:1 1.2. Servlet2 ...
- 背水一战 Windows 10 (1) - C# 6.0 新特性
[源码下载] 背水一战 Windows 10 (1) - C# 6.0 新特性 作者:webabcd 介绍背水一战 Windows 10 之 C# 6.0 新特性 介绍 C# 6.0 的新特性 示例1 ...
- C# 7.0 新特性2: 本地方法
本文参考Roslyn项目中的Issue:#259. 1. C# 7.0 新特性1: 基于Tuple的“多”返回值方法 2. C# 7.0 新特性2: 本地方法 3. C# 7.0 新特性3: 模式匹配 ...
随机推荐
- MySQL如何创建一个好索引?创建索引的5条建议【宇哥带你玩转MySQL 索引篇(三)】
MySQL如何创建一个好索引?创建索引的5条建议 过滤效率高的放前面 对于一个多列索引,它的存储顺序是先按第一列进行比较,然后是第二列,第三列...这样.查询时,如果第一列能够排除的越多,那么后面列需 ...
- KMP & AC自动机
KMP void kmp(char t[],char p[]) { int n=strlen(t),m=strlen(p); int *f=new int[m]; f[0]=f[1]=0; for(i ...
- 汉字编码对照表(gb2312/Big5/GB2312)
一.汉字编码的种类 1.GB2312又称国标码,由国家标准总局发布,1981年5月1日实施,通行于大陆.新加坡等地也使用此编码.它是一个简化字的编码规范,当然也包括其他的符号.字母.日文假名等,共74 ...
- jQuery里面click、this事件遇到(Django模型里for)相同的id名和class名想获取值
遇到的原型是这样的!下面我把它简化一下; click事件: 在浏览器里面只能获取横线上面的值,和下面的第一个值!! 这是因为id等级比class高,而且js要求id不能重复! 当 转载于:https: ...
- Shiro(一):Shiro介绍及主要流程
什么是Shiro Apache Shiro是一个强大且灵活的开源安全框架,易于使用且好理解,撇开了搭建安全框架时的复杂性. Shiro可以帮助我们做以下几件事: 认证使用者的身份 提供用户的访问控制, ...
- 短视频sdk:选择一个靠谱的短视频SDK 你需要了解这些
2017 年,短视频成为了内容创业的新风口,各种短视频 App 如雨后春笋般先后上线.随着互联网内容消费升级,视频越来越像文字.图片一样,成为每一个 App 不可或缺的一部分. 为了能够更好地聚焦于业 ...
- 使用Xamarin开发即时通信系统 -- 基础篇(大量图文讲解 step by step,附源码下载)...
如果是.NET开发人员,想学习手机应用开发(Android和iOS),Xamarin 无疑是最好的选择,编写一次,即可发布到Android和iOS平台,真是利器中的利器啊!而且,Xamarin已经被微 ...
- Gitlab常规操作
一.Git和SVN的区别 和SVN类似,Git是一个版本控制系统(Version Control System,VCS),不同的是SVN为集中式版本控制系统,为单一的集中管理的服务器,保存所有文件的修 ...
- JavaWeb----Servler
Servlet简介 Servlet就是sun公司开发动态web的一门技术 Sun在这些API中提供一个接口叫做:Servlet,如果你想开发一个Servlet程序,只需要完成两个小步骤: 编写一个类, ...
- Java——理解面向对象
1.程序设计的三种基本结构 顺序结构 顺序结构表示程序中的各操作是按照它们在源代码中的排列顺序依次执行的 选择结构 选择结构表示程序的处理需要根据某个特定的条件选择其中的一个分支执行.选择结构有单选择 ...