vue2封装input组件方式(输入的双向绑定)
vue2封装input组件
重点
首先我们要明白 vue中v-modle 的对于input 做了什么
- <input type=“text” v-model=“username”>
- <input type=“text” :value=“username” @input=“username = $event.target.value”>
以上的两行代码,所呈现的效果是一样的。也就是说: v-model=“username” 在input中做了两件事情。
- :value 绑定了值
- @input=“username = $event.target.value” 监听了值的改变
代码示例:
父组件
- <template>
- <div id=“app”>
- <lj-input placeholder=“请输入” v-model=“username”></lj-input>
- <div>{{username}}</div>
- </div>
- </template>
- <script>
- import ljInput from ‘./components/inputCom/LjInput.vue’
- export default {
- name: ‘App’,
- components: {
- ljInput
- },
- data(){
- return{
- username:”,
- }
- },
- methods: {
- }
- }
- </script>
子组件
- <template>
- <div class=“lj-input”>
- <input :class=“{‘is-disabled’:disabled}”
- :placeholder=“placeholder”
- :type=“type”
- :disabled =‘disabled’
- :value=“value”
- @input=“handleInput”
- >
- </div>
- </template>
- <script>
- export default {
- name:‘ljInput’,
- props: {
- placeholder:{
- type:String,
- default:”
- },
- type:{
- type:String,
- default:”
- },
- disabled:{
- type:Boolean,
- default:false
- },
- value:{
- type:String,
- default:”
- }
- },
- methods:{
- handleInput(e){
- // 这句代码是关键
- this.$emit(‘input’,e.target.value)
- }
- }
- }
- </script>
- <style>
- .is–disabled{
- cursor: not–allowed;
- }
- </style>
vue二次封装input的几种方式
下面就是自己封装input 框实现的效果
在看如何封装之前,先来了解一下v-model是怎么回事。
其实说白了,v-model就是change和value的结合体。
废话不多说,下面就来看一下在vue中如何封装自定义的input组件。
封装原生input
- <template>
- <input type=“text” :value=“value” @input=“handleChange” />
- </template>
- <script>
- export default {
- name: “AppInput”,
- model: {
- prop: “value”,
- event: “change”,
- },
- props: {
- value: “”,
- },
- data() {
- return {
- };
- },
- created() {},
- mounted() {},
- methods: {
- handleChange(e) {
- this.$emit(“change”, e.target.value);
- },
- },
- };
- </script>
封装el-input
- <template>
- <!– 对el-input进行了包装–>
- <div>
- <el-input
- v-model=“localValue”
- @change=“$emit(‘change’, $event)”></el-input>
- <!–
- el-input提供了input事件,让我们感知el-input内部原生input值的变化,通过$event可以获取到具体的值
- 通过emit再次传递给父组件一个input事件,父组件中,v-on:input=”searchText = $event”这句就能正常使用了
- –>
- <span style=“color: #f56c6c; font-size: 12px;“></span>
- </div>
- </template>
- <script>
- export default {
- name: “input-name”,
- props: {
- // 保证父组件中,v-bind:value可以正常设置值
- value: [String],
- },
- data() {
- return {
- // 获取props中value的值,并与el-input绑定,过程中不修改props中value的值,保证了单向数据流原则
- localValue: this.value
- }
- }
- }
- </script>
- <style lang=“less” scoped>
- </style>
上面的那种方式会在回显数据时有问题。解决办法就是:如果出现异步回显数据那么就需要用计算来作为中间值转换。
- <template>
- <!– 对el-input进行了包装–>
- <div>
- <el-input
- v-model=“localValue”
- @change=“$emit(‘change’, $event)”></el-input>
- <!–
- el-input提供了input事件,让我们感知el-input内部原生input值的变化,通过$event可以获取到具体的值
- 通过emit再次传递给父组件一个input事件,父组件中,v-on:input=”searchText = $event”这句就能正常使用了
- –>
- <span style=“color: #f56c6c; font-size: 12px;“></span>
- </div>
- </template>
- <script>
- export default {
- name: “input-name”,
- props: {
- // 保证父组件中,v-bind:value可以正常设置值
- value: [String],
- },
- data() {
- return {
- }
- },
- computed: {
- localValue: {
- get: function () {
- console.log(this.value)
- return this.value;
- },
- set: function (v) {
- v;
- },
- },
- },
- }
- </script>
- <style lang=“less” scoped>
- </style>
VUE高级用法封装input
这种方式更加简洁,并且不会出现第二种封装方式出现的bug。
- <template>
- //这里不能使用v-model,会报子组件不能直接操作父组件传入参数的错误
- //使用value的话其实就是做一个回显因为外层的v-model在这里使用已经改变了外层的值了
- <el-input
- v-bind=“$attrs”
- v-on=“$listeners”
- :value=“value”
- ></el-input>
- </template>
- <script>
- export default {
- name: “f-input”,
- data() {
- return {
- };
- },
- props: {
- value:“”
- },
- created() {},
- mounted() {},
- methods: {}
- };
- </script>
- //正常的使用方式
- <f–input v–model=“number”></f–input>
- //不用v-model语法糖的方式
- <f–input :value=“number” @change=“number = $event,target.value”></f–input>
这里核心用到了两个方法 attrs 和 listeners 其中 atters 可以把父组件标签上的所有自定义属性(不包括props,tyle,class)同步到当前元素中,listeners 可以把 f-input 标签上的所有方法同步到子组件中当前元素中。
那么上面已经知道 v-model 就是 change 和 value 的语法糖,那在 f-input 上绑定 listeners 就可以读取到 f-input 的 v-model 的 change 事件,atters 可以读取到 f-input 的 v-model 的 value 值。
$ 符号打不出来了,将就着看吧。如果还是不明白 atters和 listeners是怎么回事的可以看一下vue官网中的介绍。
看官网又出了一种封装的写法,感觉挺有意思,在这里记录一下。
默认情况下,组件上的 v-model 使用 modelValue 作为 prop 和 update:modelValue 作为事件。我们可以通过向 v-model 传递参数来修改这些名称
子组件将需要一个 firstName prop 和 lastName prop并发出 update:firstName 和 update:lastName要同步的事件
- var Component = {
- props: {
- firstName: String,
- lastName: String
- },
- emits: [‘update:firstName’, ‘update:lastName’],
- //vue3可以支持多个根元素,所有这个地方不会有报错,vue2是会报错的。
- template: `
- <input
- type=”text”
- :value=”firstName”
- @input=”$emit(‘update:firstName’, $event.target.value)”>
- <input
- type=”text”
- :value=”lastName”
- @input=”$emit(‘update:lastName’, $event.target.value)”>
- `
- }
- <template>
- <my-component
- v-model:first-name=“firstName”
- v-model:last-name=“lastName”>
- </my-component>
- firstName:{{firstName}} lastName:{{lastName}}
- </template>
- <script>
- const App = {
- setup(props, context) {
- const data= reactive({
- firstName: 0,
- lastName: 0,
- });
- return {
- …toRefs(data),
- }
- },
- components: {
- ‘my-component’: Component,
- },
- methods: { },
- };
- const app = createApp(App).mount(‘#app’);
- </script>
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持我们。
发表评论