vue组件prop变量和内部变量数据格式不一样时,变量同步prop值,变量改变通知父组件.

vue组件含有v-model的props,当对其进行封装,想对该属性进行双向绑定时,可以采用computed的方式包一层get(){return props.xxx},set(v)=>{emit('update:xxx',v)},或者使用vueuseuseModel来深层代理,但是只适合要封装的组件prop的内部的变量数据类型一致,不一致就只能拆开写,通过watch监听prop更新内部变量, 然后内部变量在内部的v-model变化时抛出事件通知父组件.
father.vue

<template>
  <div>
    <Child v-model:form-state="obj" @change="onChange"></Child>
  </div>
</template>

<script setup>
import { ref } from "vue";
import Child from "./Child.vue";

const obj = ref({
  test: "xihu"
});

const onChange = state => {
  console.log("父组件监听", state);
};
</script>

<style lang="less" scoped></style>

Child.vue

<template>
  <div>
    <a-form :model="_formState">
      <a-form-item label="tewst">
        <a-cascader
          v-model:value="_formState.test"
          :options="options"
          placeholder="Please select"
        />
      </a-form-item>
    </a-form>
  </div>
</template>

<script setup>
import { ref, watch } from "vue";
import { cloneDeep } from "lodash-es";

const props = defineProps({
  formState: {
    type: Object,
    default: () => ({ test: "" })
  },
  transform: {
    type: Function
  }
});

const emit = defineEmits(["change", "update:formState"]);
const _formState = ref({
  test: []
});

const options = [
  {
    value: "zhejiang",
    label: "Zhejiang",
    children: [
      {
        value: "hangzhou",
        label: "Hangzhou",
        children: [
          {
            value: "xihu",
            label: "West Lake"
          }
        ]
      }
    ]
  },
  {
    value: "jiangsu",
    label: "Jiangsu",
    children: [
      {
        value: "nanjing",
        label: "Nanjing",
        children: [
          {
            value: "zhonghuamen",
            label: "Zhong Hua Men"
          }
        ]
      }
    ]
  }
];

watch(
  () => props.formState,
  v => {
    const findPathById = (treeArr, id) => {
      const path = [];
      let isFind = false;

      const traverse = nodes => {
        if (!Array.isArray(nodes)) return;
        for (const node of nodes) {
          if (isFind) return;

          const { value, children } = node;
          path.push(value);

          if (value == id) {
            isFind = true;
            return;
          }

          if (children && children.length) {
            traverse(children);
          }
          if (!isFind) {
            path.pop();
          }
        }
      };

      traverse(treeArr);

      return path;
    };
    if (props.formState && props.formState.test) {
      _formState.value.test = findPathById(options, props.formState?.test);
    }
  },
  {
    immediate: true
  }
);
watch(
  () => _formState.value,
  newState => {
    emit("change", newState);
   // ❌ emit("update:formState",newState) 这里如果进行双向绑定,会触发上面的watch无限循环
  },
  {
    deep: true,
    immediate: true
  }
);
</script>

<style lang="less" scoped></style>

你可能感兴趣的:(Vue,vue.js,javascript,前端)