您现在的位置是:网站首页> 编程资料编程资料
vue3的setup语法如何自定义v-model为公用hooks_vue.js_
2023-05-24
483人已围观
简介 vue3的setup语法如何自定义v-model为公用hooks_vue.js_
前言
- 基础篇:简单介绍
vue3的setup语法如何自定义v-model; - 进阶篇:如何提取
v-model语法作为一个公用hooks;
基础
基础篇可绕过,只是对于官网给出的教程,进行了总结概括并给出demo
基本的v-model
子组件中满足两个点,即可完成自定义双向绑定:
props中定义一个值xxxemit中定义一个update:xxx事件
下面我们来写一个最基本的v-model组件:
props中定义一个modelValue值,并绑定到input的value属性上;emit中定义一个update:modelValue事件
需要注意的是,当modelValue作为props传入,update:modelValue事件将被自动注册到emit事件中
父组件中,引入modelComp子组件,并绑定test值到v-model上,test便完成了一次双向绑定。
这便是一个最基本的自定义v-model组件;
多个v-model绑定
当我们需要多个双向绑定时,如下:
子组件中,同样按着两个点来定义:
props中定义两个值,test1和test2emits中定义两个事件,update:test1和update:test2
v-model修饰符
vue提供了一些v-model修饰符,我们可以在v-model中使用他们:
在一些场景下,我们需要自己定义修饰符,来满足我们的需求,举个栗子:
默认v-model中我们绑定了a修饰符,v-model:test1中则绑定b和c两个修饰符;
对于修饰符,我们需要满足以下条件:
- 对于默认
v-model来说,需要props中定义两个值modelValuemodelModifiers,接受修饰符key值
- 对于自定义
v-model:xxx来说,props中:xxxxxxModeifiers,接受修饰符key值
由此,上代码:
进阶
问题背景
基础篇中已经讲解了如何封装一个自定义v-model的组件,可是在实际开发中,子组件中使用@input和:value来绑定我们的值,会比较麻烦,有没有更简单的办法呢?
我们通常想要对需要双向绑定的子组件,直接进行v-model绑定:
问题来了,在子组件中接受到父组件的传值时,xxx我们应该绑定谁?直接绑定props.modelValue么?
我们会得到一个错误:
⚠️reactivity.esm-bundler.js:512 Set operation on key "modelValue" failed: target is readonly.
因为props是一个readonly的值(isReadonly(props) === true),所以我们不能直接这么使用
所以,我们是需要一个中间值来绑定v-model
方式一:通过watch中转
借助内部变量绑定v-model,使用watch监听它,并同步数据props.xxx
因为有时候我们双向绑定的可能是一个对象或者数组,因此我们可以使用watch里的deep选项来深度监听并同步proxy;
watch( () => proxy.value, (v) => emit("update:modelValue",v), {deep:true} );当然,props.modelValue可能存在默认值传入,所以我们也可以加上immediate选项,使得组件在创建时,就直接给proxy赋上默认值;
方式二:computed的get和set
我们也可以借助computed提供的get和set来进行数据同步
const proxy = computed({ get() { return props.modelValue; }, set(v) { emit("update:modelValue", v); }, });终极:封装v-model的hooks
我们先来提取watch这种方式,将其封装为一个hooks
在子组件中,我们用v-model在input上绑定了一个内部值proxy,并以props.modelValue的值初始化proxy变量(ref(props.modelValue));
在watch中,我们监听input上的绑定值proxy,在input进行输入其值变化时,向外分发emit('update:modelValue',v)事件,将改变的值动态传到外部组件上
提取公用逻辑
// useVmodel1.js import { ref, watch } from "vue"; export function useVmodel(props, emit) { const proxy = ref(props.modelValue); watch( () => proxy.value, (v) => emit("update:modelValue", v) ); return proxy; }一个最简单的hooks便被封装好了;
继续抽离封装
考虑到以下几个点,继续进行抽离封装:
emit可以不传,更简洁的调用方式- 多个
v-model:test1这种情况的事件,emit("update:xxxx")中的xxxx事件名需要提取
我们可以通过vue3提供的getCurrentInstance方法,获取当前的组件实例,而modelValue可覆盖,则抽取成变量:
//useVmodel2.js import { ref, watch, getCurrentInstance } from "vue"; export function useVmodel(props, key = "modelValue", emit) { const vm = getCurrentInstance(); const _emit = emit || vm?.emit; const event = `update:${key}`; const proxy = ref(props[key]); watch( () => proxy.value, (v) => _emit(event, v) ); return proxy; }好了,现
相关内容
- Element Table行的动态合并及数据编辑示例_vue.js_
- js字符串中空格和换行符(\r,\s,\n,\r\n)浅析_javascript技巧_
- Vue实现获取后端接口API代码片段(已封装Service方法名)_vue.js_
- Vue中tab栏切换的简单实现_vue.js_
- vue 使用mescroll.js框架实现下拉加载和上拉刷新功能_vue.js_
- element表格行列的动态合并示例详解_vue.js_
- vue开发table数据合并实现详解_vue.js_
- Vue实现hash模式网址方式(就是那种带#的网址、井号url)_vue.js_
- JavaScript预解析之变量预解析和函数预解析_基础知识_
- 进入Hooks时代写出高质量react及vue组件详解_vue.js_
