美文网首页
vue(2/3)中在组件上使用v-model

vue(2/3)中在组件上使用v-model

作者: 踏莎行 | 来源:发表于2021-11-26 21:28 被阅读0次

    v-model一般用于表单数据的双向绑定,使用起来也很方便,但是本质上他还是一个语法糖,先拿input输入框举个例子

    自定义一个MyInput组件

    <template>
      <div>
        <input
          type="text"
          :value="value"
          @input="$emit('input', $event.target.value)"
        />
      </div>
    </template>
    
    <script>
    export default {
      props: {
        value: String,
      },
    
      methods: {
        change() {
          this.$emit("input", "hahah");
        },
      },
    };
    </script>
    

    创建一个父组件,导入并注册MyInput组件

    <template>
      <div>
        <MyInput :value="value" @input="value = $event"></MyInput>
        父组件的value:{{ value }}
      </div>
    </template>
    
    <script>
    import MyInput from "../components/MyInput.vue";
    export default {
      components: {
        MyInput,
      },
      data() {
        return {
          value: "",
        };
      },
    };
    </script>
    

    看结果


    Snipaste_2021-11-27_19-53-19.png

    这样我们就实现了一个v-model,本质上就是为input元素的value属性进行数据绑定,然后通过一个input事件将当前文本框的内容发送给父组件,父组件监听一个input事件,将传递过来的值赋值给value,像这样的我们就可以简写成

    <MyInput v-model="value"></MyInput>
    

    而在组件上,一个组件上的 v-model 默认会利用名为 value 的 prop 和名为 input 的事件。

    我觉得这句话很重要,以往没有仔细看文档这句话,就形成了一种定向思维,要在组件上使用v-model,组件里面必须含有input等这些表单元素才行,其实是大错特错

    当我们要使用v-model的时候,只需要在组件中定义一个value的prop,当组件内部需要修改value的值时,自定义input事件传递给父组件,让父组件修改,这样就不违背单向数据流的思想了,因为数据一般都是响应式的嘛

    下面举个五星评分组件的例子,就不写的那么完整了,星星用方块代替,点击方块进行评分,并且设置v-model绑定的值是当前评分(就是几颗星),类型是number

    • rate.vue
    <template>
      <div>
        <!-- 
          五颗基本星星,循环5的话,那么item就是1,2,3,4,5
          通过比较当前item和传进来的value比较,如果当前item小于等于value,
          说明当前星星应该是黄色的,绑定一个on的类名,它的css就是背景色为黄色
         -->
        <span
          class="rate"
          v-for="(item, index) in 5"
          :key="index"
          :class="{ on: item <= value }"
        ></span>
      </div>
    </template>
    
    <script>
    export default {
      props: {
        value: Number,
      },
    };
    </script>
    
    <style scoped>
    .rate {
      display: inline-block;
      width: 20px;
      height: 20px;
      margin: 0 10px;
      background-color: #666;
    }
    
    .on {
      background-color: yellow;
    }
    </style>
    
    • 使用组件
    <template>
      <div>
        <!-- 通过v-model绑定初始评分是2颗星 -->
        <Rate v-model="rate"></Rate>
      </div>
    </template>
    
    <script>
    import Rate from "../components/Rate.vue";
    export default {
      components: {
        Rate,
      },
      data() {
        return {
          rate: 2,
        };
      },
    };
    </script>
    

    效果,目前应该是两颗星是黄色


    init.png

    下面来写点击逻辑,其实就一行

        <span
          class="rate"
          ....
          @click="$emit('input', item)"
        ></span>
    

    点击之后,定义一个input事件,参数就是item,父组件就会监听子组件的input事件,将你绑定的值(rate)变成input事件的参数(item),然后数据是响应式的,对应的之就会被修改(变成黄色的星星的数量对应发生变化)

    大家也可以看对应的官网

    vue3在组件上使用v-model

    vue3在组件上的用法发生了变化

    value -> modelValue
    input -> update:modeVale

    那么上面的例子中

    <Rate v-model="rate"></Rate>
    

    就等价于

    <Rate :model-value="rate" @update:model-value="$event = rate"></Rate>
    

    那么Rate.vue内部就该是

    <span
      ...
      @click="$emit('update:modelValue', item)"
    ></span>
    ...
    props: {
      modelValue: Number,
    }
    ...
    

    那么input那些表单元素的绑定本质就是

    <input
      :value="modelValue"
      @input="$emit('update:modelValue', $event.target.value)"
    >
    
    • 多值双向绑定
      一般来说v-model绑定的就是modelValue,如果你想绑定多个或者绑定其他属性,那就可以给v-model添加参数
    v-model:(属性)="(为该属性绑定的值)"
    // 当然这个属性应该是子组件的一个prop,且触发方法同v-model,
    $emit('update:属性', (参数))
    

    这个是可以和v-model同时存在的

    - 子组件

    <template>
      <div style="marign: 20px">
        <h1>子组件</h1>
        <div @click="$emit('update:modelValue', '修改了')">{{ modelValue }}</div>
        <div @click="$emit('update:message', 'message修改了')">
          {{ message }}
        </div>
      </div>
    </template>
    
    <script lang="ts">
    import { defineComponent } from "vue";
    
    export default defineComponent({
      emits: ["update:modelValue", "update:message"],
      props: {
        modelValue: String,
        message: String,
      },
      setup() {},
    });
    </script>
    

    - 使用

    <template>
      <div>
        <Children v-model="value" v-model:message="otherModel"></Children>
    
        <h1>父组件数据</h1>
        <div>{{ value }}</div>
        <div>{{ otherModel }}</div>
      </div>
    </template>
    
    <script lang="ts">
    import { defineComponent, reactive, toRefs } from "vue";
    import Children from "./components/Children.vue";
    
    export default defineComponent({
      components: { Children },
    
      setup() {
        const state = reactive({
          value: "哈哈",
          otherModel: "message1",
        });
        return { ...toRefs(state) };
      },
    });
    </script>
    

    效果就是,点击子组件的文字,两边的文字内容同时修改


    Snipaste_2021-11-27_21-20-21.png

    |
    |


    1.png

    3.x官网链接:

    相关文章

      网友评论

          本文标题:vue(2/3)中在组件上使用v-model

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