setup函数
setup函数原理说明
由于setup 是在beforeCreate 和 create 生命周期阶段,组件还没有创建,即还没有进入 data 方法 阶段。
setup 返回的结果集 作为 (传统写法)data 和 method 的值,确切点说是绑定到 组件对象的属性。
< script setup> 是在单文件组件 (SFC) 中使用组合式 API 的编译时语法糖。当同时使用 SFC 与组合式 API 时该语法是默认推荐。相比于普通的 < script > 语法,具有以下特点:
要启用该语法,需要在
<script setup>
console.log('hello script setup')
script>
这个脚本块将被预处理为组件的 setup() 函数,这意味着:每次组件实例被创建的时候执行。< script setup> 中的顶层绑定都将自动暴露给模板。
响应式状态需要明确使用响应式 API 来创建。和 setup() 函数的返回值一样,ref 在模板中使用的时候会自动解包
**使用setup函数**
<template>
<div>{{ num }}div>
template>
<script>
import { ref } from "vue";
export default {
name: "Home",
setup() {
const num = ref("setup函数形式");
return { num };
},
};
script>
**使用<script setup>**
<template>
<div>{{ num }}div>
template>
<script setup>
import { ref } from "vue";
const num = ref(10784512);
script>
当使用 < script setup> 的时候,任何在 < script setup> 声明的顶层的绑定 (包括变量,函数声明,以及 import 导入的内容) 都能在模板中直接使用。
使用setup函数形式
<template>
<div>
<Child>Child>
div>
template>
<script>
import Child from "./Child.vue";
export default{
components:{
Child
}
}
script>
使用setup语法糖形式
<template>
<div>
<Child>Child>
div>
template>
<script setup>
import Child from "./Child.vue";
script>
当使用语法糖形式,不需要在component 在注册了,直接引入使用组件即可。强烈建议使用 PascalCase (驼峰式)格式以保持一致性。同时也有助于区分原生的自定义元素。
<template>
<component :is="someCondition ? Child : ToRef" />
template>
<script setup>
import {ref} from 'vue'
import Child from "./Child.vue";
import ToRef from "./Toref.vue";
const someCondition=ref('1')
script>
由于组件是通过变量引用而不是基于字符串组件名注册的,
在 < script setup> 中要使用动态组件的时候,应该使用*动态的 :is 来绑定
setup函数形式
<template>
<div class="home">
<h1>使用了setup函数h1>
<h2> {{lowercase1(name)}}h2>
div>
template>
<script>
import { ref } from 'vue'
import { lowercase } from '@/utils/lowercase.js'
export default {
setup () {
const name = ref('MYNAME')
const lowercase1 = lowercase
return { name, lowercase1 }
}
}
script>
setup语法糖形式
<template>
<div class="about">
<h1>使用了script setuph1>
<h2>1.使用变量 {{lowercase(name)}}h2>
div>
template>
<script setup>
import { lowercase } from '@/utils/lowercase.js'
import { ref } from 'vue'
const name = ref('MYNAME')
script>
不需要在定义成一个方法,script setup格式直接使用即可
setup函数形式
在 Setup 函数会接收两个参数,第一个参数就是组件的 Props传递过来的参数。和标准的组件一致,Setup 函数的 Props 是响应式的,并且会在传入新的 Props 时同步更新。
第二个参数是 content中有四个参数:
1、attrs: 该参数接受的是父组件传值到子组件的时候,子组件中未在props中配置的值;
2、emit: 该参数作为子父组件传值使用,传递给父组件需要使用到该字段,;
<template>
<div class="demo">
我是script setup的父组件
<hr />
<Child :list="list" :msg="msg" @change="handleChange">Child>
div>
template>
<script>
import { ref, defineProps, reactive } from "vue";
import Child from "./Child.vue";
export default {
components: { Child },
setup() {
let list = ref("张三");
let msg = ref("123");
const handleChange = (e) => {
console.log(e);
};
return {
list,
msg,
handleChange,
};
},
};
script>
<template>
<div>
<h3>我是子级组件h3>
<h4>我接收到父组件的 数据 => {{ list }}h4>
<hr />
<button @click="handleClick">子组件传值到父组件button>
div>
template>
<script>
import { onMounted } from 'vue';
export default {
props: {
// 注意:父组件传到子组件的字段必须要在这里定义
list: String,
},
setup(props, context) {
/**
props:
content中有四个参数:
1、attrs: 该参数接受的是父组件传值到子组件的时候,子组件中未在props中配置的值;
2、emit: 该参数作为子父组件传值使用,传递给父组件需要使用到该字段;
*/
console.log( context.attrs, "12"); //打印attrs 查看其他未定义接收的变量
const handleClick = () => {
context.emit("change", "来自子组件的消息"); //子传父方法:emit(‘自定义事件名称’,'传递的参数')
};
return {
props,
handleClick,
};
},
};
script>
setup语法糖
<template>
<div class="demo">
我是script setup的父组件
<hr>
<Child :list="list">Child>
div>
template>
<script setup>
import {ref, onMounted, reactive } from 'vue';
import Child from "./Child.vue";
const list = reactive([{name: 'zl'}])
script>
<template>
<div class="demo">
<div>我是script setup子组件 :{{ props.list[0].name }}div>
div>
template>
<script setup>
import { onMounted } from "vue";
// 子组件中, 接收 Props 参数 Vue 提供了一个 新的 API 函数 defineProps()方法,就和我们在 Vue2 的子组件中 定义 Props 待接收参数配置一样。
// 必须要使用defineProps进行配置传入的属性,否则无法获取到传入的值.
const props = defineProps({
list: {
type: Array,
required: true, // 是否必传
default: "备用数据", //默认数据
},
});
onMounted(() => {
console.log(props.list, "123");
});
script>
<template>
<div class="demo">
我是script setup的父组件
<hr>
<Child @exposeData="getData">Child>
div>
template>
<script setup>
import {ref, onMounted, reactive } from 'vue';
import Child from "./Child.vue";
const getData = (val)=>{
console.log("接收子组件的值",val)
}
script>
<template>
<div class="demo">
<h3>子组件h3>
<button @click="toValue">触发子组件数据button>
div>
template>
<script setup>
// setup 语法糖写法
//用defineEmits()来定义子组件要抛出的方法,语法defineEmits(['要抛出的方法','参数'])
const emit = defineEmits(['exposeData'])
const toValue = ()=>{
emit('exposeData','张三 -- 18')
}
script>
父组件要想通过ref获取子组件的变量或函数,子组件须使用defineExpose暴露出去
setup函数形式
<template>
<Child ref="childRef" />
<Child ref="childRefTwo" />
template>
<script>
import { ref, onMounted, getCurrentInstance } from "vue";
import Child from "./Child.vue";
export default {
components: { Child },
setup() {
const childRef = ref(null); // 当前变量必须要与子组件上绑定的ref对应起来,(不需要使用defineExpose将方法暴露出来,可以直接使用ref获取)
const instance = getCurrentInstance(); //获取当前组件实例
onMounted(() => {
// 方法一
childRef.value.open(); // 调用子组件中的open方法
// 方法二
instance.proxy.$refs.childRefTwo.open(); // 调用子组件中的open方法
});
return { childRef, instance };
},
};
script>
<template>
<div>
<div @click="open">子组件传值到父组件div>
div>
template>
<script>
import { onMounted } from "vue";
export default {
props: {
list: String,
},
setup() {
const open = () => {
console.log("open点击了");
};
return { open };
// setup函数定义的函数,不需要使用defineExpose将方法暴露出来,可以直接使用ref获取
},
};
script>
setup语法糖形式
<template>
<Child ref="childRef" />
<Child ref="childRefTwo" />
template>
<script setup>
import { ref, onMounted, getCurrentInstance } from "vue";
import Child from "./Child.vue";
const childRef = ref(null);
const instance = getCurrentInstance(); //获取当前组件实例
// 扩展讲解
// 获取当前组件的上下文,下面两种方式都能获取到组件的上下文。
// 方式一,这种方式只能在开发环境下使用,生产环境下的ctx将访问不到
// const { ctx } = getCurrentInstance();
// // 方式二,此方法在开发环境以及生产环境下都能放到组件上下文对象(推荐)
// const { proxy } = getCurrentInstance();
// // ctx 中包含了组件中由ref和reactive创建的响应式数据对象,以及以下对象及方法;
// console.log(instance,'555');
onMounted(() => {
// 方法一
childRef.value.open(); // 调用子组件中的open方法
// 方法二
instance.proxy.$refs.childRefTwo.open(); // 调用子组件中的open方法
});
script>
<template>
<div>
<div @click="open">子组件传值到父组件div>
div>
template>
<script setup>
import { onMounted,defineExpose } from "vue";
const open = () => {
console.log("open点击了");
};
defineExpose({ open }); // 必须要注册进来
// vue3中,语法糖中定义的方法,默认是不会暴露给ref进行调用的,必须要注册到defineExpose里面,
// ref才能正常访问,如果没有注册到defineExpose中,通过ref调用子组中的方法,会报错
script>
在 < script setup> 使用 slots 和 attrs 的情况应该是很罕见的,因为可以在模板中通过 s l o t s 和 slots 和 slots和attrs 来访问它们。在你的确需要使用它们的罕见场景中,可以分别用 useSlots 和 useAttrs 两个辅助函数:
<script setup>
import { useSlots, useAttrs } from 'vue'
const slots = useSlots()
const attrs = useAttrs()
script>
useSlots 和 useAttrs 是真实的运行时函数,它会返回与 setupContext.slots 和 setupContext.attrs 等价的值,同样也能在普通的组合式 API 中使用
< script setup >可以和普通的< script >一起使用。普通的< script >在有这些需要的情况下或许会被使用到:
<script>
// 普通