今年7月,尤大大宣布 Vue 3 进入 RC 阶段,这意味着 Vue 3 内核 API 与实现已趋稳定。vue
Vue做为一种渐进式框架, 借鉴了 React 的组件化和虚拟 DOM ,借鉴了 Angular 的模块化和双向数据绑定。就框架的 API 而言,对比之下,它更加轻便简洁。对于Vue的好处这里再也不赘述。node
相对vue2.x,Vue3作了不少重要的变动,特别是Composition API的引入。咱们知道,Vue 现有 API 是经过「选项」组织代码的,随着功能的增加,复杂组件的代码会变得愈来愈难维护,不少逻辑都没法复用。开发的时候复杂的组件千行代码template/data/methods来回翻,看到你头晕,而vue3可让你在接手别人的代码时更容易理清逻辑关系。下面直接进入主题,咱们来看看Vue3都有哪些新特性,相对于以前版本又有哪些变动。react
Vue 3.0 相对与以前的版本,有 6 个方面的重要变动:数组
性能上,主要是优化了虚拟 DOM,因此也就有了更加优化的编译,同时实现了更加高效的组件初始化。app
在大部分状况下,咱们并不须要 vue 中的全部功能,可是在以前的 vue 版本中,咱们没有一个合适的办法用来除去不须要的功能,而 Vue3 中,为了知足体积更小的需求,支持 Tree-shaking,也就意味着咱们能够按需求引用的内置的指令和方法。框架
Composition API 主要是提升了代码逻辑的可复用性,而且将 Reactivity 模块独立出来,这也使得 vue 3 变得更加灵活地与其余框架组合使用。dom
在书写vue2时,因为组件必须只有一个根节点,不少时候会添加一些没有意义的节点用于包裹。Fragment组件就是用于解决这个问题的(这和React中的Fragment组件是同样的)。异步
-Manual render functions can simply return Arrays (render 函数能够返回数组)async
Teleport其实就是React中的Portal。Portal 提供了一种将子节点渲染到存在于父组件之外的 DOM 节点的优秀的方案。一个 portal 的典型用例是当父组件有 overflow: hidden 或 z-index 样式时,但你须要子组件可以在视觉上“跳出”其容器。例如,对话框、悬浮卡以及提示框。ide
一样的,这和React中的Supense是同样的。Suspense 让你的组件在渲染以前进行“等待”,并在等待时显示 fallback 的内容。
vue3.0 对 TS 的支持度更高了,同时也支持 TSX 的使用;API 在 JS 与 TS 中的使用相同;类组件仍然可用,可是须要咱们引入 vue-class-component@next,该模块目前还处于 alpha 测试阶段。
自定义 render 会提供一个 API 用来建立自定义的 render,所以再也不须要为了自定义一些功能而 fork Vue 的代码。这个特性给 Weex 和 NativeScript Vue 这样的项目提供了不少便利。
在vue3中引入了Composition API(组合API),使用纯函数分隔复用代码,让逻辑变得清晰。
关于VCA,有人说跟react的hooks很像,咱们来看看做者尤大的介绍:
新版的生命周期函数,能够按需导入到组件中,且只能在 setup() 函数中使用.
import {onBeforeMount, onMounted} from 'vue' export default { setup() { onBeforeMount(() => { console.log('onBeforeMount') }) onMounted(() => { console.log('onMounted') }) }, }
setup() 函数是 vue3 中,专门为组件提供的新属性。它为咱们使用 vue3 的 Composition API 新特性提供了统一的入口。
export default { props: { str: String }, setup(props, context) { console.log(props) // str console.log(context) // attrs, slots, parent, root, emit, refs }, }
reactive() 函数接收一个普通对象,返回一个响应式的数据对象。
import { reactive } from 'vue' export default { setup() { const state = reactive({count: 0}) // 建立响应式数据对象 return state //将响应式数据对象 return 出去,供 template 使用 } }
ref() 函数根据给定的值建立一个响应式的数据对象,返回值是一个对象,这个对象上只包含一个 .value 属性
import { ref } from 'vue' export default { setup() { const count = ref(0) // 建立响应式数据对象 count,初始值为 0 console.log(count.value) // 在setup内访问count值须要.value 属性才能够,但在template中能够直接访问 return { count } }, }
toRefs() 函数能够将 reactive() 建立出来的响应式对象,转换为普通的对象,只不过,这个对象上的每一个属性节点,都是 ref() 类型的响应式数据
import { reactive, toRefs } from 'vue' export default { setup() { const state = reactive({count: 0, name:'weedsFly'}) // 用reactive集中建立多个响应式对象 const add = () => { // methods写在setup内 state.count++ } return { // ...state, // 使用展开运算符后 用reactive建立的响应式数据 变成了 固定的值 ...toRefs(state), // 能够用toRefs函数 将传进来的非响应式对象 转成 ref() 类型的响应式数据 add } }, }
经过 ref() 还能够引用页面上的元素或组件,这点和vue2的ref概念相似。
1.元素引用
import { ref, onMounted } from 'vue' export default { setup() { const h1Ref = ref(null) // 建立一个 DOM 引用 onMounted(() => { // 在 DOM 首次加载完毕以后,才能获取到元素的引用 h1Ref.value.style.color = 'pink' // h1Ref.value 是原生DOM对象 }) return { h1Ref } } }
2.组件引用
//父组件: import { ref } from 'vue' export default { setup() { const compRef = ref(null) // 建立一个组件的 ref 引用 showCompData = () => { // 展现子组件中 count 的值 console.log(compRef.value.count) } return { compRef, showCompData } } }
//子组件: import { ref } from 'vue' export default { setup() { const count = ref(0) // 定义响应式的数据 return { count } } }
omputed() 用来建立计算属性,computed() 函数的返回值是一个 ref 的实例。
1.computed建立只读的计算属性(传入一个 function 函数,能够获得一个只读的计算属性)
import { ref, computed } from 'vue' export default { setup() { const count = ref(0) const computedCount = computed(() => count.value + 1) computedCount.value = 9 // computed value is readonly. return { count, computedCount } }, }
2.computed建立可读可写的计算属性
import { ref, computed } from 'vue' export default { setup() { const count = ref(0) const computedCount = computed({ get: () => count.value + 1, set: val => { count.value = val - 1 } }) computedCount.value = 100 // 为计算属性赋值的操做,会触发 set 函数 console.log(count.value) // 触发 set 函数后,count 的值会被更新 return { count, computedCount, computedCount } }, }
1.监视单个数据源变更
import { reactive, watch } from 'vue' export default { setup() { const state = reactive({count: 100}) watch( () => state.count, (newVal, oldVal) => { console.log(newVal, oldVal)}, {lazy: true} // 在 watch 被建立的时候,不执行回调函数中的代码 ) setTimeout(() => { state.count++ }, 1500) } }
import { ref, watch } from 'vue' export default { setup() { const count = ref(100) watch( count, (newVal, oldVal) => { console.log(newVal, oldVal)}, {lazy: true} // 在 watch 被建立的时候,不执行回调函数中的代码 ) setTimeout(() => { count++ }, 1500) } }
2.监视多个数据源
import { reactive, watch } from 'vue' export default { setup() { const state = reactive({count: 100, name: 'Laiyj'}) watch( [() => state.count, () => state.name], ([newCount, newName], [oldCount, oldName]) => { console.log(newCount, oldCount) console.log(newName, oldName) }, {lazy: true} // 在 watch 被建立的时候,不执行回调函数中的代码 ) setTimeout(() => { state.count++ state.name = 'Lucy' }, 1000) } }
import { ref, watch } from 'vue' export default { setup() { const count = ref(100) const name = ref('Laiyj') watch( [count, name], ([newCount, newName], [oldCount, oldName]) => { console.log(newCount, oldCount) console.log(newName, oldName) }, {lazy: true} // 在 watch 被建立的时候,不执行回调函数中的代码 ) setTimeout(() => { count++ name = 'Lucy' }, 1000) } }
3.清除watch监视
import { ref, watch } from 'vue' export default { setup() { const count = ref(100) const stop = watch( // 建立监视,并获得 中止函数 count, (newVal, oldVal) => { console.log('I am watching.') console.log(newVal, oldVal) }, {lazy: true} // 在 watch 被建立的时候,不执行回调函数中的代码 ) setTimeout(() => { count++ }, 1000) const clearWatch = () => { stop() } return { count, clearWatch } } }
4.在 watch 中清除无效的异步任务(与节流防抖同效)
import { ref, watch } from 'vue' export default { setup() { const keyword = ref('') const asyncPrint = (val) => { // 执行异步任务,并获得关闭异步任务的 timerId return setTimeout(() => { console.log(val) }, 1000) } watch( keyword, (newVal, oldVal, onClean) => { const timeId = asyncPrint() onClean(() => {clearTimeout(timeId)}) // 若是 watch 监听被重复执行了,则会先清除上次未完成的异步任务 } ) return { keyword } } }
//父组件: import { provide, watch } from 'vue' export default { setup() { const color = ref('red') provide('themeColor', color) // 父组件经过 provide 函数向子级组件共享数据(不限层级) provide('要共享的数据名称', 被共享的数据) const changeColor = (val) => { color.value = val } return { color, changeColor } } }
// 子级组件: import { inject, watch } from 'vue' export default { setup() { const color = inject('color') // 调用 inject 函数时,经过指定的数据名称,获取到父级共享的数据 return { color } } }
以上只罗列了几个比较基础重要的API,vue3还有不少还须要多多学习 : )