在使用composition api的时候,setup()函数的写法写多了会感觉有些繁琐,比如每次都需要return出去,不同类型变量要分ref和reactive调用等。这里就记录一下尤大大在vue3正式版发布不到两个月后推出的script setup特性。
一些细节点这里没有记录,推荐看官方文档:响应式基础
网上说:从3.2之后,ref的性能提升很大,且以后基本数据类型或者是复杂数据类型都用ref去做处理。
我去看了源码,复杂数据类型还是借助了reactive
去做响应式处理,不过都用ref
确实方便一些。
<script setup>
import { ref } from 'vue'
// 定义
const obj = ref({
name: 'nick'
})
const str = ref('a')
// 然后就可以在模板或者js中使用了,但是在js中使用的时候要xxx.value去取值
<script>
<template>
<div>
{{ str }}
</div>
</template>
标签的变量能直接用在模板上,官方说可以理解成他们在同一个作用域。前面说调用属性value的方式取值比较麻烦,已经出了一个新的实验性质的写法(最近看好像又被毙掉了):
<script setup>
let count = $ref(0)
function increment() {
// 无需 .value
count++
}
</script>
<template>
<button @click="increment">{{ count }}</button>
</template>
还有个小技巧说下
<script setup>
import { ref } from 'vue'
// 定义
const arr = ref([])
let aMap = new Map()
function addItemNum(item) {
let itemCurrent = aMap.get(item.id)
if (itemCurrent) {
itemCurrent.num++
} else {
let itemNew = {
...item,
num: 1
}
arr.value.push(itemNew)
aMap.set(item.id, itemNew)
}
}
<script>
当itemCurrent.num++触发时,arr对应的子项数据是不会改变的,因为后续itemNew存在aMap变量里的并不是响应式数据,所以要这样处理下:
function addItemNum(item) {
let itemCurrent = aMap.get(item.id)
if (itemCurrent) {
itemCurrent.num++
} else {
let itemNew = ref({
...item,
num: 1
})
arr.value.push(itemNew.value)
aMap.set(item.id, itemNew.value)
}
}
<script setup>
import { computed } from 'vue'
// 定义
const a = computed(() => {
return xxx
})
// 使用 js中使用,a.value ,模板中直接{a}即可
<script>
同样可以写getter和setter:
<script setup>
import { ref, computed } from 'vue'
const a = ref('1')
const b = ref('2')
const aplusb = computed({
// getter 这个就是日常的computed功能
get() {
return a.value + ' ' + b.value
},
// setter 这个则是可以通过修改计算属性,改变所依赖响应式变量的值,例如aplusb.value = '3,4'
set(newValue) {
[a.value, b.value] = newValue.split(',') // 解构赋值语法
}
})
</script>
官方说明:
<script setup>
import { watch } from 'vue'
watch(
xxx,
() => {
// 处理逻辑
},
{
// 监听配置
immediate: true
}
)
<script>
<script setup>
import { defineProps } from 'vue'
// 定义
const props = defineProps({
a: {
type: String,
required: true,
default: ''
}
})
// 使用 props.a
<script>
<script setup>
import { useStore } from 'vuex'
// 定义
const store = useStore();
// 使用例子actions
store.dispatch("xxx", xxx).then()
<script>
// 自定义组件中
<script setup>
import { defineProps, defineEmits } from 'vue'
defineProps({
modelValue: {
type: Boolean,
required: true
}
})
const emits = defineEmits(['update:modelValue']) // 格式update:+ 双向绑定变量名称
// 修改数据:emits('update:modelValue', false)
<script>
// 外部直接v-model='xxxx',xxxx名称不需要与modelValue同名,这个是固定的
<template>
<div v-model="modelValue"></div>
</template>
<script setup>
import { defineProps, defineEmits } from "vue";
defineProps({
modelValue: {
type: Boolean,
required: true,
},
});
const emits = defineEmits(["update:modelValue", ...]);
const fn = () => {
emits("update:modelValue", false);
};
</script>
父级组件:
<xxx v-model="a"></xxx>
<script setup>
import { ref } from 'vue'
let str = ref('1')
function getStr() {
console.log(str.value)
}
</script>
<template>
<button @click="getStr">
{{ str }}
</button>
</template>
<script setup>
import foot from './foot.vue'
<script>
然后在模板中就可以直接使用了。
<div ref="dom"></div>
<script setup>
const dom = ref(null); // 以响应式的形式获取,默认给个null
// 使用 dom.value
<script>
<script setup>
import { useRouter, useRoute } from 'vue-router'
const router = useRouter()
const route = useRoute()
</script>
和setup()写法一样,用在dom“积累的最后一次更新完成后调用"
import { nextTick } from 'vue'
function increment() {
state.count++
nextTick(() => {
// 访问更新后的 DOM,拿到的是最新的dom
})
}
未来不间断补充…