Vue3.0 componsition Api

# Vue3.0 componsition Api

提示:

使用以下 api 需要导入 vue 模块进行结构 import { reactive, watchEffect, computed ,toRefs , ref, onBeforeMount, onMounted} from "vue";

setup =(将 2.x 版本中 beforeCreate 和 created)

# setup 执行方法

setup 是 vue3.x 中新的操作组件属性的方法,它是组件内部暴露出所有的属性和方法的统一 API。

// 执行时机
	setup(props,content){
	console.log('setup')
	}
	beforeCreate() {
		console.log('beforeCreate')
	},
	created() {
		console.log('created')
	},

# 接收 props 数据 && 上下文对象 content

setup 函数的第二个形参是一个上下文对象,这个上下文对象中包含了一些有用的属性,这些属性在 vue 2.x 中需要通过 this 才能访问到,在 vue 3.x 中,它们的访问方式如下:

<script lang="ts">
// 父组件
<Child msg="app" />
import Child from "./components/HelloWorld.vue"; // 引入子组件的时候注意要加后缀
export default {
	components: {
	    Child,
	},
	// 子组件
	 props: {
	    msg: String,
	 },
	setup(props,content){
		console.log(props);//接收父组件值
		console.log(content); // 上下文对象
		/*
		attrs: Object
		emit: ƒ ()
		listeners: Object
		parent: VueComponent
		refs: Object
		root: Vue
		...
		*/
	  	console.log(this) // undefined
	}
}
</script>

<template>
  <div>
    <h1>
      {{ msg }}
    </h1>
  </div>
</template>

::: error **注意:**在 setup() 函数中无法访问到 this :::

# reactive

reactive 函数接收一个普通函数,返回一个响应式的数据对象。 reactive 函数等价于 vue 2.x 中的 Vue.observable() 函数,vue 3.x 中提供了 reactive() 函数,用来创建响应式的数据对象,基本代码示例如下:

setup(props,conetnt){
    const data = reactive({
        value:1
    })
    function add(){
        data.value++
    }
    return {
       data,
       add
    }
}

# ref

ref() 函数用来根据给定的值创建一个响应式的数据对象,ref() 函数调用的返回值是一个对象,这个对象上只包含一个 .value 属性:

setup(){
		const xx =ref(初始值)   无初始值设置为null
			如果传入的是对象,将调用reactive方法进行深层响应转换。

		(1)调用
			xx.value

		(2)自动解套(即不需要xx.value获取值)
			1、在setup的return{xx},在template中直接{{xx}}

			2、在reactive定义的对象属性中
				const x=ref(xx)
				const xxx=reactive({x})
				xxx.x调用

			3、通过reactive对象调用属性赋值ref的形式,也会自动解套
				const xx=reactive({x})
				xx.x=ref(xxx)
				xx.x直接调用

		(3)获取dom的ref
			当使用组合式 API,reactive refs 和 template refs 的概念已经是统一的
				setup(){
					let x=ref(null);

					获取dom
						x.value

					return{
						x
					}
				}
			在template中
				<标签 ref='x'></标签>

		(4)使用模板语法遍历获取dom

			 template中:
				 <li v-for='(item,index) in 3' :key=index :ref="el=>{divs[index]=el}">
			          {{item}}
			      </li>

			 setup中:
				const divs = ref([])
				组件挂载后,即能通过divs.value获取遍历元素的所有dom
				return{
					divs
				}
	}

# 在 reactive 对象中访问 ref 创建的响应式数据

当把 ref() 创建出来的响应式数据对象,挂载到 reactive() 上时,会自动把响应式数据对象展开为原始的值,不需通过 .value 就可以直接被访问,例如:

setup() {
  const refCount = ref(0)
  const state = reactive({refCount})
  console.log(state.refCount) // 输出 0
  state.refCount++ // 此处不需要通过 .value 就能直接访问原始值
  console.log(refCount) // 输出 1
  return {
    refCount
  }
}

【注意:新的 ref 会覆盖旧的 ref,示例代码如下:】

setup() {
  // 创建 ref 并挂载到 reactive 中
  const c1 = ref(0);
  const state = reactive({ c1 });

  // 再次创建 ref,命名为 c2
  const c2 = ref(9);
  // 将 旧 ref c1 替换为 新 ref c2
  state.c1 = c2;
  state.c1++;

  console.log(state.c1); // 输出 10
  console.log(c2.value); // 输出 10
  console.log(c1.value); // 输出 0
}

# computed 计算属性

# 只读的计算属性

import {ref,computed} from 'vue'
export default {
	setup(){
		let refdata = ref(0);
		const comdata = computed(()=>refdata.value+2)
		function refadd() {
      		refdata.value++;
		}
		function comadd() {
		com.value++;
		}
		return {
			refdata,
			comdata,
			refadd,
			comadd
		}
	};
}

# 可读可写的计算属性

import {ref,computed} from 'vue'
export default {
	setup(){
		let refdata = ref(0);
		const computedData = computed({
      // 取值函数
      get: () => refdata.value + 1,
      // 赋值函数
      set: () => {
        refdata.value = refdata.value + 55;
      },
		});
	function refadd() {
      refdata.value++;
    }
    function comadd() {
      com.value++;
    }
	return {
		refdata,
		comdata,
		refadd,
		comadd
	}
 };
}
const com = computed(() => data.count);

# toRefs

setup(){
  const data = reactive({
    count:1
  })
  return {
    ...toRefs(data) // 将响应式的对象变为普通对象 在家 ... 结构,在模板中就可以直接使用属性,不用data.count
  }
}

# watchEffect

监听reactive函数中的count;
const com = computed(() => data.count);
watchEffect(() => {
  这里可以拿到监听后的数据;
  console.log(com.value);
});

# 生命周期

onMounted(() => {
  console.log("挂载完成");
});
onBeforeMount(() => {
  console.log("挂载前");
});
onBeforeUpdate(() => {
  console.log("更新前");
});
onUpdated(() => {
  console.log("更新完成");
});
onBeforeUnmount(() => {
  console.log("销毁前");
});
onUnmounted(() => {
  console.log("销毁完成");
});

 onRenderTriggered(e => {
      console.log();
      debugger;
      //检查哪个依赖导致组件重新呈现
    })

# 响应式数据的判断

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

# isRef

isRef() 用来判断某个值是否为 ref() 创建出来的对象; 应用场景:当需要查看某个数据是否为 ref() 创建出来的值的时候,例如:

import { ref, isRef } from "vue";
export default {
  setup() {
	let emit = ref("123");
    const unwrapped = isRef(foo) ? foo.value : foo;
	console.log(unwrapped) // 如果不用三元运算符的话,返回值是boolean值
  },
};

# isReactive

import { reactive, isReactive } from "vue";
export default {
  setup() {
    let data = reactive({
      dome: "123",
    });
    const data2 = reactive("13");
    const bool = isReactive(data);
    const bool2 = isReactive(data2);
    console.log(bool); // 返回 true
    console.log(bool2); // 返回 false,
  },
};

# 参考

微信公众号文章:vue3 的学习记录 (opens new window)

让你 30 分钟快速掌握 vue 3 (opens new window)