当前位置: 首页 > article >正文

vue3 ui组件子组件封装v-model绑定props modelValue

v-model:在vue3中,是属于“:modelValue”和“update:modelValue”组合的语法糖。

场景:父组件使用子组件通过v-model绑定收集属性值,子组件中的元素,又通过v-mode绑定父组件传递的props属性。

失败原因:在子组件中直接通过v-model绑定modelValue,打破单向数据流,导致“update:modelValue”无法正常工作。

解决1:拆分v-model

<template>
<div>
    <UI :modelValue="modelValue" @update:modelValue="handleModelValue"></UI>
</div>
</template>

<script setup>
const props = defineProps({
  modelValue: {
    type: String,
    default: ''
  }
})

const emit = defineEmits(['update:modelValue'])

function handleModelValue (val) {
    emit('update:modelValue', val)
}
</script>

解决2:computed

<template>
<div>
    <UI v-model="uiValue"></UI>
</div>
</template>

<script setup>
import { computed } from "vue"
const props = defineProps({
  modelValue: {
    type: String,
    default: ''
  }
})

const emit = defineEmits(['update:modelValue'])

const uiValue = computed({
  get () {
    return props.modelValue
  },
  set (val) {
    emit('update:modelValue', val)
  }
})
</script>

解决3:computed+代理+封装

import { computed } from "vue";

// 缓存(WeakMap避免内存泄漏)
const cacheMap = new WeakMap();

export function useVModel(props, propName, emit) {
  return computed({
    get() {
      const value = props[propName];
      
      // 如果是原始值,直接返回
      if (typeof value !== 'object' || value === null) {
        return value;
      }

      // 如果缓存中存在该属性的代理,则返回缓存的代理
      if (cacheMap.has(value)) {
        return cacheMap.get(value);
      }

      // 创建代理对象
      const proxy = new Proxy(value, {
        get(target, key) {
          return Reflect.get(target, key);
        },
        set(target, key, newValue) {
          // 更新父组件的状态
          emit('update:' + propName, {
            ...target,
            [key]: newValue
          });
          return true;
        }
      });

      // 将代理对象缓存起来
      cacheMap.set(value, proxy);
      return proxy;
    },

    set(newValue) {
      // 直接设置新的值,触发父组件的更新
      emit('update:' + propName, newValue);
    }
  });
}
<template>
<div>
    <my v-model="modelValue"></UI>
</div>
</template>

<script setup>

const props = defineProps({
  modelValue: {
    type: String,
    default: ''
  }
})
</script>

解决4:工具库vueuse(推荐)

官方地址:https://vueuse.nodejs.cn/core/useVModel/

<script lang="ts" setup>
import { useVModel } from '@vueuse/core'

const props = defineProps<{
  modelValue: string
}>()
const emit = defineEmits(['update:modelValue'])

const data = useVModel(props, 'modelValue', emit)
</script>

解决5:vue3.4新特性defineModel(推荐)

官方地址:https://cn.vuejs.org/api/sfc-script-setup.html#definemodel

// 声明 "modelValue" prop,由父组件通过 v-model 使用
const model = defineModel()
// 或者:声明带选项的 "modelValue" prop
const model = defineModel({ type: String })

// 在被修改时,触发 "update:modelValue" 事件
model.value = "hello"

// 声明 "count" prop,由父组件通过 v-model:count 使用
const count = defineModel("count")
// 或者:声明带选项的 "count" prop
const count = defineModel("count", { type: Number, default: 0 })

function inc() {
  // 在被修改时,触发 "update:count" 事件
  count.value++
}

http://www.kler.cn/a/467141.html

相关文章:

  • ESP32-C3 AT WiFi AP 启 TCP Server 被动接收模式 + BLE 共存
  • Spring SpEL表达式由浅入深
  • Vue3实现PDF在线预览功能
  • IDEA 撤销 merge 操作(详解)
  • 【操作系统不挂科】操作系统期末考试题库<2>(单选题&简答题&计算与分析题&程序分析题&应用题)
  • 认识一下,轻量消息推送 Server-Sent Events
  • 使用SSH建立内网穿透,能够访问内网的web服务器
  • 使用Docker部署最新版JupyterHub
  • 如何利用群晖NAS实现远程访问你的网页版Linux虚拟桌面环境
  • [gcc]代码演示-O使用场景
  • SQL中聚类后字段数据串联字符串方法研究
  • kernel32.dll动态链接库报错要怎解决?详细解析kernel32.dll文件缺失解决方案
  • 什么是 C++ 的序列化?
  • 【一文解析】新能源汽车VCU电控开发——能量回收模块
  • STM32-笔记23-超声波传感器HC-SR04
  • kubernets基础入门
  • 基于STM32的热带鱼缸控制系统的设计
  • 大模型数据采集和预处理:把所有数据格式,word、excel、ppt、jpg、pdf、表格等转为数据
  • 高清监控视频的管理与展示:从摄像头到平台的联接过程
  • 呼叫中心中间件实现IVR进入排队,判断排队超时播放提示音
  • Git快速入门(一)·Git软件的安装以及GitHubDesktop客户端的安装
  • 装饰器模式详解
  • clickhouse Cannot execute replicated DDL query, maximum retries exceeded报错解决
  • Android 14.0 系统限制上网系列之iptables用IOemNetd实现app上网黑名单的实现
  • 行为模式4.观察者模式------消息推送
  • LangChain+博查搜索API轻松实现实时信息搜索