<tempalte>
<div>{{person1}}--{{person2}}</div>
<!-- { name: 'Amy' }和{ name: 'Tom' },三秒后person1变成了{name: 'Tony'} -->
</template>
<script>
import { ref, reactive } from 'vue';
export default {
setup () {
const person1 = ref({ name: 'Amy' });
const person2 = reactive({ name: 'Tom' });
setTimeout(() => {
person1.value = {name: 'Tony'};
person2 = {name: 'Tony'};
}, 3000);
return { person1, person2 };
}
};
</script>
这样的运行结果颠覆了我对ref和reactive的理解,两者不是通过数据是基础类型或引用类型区分的。
ref
接受一个any类型的参数,返回{value: }包裹的Proxy,可以通过改变value属性实现响应式的赋值操作,但是在setup作用域中访问内部结构也需要带上value属性,在模板中自动拆解value的包裹。
使用场景: 适用于需要赋值操作的数据,基本类型(必须)、结构较浅的引用类型(建议)。
reactive
接受引用类型的参数,返回其Proxy,无法响应对整个Proxy的赋值。ref对引用类型的处理在包裹value后就由reactive负责。因此,reactive在官网列入响应式基础API。
使用场景: 不需要赋值操作的数据,结构较深的引用类型(建议)。
<tempalte>
<div>{{person1 === person2}}</div>
<!-- true -->
</template>
<script>
import { ref, reactive } from 'vue';
export default {
setup () {
let obj = { name: 'Amy' };
const person1 = ref(obj);
const person2 = reactive(obj);
console.log(person1.value === person2); // true
return { person1, person2 };
}
};
</script>
两者在引用类型的处理上,区别在ref拥有value的包裹,内部则一致。
相关应用
v-model
<tempalte>
<my-component v-model="data"></my-component>
<!-- 等同于 -->
<my-component
modelValue="data"
@update:modelValue="e => data.value=e"></my-component>
</template>
v-model含有隐式的赋值操作,因此v-model的props也需要传入ref处理的数据,而不是reactive。
ref Element
setup在mount之前执行,那么我们如何在其中获取ref绑定的dom?
<tempalte>
<div ref="div"></div>
</template>
<script>
import { ref, onMounted } from 'vue';
export default {
setup () {
const div = ref(null);
onMounted(() => {
console.log(div.value); // <div></div>
});
return { div };
}
};
</script>
ref生成一个包裹null的Proxy,以暴露的属性名作为向dom绑定ref的name,便可获取dom。