目录
1、同vue2中一样,在需要获取dom的元素上绑定ref即可获取到dom元素。
2、同vue2中一样,ref获取dom时必须在onMounted以后,否则获取到的是null
3、与vue2中不一样,同一个ref名称不再允许被绑定多次。
4、类似于vue2,vue3新增,当在 v-for 中使用模板引用时,对应的 ref 中包含的值是一个数组,它将在元素被挂载后包含对应整个列表的所有元素。
5、ref 还可以绑定为一个函数,会在每次组件更新时都被调用。该函数会收到元素引用作为其第一个参数。
一、模板引用中的ref
ref除了可以用来声明响应式数据外,还可以用在模板中来获取dom元素。
1、同vue2中一样,在需要获取dom的元素上绑定ref即可获取到dom元素。
这里声明的ref对象必须和模板中的ref同名。
<script setup>
import { ref, onMounted } from 'vue'
// 声明一个 ref 来存放该元素的引用
// 必须和模板里的 ref 同名
const input = ref(null)
onMounted(() => {
input.value.focus()
})
</script>
<template>
<input ref="input" />
</template>
2、同vue2中一样,ref获取dom时必须在onMounted以后,否则获取到的是null
3、与vue2中不一样,同一个ref名称不再允许被绑定多次。
如果绑定多次则最后一次绑定会覆盖前面的,因此获取到的是最后绑定的元素。
<script setup>
import { ref, onMounted } from 'vue'
const list = ref([1, 2, 3])
const itemRefs = ref([])
onMounted(() => {
console.log(`itemRefs`, itemRefs.value) // 获取到的是<div>元素,前面的丢失了。
})
</script>
<template>
<ul>
<li v-for="item in list" ref="itemRefs">
{{ item }}
</li>
<div ref="itemRefs">
</div>
</ul>
</template>
4、类似于vue2,vue3新增,当在 v-for
中使用模板引用时,对应的 ref 中包含的值是一个数组,它将在元素被挂载后包含对应整个列表的所有元素。
5、ref
还可以绑定为一个函数,会在每次组件更新时都被调用。该函数会收到元素引用作为其第一个参数。
<input :ref="(el) => { /* 将 el 赋值给一个数据属性或 ref 变量 */ }">
6、组件上的ref,获取到的是这个组件的实例。
如果没有使用<script setup>,那么父组件可以访问到子组件中的任何属性和方法,同vue2中一样。
如果使用了<script setup>的组件,则是默认私有的。一个父组件无法访问到一个使用了 <script setup>
的子组件中的任何东西。除非子组件使用 defineExpose
宏显式暴露
<script setup>
import { ref } from 'vue'
const a = 1
const b = ref(2)
// 像 defineExpose 这样的编译器宏不需要导入
defineExpose({
a,
b
})
</script>
二、组件基础
1、props和defineProps
defineProps:
在使用了<script setup>的组件中,才可以使用defineProps,它是一个编译宏命令,并不需要显式地导入。声明的 props 会自动暴露给模板。defineProps会返回一个对象,其中包含了可以传递给组件的所有 props:
<script setup>
// defineProps更推荐写成对象形式,能够标注数type,default等。
const props = defineProps(['title'])
console.log(props.title)
</script>
<template>
<h4>{{ title }}</h4>
</template>
props:
没有使用<script setup>的组件中,则还是使用props,其中props的对象格式校验,type,required,default,单向数据流等特性还是和vue2中一样。defineProps同理。
<script>
export default {
props: {
title: String,
age: {
type: Number,
required: true,
default: 18
}
},
setup(props) {
console.log(props.title)
}
}
</script>
动态绑定多个值
如果你想要将一个对象的所有属性都当作 props 传入,你可以使用没有参数的 v-bind,即只使用 v-bind
而非 :prop-name
。例如,这里有一个 post
对象:
const post = {
id: 1,
title: 'My Journey with Vue'
}
以及下面的模板:
<BlogPost v-bind="post" />
而这实际上等价于:
<BlogPost :id="post.id" :title="post.title" />
2、监听事件emits和defineEmits
defineEmits:
和 defineProps
类似,defineEmits
仅可用于 <script setup>
之中,并且不需要导入,它返回一个等同于 $emit
方法的 emit
函数。
<script setup>
// 因为vue3中不像vue2那样,能够直接获取到this.$emit,所以这个返回的emit函数非常有必要。
const emit = defineEmits(['enlarge-text'])
emit('enlarge-text')
</script>
和对 props 添加类型校验的方式类似,所有触发的事件也可以使用对象形式来描述。
<script setup>
const emit = defineEmits({
// 没有校验
click: null,
// 校验 submit 事件
submit: ({ email, password }) => {
if (email && password) {
return true
} else {
console.warn('Invalid submit event payload!')
return false
}
}
})
function submitForm(email, password) {
emit('submit', { email, password })
}
</script>
emits:
emits是vue3新增的属性,当组件显式的调用setup函数时,必须设置emits属性。
<script>
export default {
emits: ['enlarge-text'],
setup(props, ctx) {
ctx.emit('enlarge-text')
}
/**
// 也可以将emit解构出来。
setup(props, {emit}) {
emit('enlarge-text')
}
**/
}
</script>