一、文件结构
1 2 3 4 5 6 7 8 9 10 11 12
| <template> // Vue2中,template标签中只能有一个根元素,在Vue3中没有此限制 // ... </template> <script setup> </script> <style lang="scss" scoped> // 支持CSS变量注入v-bind(color) </style>
|
二、data
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| <script setup> import { reactive, ref, toRefs } from 'vue' const name = ref('Jerry') name.value = 'Tom' const state = reactive({ name: 'Jerry', sex: '男' }) state.name = 'Tom' const {name, sex} = toRefs(state) // template可直接使用{{name}}、{{sex}} </script>
|
三、method
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| <template> // 调用方法 <button @click='changeName'>按钮</button> </template> <script setup> import { reactive } from 'vue' const state = reactive({ name: 'Jery' }) const changeName = () => { state.name = 'Tom' } </script>
|
四、computed
1 2 3 4 5 6 7 8 9 10
| <script setup> import { computed, ref } from 'vue' const count = ref(1) const doubleCount = computed(() => { return count.value * 2 }) </script>
|
五、watch
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| <script setup> import { watch, reactive } from 'vue' const state = reactive({ count: 1 }) const changeCount = () => { state.count = state.count * 2 } watch( () => state.count, (newVal, oldVal) => { console.log(state.count) console.log(`watch监听变化前的数据:${oldVal}`) console.log(`watch监听变化后的数据:${newVal}`) }, { immediate: true, deep: true } ) </script>
|
六、props父传子
子组件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| <template> <span>{{props.name}}</span> // 可省略【props.】 <span>{{name}}</span> </template> <script setup> // defineProps在<script setup>中自动可用,无需导入 const props = defineProps({ name: { type: String, default: '' } }) </script>
|
父组件
1 2 3 4 5 6 7 8
| <template> <child name='Jerry'/> </template> <script setup> import child from './child.vue' </script>
|
七、emit子传父
子组件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| <template> <span>{{props.name}}</span> // 可省略【props.】 <span>{{name}}</span> <button @click='changeName'>更名</button> </template> <script setup> // defineEmits和defineProps在<script setup>中自动可用,无需导入 const props = defineProps({ name: { type: String, default: '' } }) const emit = defineEmits(['updateName']) const changeName = () => { emit('updateName', 'Tom') } </script>
|
父组件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| <template> <child :name='state.name' @updateName='updateName'/> </template> <script setup> import { reactive } from 'vue' import child from './child.vue' const state = reactive({ name: 'Jerry' }) const updateName = (name) => { state.name = name } </script>
|
八、v-model
子组件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| <template> <span @click="changeInfo">我叫{{ modelValue }},今年{{ age }}岁</span> </template> <script setup> // defineEmits和defineProps在<script setup>中自动可用,无需导入 defineProps({ modelValue: String, age: Number }) const emit = defineEmits(['update:modelValue', 'update:age']) const changeInfo = () => { emit('update:modelValue', 'Tom') emit('update:age', 30) } </script>
|
父组件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| <template> // v-model:modelValue简写为v-model // 可绑定多个v-model <child v-model="state.name" v-model:age="state.age" /> </template> <script setup> import { reactive } from 'vue' import child from './child.vue' const state = reactive({ name: 'Jerry', age: 20 }) </script>
|
九、nextTick
1 2 3 4 5 6 7
| <script setup> import { nextTick } from 'vue' nextTick(() => { }) </script>
|
十、子组件ref变量和defineExpose
- 在标准组件写法里,子组件的数据都是默认隐式暴露给父组件的,但在 script-setup 模式下,所有数据只是默认 return 给 template 使用,不会暴露到组件外,所以父组件是无法直接通过挂载 ref 变量获取子组件的数据。
- 如果要调用子组件的数据,需要先在子组件显示的暴露出来,才能够正确的拿到,这个操作,就是由 defineExpose 来完成。
子组件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| <template> <span>{{state.name}}</span> </template> <script setup> import { defineExpose, reactive, toRefs } from 'vue' const state = reactive({ name: 'Jerry' }) const changeName = () => { state.name = 'Tom' } defineExpose({ ...toRefs(state), changeName }) </script>
|
父组件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| <template> <child ref='childRef'/> </template> <script setup> import { ref, nextTick } from 'vue' import child from './child.vue' const childRef = ref('childRef') nextTick(() => { console.log(childRef.value.name) childRef.value.changeName() }) </script>
|
十、插槽slot
子组件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| <template> <slot/> <slot name='title'/> <slot name="footer" :scope="state" /> </template> <script setup> import { useSlots, reactive } from 'vue' const state = reactive({ name: '张三', age: '25岁' }) const slots = useSlots() const defaultSlot = reactive(slots.default && slots.default().length) console.log(defaultSlot) const titleSlot = reactive(slots.title && slots.title().length) console.log(titleSlot) </script>
|
父组件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| <template> <child> <span>我是默认插槽</span> <template #title> <h1>我是具名插槽</h1> <h1>我是具名插槽</h1> <h1>我是具名插槽</h1> </template> <template #footer="{ scope }"> <footer>作用域插槽——姓名:{{ scope.name }},年龄{{ scope.age }}</footer> </template> </child> </template> <script setup> import child from './child.vue' </script>
|
十二、路由useRoute和useRouter
1 2 3 4 5 6 7 8 9 10 11 12 13
| <script setup> import { useRoute, useRouter } from 'vue-router' const route = useRoute() const router = useRouter() console.log(route.query) router.push('/newPage') </script>
|
十三、路由导航守卫
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| <script setup> import { onBeforeRouteLeave, onBeforeRouteUpdate } from 'vue-router' onBeforeRouteLeave((to, from, next) => { next() }) onBeforeRouteUpdate((to, from, next) => { next() }) </script>
|
十四、store
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| <script setup> import { useStore } from 'vuex' import { key } from '../store/index' const store = useStore(key) store.state.xxx store.commit('fnName') store.dispatch('fnName') store.getters.xxx </script>
|
十五、生命周期
通过在生命周期钩子前面加上 “on” 来访问组件的生命周期钩子。
下表包含如何在 Option API 和 setup() 内部调用生命周期钩子
Option API |
setup中 |
beforeCreate |
不需要 |
created |
不需要 |
beforeMount |
onBeforeMount |
mounted |
onMounted |
beforeUpdate |
onBeforeUpdate |
updated |
onUpdated |
beforeUnmount |
onBeforeUnmount |
unmounted |
onUnmounted |
errorCaptured |
onErrorCaptured |
renderTracked |
onRenderTracked |
renderTriggered |
onRenderTriggered |
activated |
onActivated |
deactivated |
onDeactivated |
十六、CSS变量注入
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| <template> <span>Jerry</span> </template> <script setup> import { reactive } from 'vue' const state = reactive({ color: 'red' }) </script> <style scoped> span { // 使用v-bind绑定state中的变量 color: v-bind('state.color'); } </style>
|
十七、原型绑定与组件内使用
main.js
1 2 3 4 5 6 7 8 9
| import { createApp } from 'vue' import App from './App.vue' const app = createApp(App)
const prototype = app.config.globalProperties
prototype.name = 'Jerry'
|
组件内使用
1 2 3 4 5 6 7 8 9
| <script setup> import { getCurrentInstance } from 'vue' const { proxy } = getCurrentInstance() console.log(proxy.name) </script>
|
十八、对 await 的支持
不必再配合 async 就可以直接使用 await 了,这种情况下,组件的 setup 会自动变成 async setup 。
1 2 3
| <script setup> const post = await fetch('/api').then(() => {}) </script>
|
十九、定义组件的name
用单独的