Vue3 知识点总结

发布于:2022-12-20 ⋅ 阅读:(455) ⋅ 点赞:(0)

 ###  setup


setup是所有组合API "表演的舞台"
组件中所用到的:数据 方法等等,均要配置在setup中
setup函数的返回值:返回一个对象 则对象中的属性,方法,在模板中可以直接使用


注意:
1.vue3尽量不要与vue2配置混用
2.setup不能是一个async函数,因为返回值不再是reture的对象,而是promise,模板看不到return对象中的属性

 

###  ref函数


作用:定义一个响应式的数据
接收的数据可以是:基本类型 对象类型
1.创建一个包含响应式数据的引用对象:


2.js中操作数据:  


3.模板中读取数据: 

 

### reactive函数


作用:定义一个对象类型的响应式的数据  (基本类型不要用它 要用ref函数)
语法:
const 代理对象 = reactive (源对象) 接收一个对象(或数组) 返回一个代理对象(Proxy的实例对象)

### vue2的响应式


实现原理:
对象类型:通过object.defineProperty()对属性的读取,修改进行拦截(数据劫持)
数组类型:通过重写更新数组的一系列方法来实现拦截(对数组的变更方法进行了包裹)
存在问题:
新增属性,删除属性,界面不会更新
直接通过下表修改数组,界面不会自动更新

### vue3的响应式


实现原理:
通过Proxy(代理):拦截对象中任意属性的变化,包括:属性值的读写 属性的添加 属性的删除等
通过Reflect(反射):对被代理(源)对象的属性进行操作


### reactive对比ref


从定义数据角度对比:
   ref用来定义:基本类型数据
   reactive用来定义:对象(或数组)类型数据
   ref也可以用来定义对象(或数组)类型数据,它内部会自动通过reactive转为代理对象


从原理角度对比:
   ref通过object.defineProperty()的get与set来实现响应式(数据劫持)
   reactive通过使用Proxy来实现响应式(数据劫持),并通过Reflect操作源对象内部的数据


从使用角度对比:
   ref定义的数据:操作数据需要.value,读取数据时模板中直接读取不需要.value
   reactive定义的数据:操作数据与读取数据:均不需要.value

###  setup的两个注意点


setup执行时机
   在beforeCreate之前执行一次,this是undefined


setup的参数
   props:值为对象 包含:组件外部传递过来 且组件内部声明接受了的属性
   context:上下文对象
      attrs:值为对象 包含:组件外部传递过来 但没有在props配置中声明的属性 相当于this.$attrs
      slots:收到的插槽内容 相当于this.$slots
      emit:分发自定义事件的函数 相当于 this.$emit


### computed函数


与vue2中的配置功能一致
写法:

<template>
  <h1>一个人的信息</h1>
  姓:<input type="text" v-model="person.firstName">
  <br>
  <br>
  名:  <input type="text" v-model="person.lastName">
  <br>
  <br>
  <span>全名:{{person.fullName}}</span>
  <br>
  <br>
  <input type="text" v-model="person.fullName">
</template>

<script>
  import { reactive,computed } from "vue";
export default {
  name: "computed",
  setup() {

    // 数据
    let person = reactive({
      firstName:'蒋',
      lastName:'丞'
    })
  

    // 计算属性 --简写 (没有考虑计算属性被修改的情况)
    // person.fullName = computed(()=>{
    //   return person.firstName + '-' + person.lastName
    // }) 

    // 完整写法
    person.fullName = computed({
      get(){
        return person.firstName + '-' + person.lastName
      },
      set(value){
        const nameArr = value.split('-')
        person.firstName = nameArr[0]
        person.lastName = nameArr[1]
      }
    }) 

    // 返回一个对象
    return {
      person
      
    };
  },
};
</script>



### watch函数


与vue2中的配置功能一致
两个小坑:
   监视reactive定义的响应式数据时:oldValue无法正确获取,强制开启了深度监视(deep配置无效)
   监视reactive定义的响应式数据中某个属性时:deep配置有效
   
   

<template>
	<h2>当前求和为:{{sum}}</h2>
	<button @click="sum++">点我+1</button>
	<hr>
	<h2>当前的信息为:{{msg}}</h2>
	<button @click="msg+='!'">修改信息</button>
	<hr>
	<h2>姓名:{{person.name}}</h2>
	<h2>年龄:{{person.age}}</h2>
	<h2>薪资:{{person.job.j1.salary}}K</h2>
	<button @click="person.name+='~'">修改姓名</button>
	<button @click="person.age++">增长年龄</button>
	<button @click="person.job.j1.salary++">涨薪</button>
</template>

<script>
	import {ref,reactive,watch} from 'vue'
	export default {
		name: 'Watch',
		setup(){
			//数据
			let sum = ref(0)
			let msg = ref('你好啊')
			let person = reactive({
				name:'蒋丞',
				age:18,
				job:{
					j1:{
						salary:20
					}
				}
			})

			//情况一:监视ref所定义的一个响应式数据
			/* watch(sum,(newValue,oldValue)=>{
				console.log('sum变了',newValue,oldValue)
			},{immediate:true}) */

			//情况二:监视ref所定义的多个响应式数据
			/* watch([sum,msg],(newValue,oldValue)=>{
				console.log('sum或msg变了',newValue,oldValue)
			},{immediate:true}) */

			/* 
				情况三:监视reactive所定义的一个响应式数据的全部属性
						1.注意:此处无法正确的获取oldValue
						2.注意:强制开启了深度监视(deep配置无效)
			*/
			/* watch(person,(newValue,oldValue)=>{
				console.log('person变化了',newValue,oldValue)
			},{deep:false}) //此处的deep配置无效 */

			//情况四:监视reactive所定义的一个响应式数据中的某个属性
			/* watch(()=>person.name,(newValue,oldValue)=>{
				console.log('person的name变化了',newValue,oldValue)
			})  */

			//情况五:监视reactive所定义的一个响应式数据中的某些属性
			/* watch([()=>person.name,()=>person.age],(newValue,oldValue)=>{
				console.log('person的name或age变化了',newValue,oldValue)
			})  */

			//特殊情况
			/* watch(()=>person.job,(newValue,oldValue)=>{
				console.log('person的job变化了',newValue,oldValue)
			},{deep:true}) //此处由于监视的是reactive所定义的对象中的某个属性,所以deep配置有效 */


			//返回一个对象(常用)
			return {
				sum,
				msg,
				person
			}
		}
	}
</script>


   

 

### watchEffect函数


watch函数的套路是:既要指明监听的属性,也要指明监听的回调
watchEffect函数的套路是:不用指明监视哪个属性,监视的回调中用到哪个属性,那就监视哪个属性
watchEffect函数有点像computed:
   但computed注重计算出来的值(回调函数的返回值),所以必须要写返回值
   而watchEffect更注重的是过程(回调函数的返回体),所以不用写返回值

<!-- watchEffect所指定的回调中用到的数据只要发生变化,则直接重新执行回调-->
 

<template>
  <h2>当前求和为:{{ sum }}</h2>
  <button @click="sum++">点我+1</button>
  <hr />
  <h2>当前的信息为:{{ msg }}</h2>
  <button @click="msg += '!'">修改信息</button>
  <hr />
  <h2>姓名:{{ person.name }}</h2>
  <h2>年龄:{{ person.age }}</h2>
  <h2>薪资:{{ person.job.j1.salary }}K</h2>
  <button @click="person.name += '~'">修改姓名</button>
  <button @click="person.age++">增长年龄</button>
  <button @click="person.job.j1.salary++">涨薪</button>
</template>

<script>
import { ref, reactive, watch, watchEffect } from "vue";
export default {
  name: "watchEffect",
  setup() {
    //数据
    let sum = ref(0);
    let msg = ref("你好啊");
    let person = reactive({
      name: "张三",
      age: 18,
      job: {
        j1: {
          salary: 20,
        },
      },
    });

    //监视
    /* watch(sum,(newValue,oldValue)=>{
				console.log('sum的值变化了',newValue,oldValue)
			},{immediate:true}) */

    watchEffect(() => {
      const x1 = sum.value;
      const x2 = person.job.j1.salary;
      console.log("watchEffect所指定的回调执行了");
    });

    //返回一个对象(常用)
    return {
      sum,
      msg,
      person,
    };
  },
};
</script>

 


### 自定义hook函数


本质是一个函数 把setup函数中使用的Composition API进行了封装
自定义hook的优势:复用代码,让setup中的逻辑更清楚易懂


### toRef和toRefs


作用:创建一个ref对象,其value值指向另一个对象中的某个属性
语法:const name = toRef(person,'name')
应用:要将响应式对象中的某个属性单独提供给外部使用时
扩展:toRef和toRefs功能一致,但是toRefs可以批量创建多个ref对象 语法:toRefs(person)

<template>
	<h4>{{person}}</h4>
	<h2>姓名:{{name}}</h2>
	<h2>年龄:{{age}}</h2>
	<h2>薪资:{{job.j1.salary}}K</h2>
	<button @click="name+='~'">修改姓名</button>
	<button @click="age++">增长年龄</button>
	<button @click="job.j1.salary++">涨薪</button>
</template>

<script>
	import {ref,reactive,toRef,toRefs} from 'vue'
	export default {
		name: 'Demo',
		setup(){
			//数据
			let person = reactive({
				name:'蒋丞',
				age:18,
				job:{
					j1:{
						salary:20
					}
				}
			})


			// const name2 = toRef(person,'name')
			// console.log('####',name2)

			const x = toRefs(person)
			console.log('******',x)

			//返回一个对象(常用)
			return {
				person,
				// name:toRef(person,'name'),
				// age:toRef(person,'age'),
				// salary:toRef(person.job.j1,'salary'),
				...toRefs(person)
			}
		}
	}
</script>


### shallowReadonly 与 readonly

 


readonly:让一个响应式数据变为只读的(深只读)
shallowReadonly:让一个响应式数据变为只读的(浅只读)
应用场景:不希望数据被修改时

<template>
	<h4>当前求和为:{{sum}}</h4>
	<button @click="sum++">点我++</button>
	<hr>
	<h2>姓名:{{name}}</h2>
	<h2>年龄:{{age}}</h2>
	<h2>薪资:{{job.j1.salary}}K</h2>
	<button @click="name+='~'">修改姓名</button>
	<button @click="age++">增长年龄</button>
	<button @click="job.j1.salary++">涨薪</button>
</template>

<script>
	import {ref,reactive,toRefs,readonly,shallowReadonly} from 'vue'
	export default {
		name: 'Demo',
		setup(){
			//数据
			let sum = ref(0)
			let person = reactive({
				name:'张三',
				age:18,
				job:{
					j1:{
						salary:20
					}
				}
			})

			// person = readonly(person)
			person = shallowReadonly(person)  //深层次不受影响
			// sum = readonly(sum)
			// sum = shallowReadonly(sum)

			//返回一个对象(常用)
			return {
				sum,
				...toRefs(person)
			}
		}
	}
</script>


### toRaw 与 markRaw


toRaw:
   作用:将一个由reactive生成的响应式对象转化为普通对象
   使用场景:用于读取响应式对象对应的普通对象,对这个普通对象的所有操作,不会引起页面的更新
markRaw:
   作用:标记一个对象 使其永远不会再成为响应式对象
   应用场景:
   1.有些值不应该被设置为响应式的,例如复杂的第三方类库等
   2.当渲染具有不可变数据源的大列表时 条过响应式转换可以提高性能

 

<template>
	<h2>姓名:{{name}}</h2>
	<h2>年龄:{{age}}</h2>
	<h2>薪资:{{job.j1.salary}}K</h2>
	<h3 v-show="person.car">座驾信息:{{person.car}}</h3>
	<button @click="name+='~'">修改姓名</button>
	<button @click="age++">增长年龄</button>
	<button @click="job.j1.salary++">涨薪</button>
	<button @click="showRawPerson">输出原始的percon</button>
	<button @click="addCar">给人添加一台车</button>
	<button @click="person.car.name+='!'">换台车</button>
	<button @click="person.car.price++">换价格</button>
</template>

<script>
	import {ref,reactive,toRefs,toRaw, markRaw} from 'vue'
	export default {
		name: 'Demo',
		setup(){
			//数据
			let person = reactive({
				name:'蒋丞',
				age:18,
				job:{
					j1:{
						salary:20
					}
				}
			})

			function showRawPerson(){
				const p = toRaw(person)
				p.age++
				console.log(p);
			}
			

			function addCar(){
				let car = {name:'凯迪拉克',price:40}
				person.car = markRaw(car)
			}

			//返回一个对象(常用)
			return {
				person,
				...toRefs(person),
				showRawPerson,
				addCar
			}
		}
	}
</script>

 

### customRef

<template>
  <input type="text" v-model="keyword" />
  <h3>{{ keyword }}</h3>
</template>

<script>
import { ref, customRef } from "vue";
export default {
  name: "APP",
  setup() {
    //  自定义一个ref---名为:nyRef
    function myRef(value, delay) {
      let timer;
      return customRef((track, trigger) => {
        return {
          get() {
            console.log(`有人从myRef这个容器中读取数据来,我把${value}给他了`);
            track(); //通知Vue追踪value的变化(提前和get商量一下,让他认为这个value是有用的)
            return value;
          },
          set(newValue) {
            console.log(`有人把myRef这个容器中数据改为了:${newValue}`);
            //防抖
            clearTimeout(timer);
            // 延时展示
            timer = setTimeout(() => {
              value = newValue;
              trigger(); //通知Vue去重新解析模板
            }, delay);
          },
        };
      });
    }

    let keyword = myRef("hello",500); //使用自定义的ref

    return { keyword };
  },
};
</script>

<style>
</style>




### provide 与 inject


作用:实现祖与后代组件间通信
套路:父组件有一个 provide选项来提供数据 后代组件有一个inject选项来开始使用这些数据
具体写法:
祖组件中:
   

setup() {
    let car = reactive({name:'凯迪拉克',price:'40W'})
    provide('car',car)  //给自己的后台组件传递数据
    return {...toRefs(car)}
   },


后代组件中:

setup() {
    let car = inject('car')  //给后代组件注入数据
    return {car}
   },

### 


  响应式数据的判断

console.log(isRef(sum));   //检查一个值是否为一个ref对象
console.log(isReactive(car));  //检查一个对象是否是由reactive创建的应式处理
console.log(isReadonly(car2));  //检查一个对象是否是由readonly创建的读代理
console.log(isProxy(car));  //检查一个对象是否由reactive或者readonly法创建的代理

## Composition API 的优势


可以更加优雅的组织我们的代码,函数。让相关功能的代码更加有序的组织在一起。

### 新的组件

## 1.Fragment

在Vue2中: 组件必须有一个根标签
在Vue3中: 组件可以没有根标签, 内部会将多个标签包含在一个Fragment虚拟元素中
好处: 减少标签层级, 减小内存占用


## 2.Teleport

- 什么是Teleport?—— `Teleport` 是一种能够将我们的组件html结构移动到指定位置的技术。

 

<teleport to="移动位置">
      <div v-if="isShow" class="mask">
          <div class="dialog">
              <h3>我是一个弹窗</h3>
              <button @click="isShow = false">关闭弹窗</button>
          </div>
      </div>
  </teleport>


 

本文含有隐藏内容,请 开通VIP 后查看