在Vue开发中,ref和$attrs是处理组件引用与跨级属性传递的常用工具,而v-model和.sync则是简化父子通信的语法糖。本文结合具体代码,梳理它们的核心用法与常见场景。
## ref的三种用法
ref可以在三种场景下使用,分别获取不同对象:
1. 加在普通HTML元素上,通过this.$refs.name获取DOM节点。
2. 加在子组件上,获取的是组件实例,可以调用子组件的所有方法和属性。
3. 在v-for中配合ref使用,会返回一个数组,包含对应循环项的所有实例或DOM节点,不会因为重名而被覆盖。
注意:this.$refs对象中存储了所有设置了ref属性的元素,如果出现同名,后者会覆盖前者(v-for场景除外)。普通元素返回DOM对象,Vue组件返回组件实例。
示例(省略具体代码,读者可自行测试):- <div ref="myDiv">普通元素</div>
- <child-component ref="myChild"></child-component>
- <div v-for="item in list" :key="item.id" :ref="'item_' + item.id">...</div>
复制代码 通过this.$refs.myDiv获取DOM,this.$refs.myChild获取组件实例,而v-for中建议使用函数式ref或利用数组索引。
## $attrs:跨级属性传递的桥梁
当父组件向子组件传递属性时,如果子组件的props中没有声明该属性,那么该属性会进入子组件的$attrs对象中。这使得我们可以方便地将未在props中定义的值继续向下传递,避免“逐层声明”的冗余。
例如,父组件传递了propA(已定义)、propB(未定义)和grand-id(未定义),子组件通过this.$attrs可以获取到{ propB, grandId }(grand-id自动转为驼峰grandId)。
若需要在子组件中继续向孙组件传递这些未声明的属性,可以使用v-bind="$attrs"。这等价于逐一绑定每个属性:- <grand-child v-bind="$attrs"></grand-child>
复制代码 这样孙组件既可以通过props接收,也可以通过this.$attrs继续传递。
## 语法糖:v-model 和 .sync
在父子组件通信中,Vue提供了两个语法糖简化双向绑定。
### v-model
v-model本质上是:value和@input的组合。父组件写:- <child v-model="parentValue"></child>
复制代码 子组件内部接收value为props,并在值变化时触发input事件:- export default {
- props: ['value'],
- data() {
- return {
- inputValue: this.value
- }
- },
- watch: {
- inputValue(newVal) {
- this.$emit('input', newVal)
- }
- }
- }
复制代码 这样父组件的parentValue就会随子组件的inputValue变化而更新。
### .sync 修饰符
对于普通属性(非value),可以用.sync实现类似v-model的效果。父组件写法:- <child :changep.sync="object.p"></child>
复制代码 子组件中通过$emit('update:changep', newValue)来触发更新:- methods: {
- clickHandle() {
- this.$emit('update:changep', '改变了对应的p')
- }
- }
复制代码 这等价于父组件监听@update:changep事件并更新对应的属性值。
## 总结
ref提供了对DOM或组件实例的直接访问,适合操作焦点、集成第三方库等场景;$attrs简化了跨级属性传递,尤其适用于高阶组件或封装库;v-model和.sync则让双向绑定更简洁。掌握这些技巧,可以编写更清晰、可维护的Vue组件。 |