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

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官网链接:

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 200,612评论 5 471
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,345评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 147,625评论 0 332
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,022评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,974评论 5 360
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,227评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,688评论 3 392
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,358评论 0 255
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,490评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,402评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,446评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,126评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,721评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,802评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,013评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,504评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,080评论 2 341

推荐阅读更多精彩内容