什么是单向数据流
单向数据流是指数据只能在一个方向上流动,即从父组件到子组件。在 Vue.js 中,单向数据流是指数据只能从父组件传递给子组件,而不能从子组件传递给父组件。
为什么需要单向数据流
单向数据流可以确保数据的流动清晰,易于维护和调试。同时,单向数据流也可以避免子组件意外修改父组件的数据,从而导致数据的不一致。
<!-- 这样直接绑定数据是不应该的,会直接修改父组件传递的数据,而造成打破单向数据流,为以后的维护调试埋雷 --> <input type="text" v-model="modelValue.keyWord" /> <select> <option v-for="item in modelValue.select" :key="item" :value="item"> {{ item }} </option> </select>
<script setup> const _ = defineProps({ modelValue: { type: Object, default: () => {} } }); </script>
|
保护单向数据流的方案
- 为每个数据绑定一个事件,改变触发通知父组件 (每个数据都绑定一个,不是最优解)
- 为每个数据绑定一个计算属性,get 返回父组件传递的数据,set 就触发自定义事件通知父组件修改了
(也不是最优解,每个属性都要绑定一个,和上一个方案差不多,
因为计算属性监听的修改是对应的属性直接赋值才会触发 set)
比如:data.xxx=xxx? 才会触发但是我们修改属性是 data.xxx.value=xxx
- 计算属性结合代理
父组件
<template> <childComp v-model="data" @updateProps="handleUpdateProps" /> </template>
<script setup lang="ts"> import { reactive } from "vue"; import childComp from "./child.vue"; const data = reactive({ keyWord: "hello", select: ["a", "b", "c"], }); const handleUpdateProps = (obj) => { data.keyWord = obj.keyWord; data.select = obj.select; }; </script>
<style scoped lang="scss"></style>
|
子组件
<script setup lang="ts"> import { computed } from "vue"; const _ = defineProps({ modelValue: { type: Object, default: () => {}, }, });
//不使用update:modelValue 只是想把变化显示出来 const emit = defineEmits(["updateProps"]); const model = computed({ get() { const proxy = new Proxy(_.modelValue, { get(tar, val) { return Reflect.get(tar, val); }, set(tar, key, val) { emit("updateProps", { ...tar, [key]: val, }); return true; }, }); return proxy; }, set(val) { emit("updateProps", val); }, }); </script>
|
函数抽离
export function useVModel(props, propName,emit) { const model = computed({ get() { const proxy = new Proxy(props[propName], { get(tar, val) { return Reflect.get(tar, val); }, set(tar, key, val) { emit(`update:${propName}`, { ...tar, [key]: val, }); return true; }, }); return proxy; }, set(val) { emit("updateProps", val); }, }); }
|