美文网首页
组件的v-model

组件的v-model

作者: 未路过 | 来源:发表于2022-10-04 12:41 被阅读0次

1.组件的v-model

image.png

App.vue

<template>
  <!-- <input v-model="message"> -->
  <!-- <input :value="message" @input="message=$event.target.value"> -->

  <!-- 组件上使用v-model -->
  <hy-input v-model="message"></hy-input>
  <!-- 相当于帮你绑定一个熟悉叫做modelValue这个属性 -->
  <!--   <hy-input
    :modelValue="message"
    @update:model-value="message = $event"
  ></hy-input> -->
</template>

<script>
import HyInput from "./HyInput.vue";
export default {
  components: {
    HyInput,
  },
  data() {
    return {
      message: "hello world",
    };
  },
};
</script>

<style></style>

HyInput.vue

<template>
  <div>
    <button @click="btnClick">HyInput按钮</button>
    <h2>HyInput的message:{{ modelValue }}</h2>
  </div>
</template>

<script>
export default {
  props: {
    modelValue: String,
  },
  emits: ["update:modelValue"],
  methods: {
    btnClick() {
      this.$emit("update:modelValue", "testtest");
    },
  },
};
</script>

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

2. 实现v-model

方式一:


image.png
<template>
  <div>
    <input :value="modelValue" @input="btnClick" />
  </div>
</template>

<script>
export default {
  props: {
    modelValue: String,
  },
  emits: ["update:modelValue"],
  methods: {
    btnClick(event) {
      this.$emit("update:modelValue", event.target.value);
    },
  },
};
</script>

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


方式二:


image.png
<template>
  <div>
    <!-- 
绑定 modelValue 是不对的,因为props是单向数据流,子不能修改父的值,只能emit发送过去
      <input v-model="modelValue" />
     -->
    <input v-model="value" />
  </div>
</template>

<script>
export default {
  props: {
    modelValue: String,
  },
  computed: {
    value: {
      set(newValue) {
        this.$emit("update:modelValue", newValue);
      },
      get() {
        return this.modelValue;
      },
    },
  },
};
</script>

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

3. 绑定多个属性

image.png

App.vue

<template>
  <!-- 绑定两个v-model -->
  <!-- 组件是可以传参数的,在冒号后面
  这时候子组件里面就多了一个props属性title,
  也多了一个emits事件"update:title""
   -->
  <hy-input v-model="message" v-model:title="title"></hy-input>
  <h2>{{ message }}</h2>
  <h2>{{ title }}</h2>
</template>

<script>
import HyInput from "./HyInput.vue";
export default {
  components: {
    HyInput,
  },
  data() {
    return {
      message: "hello world",
      title: "hahahha",
    };
  },
};
</script>

<style></style>

HyInput.vue

<template>
  <div>
    <input v-model="value" />
    <input v-model="titleData" />
  </div>
</template>

<script>
export default {
  props: {
    modelValue: String,
    title: String,
  },
  emits: ["update:modelValue", "update:title"],
  computed: {
    value: {
      set(newValue) {
        this.$emit("update:modelValue", newValue);
      },
      get() {
        return this.modelValue;
      },
    },
    titleData: {
      set(newValue) {
        this.$emit("update:title", newValue);
      },
      get() {
        return this.title;
      },
    },
  },
};
</script>

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

4.绑定的data是一个对象的时候

App.vue

<template>
  <!-- 绑定两个v-model -->
  <!-- 组件是可以传参数的,在冒号后面
  这时候子组件里面就多了一个props属性title,
  也多了一个emits事件"update:title""
   -->
  <hy-input v-model="data"></hy-input>
  <h2>{{ data.name }}</h2>
  <h2>{{ data.title }}</h2>
  <button @click="btnclick">button</button>
</template>

<script>
import HyInput from "./HyInput.vue";
import { ref } from "vue";
export default {
  components: {
    HyInput,
  },
  setup() {
    const data = ref({
      name: "why",
      title: "vue3",
    });
    const btnclick = () => {
      data.value.name = "chang name";
      data.value.title = "new title";
      //对ref对象里面的某个属性修改的话,也是响应式的。
    };
    return {
      data,
      btnclick,
    };
  },
};
</script>

<style></style>

HyInput.vue

<template>
  <div>
    <input v-model="data['name']" /> <input v-model="data['title']" />
    {{ modelValue }}
    {{ data }}
  </div>
</template>

<script>
import { ref, watch } from "vue";
export default {
  props: {
    modelValue: {
      type: Object,
      required: true,
    },
  },
  emits: ["update:modelValue"],
  /*   setup(props, { emit }) {
    const data = computed({
      get: () => props.modelValue,
      set: (newValue) => {
        emit("update:modelValue", newValue);
      },
    });
    按照只有一个数据的时候的那种写法,看起来也是可以的,
但是实际上,data.title或者data.name的值改变的时候,
set函数式不会触发的,所有只能get,不能set。
    但是这个时候父组件的值也有相对应的改变,
那是因为这个时候相当于
子组件直接oninput事件改变了data.name的值,
因为你拿data.title,实际上就是把input的值给props.modelValue.value,所以oninput的时候,
也会把input的value给props.modelValue.value,
实际上还是单向绑定。

    */
  //第一点,表单里面的input的v-model绑定的
//一定不是props过来的data,只有一个数据的话,
//式给这个数据一个相对应的计算属性,v-model绑定这个计算属性。从而操作。
  //第二点,我们props传过来的这个对象里面有很多数据,
//每个都给一个computed属性,很麻烦,
//我们直接复制一个对象给子组件,子组件监听变化
  setup(props, { emit }) {
    //reactive在进行双向绑定的时候,多少有些问题,推荐使用ref
    const data = ref({ ...props.modelValue });
    //这样写的话,就data变成了响应式,
//一旦modelValue发生变化的话,data也就会发生变化。
//但是data发生变化,modelValue不会发生变化。

    //把props.modelValue的属性全部拷贝一份给这个data变量。
//现在这个data和以前的props.modelValue就没有任何关系了
    //这个时候data里面的两个属性就和两个input双向绑定住了
    //改变input里面的东西,这个data属性有改变,
//但是父元素里面的data,也就是props.modelValue是没有改变的
    watch(
      data,
      (newValue) => {
        console.log(newValue);
        emit("update:modelValue", newValue);
      },
      { deep: true, immediate: true }
    );
    return { data };
  },
};
</script>

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

相关文章

网友评论

      本文标题:组件的v-model

      本文链接:https://www.haomeiwen.com/subject/jkmyartx.html