vue3技术简易入门剖析

Posted teayear

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了vue3技术简易入门剖析相关的知识,希望对你有一定的参考价值。

vue3 入门

本章内容

  • vue3简介
  • vue3项目构建工具vite
  • vue3组合式API
  • vue3响应式原理–Proxy+Object.defineProperty()
  • computed计算属性
  • watch侦听器
  • 函数的使用
  • 新增内置组件

一、vue3

1.1 简介

  • 2020年9月18日发布,3.0版本 代号 ‘one piece’。
  • 3.0版本代表了超过2年的开发工作,包括30多个RFC、2600多个提交、来自99个贡献者的628个请求,以及核心回购之外的大量开发和文档工作。
  • gitHub地址:https://github.com/vuejs/core/releases/tag/v3.0.0

1.2 优势

  • 与Vue 2相比,Vue 3在打包大小(体积最多轻41%)、初始渲染(最多快55%)、更新(最多快133%)和内存使用(最多少54%)方面都有显著的性能改进。
  • 使用Proxy代替Object.defineProperty()实现响应式
  • 重写虚拟DOM的实现 diff 算法
  • 更好的支持TypeScript
  • TreeShaking(打包时把无关代码全部干掉,体积更小)

1.3 新的特性

二、Vue3项目构建

2.1 vue-cli构建项目(现阶段开发必用)

#vue3对vue-cli的版本要求必须在4.5.0以上
执行命令:vue -V查看vue-cli版本
如果版本低于4.5.0 可以重新执行命令 npm install -g @vue/cli安装最新版
## 创建项目
vue create 项目名
## 启动项目
cd  项目目录
npm run serve

2.2 vite构建项目(vue官方出版的)

2.2.1 vite简介

官网地址:https://vitejs.cn/

Vite(法语意为 “快速的”,发音 /vit/

,发音同 “veet”)是一种新型前端构建工具,能够显著提升前端开发体验。它主要由两部分组成:

Vite 意在提供开箱即用的配置,同时它的 插件 APIJavaScript API 带来了高度的可扩展性,并有完整的类型支持。

grant gulp webpack

2.2.2 传统构建与vite构建对比图

基于打包器启动时,重建整个包的效率很低。原因显而易见:因为这样更新速度会随着应用体积增长而直线下降。

一些打包器的开发服务器将构建内容存入内存,这样它们只需要在文件更改时使模块图的一部分失活[1],但它也仍需要整个重新构建并重载页面。这样代价很高,并且重新加载页面会消除应用的当前状态,所以打包器支持了动态模块热重载(HMR):允许一个模块 “热替换” 它自己,而不会影响页面其余部分。这大大改进了开发体验 —— 然而,在实践中我们发现,即使采用了 HMR 模式,其热更新速度也会随着应用规模的增长而显著下降。

在 Vite 中,HMR 是在原生 ESM 上执行的。当编辑一个文件时,Vite 只需要精确地使已编辑的模块与其最近的 HMR 边界之间的链失活[1](大多数时候只是模块本身),使得无论应用大小如何,HMR 始终能保持快速更新。

2.2.3 构建vite项目

## 创建项目
npm init vite-app 项目名
## 进入项目
cd 项目名
## 安装依赖包  vite项目需要自己手动安装依赖包
npm install
## 运行项目
npm run dev

2.2.4 vite构建vue3项目的结构分析

  1. 目录结构基本没有什么变化,用法一样

  2. main.js分析

    //此处的引入import 不在是 Vue的构造函数了 引入的是一个名为  createApp的工厂函数。
    createApp(App).mount("#app")这句代码可以拆分成两部分代码
    //创建实例对象
    //注意:此处创建的app跟之前的vm实例对象不一样了,可以看成是一个轻量级的vm实例对象。
    let app = createApp(App)
    //挂载模板
    app.mount('#app')
    
  3. vue2实例对象与vue3实例对象的对比

    vue2的实例对象:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZdA6uB2G-1655452084593)(assets/image-20220308104303764.png)]

    vue3的实例对象:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QfO6UVqi-1655452084594)(assets/image-20220308104022830.png)]

    **注意:**在vue3构建的项目中无法再使用vue2创建vue实例的Vue构造方法了。必须使用vue3的写法,引入createApp()工厂方法

  4. 普通组件中的变化

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-R1GwiOcF-1655452084596)(assets/image-20220308104731384.png)]

    **注意:**定义组件时 DOM结构可以不用根标签包括了。

2.3 vue3配套的开发者工具

打开chrome应用商店 下载beta版 就是vue3的开发者工具版本,之前安装的应该也可以使用。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kB9O8dNs-1655452084596)(assets/image-20220308112040949.png)]

三、vue3常用的组合式(Composition)API

3.1 什么是组合式API

通过创建 Vue 组件,我们可以将界面中重复的部分连同其功能一起提取为可重用的代码段。仅此一项就可以使我们的应用在可维护性和灵活性方面走得相当远。然而,我们的经验已经证明,光靠这一点可能并不够,尤其是当你的应用变得非常大的时候——想想几百个组件。处理这样的大型应用时,共享和重用代码变得尤为重要。

使用 (datacomputedmethodswatch) 组件选项来组织逻辑通常都很有效。然而,当我们的组件开始变得更大时,逻辑关注点的列表也会增长。尤其对于那些一开始没有编写这些组件的人来说,这会导致组件难以阅读和理解。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3EoQG5rU-1655452084598)(assets/options-api.png)]

这是一个大型组件的示例,其中逻辑关注点按颜色进行分组。

这种碎片化使得理解和维护复杂组件变得困难。选项的分离掩盖了潜在的逻辑问题。此外,在处理单个逻辑关注点时,我们必须不断地“跳转”相关代码的选项块。

如果能够将同一个逻辑关注点相关代码收集在一起会更好。而这正是组合式 API 使我们能够做到的。

3.2 组合式API基础使用----setup

既然我们知道了为什么,我们就可以知道怎么做。为了开始使用组合式 API,我们首先需要一个可以实际使用它的地方。在 Vue 组件中,我们将此位置称为 setup

为什么要使用setup()函数: https://zhuanlan.zhihu.com/p/68477600

3.2.1 setup 组件选项

**注意:**在 setup 中你应该避免使用 this,因为它不会找到组件实例。setup 的调用发生在 data property、computed property 或 methods 被解析之前,所以它们无法在 setup 中被获取。

setup 选项是一个接收 propscontext 的函数,我们将在之后进行讨论。此外,我们将 setup 返回的所有内容都暴露给组件的其余部分 (计算属性、方法、生命周期钩子等等) 以及组件的模板。

**使用方式一:**在vue3中 之前定义的data,methods,computed,watch,directives还都仍然可以使用 用法跟vue2是完全一样的,但是过滤器不能使用了

<template>
	<h1> msg </h1>
	<button @click="count++">count is:  count </button>
	<p>msg1</p>
	<p v-color='"blue"'>计算属性aaa</p>
	<p>过滤器count | bbb</p>
	<button type="button" @click="changeMsg">改变msg</button>
</template>
<script>
	import ref from 'vue'
	export default 
		name: 'HelloWorld',
		props: 
			msg: String
		,
		data()
			return 
				count:0,
				msg1:'',
			
		,
		methods:
			changeMsg()
				this.msg1 = this.msg
			
		,
		computed:
			aaa()
				return this.count+1
			
		,
		watch:
			count(newVal,oldVal)
				console.log(newVal,oldVal)
			
		,
		filters:
			bbb(val)
				return val+5
			
		,
		directives:
			color(el,binding)
				el.style.color = binding.value
			
		
	
</script>

使用方式二:setup基本用法

在实例中不在配置data,methods,computed…等独立配置项 而是在其中添加一个setup()项, 所有的配置内容都写在其中,最终把页面中需要用到的数据通过return 暴漏出去。

<template>
	<h1>这里是组件age</h1>
	<button type="button" @click="age+=1">点我</button>
</template>

<script>
	import ref from 'vue'
	export default 
		components:,
        //定义setup函数
		setup()
			let name = '张三'
			let age = ref(58)
			return
				name,age
			
		
	
</script>

注意:

  • setup是vue3中的一个配置项

  • 组件中需要用到的所有的数据, 函数,等都要配置在setup函数中

  • setup函数中需要有return返回值 返回的是一个对象 其中包含的数据,可以在页面中直接使用;

  • 在vue3中仍然可以使用vue2的data,methods等配置项,并且 这些配置项中也可以访问到setup中配置的信息.

    但是setup中无法访问到vue2配置中的信息。 重名变量,setup优先.

  • vue2和vue3的语法推荐大家不要混合使用, 用哪一个就全部都用那一个!

3.3 ref函数的使用

3.3.1 ref函数的使用----基本数据类型

**发现问题:**在以上案例中,如果我们想点击按钮修改age的值,会发现 页面中是无法更新渲染age数据的 为什么?

ref 的响应式变量

在 Vue 3.0 中,我们可以通过一个新的 ref 函数使任何响应式变量在任何地方起作用,如下所示:

//一定要先导入
import  ref  from 'vue'

const counter = ref(0)

ref 接收参数并将其包裹在一个带有 value property 的对象中返回,然后可以使用该 property 访问或更改响应式变量的值:

import  ref  from 'vue'

const counter = ref(0)

console.log(counter) //  value: 0 
console.log(counter.value) // 0

counter.value++
console.log(counter.value) // 1

将值封装在一个对象中,看似没有必要,但为了保持 javascript 中不同数据类型的行为统一,这是必须的。这是因为在 JavaScript 中,NumberString 等基本类型是通过值而非引用传递的:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fyLxXbYc-1655452084599)(assets/pass-by-reference-vs-pass-by-value-animation.gif)]

在任何值周围都有一个封装对象,这样我们就可以在整个应用中安全地传递它,而不必担心在某个地方失去它的响应性。

换句话说,ref 为我们的值创建了一个响应式引用。在整个组合式 API 中会经常使用引用的概念。

使用: let age = ref(58) 此句代码 58 被ref包括后 并不是说age=58 此时的age是一个对象RefImpl 其中包含一个属性value, 我们使用age.value才可以真正的取到数值58 ;

此处的控制台输出为:

小结:

  • 页面模板中展示数据直接使用向外返回的属性名就可以了 不需要加.value

  • 在setup中定义的基本数据类型如果想实现响应式,必须用ref()包括 , 并且如果在setup中想对数据做修改 , 必须通过 属性名.value才可以完成 ;

3.3.2 ref函数的使用----对象类型

在setup中添加如下代码 son对象: 点击按钮 改变 son中的数据

<template>
	<h2>儿子的名字:son.name</h2>
	<h2>儿子的年龄:son.age</h2>
	<button type="button" @click="changeSonAge">点我改变儿子的年龄+1</button>
</template>

<script>
    //需要先导入ref函数
	import ref from 'vue'
	export default 
		components:,
		setup()
			let son = ref(
				name:'张三',
				age:18
			)
			
			function changeSonAge()
                //报错
				son.value.age.value += 1 
                
                //有效代码
                son.value.age += 1
				console.log(son)
			
			//返回页面中需要使用的数据
			return
				son,changeSonAge
			
		
	
</script>

此时虽然同样是用 ref包括的数据 但是操作时 只需要取出 son.value操作属性就可以了, 不需要使用son.value.age.value这样会报错 ;

原因: 此处我们打印 son对象 发现 被ref()包括的son对象是如下形式:

此时虽然整体的son还是 RefImpl形式 , 但是其中的value 属性却变成了 proxy 形式 是 ES6的新特性 : 代理

小结:

  • ref包括对象类型的数据 生成也是RefImpl 形式
  • 其中的value属性 是 proxy 形式

注意:

  • vue3中ref对基本类型的响应式原理 仍然是 Object.defineProperty() getter和setter
  • vue3中ref 对引用对象类型的响应式原理是 ES6中的proxy

3.4 reactive 函数的使用

简介:

  • 使用reactive来定义一个对象类型的响应式数据, (基本类型使用ref函数)
  • 基于ES6的proxy代理来实现 响应式原理

使用:

<template>
	<h2>儿子的名字:son.name</h2>
	<h2>儿子的年龄:son.age</h2>
	<button type="button" @click="changeSonAge">点我改变儿子的年龄+1</button>
</template>

<script>
	import ref,reactive from 'vue'
	export default 
		components:,
		setup()
			let son = reactive(
				name:'张三',
				age:18
			)
			
			function changeSonAge()
				son.age += 1 
				console.log(son)
			
			
			return
				name,age,son,changeSonAge
			
		
	
</script>

此处把son对象使用reactive函数包括起来 此时再想操作son中的age属性就不需要添加value了 可以直接使用son.age操作, 因为此时返回的直接就是 proxy代理对象 把son对象换成数组 一样可以操作 , 并且可以直接通过下标来对数组进行修改(vue2中不行) ;

注意: ref函数包括对象类型实现响应式就是因为 ref在底层调用了reactive函数 ;

小结:

  • vue3中基本类型都使用ref函数包括
  • 对象(引用类性)都是用 reactive函数包括
  • 使用之前记得先引入函数。

3.5 setup函数中的两个参数和自定义事件的使用

setup完整语法格式: setup(props,context)

  • props 参数 表示接收父组件传递来的数据

  • context是当前组件的上下文 我们在控制台打印context可以得到如下图所示内容

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wa3GIxwK-1655452084600)(assets/image-20220308220827367.png)]

    • attrs: 当子组件中没有声明props属性时, 父向子传递的数据会保存在attrs中

    • emit: 自定义事件会保存在此处

      子组件中:

      <button @click="bbb">子组件中触发自定义事件</button>
      export default
          //此处添加emits属性 把自定义的事件类型填入
          emits:['hello'],
          setup(props,context)
              function bbb()
                  console.log('hello自定义事件触发了')
                  //通过context调用emit方法来完成自定义事件
                  context.emit('hello','你好哈哈哈')
              
      
              return
                  bbb
              
      	
      
      

      父组件中:

      <Son @hello='aaa'></Son>
      setup()
          //自定义事件触发aaa函数 val就是子组件传递来的数据
          function aaa(val)
              console.log('接收到子组件传递来的数据:',val)
          
      
          return
              aaa
          
      
      
    • **slots:**插槽内容会保存在此处(了解)

      其中包含的只是 虚拟DOM

3.6 provide与inject / 祖孙(后代)传递数据

**简介:**通常,当我们需要从父组件向子组件传递数据时,我们使用 props。想象一下这样的结构:有一些深度嵌套的组件,而深层的子组件只需要父组件的部分内容。在这种情况下,如果仍然将 prop 沿着组件链逐级传递下去,可能会很麻烦。

对于这种情况,我们可以使用一对 provideinject。无论组件层次结构有多深,父组件都可以作为其所有子组件的依赖提供者。这个特性有两个部分:父组件有一个 provide 选项来提供数据,子组件有一个 inject 选项来开始使用这些数据。

**主要作用:**父组件向后代组件传递数据。

祖组件使用privade定义要传递的数据,在后代组件中通过inject来接收参数。

//祖组件中 定义privade传递数据
provide('fage',fage.value)
//后代组件 接收privade数据的方式二
let fage =  inject('fage')

四、vue3中的响应式原理

4.1 vue2中的响应式原理

通过 Object.defineProperty() 方法来实现。通过gettersetter方法来完成。

Object.defineProperty(obj,'属性',
	get(),set()
)

4.2 vue3的响应式原理

ref() ===> reactive()

通过Es6中的 proxy 代理来完成的。

4.2.1 回顾ES6中proxy的使用

	<body>
		<script type="text/javascript">
			let obj = 
				name:'张三',
				age:18,
				address:'郑州'
			
            
			let p = new Proxy(obj,
				//target表示 被代理对象  propKey表示读取的属性值
				get(target,propKey)
					console.log(`获取了$propKey属性`)
					return target[propKey]
				,
				set(target,propKey,value)
					console.log(`修改了$propKey属性`)
					target[propKey] = value
				,
				deleteProperty(target,propKey)
					console.log(`删除了$propKey属性`)
					return delete target[propKey]
				
			)
		</script>
	</body>
</html>
获取属性调用get()方法
修改或者新增属性调用set()方法
删除属性调用deleteProperty()方法

4.2.2 ES6 中的 Reflect 反射

反射:获取对象中的属性值

概念: 见教程:https://es6.ruanyifeng.com/#docs/reflect

**使用:**Reflect是与Proxy 完全对应的方法,我们可以通过Proxy代理对 对象的操作添加一些拦截 做一些事情,同时可以使用Reflect反射 来从对象中获取数据。主要用途:封装底层框架,保证代码顺利执行

	<body>
		<script type="text/javascript">
			let obj = 
				name:'张三',
				age:18,
				address:'郑州'
			
			let p = new Proxy(obj,
				//target表示 被代理对象  propKey表示读取的属性值
				get(target,propKey)
					console.log(`获取了$propKey属性`)
					return Reflect.get(target,propKey)
				,
				set(target,propKey,value)
					console.log(`修改了$propKey属性`)
					Reflect.set(target,propKey,value)
				,
				deleteProperty(target,propKey)
					console.log(`删除了$propKey属性`)
					return Reflect.deleteProperty(target,propKey)
				
			)
		</script>
	</body>
</html>

五、computed计算属性

仍然可以按照vue2中的语法来实现计算属性。

但是这里我们推荐使用vue3

  • 首先引入computed

    import computed from 'vue'
    
  • 在setup中定义计算属性

    <template>
    	<input v-model="msg"/>
    	<p>转为大写:newVal</p>
    </template>
    <script>
    	import ref,computed from 'vue'
    	export default
    		setup()
    			let msg = ref('')
    			
    			//定义计算属性
    			let newVal = computed(()=>
    				return msg.value.toUpperCase()
    			)
    			
    			return msg,newVal
    		
    	
    </script>
    

六、watch侦听器

首先:vue2中侦听器的使用方式在vue3中仍然可以使用

6.1 watch侦听

vue3的方式定义侦听器:

语法格式:

import watch from 'vue'
export default
    watch(被监视的数据,监视的回调函数),
     watch(name,(newVal,oldVal)=>)

案例:

<template>
	<!-- vue3中的侦听器 -->
	<h1>数量:count</h1>
	<button type="button" @click='count++'>点我+1</button>
	<h1>数量:num</h1>
	<button type="button" @click='num+=2'>点我+2</button>
	<h1>===========================reactive数据监听====================================</h1>
	<h1>姓名:obj.name</h1>
	<button type="button" @click='obj.name+="#"'>点我改变名字</button>
	<h1>年龄:obj.age</h1>
	<button type="button" @click='obj.age+=1'>点我改变年龄</button>
	<h1>班级:obj.class.c1</h1>
	<button type="button" @click='obj.class.c1+="--"'>点我改变班级</button>
</template>

<script>
	import ref,reactive,watch from 'vue'
	export default
		setup()
			let count = ref(0)
			let num = ref(10)
			
			let obj = reactive(
				name:'张三',
				age:18,
				address:'郑州',
				class:
					c1:'qy147',
					c2:'qy148'
				
			)
			//监视一个数据
			/* watch(count,(newVal,oldVal)=>
				console.log(newVal,oldVal)
			) */
			//监听多个数据  此时的newVal,oldVal 都是以数组形式展示数据
			/* watch([count,num],(newVal,oldVal)=>
				console.log(newVal,oldVal)
			) */
			
			//监听reactive对象数据
			//注意:此处可以监听到数据的改变,但是无法获取到oldVal
			//reactive响应式数据的监听,vue3会自动开启深度监听 并且是强制开启的 deep配置没有效果
			/* watch(obj,(newVal,oldVal)=>
				console.log(newVal,oldVal)
			,immediate:true) */
			
			//监听对象中单独的属性
			//注意:需要把要监听的属性以函数的形式返回 才可以监视到
			//此时的oldVal也可以使用
			/* watch(()=>obj.class.c1,(newVal,oldVal)=>
				console.log(newVal,oldVal)
			,immediate:true) */
			
			
			//此时直接监听class对象  此时需要开启 deep:true属性
			watch(()=>obj.class,(newVal,oldVal)=>
				console.log(newVal,oldVal)
			,immediate:true,deep:true)
			
			return count,num,obj
		
	
</script>

6.2 watchEffect 侦听

**简介:**立即执行传入的一个函数,同时响应式追踪其依赖,并在其依赖变更时重新运行该函数。也就是说监视的回调函数中用到了哪个属性,那么当这个属性发生改变时,watchEffect回调就会执行。

watchEffect(()=>
    num.value+=1
    console.log('watchEffect执行了')
)

只要num的值 发生了改变 watchEffect中的回调函数就会执行。

七、vue3内置组件

7.1 Fragment组件

概念:Fragment就是一个虚拟的元素,vue3中元素不必使用根元素包括,其实就是放在一个Fragment虚拟元素中了。

7.2 Teleport组件 传送门

**简介:**Vue 鼓励我们通过将 UI 和相关行为封装到组件中来构建 UI。我们可以将它们嵌套在另一个内部,以构建一个组成应用程序 UI 的树。

然而,有时组件模板的一部分逻辑上属于该组件,而从技术角度来看,最好将模板的这一部分移动到 DOM 中 Vue app 之外的其他位置。

一个常见的场景是创建一个包含全屏模式的组件。在大多数情况下,你希望模态框的逻辑存在于组件中,但是模态框的快速定位就很难通过 CSS 来解决,或者需要更改组件组合。

语法格式:

<teleport to="#Father"></teleport>
通过to属性指定要传送的位置。to属性的值: 可以是html标签名  也可以是标签的id值

官方案例: 点击按钮 打开弹出框,teleport内置组件可以让弹出框显示在指定的位置

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7ZjdmYW1-1655452084601)(assets/image-20220309110532944.png)]

Father.vue组件:

<template>
	<div id="Father">
		<h1>这里是父组件</h1>
		<Son></Son>
	</div>
</template>

<script>
	import Son from './Son.vue'
	export default
		components:Son
	
</script>

<style scoped>
	#Father
		border:1px solid red;
		background-color: red;
		line-height: 100px;
	
</style>

Son.vue组件

<template>
	<div id="son">
		<h1>这里是儿子组件</h1>
		<Child></Child>
		<button type="button" @click='isShow=true'>打开弹窗</button>
		<Dialog v-if="isShow" @closeDialog='bbb'></Dialog>
	</div>
</template>
<script>
	import Child from './Child.vue'
	import Dialog from './Dialog.vue'
	import ref from 'vue'
	export default
		components:Child,Dialog,
		//emits:['closeDialog'],
		setup(props,context)
			let isShow = ref(false)
			
			function bbb(val)
				isShow.value = val
			
			
			return isShow,bbb
		
	
</script>

<style scoped>
	#son
		border:1px solid red;
		background-color: gray;
		line-height: 100px;
	
</style>

Child.vue组件

<template>
	<div id="child">
		<h1>这里是孙子组件</h1>
		<button type="button" @click='isShow=true'>打开弹窗</button>
		<Dialog v-if="isShow" @closeDialog='bbb'></Dialog>
	</div>
</template>

<script>
	import Dialog from './Dialog.vue'
	import ref from 'vue'
	export default
		components:Dialog,
		//emits:['closeDialog'],
		setup()
			let isShow = ref(false)
			
			function bbb(val)
				isShow.value = val
			
			
			return isShow,bbb
		
	
</script>

<style scoped>
	#child
		border:1px solid red;
		background-color: blue;
		line-height: 100px;
		color: white;
	
</style>

Dialog.vue组件:

<template>
	<teleport to="#Father">
		<div id="dialog">
			<div class="dialog">
				<h2>这里是弹出层组件</h2>
				<h3>你好啊哈哈哈</h3>
				<button type="button" @click="close">点我关闭</button>
			</div>
		</div>
	</teleport>
</template>

<script>
	import ref from 'vue'
	export default
		emits:['closeDialog'],
		setup(props,context)
			let isShow = ref(true)
			
			function close()
				context.emit('closeDialog',false)
			
			
			returnisShow,close
		
	
</script>

<style scoped>
	#dialog
		background-color: rgba(0,0,0,0.5);
		position: absolute;
		top: 0;
		left: 0;
		right: 0;
		bottom: 0;
	
	.dialog
		width: 300px;
		height: 300px;
		background-color: yellow;
		margin: auto;
		margin-top: 200px;
	
</style>

完成效果:让dialog弹出层 能够显示在teleport的to属性指定的位置。

7.3 Suspense组件

八、vue3的生命周期

8.1 vue2的生命周期

8.2 vue3生命周期

**注意:**vue2的生命周期写法在vue3中同样可以使用。

vue3生命周期图解:

你可以通过在生命周期钩子前面加上 “on” 来访问组件的生命周期钩子。

下表包含如何在 setup () 内部调用生命周期钩子:

选项式 APIHook inside setup
beforeCreatesetup()
createdsetup()
beforeMountonBeforeMount
mountedonMounted
beforeUpdateonBeforeUpdate
updatedonUpdated
beforeUnmountonBeforeUnmount
unmountedonUnmounted
errorCapturedonErrorCaptured
renderTrackedonRenderTracked
renderTriggeredonRenderTriggered
activatedonActivated
deactivatedonDeactivated

**注意:**因为 setup 是围绕 beforeCreatecreated 生命周期钩子运行的,所以不需要显式地定义它们。换句话说,在这些钩子中编写的任何代码都应该直接在 setup 函数中编写。

vue3中生命周期钩子的使用方法(组合API形式):

这些函数接受一个回调函数,当钩子被组件调用时将会被执行:

<template>
	<h1>App.vue组件</h1>
	<h3>age</h3><button @click="age+=1">点我</button>
</template>

<script>
    //首先导入需要使用生命周期钩子函数
	import ref,onBeforeMount,onMounted,onBeforeUpdate,onUpdated,onBeforeUnmount,onUnmounted from 'vue'
	export default 
		name: 'App',
		components: ,
		setup()
			let age = ref(18)
			
			console.log('================beforeCreate======================')
			console.log('================created======================')
			onBeforeMount(()=>
				console.log('================onBeforeMount======================')
			)
			
			onMounted(()=>
				console.log('================onMounted======================')
			)
			
			onBeforeUpdate(()=>
				console.log('================onBeforeUpdate======================')
			)
			
			onUpdated(()=>
				console.log('================onUpdated======================')
			)
			
            //当组件进行切换时 可以调用卸载钩子函数
			onBeforeUnmount(()=>
				console.log('================onBeforeUnmount======================')
			)
			
			onUnmounted(()=>
				console.log('================onUnmounted======================')
			)
			
			return age
		
	
</script>

九、响应式API的使用

9.1 响应性基础API

9.1.1 reactive 与 shallowReactive

  • reactive

    **概念:**返回对象的响应式副本

    const obj = reactive( count: 0 )
    

    响应式转换是“深层”的——它影响所有嵌套 property。在基于 ES2015 Proxy 的实现中,返回的 proxy 是等于原始对象的。建议只使用响应式 proxy,避免依赖原始对象。

  • shallowReactive

    **概念:**创建一个响应式代理,它跟踪其自身 property 的响应性,但不执行嵌套对象的深层响应式转换 (暴露原始值)。

    只处理对象最外层属性的响应式,内层嵌套的数据就不再是响应式数据了。

    const state = shallowReactive(
      foo: 1,
      nested: 
        bar: 2
      
    )
    
    // 改变 state 本身的性质是响应式的
    state.foo++
    // ...但是不转换嵌套对象
    isReactive(state.nested) // false
    state.nested.bar++ // 非响应式
    

9.1.2 readonly 与 shallowReadonly