Vue3.0 暴露变量必须 return 出来,template中才能使用;
Vue3.2 中 只需要在 script 标签上加上 setup 属性,组件在编译的过程中代码运行的上下文是在 setup() 函数中,无需return,template可直接使用。
文件结构
<template>
// Vue2中,template标签中只能有一个根元素,在Vue3中没有此限制
// ...
</template>
<script setup>
// ...
</script>
<style lang="scss" scoped>
// 支持CSS变量注入v-bind(color)
</style>
响应式数据
<script setup>
import { reactive, ref, toRefs } from 'vue'
// ref声明响应式数据,用于声明基本数据类型
const name = ref('Jerry')
// 修改
name.value = 'Tom'
// reactive声明响应式数据,用于声明引用数据类型
const state = reactive({
name: 'Jerry',
sex: '男'
})
// 修改
state.name = 'Tom'
// 使用toRefs解构 template可直接使用{{name}}、{{sex}}
const {name, sex} = toRefs(state)
</script>
声明method方法
<template>
// 调用方法
<button @click='changeName'>按钮</button>
</template>
<script setup>
import { reactive } from 'vue'
const state = reactive({
name: 'Jery'
})
// 声明method方法
const changeName = () => {
state.name = 'Tom'
}
</script>
computed
<script setup>
import { computed, ref } from 'vue'
const count = ref(1)
// 通过computed获得doubleCount
const doubleCount = computed(() => {
return count.value * 2
})
</script>
watch
<script setup>
import { watch, reactive } from 'vue'
const state = reactive({
count: 1
})
// 声明方法
const changeCount = () => {
state.count = state.count * 2
}
// 监听count
watch(
() => state.count,
(newVal, oldVal) => {
console.log(state.count)
console.log(`watch监听变化前的数据:${oldVal}`)
console.log(`watch监听变化后的数据:${newVal}`)
},
{
immediate: true, // 立即执行
deep: true // 深度监听
}
)
</script>
props父传子 / emit子传父
父组件
<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>
子组件
<template>
<span>{{props.name}}</span>
<span>{{name}}</span>
<button @click='changeName'>更名</button>
</template>
<script setup>
// import { defineEmits, defineProps } from 'vue'
// defineEmits和defineProps在<script setup>中自动可用,无需导入
// 需在.eslintrc.js文件中【globals】下配置【defineEmits: true】、【defineProps: true】
// 声明 props 属性
const props = defineProps({
name: {
type: String,
default: ''
}
})
// 声明 emit 事件
const emit = defineEmits(['updateName'])
const changeName = () => {
emit('updateName', 'Tom')
}
</script>
子组件ref变量和defineExpose
在标准组件写法里,子组件的数据都是默认隐式暴露给父组件的,
但在script-setup 模式下,所有数据只是默认 return 给 template 使用,不会暴露到组件外,所以父组件是无法直接通过挂载 ref 变量获取子组件的数据。
如果要调用子组件的数据,需要先在子组件显示的暴露出来,才能够正确的拿到,这个操作,就是由 defineExpose 来完成。
父组件
<template>
<child ref='childRef'/>
</template>
<script setup>
import { ref, nextTick } from 'vue'
// 引入子组件
import child from './child.vue'
// 子组件ref
const childRef = ref('childRef')
// nextTick
nextTick(() => {
// 获取子组件name
console.log(childRef.value.name)
// 执行子组件方法
childRef.value.changeName()
})
</script>
子组件
<template>
<span>{{state.name}}</span>
</template>
<script setup>
import { reactive, toRefs } from 'vue'
// defineExpose无需引入
// import { defineExpose, reactive, toRefs } from 'vue'
// 声明state
const state = reactive({
name: 'Jerry'
})
// 将方法、变量暴露给父组件使用,父组件才可通过ref API拿到子组件暴露的数据
defineExpose({
// 解构state
...toRefs(state),
// 声明方法
changeName () {
state.name = 'Tom'
}
})
</script>
路由useRoute和useRouter
<script setup>
import { useRoute, useRouter } from 'vue-router'
// 必须先声明调用
const route = useRoute()
const router = useRouter()
// 路由信息
console.log(route.query)
// 路由跳转
router.push('/newPage')
</script>
vuex
*Vue3 中的Vuex不再提供辅助函数写法
<script setup>
import { useStore } from 'vuex'
import { key } from '../store/index'
// 必须先声明调用
const store = useStore(key)
// 获取Vuex的state
store.state.xxx
// 触发mutations的方法
store.commit('fnName')
// 触发actions的方法
store.dispatch('fnName')
// 获取Getters
store.getters.xxx
</script>
全局事件绑定与组件内使用
main.js
import { createApp } from 'vue'
import App from './App.vue'
const app = createApp(App)
// 获取原型
const prototype = app.config.globalProperties
// 绑定参数
prototype.name = 'Jerry'
组件内使用
<script setup>
import { getCurrentInstance } from 'vue'
// 获取原型
const { proxy } = getCurrentInstance()
// 输出
console.log(proxy.name)
</script>
对 await 的支持
不必再配合 async 就可以直接使用 await 了,这种情况下,组件的 setup 会自动变成 async setup
<script setup>
const post = await fetch('/api').then(() => {})
</script>
provide和inject
父组件
<script setup>
import { provide } from 'vue'
// 声明provide
provide('provideState',
changeName: () => {name.value = 'Tom'}
)
</script>
子组件
子组件
<script setup>
import { inject } from 'vue'
// 注入
const provideState = inject('provideState')
// 子组件触发name改变
provideState()
</script>
关于Component标签动态渲染组件
在 < script setup> 中要使用动态组件时,需要直接用 :is=“Component” 直接绑定到组件本身,而不是字符串的组件名。
<template>
<component
:is="typeComponentMap[currentComp]?.modal"
:id="asDetailId"
></component>
</template>
<script setup lang="ts">
import productValueDetails from '/@/views/economics/project/index/productValueDetails/index.vue'
import collectionDetails from '/@/views/economics/project/index/collectionDetails/index.vue'
import projectDetails from '/@/views/economics/project/details/index.vue'
import balanceDetails from '/@/views/economics/project/index/balanceDetails/index.vue'
const typeComponentMap: any = {
productValueDetails: {
title: '项目产值明细',
modal: productValueDetails
},
collectionDetails: {
title: '项目收款明细',
modal: collectionDetails
},
projectDetails: {
title: '项目详情',
modal: projectDetails
},
balanceDetails: {
title: '项目盈亏明细',
modal: balanceDetails
}
}
const props = defineProps({
// 业务名: 对应typeComponentMap的key
currentComp: {
type: String,
default: ''
},
// 业务需要的id
asDetailId: {
type: String,
default: ''
}
})
</script>
<style scoped></style>