vue3的新特性

vue3的新特性

一、setup

1、是vue3.0的中的一个新增配置项,值为一个函数。
2、setup是所有composition API(组合式api)展示的舞台。
3、setup函数的两种返回值:
若返回一个对象,则对象中的属性、方法, 在模板中均可以直接使用。(重点关注!)
若返回一个渲染函数:则可以自定义渲染内容。(了解) (不常用)
注意点:
1、尽量不要和vue2.x版本混用。

  • vue2.x版本可以访问到setup里的属性。
  • setup访问不到vue2.x版本的属性。
  • 如果有重名,setup优先

2、setup不能是一个async函数,因为返回值不再是对象, 而是promise, 模板看不到return对象中的属性。
3、setup执行顺序在beforeCreat,并且在setup中this为undefined
4、setUp(props, contex)接受两个参数

  • props:值为对象,包含:组件外部传递过来,且组件内部声明接收了的属性(其实就是vue2.0的props功能)
  • context:上下文对象(其中可以获取到1、attrs组件外部传递过来,但没有在props配置中声明的属性。2、slots:插槽内容3、emit:分发自定义事件的函数,并且以后在setup中不能写this.$emit,要写context.emit)
<template>
  <h2>姓名:{{name}}</h2>
  <h2>年龄:{{age}}</h2>
  <button @click="sayInfo">显示信息</button>
</template>

<script>
export default {
  name: "App",
  setup(){
  	//此时的数据不具有双向绑定的功能
    let name = "小明"
    let age = 18

    // 方法
    function sayInfo(){
      alert(`你好${name},你太厉害了吧`)
    }
    // 想要在模板中使用setup中的方法或者数据,必须return
    return {
      name,age, gender,sayInfo
    }
     // return ()=> h('h1','试试')
  }
};
</script>


二、ref

作用:定义一个响应式数据。
语法:let xxx = ref(xxx)
注意点:

  • ref(),括号中可以填基本数据类型和也可以是对象类型
    • 填基本数据类型会返回一个RefImpl的实例对象,RefImpl类中有getter和setter可以检测到数据的变化。
    • 填对象类型的数据:其实就是使用了Vue3.0中的一个新函数—— reactive函数。
  • js操作值的方法是xxx.value,模板中直接{{xxx}}
  • 使用之前要先引入。
<template>
  <h2>姓名:{{ name }}</h2>
  <h2>年龄:{{ age }}</h2>
  <button @click="changeInfo">修改信息</button>
</template>

<script>
import { ref } from "vue";
export default {
  name: "App",
  setup() {
    // 数据
    let name = ref("小明");
    let age = ref(18);
    // 方法
    function changeInfo() {
      name.value = "小明";
      age.value = 48;
    }
    return {
      name,
      age,
      changeInfo,
    };
  },
};
</script>

三、reactive

作用:定义一个响应式对象。
语法:let xxx = reactive(xxx)
注意点:

  • reactive(),括号要填对象类型
    • 填基本数据类型会返回一个proxy实例对象。
    • 填对象类型的数据:其实就是使用了Vue3.0中的一个新函数—— reactive函数。
  • js操作值的方法是xxx.value,模板中直接{{xxx}}
  • 使用之前要先引入。
  • 上面ref()方法虽然也可以填对象,但是他的本质还是调用了reactive方法,并且js操作时还需要xxx.value,多此一举。而且使用reactive()定义的响应式对象是深层次的,不会出现vue2对象数据层级过深,不改变的情况。
<template>
  <h2>姓名:{{ yk.name }}</h2>
  <h2>年龄:{{ yk.age }}</h2>
  <h2>爱好:{{ yk.hobby }}</h2>
  <h3>测试数据:{{ yk.job.a.b.c }}</h3>
  <button @click="changeInfo">修改信息</button>
</template>

<script>
import { reactive } from "vue";
export default {
  name: "App",
  setup() {
    // 数据
    let yk = reactive({
      age: 18,
      hobby: ["吃饭", "睡觉", "打豆豆"],
      job: {
        a: {
          b: {
            c: 666,
          },
        },
      },
    });

    // 方法
    function changeInfo() {
      yk.age = 48;
      yk.job.a.b.c = 888;
      // 直接通过数组下标修改,可以触发响应式
      yk.hobby[0] = "打豆豆";
    }
    return {
      yk,
      changeInfo,
    };
  },
};
</script>

三、计算属性computed

与vue2.x相比,功能几乎一样,但是写法有些许变动。

<template>
  姓:<input v-model="person.firstName"></input>
 名: <input  v-model="person.lastName"></input>
  姓名:<input  v-model="person.fullName"></input>
</template>

<script>
//先引入
import {computed,reactive } from 'vue'
export default {
  name: "App",
  setup() {
  	let person = reactive({
		firstName :"小",
		lastName:"明",
		fullName:""
	})
    //计算属性 —— 简写
    //let 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

和计算属性差不多,在vue3中和只是语法上上的改变。
注意点:

  • 监视reactive定义的响应式数据时:oldValue无法正确获取、强制开启了深度监视(deep配置失效)
  • 监视reactive定义的响应式数据中某个属性时(这个属性需是对象):deep配置有效
//情况一:监视ref定义的响应式数据
watch(sum,(newValue,oldValue)=>{
	console.log('sum变化了',newValue,oldValue)
})
//如果用ref定义了一个对象
watch(person.value,(newValue,oldValue)=>{
	console.log('person变化了',newValue,oldValue)
})
 
//情况二:监视多个ref定义的响应式数据
watch([sum,msg],(newValue,oldValue)=>{
	console.log('sum或msg变化了',newValue,oldValue)
}) 
//情况三:监视reactive定义的响应式数据
watch(person,(newValue,oldValue)=>{
	console.log('person变化了',newValue,oldValue)
},{immediate:true,deep:false}) //此处的deep配置不再奏效

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

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

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


四、watchEffect函数

watch是:既要指明监视的属性,也要指明监视的回调。
watchEffect是:不用指明监视哪个属性,监视的回调中用到哪个属性,那就监视哪个属性。
这个函数的功能和计算属性差不多,但是

  • 但computed注重的计算出来的值(回调函数的返回值),所以必须要写返回值。
  • 而watchEffect更注重的是过程(回调函数的函数体),所以不用写返回值。
//watchEffect所指定的回调中用到的数据只要发生变化,则直接重新执行回调。
watchEffect(()=>{
    const x1 = sum.value
    const x2 = person.age
    console.log('watchEffect配置的回调执行了')
})

五、生命周期钩子

1、vue3.0中可以继续使用vue2.x中的生命周期钩子,但是有两个被更名:

  • beforeDestroy改成beforUnmount
  • destroyed改成 unmounted

2、vue3.0也提供了composition API形式的生命周期钩子,与vue2.x钩子对应关系如下:

  • beforeCreate======>setup()
  • created==========>setup()
  • beforeMount======>onBeforeMount
  • mounted=========>onMounted
  • beforeUpdate=====>onBeforeUpdate
  • updated =========>onUpdated
  • beforeUnmount ===>onBeforeUnmount
  • unmounted ======>onUnmounted

六、自定义hook函数

  • 什么是hook?-------本质是一个函数,把setup中使用的compositionAPI进行了封装。
  • 类似于vue2.x中的mixin。
  • 自定义hook的优势:复用代码,让setup中的逻辑更清晰。
  • emmmm感觉就是模块导入,和vue2.x 的mixin也有些许差别。

创建一个hook文件夹,里面创建文件point.js

import { reactive, onMounted, onBeforeUnmount } from "vue";
export default function() {
    //实现鼠标“打点”相关的数据
    let point = reactive({
        x: 0,
        y: 0,
    });

    //实现鼠标“打点”相关的方法
    function savePoint(event) {
        point.x = event.pageX;
        point.y = event.pageY;
        console.log(event.pageX, event.pageY);
    }

    //实现鼠标“打点”相关的生命周期钩子
    onMounted(() => {
        window.addEventListener("click", savePoint);
    });

    onBeforeUnmount(() => {
        window.removeEventListener("click", savePoint);
    });

    return point;
}

在组件中使用

<template>
<h2>当前点击时鼠标的坐标为:x:{{point.x}},y:{{point.y}}</h2>
</template>

<script>
  import usePoint from '../hook/point.js'
  export default {
    name:'HelloWorld',
    setup(){
      const point = usePoint()
      return {point}
    }
  }
</script>

七、toRef和toRefs

  • 作用:创建一个 ref 对象,其value值指向另一个对象中的某个属性。
  • 语法:const name = toRef(person,‘name’)
  • 应用: 要将响应式对象中的某个属性单独提供给外部使用时。
  • 扩展:toRefs与toRef功能一致,但可以批量创建多个 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: 'HelloWorld',
		setup(){
			let person = reactive({
				name:'张三',
				age:18,
				job:{
					j1:{
						salary:20
					}
				}
			})
			
			// const name1 = person.name
			// console.log('%%%',name1)

			// 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>

八、其他新特性

1、shallowReactive 与 shallowRef

  • shallowReactive:只处理对象最外层属性的响应式(浅响应式)。
  • shallowRef:只处理基本数据类型的响应式, 不进行对象的响应式处理。
  • 什么时候使用?
    1、如果有一个对象数据,结构比较深, 但变化时只是外层属性变化 ===> shallowReactive。
    2、如果有一个对象数据,后续功能不会修改该对象中的属性,而是生新的对象来替换 ===> shallowRef。

2、readonly 与 shallowReadonly

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

3、toRaw 与 markRaw

toRaw
作用:将一个由reactive生成的响应式对象转为普通对象。
使用场景:

  • 用于读取响应式对象对应的普通对象,对这个普通对象的所有操作,不会引起页面更新。

markRaw
作用:标记一个对象,使其永远不会再成为响应式对象。
应用场景:

  • 有些值不应被设置为响应式的,例如复杂的第三方类库等。
  • 当渲染具有不可变数据源的大列表时,跳过响应式转换可以提高性能

4、customRef

作用:创建一个自定义的 ref,并对其依赖项跟踪和更新触发进行显式控制。

实现防抖效果

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

<script>
import { customRef } from "vue";
export default {
  name: "App",
  setup() {
    //自定义一个ref——名为:myRef
    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 = ref('hello') //使用Vue提供的ref
    let keyWord = myRef("hello", 500); //使用程序员自定义的ref

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

5、provide 与 inject

作用:实现祖与后代组件间通信

套路:父组件有一个 provide 选项来提供数据,后代组件有一个 inject 选项来开始使用这些数据

具体写法
祖组件中:

setup(){
	......
    let car = reactive({name:'奔驰',price:'40万'})
    provide('car',car) // 给自己的后代组件传递数据
    ......
}

后代组件中:

setup(props,context){
	......
    const car = inject('car') // 拿到祖先的数据
    return {car}
	......
}

6、响应式数据的判断

isRef: 检查一个值是否为一个 ref 对象。
isReactive: 检查一个对象是否是由 reactive 创建的响应式代理。
isReadonly: 检查一个对象是否是由 readonly 创建的只读代理。
isProxy: 检查一个对象是否是由 reactive 或者 readonly 方法创建的代理。

九、新的组件

1、Fragment

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

2、Teleport

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

3、Suspense

等待异步组件时渲染一些额外内容,让应用有更好的用户体验

使用步骤:

异步引入组件

import {defineAsyncComponent} from 'vue'
const Child = defineAsyncComponent(()=>import('./components/Child.vue'))

使用Suspense包裹组件,并配置好default与 fallback

<template>
	<div class="app">
		<h3>我是App组件</h3>
		<Suspense>
		//default:就是组件要显示的内容
			<template v-slot:default>
				<Child/>
			</template>
			//fallback:就是组件没加载完全的“备胎”
			<template v-slot:fallback>
				<h3>加载中.....</h3>
			</template>
		</Suspense>
	</div>
</template>

十、其他变化

1、data选项应始终被声明为一个函数

2、过渡类名的更改

//Vue2.x写法
.v-enter,
.v-leave-to {
  opacity: 0;
}
.v-leave,
.v-enter-to {
  opacity: 1;
}

//Vue3.x写法
.v-enter-from,
.v-leave-to {
  opacity: 0;
}

.v-leave-from,
.v-enter-to {
  opacity: 1;
}

3、移除keyCode作为 v-on 的修饰符,同时也不再支持config.keyCodes

4、移除v-on.native修饰符

5、移除过滤器(filter)

哔哩哔哩的尚硅谷教学视频-笔记
链接:https://www.bilibili.com/video/BV1Zy4y1K7SH?p=158

上一篇:PromQL


下一篇:Vue3 antdv 简单表单校验