v-model封装组件(定义 model 属性)

一、vue2.0

1、父级组件调用子组件counterComponents

ini 复制代码
<counterComponents v-model="item.totalNumber"/>

2、子组件counterComponents.vue

需求:计数器的输入值在1-30的范围的正整数 主要代码 子组件绑定值::value="innerValue" 组件更新数据: this.$emit('change',newInnerValue + 1)

js 复制代码
export default {
  // 使用 model 配置,支持 v-model
  model:{
    prop: 'value',
    event:'change'
  },
  props: {
    value: {
      type: Number,
      default: 1
    },
  },
  data() {
    return {
      innerValue: this.value
    }
  },
  watch: {
    // 监听外部 value 变化,同步到内部值
    value: {
      immediate: true,
      handler(newVal) {
        this.innerValue = newVal
      }
    }
  }
}

完整代码

js 复制代码
<template>
  <div
    class="pi-align-center"
    @click.stop="()=>{}">
    <span class="pi-pd-right-20">货物件数 </span>
    <div class="counter-containers pi-align-center pi-justify-between">
      <div
        class="pi-pd-lr-10 btn"
        @click.stop="handleCount('subtract')">
        <pi-icon
          name="subtract"
          size="30" />
      </div>
      <pi-input
        :value="innerValue"
        placeholder=""
        :customStyle="{
          background: '#ffffff',
          borderLeft: '1rpx solid #d7d7d7',
          borderRight: '1rpx solid #d7d7d7',
        }"
        customClass="pi-text-center"
        @input="handleInput"
      />
      <div
        class="pi-pd-lr-10 btn"
        @click.stop="handleCount('add')">
        <pi-icon
          name="add"
          size="30" />
      </div>
    </div>
  </div>
</template>
<script>
export default {
  // 使用 model 配置,支持 v-model
  model:{
    prop: 'value',
    event:'change'
  },
  props: {
    value: {
      type: Number,
      default: 1
    },
    min: {
      type: Number,
      default: 1,
    },
    max: {
      type: Number,
      default: 30,
    }
  },
  data() {
    return {
      innerValue: this.value
    }
  },
  computed: {

  },
  watch: {
    // 监听外部 value 变化,同步到内部值
    value: {
      immediate: true,
      handler(newVal) {
        this.innerValue = newVal
      }
    }
  },
  methods: {
    handleCount(sign) {
      const newInnerValue = this.innerValue
      if (sign === 'add') {
        if (newInnerValue + 1 > this.max) return
        this.$emit('change',newInnerValue + 1)
      } else {
        if (newInnerValue - 1 < this.min) return
        this.$emit('change',newInnerValue - 1)
      }
    },
    handleInput(e) {
      const num = e.replace(/[^0-9]/g, '')
      const number = num ? num * 1 : 0
      if (number) {
        const maxNumber = number > this.max ? this.max : number
        this.$emit('change',maxNumber)
      } else {
        this.$emit('change',1)
      }
    },
  },
}
</script>
<style lang="scss" scoped>
.counter-containers {
  width: 200rpx;
  background-color: #f2f2f2;
  border: 1rpx solid #d7d7d7;
  border-radius: 10rpx;
  overflow: hidden;
  box-sizing: border-box;
  .btn {
    cursor: pointer;
  }
}
</style>

二、vue3.4前

父组件代码

xml 复制代码
<script setup lang="ts">
import { ref } from 'vue';
import dialogComponent from '@/components/dialogComponent.vue';
let isShow = ref(false)
</script>
<template>
    <div>
        <button @click="isShow = true ">打开</button>
        <dialogComponent v-model="isShow"/>
    </div>
</template>

子组件代码

xml 复制代码
<script setup lang="ts">
    const props = defineProps(['modelValue'])
    const emit  =  defineEmits(['update:modelValue'])
    
</script>
<template>
    <div v-if="props.modelValue">
        弹框
        <button @click="emit('update:modelValue', false)">关闭</button>
    </div>
</template>

三、vue3.4后

父组件代码

xml 复制代码
<script setup lang="ts">
import CounterComponent from '@/components/CounterComponent.vue';
import { ref } from 'vue';
let count = ref(0)
const add = () =>{
    count.value = Number(count.value)+1
}
</script>
<template>
    <div>
        <button @click="add">+1</button>
        <CounterComponent v-model="count"/>
        <div>{{ count }}</div>
    </div>
</template>

子组件代码

xml 复制代码
<script setup lang="ts">
    // 声明一个双向绑定 prop
    const model = defineModel();
</script>
<template>
    <div> 
        <input type="number"v-model="model">
    </div>
</template>
相关推荐
福兮说2 小时前
设计稿是 #4A7C6F,页面量出来是 #4B7C6F:HEX、HSL、透明度、canvas 来回转的七个坑
前端·javascript·css·canvas
郑州光合科技余经理3 小时前
海外版外卖加盟:总站与分站配送规则怎么分开管
java·开发语言·前端·后端·uni-app·php·ai编程
专业程序开发源3 小时前
springboot简历管理系统81389-计算机课程设计、毕业设计
java·vue.js·spring boot·后端·spring·php·课程设计
专业程序开发源3 小时前
springboot社区养老系统44071-计算机课程设计、毕业设计
vue.js·spring boot·后端·python·django·php·课程设计
小呆呆6663 小时前
副业搞起来,小说,漫画,漫剧的成本优化思路
前端·后端·面试
Dovis(誓平步青云)4 小时前
浇水提醒刚弹出又消失,植物状态别只存一个百分比
开发语言·前端·javascript·pdf·ecmascript·电脑
码艺-Alimjan4 小时前
Vben Admin 新增维吾尔语 Vben-Modal的关键坑之一
前端·javascript·vue.js
可乐鸡翅yeah_5 小时前
hls.js 手动自定义 http 请求 loader,修改请求头实战
开发语言·前端·javascript·网络协议·http·ecmascript·m3u8在线
IT_陈寒5 小时前
Vite静态资源导入这个坑我帮你们踩过了
前端·人工智能·后端
广州华水科技5 小时前
大坝安全监测解决方案:单北斗GNSS形变监测系统应用与维护
前端