<template> <button @click="increment"> Count is: {{ state.count }}, double is: {{ state.double }} </button></template> <script> import { reactive, computed } from 'vue' export default { setup() { const state = reactive({ count: 0, double: computed(() => state.count * 2), }) function increment() { state.count++ } return { state, increment, } }, }</script>
Vue3会带来些什么?
- 更快
- 更小
- 更易于维护
重写虚拟DOM
Vue3重写了虚拟DOM的实现方法,初始渲染/更新可以提速达100%。
对于Vue2.x版本的虚拟DOM来说,Vue会遍历<template>
模板中的所有内容,并根据这些标签生成对应的虚拟DOM(虚拟DOM一般指采用key/value对象来保存标签元素的属性和内容),当有内容改变时,遍历虚拟DOM来diff找到对应的标签元素所对应的DOM节点,并改变其内容。例如下面这段内容:
<template> <div class="content"> <p>number1</p> <p>number2</p> <p>number3</p> <p>{{count}}</p> </div></template>
当触发双向绑定时,遍历所有的<div>
标签和<p>
标签,找到{{count}}变量对应的<p>
的DOM节点,并改变其内容。这对于那些纯静态<p>
的节点进行diff其实是比较浪费资源的,当节点的数量很少时,表现并不明显,但是一旦节点的数量过大,在性能上就会慢很多。对此,Vue3再次基础上进行了优化主要有:
标记静态内容,并区分动态内容。
更新时只diff动态的部分。
针对上面的代码,Vue3中首先会区分出{{count}}这部分动态的节点,在进行diff时,只针对这些节点进行,从而减少资源浪费,提升性能
基于Proxy的响应式对象
Proxy API
对应的Proxy
对象是ES2015就已引入的一个原生对象,用于定义基本操作的自定义行为(如属性查找、赋值、枚举、函数调用等)。
从字面意思来理解,Proxy
对象是目标对象的一个代理器,任何对目标对象的操作(实例化,添加/删除/修改属性等等),都必须通过该代理器。因此我们可以把来自外界的所有操作进行拦截和过滤或者修改等操作。例如下面的示例:
let foo = { a:1, b:2 }let handler = { set:(obj,key,value)=>{ console.log('set') obj[key] = value return true } }let p = new Proxy(foo,handler)p.a = 3 // 打印出console.log('set')
在Vue2.x中,使用Object.defineProperty()
来实现响应式对象,对于一些复杂的对象,还需要循环递归的给每个属性增加上getter/setter监听器,这使得组件的初始化非常耗时,而Vue3中,composition-api提供了一种创建响应式对象的方法reactive,其内部就是利用了Proxy API来实现的,这样就可以不用针对每个属性来一一进行添加,减少开销提升性能。更多关于Proxy和响应式对象可以参考这篇[文章](Proxy API--Vue3响应式对象reactive初探)。
Tree shaking支持
Tree shaking是一个术语,通常用于描述移除JavaScript上下文中的未引用代码(dead-code),就像一棵大树,将那些无用的叶子都摇掉。它依赖于 ES2015 模块语法的 静态结构 特性,例如 import 和 export。这个术语和概念在打包工具rollup和wepack中普及开来。
import {get} from './api.js'let doSome = ()=>{ get() } doSome()api.js代码:let post = ()=>{ console.log('post') }export postlet get = ()=>{ console.log('get') }export get
上面代码中,api.js代码中的post方法相关内容是没有被引入和使用的,有了Tree shaking之后,这部分内容是不会被打包的,这就在一定程度上减少了资源的大小。使用Tree shaking的原理是ES6的模块静态分析引入,这就可以在编译时正确判断到底加载了什么代码,但是要注意import 和 export是ES6原生的而不是通过babel或者webpack转化的。
在Vue3中,对代码结构进行了优化,让其更加符合Tree shaking的结构,这样使用相关的api时,不会把所有的都打包进来,只会打包你用到的api,例如:
<!-- vue 2.x -->import Vue from 'vue'new Vue()Vue.nextTick(() => {})const obj = Vue.observable({}) <!-- vue 3.x -->import { nextTick, observable,createApp } from 'vue'nextTick(() => {})const obj = observable({})createApp({})
同时,例如<keep-alive>
和<transition>
,<teleport>
等内置组件,如果没有使用也不会被打包到资源里。
搭建vue3.0项目
使用脚手架,注意是vue-cli 3.0版本以上,因为要使用命令vue create,3.0以前的版本是不支持的
npm install -g
@vue``/cli
vue create vue3
//创建项目文件夹
vue add vue-next
//创建vue3.0 依赖直接就安装好了
vue-cli 3.0 是没有webpack配置文件的,vue自己封装了webpack的配置;我们只需要在根目录创建vue.config.js文件,即可对webpack进行配置,而且cli3.0是基于webpack4的。
vue3.0中public文件夹取代了2.0的static
升级到vue3.0的变化
1,main.js
//vue3.0import { createApp } from 'vue';import App from './App.vue'createApp(App).mount('#app') //vue2.0import Vue from 'vue'import App from './App.vue'Vue.config.productionTip = falsenew Vue({ render: h => h(App),}).$mount('#app')
通过上述的代码我们会发现3.0比2.0的要精简了许多,同时还引入了一个新的函数名createApp,会把容器挂载到它上面来。
2,data
**
<template> <div class="hello"> 123 </div> <div>{{name.name}}</div></template>import {reactive} from 'vue'export default { setup(){ const name = reactive({ name : 'helloWorld' }) return {name} } }
**
在新版当中setup等效于之前2.0版本当中得到beforeCreate,和created,它是在组件初始化的时候执行,甚至是比created更早执行。值得注意的是,在3.0当中如果要想使用setup里的数据,需要将用到值return出来,返回出来的值在模板当中都是可以使用的。
3,method
<div class="hello"> <div>{{name.name}}</div> <div>{{count}}</div> <button @click="increamt">button</button> </div> </template> <script>import {reactive,ref} from 'vue'export default { setup(){ const name = reactive({ name:'hello' }) const count=ref(0) const increamt=()=>{ count.value++ } return {name,count,increamt} } }
引用了vue提供的ref新函数,它的作用是用来创建一个引用值,它主要是对String,Number,Boolean的数据响应作引用。也许有人会问,为什么不直接给count赋值,而是采用ref(0)这样的方式来创建呢,按我的理解就是,如果直接给count赋值就是等于把这个值直接抛出去了,就很难在找到它,而
采用ref这种方法等于你在向外抛出去值的是同时,你还在它身上牵了一根绳子,方便去追踪它。
需要注意的时,在ref的函数中,如何你要去改变或者去引用它的值,ref的这个方法提供了一个value的返回值,对值进行操作。
4,生命周期
beforeCreate -> 使用 setup()
created -> 使用 setup()
beforeMount -> onBeforeMount
mounted -> onMounted
beforeUpdate -> onBeforeUpdate
updated -> onUpdated
beforeDestroy -> onBeforeUnmount
destroyed -> onUnmounted
errorCaptured -> onErrorCaptured
5,computed
<template> <div class="hello"> <div>{{name.name}}</div> <div>{{count}}</div> <div>计算属性{{computeCount}}</div> <button @click="increamt">button</button> </div> </template> <script>import {reactive, ref, onMounted,computed} from 'vue'export default { setup(){ const name = reactive({ name:'王' }) const count=ref(0) const increamt=()=>{ count.value++ } const computeCount=computed(()=>count.value*10)//使用computed记得需要引入,这也是刚接触3.0容易忘记的事情 onMounted(()=>{ console.log('123') }) return {name,count,increamt,computeCount} } }</script>
6,组件的使用
在开始介绍3.0组件的用法之前,我们可以先回顾一下2.0使用组件的方式。 在2.0当中,哪个页面需要使用组件就在哪个页面里引入该组件,同时在页面注册这个组件。在传递参数时,父组件传递参数给子组件,子组件就会接收父组件传递过来的参数。
<template> <div id="app"> <HelloWorld msg="Welcome to Your Vue.js App"/> </div></template> <script>import HelloWorld from './components/HelloWorld.vue' export default { name: 'App', components: { HelloWorld }}</script> 子组件<template> <div class="hello"> <h1>{{ msg }}</h1> </div></template> <script>export default { name: 'HelloWorld', props: { msg: String }, data(){ return{ } }, method:{ handleClick(){ this.$emit('childclick','123') } }}</script>
以上是最常见的父子组件之间的调用,但是在vue3.0中就存在差异。
父组件 <template> <div class="hello"> <div>123</div> <NewComp :name="name" @childClick="parentClick"/> </div> </template> <script>import {reactive} from 'vue'import NewComp from './newComp.vue'export default { components:{ NewComp }, setup(){ const name=reactive({ name:'hello 番茄' }) const parentClick=(e)=>{ console.log(e) console.log('123') } return {name,parentClick} } }</script> 子组件 <template> <div> <button @click="handleClick">组件</button> </div></template> <script>export default { setup(props,{emit} ){ const handleClick=()=>{ emit('childClick','hello') } return { props, handleClick } }}</script>
通过上面的vue3.0父子组件之间的调用,我们不难发现,父组件当中在调用子组件时,基本与2.0相同,而在子组件当中,要想获取到父组件传递过来的参数,我们是直接在setup()中直接获取到props值和emit事件。这是因为setup为我们提供了props以及context这两个属性,而在context中又包含了emit等事件。
另外,vue3.0已经没有this关键字了,基于Proxy实现响应式数据。
如果想在v2.x中使用3.0的内容,可通过以下方式
npm install '@vue/composition-api'
在main.js中引入
import VueCompositionApi from '@vue/composition-api';Vue.use(VueCompositionApi);
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!