如何正确使用 v-model 和 Composition API :value="modelValue" 语法?将 Vue2 自定义输入转换为 Vue3
Posted
技术标签:
【中文标题】如何正确使用 v-model 和 Composition API :value="modelValue" 语法?将 Vue2 自定义输入转换为 Vue3【英文标题】:How to properly work with v-model and the Composition API :value="modelValue" syntax? Converting Vue2 custom input into Vue3 【发布时间】:2021-12-24 05:19:12 【问题描述】:我有一个有用的小 custom input 我一直在我的所有 Vue2 项目中使用(允许您自定义自动对焦、自动增长和去抖动),但是现在我在 Vue3 中工作,我一直在尝试创建一个更新的版本。
我还没有完成它,但是我在 Vue3 的组合 API :value="modelValue"
语法上遇到了一些问题。在我的 CodeSandbox 中,我有两个输入,一个使用新语法,另一个直接使用 v-model
。后者有效,而 :value="valueInner"
抛出 Extraneous non-props attributes
错误。
我在这里做错了什么,我怎样才能让它与 :value="modelValue"
语法一起工作?
干杯!
Link to CodeSandbox
注意: 我仍然需要在 App.vue 中添加自动增长并添加所有用例。
CInput
<template>
<input
ref="inputRef"
data-cy="input-field"
v-if="type !== 'textarea'"
:disabled="disabled"
:type="type"
:placeholder="placeholder"
:readonly="readonly"
:required="required"
:autofocus="autofocus"
:debounce="debounce"
:value="valueInner"
/>
<!-- <input
ref="inputRef"
data-cy="input-field"
v-if="type !== 'textarea'"
:disabled="disabled"
:type="type"
:placeholder="placeholder"
:readonly="readonly"
:required="required"
:autofocus="autofocus"
:debounce="debounce"
v-model="valueInner"
/> -->
</template>
<script>
import defineComponent, ref, onMounted, nextTick, watch from "vue";
export default defineComponent(
props:
/** html5 attribute */
disabled: type: String ,
/** HTML5 attribute (can also be 'textarea' in which case a `<textarea />` is rendered) */
type: type: String, default: "text" ,
/** HTML5 attribute */
placeholder: type: String ,
/** HTML5 attribute */
readonly: type: Boolean ,
/** HTML5 attribute */
required: type: Boolean ,
/** v-model */
modelValue: type: [String, Number, Date], default: "" ,
autofocus: type: Boolean, default: false ,
debounce: type: Number, default: 1000 ,
,
emits: ["update:modelValue"],
setup(props, emit )
const inputRef = ref(null);
const timeout = ref(null);
const valueInner = ref(props.modelValue);
if (props.autofocus === true)
onMounted(() =>
// I don't know we need nexttick
nextTick(() =>
inputRef.value.focus();
// setTimeout(() => inputRef.value.focus(), 500);
);
);
watch(valueInner, (newVal, oldVal) =>
const debounceMs = props.debounce;
if (debounceMs > 0)
clearTimeout(timeout.value);
timeout.value = setTimeout(() => emitInput(newVal), debounceMs);
console.log(newVal);
else
console.log(newVal);
emitInput(newVal);
);
function emitInput(newVal)
let payload = newVal;
emit("update:modelValue", payload);
// const onInput = (event) =>
// emit("update:modelValue", event.target.value);
// ;
return inputRef, valueInner ;
,
);
</script>
App.vue
<template>
<CInput :autofocus="true" v-model.trim="inputValue1" />
<CInput :autofocus="false" v-model.trim="inputValue2" />
<pre>Input Value 1: inputValue1 </pre>
<pre>Input Value 2: inputValue2 </pre>
</template>
<script>
import ref from "vue";
import CInput from "./components/CInput.vue";
export default
name: "App",
components: CInput ,
setup()
const inputValue1 = ref("");
const inputValue2 = ref("");
return inputValue1, inputValue2 ;
,
;
</script>
<style>
#app
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
</style>
【问题讨论】:
【参考方案1】:完整的警告是:
[Vue 警告]:无关的非道具属性(modelModifiers)已传递给组件,但无法自动继承,因为组件呈现片段或文本根节点。
CInput
有多个根节点(即<input>
和注释节点),因此组件被呈现为片段。 CInput
上的 .trim
修饰符通常传递到根节点的 v-model
,如 demo 所示。由于实际代码是一个片段,Vue 无法为您决定将modelModifiers
属性传递到何处,从而导致您观察到的警告。
但是,declaring a modelModifiers
prop to receive the modifiers 足以解决问题:
// CInput.vue
export default
props:
modelModifiers:
default: () => ()
demo
【讨论】:
我不知道为什么我没有收到这方面的通知,但是很好的解释! modelModifiers 和 vue 做它自己的事件触发版本有点让我失望,但这是一个很好的解释!【参考方案2】:到目前为止,我只使用 Vue 3 + Vite 构建了一个应用程序。
我只使用了<script setup>
方法并坚持使用它,这就是定义道具时的样子:
<script setup>
import onMounted from 'vue'
const props = defineProps(
readonly: type: Boolean ,
required: type: Boolean ,
)
onMounted(() =>
console.dir(props.readonly)
)
</script>
在 Vite 设置中,defineProps
是全局注册的,似乎是唯一不需要 import
的方法,我不知道这是否适用于任何其他编译器方法.
Vue3 中的v-model
弹出为modelValue
而不是value
,也许你可以defineProp
和modelValue
,除非它默认始终存在?
这里有一些解释:https://v3.vuejs.org/guide/migration/v-model.html#_2-x-syntax
希望这适用于您并有所帮助。
【讨论】:
感谢您的评论!我尝试了这种语法,不幸的是没有任何改变。我想我现在会使用 v-model 并希望一切顺利。我几乎可以肯定我需要以某种身份使用:value="modelValue"
。以上是关于如何正确使用 v-model 和 Composition API :value="modelValue" 语法?将 Vue2 自定义输入转换为 Vue3的主要内容,如果未能解决你的问题,请参考以下文章
Vue.js 如何使用 v-model 和计算属性以及复选框来镜像输入字段