setup 语法糖
详解:
1.目前setup sugar已经进行了定稿,vue3 + setup sugar + TS的写法看起来很香,写本文时 Vue 版本是 "^3.2.6"
2.新的 setup 选项是在组件创建之前, props 被解析之后执行,是组合式 API 的入口。
WARNING\ 在
setup中你应该避免使用this,因为它不会找到组件实例。setup的调用发生在dataproperty、computedproperty 或methods被解析之前,所以它们无法>在setup中被获取。
setup 选项是一个接收 props 和 context 的函数,我们将在之后进行讨论。此外,我们将 setup 返回的所有内容都暴露给组件的其余部分 (计算属性、方法、生命周期钩子等等) 以及组件的模板。
它是 Vue3 的一个新语法糖,在 setup 函数中。所有 ES 模块导出都被认为是暴露给上下文的值,并包含在 setup() 返回对象中。相对于之前的写法,使用后,语法也变得更简单。
基础模板
<template>
<div>
</div>
</template>
<script setup>
</script>
<style lang="scss" scoped>
</style>
1. 属性和方法无需返回,直接使用
以前使用响应式数据是
<template>
{{msg}}
</template>
<script>
import { ref } from 'vue'
export default {
setup () {
const msg = ref('你好 vue3');
return {
msg
}
}
}
</script>
现在使用
<template>
{{msg}}
</template>
<script setup>
import { ref } from 'vue'
const msg = ref('你好 vue3');
</script>
reactive, computed, 也一样可以使用:
<template>
<div>{{msg}}</div>
<div>{{objs.a1}}</div>
<div>{{sum}}</div>
</template>
<script setup>
import { ref, reactive, computed } from 'vue'
const msg = ref('你好 vue3');
const objs = reactive({
a1: 1,
b1: 2
})
const sum = computed(() => {
return obj.a1 + 3;
});
</script>
2. 组件自动注册
父组件
<template>
<div class="login">
<HelloWorld :msg="msg" @changMsg="changMsg"></HelloWorld>
</div>
</template>
<script setup>
import HelloWorld from '../components/HelloWorld.vue'
import { ref } from 'vue'
const msg = ref('我是父组件的msg')
const changMsg = (val) =>{
msg.value = val
}
</script>
<style lang="scss" scoped>
</style>
子组件
<template>
<h1>{{ msg }}</h1>
<el-button @click="handleChange">改变父组件的msg</el-button>
</template>
<script setup>
import { defineProps, defineEmits } from 'vue'
defineProps({
msg: String
})
const emit = defineEmits(['changMsg'])
const handleChange = () =>{
emit('changMsg','子附件改变父组件的值')
}
</script>
<style lang="scss" scoped>
</style>
main.js的引入
import { createApp } from 'vue'
import App from './App.vue'
import router from './router';
import store from './store'
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
const app = createApp(App)
app.use(ElementPlus).use(router).use(store).mount('#app')
vuex的操作
./store/index.js
import { createApp } from 'vue'
import { createStore } from 'vuex'
// Create a new store instance.
const store = createStore({
state() {
return {
userInfo: { name: 'tanwei', age: 18 }
}
},
mutations: {
increment(state) {
state.count++
},
changeUserInfo(state, val) {
console.log(state, 111);
state.userInfo = val
}
},
actions: {
changeUserInfoAction({ commit }, val) {
commit('changeUserInfo', val)
}
}
})
export default store;
在main.js里引用
import { createApp } from 'vue'
import App from './App.vue'
import router from './router';
import store from './store'
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
const app = createApp(App)
app.use(ElementPlus).use(router).use(store).mount('#app')
在组件内使用
<template>
<div class="login">
{{userInfo.name}}
<el-button @click="changeUserInfo">修改vuex用户信息</el-button>
</div>
</template>
<script setup>
import { ref, reactive, toRefs } from 'vue'
import { useStore } from "vuex";
const store = useStore();
const { userInfo } = toRefs(store.state);
const changeUserInfo = () => {
store.dispatch('changeUserInfoAction',{name:'hahaha',age:19})
}
</script>
<style lang="scss" scoped>
</style>
对外暴露属性(defineExpose)
<script setup> 的组件默认不会对外部暴露任何内部声明的属性。
如果有部分属性要暴露出去,可以使用 defineExpose
子组件 Child.vue
<template>
{{msg}}
</template>
<script setup>
import { ref } from 'vue'
let msg = ref("组件");
let num = ref(1234);
// defineExpose无需导入,直接使用
defineExpose({
msg,
num
});
</script>
父组件 Home.vue
<template>
<Child ref="child" />
</template>
<script setup>
import { ref, onMounted } from 'vue'
import Child from '@/components/Child.vue'
let child = ref(null);
onMounted(() => {
console.log(child.value.msg); // Child Components
console.log(child.value.num); // 123
})
</script>