参考element源码用vue写一个input的受控组件
在react当中,表单元素 input
中设置了 value
,则为受控组件,通过 onChange
事件中 setState()
改变 value
值来更新 state
值和DOM中渲染的值。但在vue中,表单元素设置 value
值,即使 value
值改变了,dom中 value
的表现也和data中的 value
不一致
vue和react中受控组件的不同
在 HTML 中,表单元素(如 <input>
、 <textarea>
和 <select>
)通常自己维护 state
,并根据用户输入进行更新。而在 React 中,可变状态(mutable state)通常保存在组件的 state
属性中,并且只能通过使用 setState()
来更新。
我们可以把两者结合起来,使 React 的 state
成为“唯一数据源”。渲染表单的 React 组件还控制着用户输入过程中表单发生
import React, { useState } from "react";
export default function App() {
const [vale, setValue] = useState(0);
const changeEvent = function(e) {
console.log(e);
setValue(123);//value和渲染的值都为123
}
return (
<div className="App">
<input type="text" value={value} onChange={changeEvent} />
</div>
);
}
复制代码
而在vue中,改变 value
的值,只有 data
中的状态改变了,而原生DOM中的 value
值并没有被改变,最终渲染出来的仍然为用户输入的值
<template>
<input :value="value" @input="setValue" />
</template>
<script>
export default {
name: "App",
components: {},
data: function () {
return {
value: '',
};
},
methods: {
setValue(e) {
this.value = 123//仅仅data中value的值改变了,DOM中渲染的value值仍为输入的值
}
}
};
</script>
复制代码
用vue写一个input受控组件
在日常业务中,受控组件的需求经常被用到,用来给input框输入的限制,例如一个仅可以输入数字的 input
框。在使用elementUI的时候,发现其 <el-input>
为受控组件,于是去 elementUI-github 上看了这种操作是如何实现的。
核心原理就是在更新自己的 data
值的同时,一起更新原生input DOM上的 value
。
代码如下:
首先写一个完全像一个普通的 <input>
元素一样使用的 <CtrlInput>
组件
<template>
<label>
<input v-bind="$attrs" :value="value" v-on="inputListeners" />
</label>
</template>
<script>
export default {
name: "CtrlInput",
props: {
value: {
type: String
}
},
computed: {
inputListeners() {
return {
//从父级添加所有的监听器
...this.$listeners,
// 然后我们添加自定义监听器
// 这里确保组件配合 `v-model` 的工作
input: e => {
this.$emit("input", e.target.value);
}
};
}
}
};
</script>
<style scoped></style>
复制代码
所有跟原生 input
相同的 attribute
和监听器都可以正常工作,并且确保组件配合 v-model
也可以工作
然后在 input
监听器中,设置 nativeInputValue
(原生DOM的 value
值)和 data
中的 value
一样即可。
<template>
<label>
<input ref="input" v-bind="$attrs" :value="value" v-on="inputListeners" />
</label>
</template>
<script>
export default {
name: "CtrlInput",
props: {
value: {
type: String
}
},
computed: {
inputListeners() {
return {
//从父级添加所有的监听器
...this.$listeners,
// 然后我们添加自定义监听器
// 这里确保组件配合 `v-model` 的工作
input: e => {
this.$emit("input", e.target.value);
// 保证原生的input value 是可控的
// ensure native input value is controlled
this.$nextTick(this.setNativeInputValue);
}
};
},
nativeInputValue() {
//将传入的值转为String,防止出错
return this.value === null || this.value === undefined
? ""
: String(this.value);
}
},
methods: {
setNativeInputValue() {
// 将展示的原生的input value 和this中的input value保持一致
const input = this.$refs.input;
if (!input) return;
if (input.value === this.nativeInputValue) return;
input.value = this.nativeInputValue;
}
},
watch: {
//将展示的原生的input value 和this中的input value保持一致
nativeInputValue() {
this.setNativeInputValue();
}
}
};
</script>
<style scoped></style>
复制代码
this.nextTick(this.setNativeInputValue); 这行代码意思就是在 data 中的 value 改变完,并且渲染完成后(使用 nextTick )再改变 nativeInputValue 的值,即可让原生DOM和自身的state保持一致
使用
需求:仅可输入数字的input框,输入其他字符就不显示
<template>
<div>
仅可以输入数字的受控组件
<CtrlInput
type="text"
placeholder="请输入数字"
:value="value"
@input="handleInput"
></CtrlInput>
</div>
</template>
<script>
import CtrlInput from "./CtrlInput";
export default {
name: "Demo",
components: {
CtrlInput
},
data() {
return {
value: ""
};
},
methods: {
handleInput(v) {
if (/^[0-9]*$/.test(v)) {
this.value = v;
}
}
}
};
</script>
复制代码
相关文章
- vue中父组件向子组件传值
- 请简述什么是Vue组件化开发_vue组件化开发
- codeblocks批量注释快捷键_vue多行注释快捷键
- Vue 强制刷新文档流
- vue子组件传值给父组件_子组件调用父组件中的方法
- vue源码分析-从new Vue开始
- Vue组件是怎样挂载的
- KUI for Vue.js
- 「后端小伙伴来学前端了」关于 Vue中 Slot 插槽的使用,实用且也是组件中必会的一个知识,另外也可以实现父子组件之间通信
- vue页面刷新_vue强制重置组件
- Vue富文本_ueditor编辑器
- 请说下封装 vue 组件的过程?_vue 自己封装过哪些通用组件
- Vue(renren-fast_vue_master)项目目录结构[通俗易懂]
- Vue自动化全局注册基础组件
- vue开发后打包部署的网站页面变灰色
- Vue指令之条件渲染
- vue源码分析-从new Vue开始_2023-02-24
- 自定义事件在 Vue.js 组件中的应用
- ruoyi-vue版本(十二)用户登陆的逻辑,在线用户的查询与强退出 思路
- 前端 CST和GMT+0800时间转换(js/vue/react/jsp通用)
- Vue接入Redis拓展应用的可能性(vue调redis)