VUE3新特性

记录一些vue3的特性

difineProps()

1、用于组件通信中父级组件给子级组件传值,其用来声明props,其接收值为props选项相同的值

2、默认支持常见的类型检查,在ts下,我们需要明确变量的类型,类型经常是我们的自定义类型

3、只能在<script setup>中使用

4、不需要被导入即可使用,它会在编译<script setup>语法块时一同编译掉

5、必须在<script setup>的顶层使用,不可以在<script setup>的局部变量中引用

6、不可以访问 <script setup> 中定义的其他变量,因为在编译时整个表达式都会被移到外部的函数中

// 父组件
<template>
	<Aritice :title="AriticeItem.title" :info="AriticeItem.info" :author="AriticeItem.author">
	 <!-- v-bind ( : ) ,父组件将值绑定到子组件上 -->
    </Aritice>
</template>
<script setup>
	import { reactive } from 'vue';
	import Article from '@/components/Article.vue';
	const AriticeItem = reactive({
		title: '文章标题',
	    info: '文章内容',
	    author: 'X',
	  });
</script>
// 子组件
<template>
	<section>
  		<p>{{ title }}</p>
    	<p>{{ info }}</p>
    	<p>{{ author }}</p>
	</section>
</template>
<script setup>
	const props = defineProps({
		title: {
            type:String ,// 如果可能存在多个类型,则可以写成 [String,Number]
            default:'默认值',
            required: true// 是否必传 ,在不声明为true 的情况下,所有prop 默认为非必填。
        },
		info: String,
		author: String,
	});// 对象形式声明 props
	// 等价于以 字符串数组声明 props
	//const props = defineProps(['title', 'info', 'author']);
	// 如果在setup中使用则直接 props.title
</script>

需要注意的是,props传递数据一般是单向的,不建议在子组件中修改props中的值,如果需要在子组件中对props的值进行处理,使用ref将他变为响应式状态数据

const formatTitle = ref(props.title)
//这样,子组件中后续对 formatTitle 的修改,就与原props.title 无关联了

defineEmits()

1、用于组件通信中子级组件向父级组件传值,其用来声明emit,其接收内容于emit选项一致

2、只能在<script setup>中使用

3、不需要被导入即可使用,它会在编译<script setup>语法块时一同编译掉,

4、必须在<script setup>的顶层使用,不可以在<script setup>的局部变量中引用

// 子组件
<div class="hello">
  <button @click="btn">点击</button>
</div>
<script setup>
/**
 * 在子组件中使用defineEmits来声明emits
 * 其接收值与emit选项一致
 * 传入的选项在全局变量
 * emits函数是defineEmits返回值
 * defineEmits函数参数是个数组,数组内容是自定义函数名称
 * emits函数第一个参数是自定义事件名称,第二个参数是需要传递的内容
 * defineEmits如果放在局部。不在全局。则报错
 * defineEmits is not defined
 * @type {EmitFn<string[]>}
 */
const emits = defineEmits(['handle']);
const btn = () => {
  emits('handle', '张三')
}
</script>
// 父级组件中
<div class="home">
  <HelloWorld @handle="handleClick"/>
</div
<script setup>
import HelloWorld from '@/components/HelloWorld'
/**
 * 在父级组件中,使用子级的自定义事件,
 * 在html中去写@自定义事件名称=事件名称
 * 函数中data是个形参,为子级传递过来的数据
 * @param data
 */
const handleClick = function (data) {
  console.log(data)
}
</script>

如果参数有多个,建议用对象形式传递

//子组件发送
emits('increase', {params1: '1',params2: '2'});
//父组件监听
const handleIncrease = (params) => {
	console.log(params); //{params1: '1',params2: '2'}
};

provide&inject依赖注入

通常用于跨级组件之间传递数据

provide() 接受两个参数:

  • 第一个参数是要注入的 key,可以是一个字符串或者一个 symbol;
  • 第二个参数是要注入的值。

inject()可以接受三个参数:

  • 第一个参数是注入的 key。
  • 第二个参数是可选的,即在没有匹配到 key 时使用的默认值。它也可以是一个工厂函数,用来返回某些创建起来比较复杂的值。
  • 第三个参数是可选的,类型为布尔值。当第二个参数的值就是一个函数,而不是工厂函数时,需要使用将值设置为 false。

当使用响应式 provide/inject 值时,建议尽可能将任何对响应式状态的变更都保持在 provider 内部。这样可以确保 provide 的状态和变更操作都在同一个组件内,使其更容易维护。

// 父组件
<template>
  <section class="item" @click="onClick">PARENT {{ num }}</section>
  <childVue /> <!-- 引入子组件 -->
</template>
<script setup>
  import childVue from './child.vue';
  import { ref, provide } from 'vue';
  const num = ref(0);
  const onClick = () => {
    num.value++;
  }; 
  // 新增函数
  const increaseNum = (params) => {
    num.value += params;
  };
  // 将 increaseNum 函数作为值提供
  provide('count', { num, increaseNum });
</script>

// 孙组件,通过父组件传递过来的函数修改num值,不要自身直接修改
<template>
  <!-- 新增点击事件 -->
  <section class="item"  @click="onClick">GRANDCHILDREN {{ num }}</section>
</template>
<script setup>
  import { inject } from 'vue';
  // 在注入出添加 increaseNum 变量
  const { num, increaseNum } = inject('count');
  // 新增的点击事件,触发 increaseNum 并且传参为 2 
  const onClick = () => {
    increaseNum(2);
  };
</script>

Last Updated:
Contributors: liushun-ing