【Vue3】setup(setup函数与script setup)示例,用法以及原理(持续更新)

目录
- setup函数
- setup函数原理说明
 - setup函数特性
 - setup函数注意点
 - setup函数中的watch与computed
 - setup拆分实例
 
 - script setup
- setup 包含的生命周期
 - script setup使用方法
 - script setup的作用
- 自动注册子组件
 - 属性和方法无需返回
 - 支持props、emit和context
- defineProps, defineEmits
 - defineExpose
 - useSlots 和 useAttrs
 - 实例
 
 
 
 
Vue3 中的setup 一种是setup函数,一种是script setup
setup函数
setup函数原理说明
由于setup 是在beforeCreate 和 create 生命周期阶段,组件还没有创建,即还没有进入 data 方法 阶段。
setup 返回的结果集 作为 (传统写法)data 和 method 的值,确切点说是绑定到 组件对象的属性。
setup函数特性
1、setup函数是处于 生命周期函数 beforeCreate 和 Created 两个钩子函数之间的函数 也就说在 setup函数中是无法 使用 data 和 methods 中的数据和方法的
2、setup函数是 Composition API(组合API)的入口
3、在setup函数中定义的变量和方法最后都是需要 return 出去的 不然无法再模板中使用
setup 函数将接收两个参数,props&context
Props :props接收父组件传入的值,为Proxy对象,且为响应式,所以不能使用 ES6 解构,它会消除 prop 的响应性
context:官方解释=>context 是一个普通的 JavaScript 对象,它暴露组件的三个 property:
export default {  setup(props, context) {
    // Attribute (非响应式对象)
    console.log(context.attrs)
    // 插槽 (非响应式对象)
    console.log(context.slots)
    // 触发事件 (方法)
    console.log(context.emit)
  }
}
setup函数注意点
1、由于在执行 setup函数的时候,还没有执行 Created 生命周期方法,所以在 setup 函数中,无法使用 data 和 methods 的变量和方法
2、由于我们不能在 setup函数中使用 data 和 methods,所以 Vue 为了避免我们错误的使用,直接将 setup函数中的this修改成了 undefined
3、setup函数只能是同步的不能是异步的
setup函数中的watch与computed
看下面的setup拆分实例 grandson.vue的例子
setup拆分实例
main.js
import { createApp } from \'vue\'import App from \'./App.vue\'
createApp(App).mount(\'#app\')
App.vue
<script setup>import Parent from \'./components/parent.vue\'
</script>
<template>
  <Parent></Parent>
</template>
<style>
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>
parent.vue
<template>    <div @click="handleClick">我是父组件 {{info}}
        <son></son>
    </div>
</template>
<script>
import { defineComponent } from \'vue\'
import son from \'./son.vue\'
import useInfo from \'./info.js\'
export default defineComponent({
    setup() {
        let {info, handleClick} = useInfo()
        return {
            info,
            handleClick
        }        
    },
    components: {
        son
    }
})
</script>
info.js
import {provide, reactive, ref } from \'vue\'
let useInfo = () => {
    let info = ref(123);
        let datas = reactive({
            width: 100,
            height: 50,
            bg: \'pink\'
        });
        const updateInfo = (val) => {
            info.value = val
        }
        const handleClick = () => {
            console.log(\'handleClick了\');
            info.value++;
            console.log(\'info.value:\' + info.value);
        }
        provide(\'info\', info);
        provide(\'datas\', datas)
        provide("updateInfo", updateInfo);
        return {
            info,
            handleClick
        }
}
export default useInfo
son.vue
<template>    <div>我是子组件 {{info}}
        <grand-son ref="compa"></grand-son>
    </div>
</template>
<script>
import { defineComponent, inject } from \'vue\'
import grandSon from \'./grandSon.vue\';
export default defineComponent({
    setup() {
        const info = inject(\'info\');
        return {
            info
        }
    },
    components: {
        grandSon
    }
})
</script>
grandson.vue
<template>    <div>我是孙子组件 <button @click="updateInfo(\'456\')">点击更新info</button>{{info}} computed: {{computedInfo}}<br />宽度{{datas.width}},  高度:{{datas.height}}, 背景: {{datas.bg}}</div>
</template>
<script>
import { defineComponent , inject, watch, computed} from \'vue\'
export default defineComponent({
    setup() {
        const info = inject(\'info\');
        const updateInfo = inject(\'updateInfo\');
        const datas = inject(\'datas\');
        watch(info, (val) => {
            console.log(\'变了\');
            console.log(val);
        });
        const computedInfo = computed(() => { 
            console.log(\'computed 改变了info\')
            return info.value + 10
        })
        return {
            info,
            datas,
            updateInfo,
            computedInfo
        }
    },
})
</script>
script setup
script setup 是在单文件组件 (SFC) 中使用组合式 API 的编译时语法糖。
<script setup>// 变量
const msg = \'Hello!\'
// 函数
function log() {
  console.log(msg)
}
// click 那里有问题
</script>
<template>
<div>
  <div @click="log">我是: {{ msg }}</div>
</div>
</template>
setup 包含的生命周期
script setup使用方法
<script setup></script>script setup的作用
自动注册子组件
Vue2
<template>  <div>
    <h2>父组件!</h2>
    <Child />
  </div>
</template>
<script>
import Child from \'./Child.vue\'
export default {
    component: {
        Child // 注册子组件后方可在template中使用
    }
}
</script>
Vue3:
<template>  <div>
    <h2>父组件!</h2>
    <Child />
  </div>
</template>
<script>
import { defineComponent, ref } from \'vue\';
import Child from \'./Child.vue\'
export default defineComponent({
 components: { 
     Child // 注册子组件后方可在template中使用
 }, 
 setup() { 
     return { 
     } 
 }
});
</script>
setup script语法
<template>  <div>
    <h2>父组件!-setup script</h2>
    <Child />
  </div>
</template>
<script setup>
import Child from \'./Child.vue\'
// 省略了子组件注册的过程,import后可直接在template中使用
</script>
属性和方法无需返回
vue3.x语法:
如需在template中使用属性和方法,必须手动返回对应的属性和方法。这种composition API的编写规则,相对繁琐。如下:
<template>  <div>
    <h2 @click="addCount">购买数量 {{ count}} 件</h2>
  </div>
</template>
<script>
import { defineComponent, ref } from \'vue\';
export default defineComponent({
    setup() {
        const count = ref(1)
        const addCount = () => {
          count.value++
        }
        return {
            count,
            addCount
        }
    }
});
</script>
setup script语法
<template>  <div>
    <h2 @click="addCount">购买数量 {{ count}} 件</h2>
  </div>
</template>
<script setup>
import { ref } from \'vue\';
const count = ref(1)
const addCount = () => {
  count.value++
}
</script>
支持props、emit和context
vue3.x语法
前面setup函数中提及,setup函数包含props和context2个参数,通过这两个参数,达到数据通信及事件触发的目的。
setup scrip语法
没有setup()那怎么获取到props和context呢?
setup script语法糖提供了三个新的API来供我们使用:defineProps、defineEmit和useContext。
defineProps用来接收父组件传来的值props;
defineEmit用来声明触发的事件表;
useContext用来获取组件上下文context
defineProps, defineEmits
在 script setup 中必须使用 defineProps 和 defineEmits API 来声明 props 和 emits ,它们具备完整的类型推断并且在 script setup 中是直接可用的。
<script setup>const props = defineProps({
  foo: String
});
const emit = defineEmits([\'change\', \'delete\']);
// setup code
</script>
defineExpose
使用 script setup 的组件是默认关闭的,也即通过模板 ref 或者 $parent 链获取到的组件的公开实例,不会暴露任何在 script setup 中声明的绑定。当父组件通过模板 ref 的方式获取到当前组件的实例。
<script setup>import { ref } from \'vue\'
const a = 1
const b = ref(2)
defineExpose({
  a,
  b
})
</script>
useSlots 和 useAttrs
在 script setup 使用 slots 和 attrs 的情况应该是很罕见的,因为可以在模板中通过 $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 中使用。
实例
父组件:
<template>  <div>
    <h2>我是父组件!-setup script</h2>
    <Child ref="child" msg="hello" @child-click="childCtx" />
  </div>
</template>
<script setup>
import { ref, onMounted } from \'vue\'
import Child from \'./child.vue\'
const childCtx = (e) => {
  console.log(\'我是emit出来的值:\' + e) 
}
let child = ref(null);
onMounted(() => {
	console.log(\'我是expose出来的值:\' + child.value.name); // 123
})
</script>
子组件:
<template>  <div>
    <span @click="handleClick">我是子组件! -- msg: {{ props.msg }}</span>
  </div>
</template>
<script setup>
import { ref, defineProps, defineEmits, defineExpose, useAttrs, useSlots } from \'vue\'
const name = ref(\'expose name value\')
const emit = defineEmits([\'child-click\'])
const props = defineProps({
  msg: String
})
const handleClick = () => {
  emit(\'child-click\', \'emit click value\')
}
const slots = useSlots();
const attrs = useAttrs();
console.log(slots)
console.log(attrs)
defineExpose({
  name
})
</script>
以上是 【Vue3】setup(setup函数与script setup)示例,用法以及原理(持续更新) 的全部内容, 来源链接: utcz.com/z/375971.html

