v-model vue2-vue3实现跨组件双向绑定不同方法

1,163 阅读1分钟

vue2:

1.在调用组件父组件内 创建响应式数据 并使用v-model绑定传入封装好的input组件内
<template>
	<div>
		<el-form :rules="rules" ref="Form" :model="Form">
			<el-form-item label="姓名" prop="name">
				<Input v-model="Form.name" />
			</el-form-item>
			<el-form-item label="密码" prop="pwd">
				<Input v-model="Form.pwd" />
			</el-form-item>
			<el-form-item>
				<el-button
					type="primary"
					@click="submitForm"
					style="marginLeft:110px ;"
					>登录</el-button
				>
			</el-form-item>
		</el-form>
	</div>
</template>

<script>
	import ElForm from "./ElForm.vue";
	import ElFormItem from "./ElFormItem.vue";
	import Input from "./Input.vue";
	export default {
		components: {
			ElForm,
			ElFormItem,
			Input
		},
		data() {
			return {
				Form: { name: "11", pwd: "22" },
		},
		
	};
</script>

<style lang="scss" scoped>
</style>

2.input组件内使用value接收并绑定v-model传入值,在输入动作发生时,通过input事件,以及this.$emit将输入值赋值给v-model绑定的变量,注意 vue2 emit事件名必须是input
<template>
	<div class="myInput">
		<input type="text" @input="input" class="inputinner" :value="value" />
	</div>
</template>

<script>
	export default {
		name: "MyInput",
		props: {
			value: {
				type: String
			}
		},
		data() {
			return {};
		},
		methods: {
			input(e) {
				this.$emit("input", e.target.value);
			
			}
		}
	};
</script>

<style lang="scss" scoped>
	.myInput {
		margin: 5px 10px;
		.inputinner {
			background-color: #fff;
			background-image: none;
			border-radius: 4px;
			border: 1px solid #dcdfe6;
			box-sizing: border-box;
			color: #606266;
			display: inline-block;
			font-size: inherit;
			height: 40px;
			line-height: 40px;
			outline: none;
			padding: 0 15px;
			transition: border-color 0.2s cubic-bezier(0.645, 0.045, 0.355, 1);
			width: 100%;
		}
	}
</style>

vue3:

1.在调用组件父组件内 创建响应式数据 并使用v-model绑定传入封装好的input组件内
<template>
     <div  class="container">
        <div class="mb-3">
          <label for="exampleInputEmail1" class="form-label">邮箱地址</label>
          <ValidateInput :rules="emailRules" **v-model="emailVal"** />
          {{emailVal}}
        </div>
     </div>
</template>
<script lang="ts">
import { defineComponent, ref } from 'vue'
import 'bootstrap/dist/css/bootstrap.min.css'
import ValidateInput, { RulesProp } from './components/ValidateInput.vue'
export default defineComponent({
  name: 'App*',*
  components: {
    ValidateInput
  },
  setup () {
   ** const emailVal = ref('你好')**
    return {
      emailVal
    }
  }
})
</script>

<style>
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  color: #2c3e50;
  margin-top: 60px;
}
</style>
2.在子组件内props内 使用 modelValue 接收参数,并创建响应式数据 将modelValue初始化给该数据,并在input上使用:value绑定,当输入事件发生时,使用@input绑定事件,将回调参数赋值给响应式数据,并使用 context,emit('update:modelValue',e.target.value)实现双向绑定
<template>
    <div class="validate-input-container pb-3 ">
    <input type="text"
      class="form-control"
      :class="{'is-invalid': inputRef.error}"
    **  :value='inputRef.val'**
      @blur="validateInput"
      @input="updateValue"
    >
    <span v-if="inputRef.error" class="invalid-feedback">{{inputRef.message}}</span>
  </div>
</template>

<script lang='ts'>
import { defineComponent, PropType, reactive } from 'vue'
const emailReg = /^[a-zA-Z0-9.!#$%&’*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/
interface RuleProp{
    type:'required' | 'email';
    message:string
}
export type RulesProp=RuleProp []
export default defineComponent({
  props: {
    rules: Array as PropType<RulesProp>,
  **  modelValue: {
      type: String,
      required: true
    }**
  },
  setup (props, context) {
    const inputRef = reactive({
    **  val: props.modelValue,**
      error: false,
      message: ''
    })
   ** const updateValue = (e:KeyboardEvent) => {
      const targetValue = (e.target as HTMLInputElement).value
      inputRef.val = targetValue
      context.emit('update:modelValue', targetValue)
    }**
    const validateInput = () => {
      if (props.rules) {
        const allPassed = props.rules.every(rule => {
          let passed = true
          inputRef.message = rule.message
          switch (rule.type) {
            case 'required':
              passed = (inputRef.val.trim() !== '')
              break
            case 'email':
              passed = emailReg.test(inputRef.val)
              break
            default:
              break
          }
          return passed
        })
        inputRef.error = !allPassed
      }
    }
    return {
      validateInput,
      inputRef,
      updateValue
    }
  }
})
</script>

<style lang="scss" scoped>

</style>