react和vue2/3父子组件的双向绑定

这篇具有很好参考价值的文章主要介绍了react和vue2/3父子组件的双向绑定。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

Vue3

父子传值:props(attrs)/emit

父传子

props

父child :属性名="变量"

子props=defineProps({属性名:type...})

attrs父作用域(除 class、 style 、 props )属性集合

父child :属性名="变量",属性名="常量"

子 attrs = useAttrs()

子传父emits+@=v-on:

父child @事件名"="parentClick",parentClick(msg)

子emit = defineEmits(["事件名",...]),emit("key",msg)

双向绑定v-model(支持多个v-model,所以取消了.sync)

v-model:modelValue简写为v-model

父child  v-model:属性名="变量"

子emit = defineEmits(["事件名",...]),emit("事件名",值)

父调子事件/属性:expose / ref

父child ref="childComp",childComp.value.属性/方法

子defineExpose({属性: "msg",方法(){  }})

祖传孙provide / inject依赖注入【不推荐】

耦合性增加->依赖关系复杂化->重用性和可维护性低

父provide("key",msg)

子inject("key")

跨组件事件触发/监听器mitt:on/off,emit

代替vue2的eventbus

轻量级:仅有200字节

支持全部事件的监听和批量移除

跨框架:不依赖 Vue 实例,React / Vue/jQuery

原理:map 保存函数

直接在组件内导入使用:分散式更方便管理和排查问题

Vue2

父子传值:props(attrs)/emit

父传子

props

父child :属性名="父组件实例变量"

A.数组:props:['属性名']

B.对象:props:{属性名:{type:,default:}}

attrs父作用域(除 class、 style 、 props )属性集合

父child :属性名="变量",属性名="常量"

子 this.$attrs

子传父emits+@=v-on:

父child @事件名"="parentClick",parentClick(msg)

子this.$emit("事件名",msg)

双向绑定值

.sync(支持多个,update:属性名)

父child :属性名.sync="变量"

子 this.$emit("update:属性名", 属性值 ); 

v-model(支持一个,自定义prop+event名)

语法糖:value 和 @input

model 选项自定义 prop 和 event 的名称

副作用:当绑定响应式对象上不存在的属性,会让它响应式

父子传属性/方法

父传子

this.$parent

this.$root : App.vue

this.$listeners:父组件.native 除外的监听事件集合

调用:this.$listeners.事件名

子传父

this.$children[0]

ref

父child ref="childComp",childComp.所有的属性/方法

祖传孙provide / inject依赖注入:推荐传递常量/方法

父provide(){return obj }

子inject[“name”,“msg”],this.msg

跨组件事件通信EventBus中央事件总线

定义

使用:emit、on、off

slot:父传子组件,子传父数据

单个/默认/匿名插槽slot

v-slot="name",在2.6后可缩写为#"name"

父v-slot="子slot中的变量"

子slot :属性名="变量"

具名插槽slot name="":多个插槽,需要区分

作用域/带数据的插槽

内置指令:数据/事件关联DOM

v-bind(简写:):绑定属性到 Vue 实例中的数据

v-on (简写@): 监听DOM事件、触发Vue实例中的方法


Vue3

Vue3 从实例中完全删除了 $on$off 和 $once 方法

父子传值:props(attrs)/emit

父传子

props
父child :属性名="变量"
子props=defineProps({属性名:type...})
// Parent.vue 传送
<child :msg2="msg2"></child>
<script setup>
    import child from "./child.vue"
    import { ref, reactive } from "vue"
    const msg2 = ref("这是传给子组件的信息2")
    // 或者复杂类型
    const msg2 = reactive(["这是传级子组件的信息2"])
</script>

// Child.vue 接收
<script setup>
    // 不需要引入 直接使用
    // import { defineProps } from "vue"
    const props = defineProps({
        // 写法一
        msg2: String
        // 写法二
        msg2:{
            type:String,
            default:""
        }
    })
    console.log(props) // { msg2:"这是传级子组件的信息2" }
</script>
attrs父作用域(除 class、 style 、 props )属性集合
父child :属性名="变量",属性名="常量"
子 attrs = useAttrs()
// Parent.vue 传送
<child :msg1="msg1" :msg2="msg2" title="3333"></child>
<script setup>
    import child from "./child.vue"
    import { ref, reactive } from "vue"
    const msg1 = ref("1111")
    const msg2 = ref("2222")
</script>

// Child.vue 接收
<script setup>
// 3.2版本不需要引入,直接用
    import { useAttrs } from "vue"
    
// 如果没有用 props 接收 msg1 的话就是 { msg1: "1111", msg2:"2222", title: "3333" }
    const props = defineProps({
        msg1: String
    })

    const attrs = useAttrs()
    console.log(attrs) // { msg2:"2222", title: "3333" }
</script>

子传父emits+@=v-on:

父child @事件名"="parentClick",parentClick(msg)
子emit = defineEmits(["事件名",...]),emit("key",msg)
//父组件
<template>
  <my-son  @childClick="childClick" />
</template>

<script lang="ts" setup>
import MySon from "./MySon.vue";

let childClick = (e: any):void => {
  console.log('from son:',e);  
};
</script>


//子组件
<template>
  <span @click="sonToFather">信息:{{ props.foo }}</span>
</template>

<script lang="ts" setup>
const emit = defineEmits(["childClick"]);     // 声明触发事件 childClick

const sonToFather = () =>{
    emit('childClick' , props.foo)
}
</script>

双向绑定v-model(支持多个v-model,所以取消了.sync

v-model:modelValue简写为v-model
父child  v-model:属性名="变量"
子emit = defineEmits(["事件名",...]),emit("事件名",值)
//child.vue
<template>
  <span @click="changeInfo">我叫{{ modelValue }},今年{{ age }}岁</span>
</template>

<script setup>
  // import { defineEmits, defineProps } from 'vue'
  // defineEmits和defineProps在<script setup>中自动可用,无需导入
  // 需在.eslintrc.js文件中【globals】下配置【defineEmits: true】、【defineProps: true】

  defineProps({
    modelValue: String,
    age: Number
  })

  const emit = defineEmits(['update:modelValue', 'update:age'])
  const changeInfo = () => {
    // 触发父组件值更新
    emit('update:modelValue', 'Tom')
    emit('update:age', 30)
  }
</script>
//parent.vue
<template>
  // v-model:modelValue简写为v-model
  // 可绑定多个v-model
  <child
    v-model="state.name"
    v-model:age="state.age"
  />
</template>

<script setup>
  import { reactive } from 'vue'
  // 引入子组件
  import child from './child.vue'

  const state = reactive({
    name: 'Jerry',
    age: 20
  })
</script>


父调子事件/属性:expose / ref

父child ref="childComp",childComp.value.属性/方法

子defineExpose({属性: "msg",方法(){  }})

// Child.vue
<script setup>
    // 方法一 不适用于Vue3.2版本,该版本 useContext()已废弃
    import { useContext } from "vue"
    const ctx = useContext()
    // 对外暴露属性方法等都可以
    ctx.expose({
        childName: "这是子组件的属性",
        someMethod(){
            console.log("这是子组件的方法")
        }
    })
    
    // 方法二 适用于Vue3.2版本, 不需要引入
    // import { defineExpose } from "vue"
    defineExpose({
        childName: "这是子组件的属性",
        someMethod(){
            console.log("这是子组件的方法")
        }
    })
</script>

// Parent.vue  注意 ref="comp"
<template>
    <child ref="comp"></child>
    <button @click="handlerClick">按钮</button>
</template>
<script setup>
    import child from "./child.vue"
    import { ref } from "vue"
    const comp = ref(null)
    const handlerClick = () => {
        console.log(comp.value.childName) // 获取子组件对外暴露的属性
        comp.value.someMethod() // 调用子组件对外暴露的方法
    }
</script>

祖传孙provide / inject依赖注入【不推荐】

耦合性增加->依赖关系复杂化->重用性和可维护性低

耦合性:关联度

父provide("key",msg)

子inject("key")

// Parent.vue
<script setup>
    import { provide } from "vue"
    provide("name", "沐华")
</script>

// Child.vue
<script setup>
    import { inject } from "vue"
    const name = inject("name")
    console.log(name) // 沐华
</script>

跨组件事件触发/监听器mitt:on/off,emit

代替vue2的eventbus

轻量级:仅有200字节

支持全部事件的监听和批量移除

跨框架:不依赖 Vue 实例,React / Vue/jQuery

原理:map 保存函数

export default function mitt(all) {
	all = all || new Map();
//命名为type的事件
	return {
		all,
        //监听type事件,绑定handler
		on(type, handler) {
			const handlers = all.get(type);
			const added = handlers && handlers.push(handler);
			if (!added) {
				all.set(type, [handler]);
			}
		},
       //移除type事件,解绑handler
		off(type, handler) {
			const handlers = all.get(type);
			if (handlers) {
				handlers.splice(handlers.indexOf(handler) >>> 0, 1);
			}
		},
       //触发type事件,传递evt事件参数给handler(遍历执行与其绑定的所有handler)
		emit(type, evt) {
			((all.get(type) || [])).slice().map((handler) => { handler(evt); });
			((all.get('*') || [])).slice().map((handler) => { handler(type, evt); });
		},
        clear(){
            // 清空所有事件处理程序
            all.clear();
        },
	};
}

直接在组件内导入使用:分散式更方便管理和排查问题

npm i mitt -save

import mitt from 'mitt'

const emitter = mitt()

// listen to an event
emitter.on('foo', e => console.log('foo', e) )

// listen to all events
emitter.on('*', (type, e) => console.log(type, e) )

// fire an event
emitter.emit('foo', { a: 'b' })

// clearing all events
emitter.all.clear()

// working with handler references:
function onFoo() {}
emitter.on('foo', onFoo)   // listen
emitter.off('foo', onFoo)  // unlisten

Vue3.x 推荐使用 mitt.js - 掘金

Vue2

父子传值:props(attrs)/emit

父传子

props
父child :属性名="父组件实例变量"
A.数组:props:['属性名']
B.对象:props:{属性名:{type:,default:}}
// Child.vue 接收
export default {
  // 写法一 用数组接收
  props:['msg'],
  // 写法二 用对象接收,可以限定接收的数据类型、设置默认值、验证等
  props:{
      msg:{
          type:String,
          default:'这是默认数据'
      }
  },
  mounted(){
      console.log(this.msg)
  },
}
attrs父作用域(除 class、 style 、 props )属性集合
父child :属性名="变量",属性名="常量"
子 this.$attrs

子传父emits+@=v-on:

父child @事件名"="parentClick",parentClick(msg)
子this.$emit("事件名",msg)
// Child.vue 派发
export default {
  data(){
      return { msg: "这是发给父组件的信息" }
  },
  methods: {
      handleClick(){
          this.$emit("sendMsg",this.msg)
      }
  },
}
// Parent.vue 响应
<template>
    <child v-on:sendMsg="getChildMsg"></child>
    // 或 简写
    <child @sendMsg="getChildMsg"></child>
</template>

export default {
    methods:{
        getChildMsg(msg){
            console.log(msg) // 这是父组件接收到的消息
        }
    }
}

双向绑定值

.sync(支持多个,update:属性名

 .sync 修饰符是单向数据流的典型范式。 『数据向下,事件向上』

react和vue2/3父子组件的双向绑定,React和Vue,前端,react.js,vue.js,前端

父child :属性名.sync="变量"
子 this.$emit("update:属性名", 属性值 ); 
//父组件
<template>
    <TestCom :num.sync="data"></TestCom>
</template>
<script>
export default({
  components: {
    TestCom,
  },
  data() {
    return {
      data:2
    }  
  },
});
</script>


//子组件
<template>
  <div>
    <button @click="cahngeNum">按钮</button>
    {{ num }}
  </div>
</template>

<script>
export default({
  props: {
    num: {
      default: "",
      type: String,
    },
  },
  methods: {
    cahngeNum() {
       // 事件名称的格式 'update:' + prop名称 
      this.$emit("update:num", 999); 
    },
  },
});
</script>
v-model(支持一个,自定义prop+event名)

除了传递基本的值之外,还可以传递其他类型,比如对象或数组。

语法糖:value @input

语法糖,简单来说就是『便捷写法』。

<input v-model="searchText">
语法糖 等价于:
<input
  :value="searchText"
  @input="searchText = $event.target.value"
>

当用户在输入框中输入文本时,userMessage 的值会实时更新,

并且当 userMessage 的值改变时,输入框中的值也会自动更新。

v-model 在内部相当于使用 :value @input 来实现数据的绑定监听

// Parent.vue
<template>
    <child v-model="value"></child>
</template>
<script>
export default {
    data(){
        return {
            value:1
        }
    }
}

// Child.vue
<template>
    <input :value="value" @input="handlerChange">
</template>
export default {
    props:["value"],
    methods:{
        handlerChange(e){
            this.$emit("input", e.target.value)
          
        }
    }
}
</script>

model 选项自定义 prop 和 event 的名称

默认情况下,v-model 会使用子组件的 value 属性作为 prop 名,使用 input 事件来触发更新。

  1. 适应不同的数据源,与其他组件集成不会产生命名冲突

  2. 提高代码可读性: 比起value更具有语义,使其他开发者更容易理解组件的预期用法和行为。

<!-- CustomInput.vue -->
<template>
  <input :value="internalValue" @input="updateParentValue" />
</template>

<script>
export default {
  props: {
    // 使用自定义的 prop 名 customProp
    customProp: String,
  },
  // 通过 model 选项自定义 v-model 的 prop 和事件名
  model: {
    prop: 'customProp',
    event: 'customEvent'
  }
  data() {
    return {
      internalValue: this.customProp
    };
  },
  methods: {
    // 使用自定义的事件名 customEvent
    updateParentValue(event) {
      this.internalValue = event.target.value;
      // 触发自定义事件,通知父组件更新值
      this.$emit('customEvent', this.internalValue);
    }
  },

};
</script>
副作用:当绑定响应式对象上不存在的属性,会让它响应式
// template中:
<el-input v-model="user.tel"></el-input>
// script中:
export default {
  data() {
    return {
      user: {
        name: '参宿7',
      }
    }
  }
}

父子传属性/方法

父传子

this.$parent
this.$root : App.vue
this.$listeners:父组件.native 除外的监听事件集合
调用:this.$listeners.事件名

将父组件传递的事件监听器绑定到子组件上,以实现一种“透明传递”的效果。这种方式使得子组件不需要显式声明和监听来自父组件的事件

父组件 自定义的所有事件,都被保存在子组件的vm.$listeners属性里,和$attrs一样可以层层传递

son组件可以响应father组件的2个自定义事件speak()、write()

grandson组件可以响应father组件的2个自定义事件speak()、write(),并且还可以响应son组件的1个自定义事件sonCry()

子传父

this.$children[0]
ref
父child ref="childComp",childComp.所有的属性/方法
// Child.vue
export default {
    data(){
        return {
            name:"沐华"
        }
    },
    methods:{
        someMethod(msg){
            console.log(msg)
        }
    }
}

// Parent.vue
<template>
    <child ref="child"></child>
</template>
<script>
export default {
    mounted(){
        const child = this.$refs.child
        console.log(child.name) // 沐华
        child.someMethod("调用了子组件的方法")
    }
}
</script>
祖传孙provide / inject依赖注入:推荐传递常量/方法

要注意的是 provide 和 inject 传递的数据不是响应式的,除非传入的就是一个可监听的对象

父provide(){return obj }

obj={name:,msg:}

子inject[“name”,“msg”],this.msg

跨组件事件通信EventBus中央事件总线

定义

// 方法一:独立的事件总线文件
// 抽离成一个单独的 js 文件 Bus.js导出 ,然后在需要的地方导入
// 保持了代码的模块化和清晰性。事件总线和组件逻辑分离,使得维护和理解代码变得更容易。
// Bus.js
import Vue from "vue"
export default new Vue()

// 方法二 全局挂载到Vue原型
// main.js
import Vue from "vue"
Vue.prototype.$bus = new Vue()

// 方法三 注入到 Vue 根对象上,作为Vue实例的数据属性
// 组件通过this.$root.Bus访问
// main.js
import Vue from "vue"
new Vue({
    el:"#app",
    data:{
        Bus: new Vue()
    }
})

使用:emit、on、off

// 在需要向外部发送自定义事件的组件内
<template>
    <button @click="handlerClick">按钮</button>
</template>
import Bus from "./Bus.js"
export default{
    methods:{
        handlerClick(){
            // 自定义事件名 sendMsg
            Bus.$emit("sendMsg", "这是要向外部发送的数据")
        }
    }
}

// 在需要接收外部事件的组件内
import Bus from "./Bus.js"
export default{
    mounted(){
        // 监听事件的触发
        Bus.$on("sendMsg", data => {
            console.log("这是接收到的数据:", data)
        })
    },
    beforeDestroy(){
        // 取消监听
        Bus.$off("sendMsg")
    }
}

slot:父传子组件,子传父数据

单个/默认/匿名插槽slot

v-slot="name",在2.6后可缩写为#"name"

父v-slot="子slot中的变量"

子slot :属性名="变量"

// Child.vue
<template>
    <div>
        <slot :user="user"></slot>
    </div>
</template>
export default{
    data(){
        return {
            user:{ name:"沐华" }
        }
    }
}

// Parent.vue
<template>
    <div>
        <child v-slot="slotProps">
            {{ slotProps.user.name }}
        </child>
    </div>
</template>

具名插槽slot name="":多个插槽,需要区分

<template>
  // 匿名插槽
  <slot/>
  // 具名插槽
  <slot name='title'/>
</template>

<script setup>
  import { useSlots, reactive } from 'vue'
  const slots = useSlots()
  // 匿名插槽使用情况
  const defaultSlot = reactive(slots.default && slots.default().length)
  console.log(defaultSlot) // slot内的标签
  // 具名插槽使用情况
  const titleSlot = reactive(slots.title && slots.title().length)
  console.log(titleSlot) // 1
  const state = reactive({
    name: '张三',
    age: '25岁'
  })
  
</script>

<template>
  <child>
    // 匿名插槽
    <span>我是默认插槽</span>
    // 具名插槽
    <template #title>
      <h1>我是具名插槽</h1>
    </template>
  </child> 
</template>

作用域/带数据的插槽

<template>
  <slot name="footer" :scope="state" />
</template>

<script setup>
  import { reactive } from 'vue'

  const state = reactive({
    name: '张三',
    age: '25岁'
  })
  
</script>

 //  { scope } 表示从插槽的内容中解构出一个名为 scope 的变量
    <template #footer="{ scope }">
      <footer>作用域插槽——姓名:{{ scope.name }},年龄{{ scope.age }}</footer>
    </template>

内置指令:数据/事件关联DOM

数据事件处理程序DOM 元素关联,以实现动态数据渲染、事件处理、条件渲染、循环渲染等功能。

v-bind(简写:):绑定属性到 Vue 实例中的数据

它允许你在模板中动态设置元素属性的值

<div v-bind:id="id"></div>
<div :id="id"></div>

v-on (简写@): 监听DOM事件、触发Vue实例中的方法

<button @click="doSomething">Click me</button>

vue父子组件之间双向数据绑定的(vue2/vue3)_vue3父子组件双向绑定_前端一枚的博客-CSDN博客

Vue3的8种和Vue2的12种组件通信,值得收藏 - 掘金文章来源地址https://www.toymoban.com/news/detail-586294.html

到了这里,关于react和vue2/3父子组件的双向绑定的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【vue2第十一章】v-model的原理详解 与 如何使用v-model对父子组件的value绑定 和修饰符.sync

    v-model的原理详解 v-model的本质就是一个语法糖,实际上就是 :value=\\\"msg\\\" 与 @input=\\\"msg = $event.target.value\\\" 的简写。 :value=\\\"msg\\\" 从数据单向绑定到input框,当data数据中的msg内容一旦改变,而input框数据也随之改变。 @input=\\\"msg = $event.target.value\\\" 是为input框绑定了input事件,内容改变则触发

    2024年02月10日
    浏览(27)
  • vue2双向数据绑定基本原理

    vue2的双向数据绑定(又称响应式)原理,是通过数据劫持结合发布订阅模式的方式来实现的,通过 Object.defineProperty() 来劫持各个属性的 setter , getter ,在数据变动时发布消息给订阅者,触发相应的监听回调来渲染视图。也就是说数据和视图同步,数据发生变化,视图跟着变化

    2023年04月10日
    浏览(43)
  • 前端react入门day02-React中的事件绑定与组件

    (创作不易,感谢有你,你的支持,就是我前行的最大动力,如果看完对你有帮助,请留下您的足迹) 目录 React中的事件绑定 React 基础事件绑定 使用事件对象参数  传递自定义参数  同时传递事件对象和自定义参数  React中的组件  组件是什么 React组件 useState  修改状态的规

    2024年02月06日
    浏览(39)
  • 前端2023最全面试题(javaScript、typeScript、vue2、vue3、html、css、uniapp、webpack、vite、react)

    答案:JavaScript中的闭包是一种函数,它有权访问其词法环境的变量和其它函数。这意味着,即使其包含它的函数已经执行完毕,其词法环境仍然存在,因此可以访问其作用域内的变量。 答案:回调函数是在某个特定事件之后执行的函数。在JavaScript中,通常使用回调函数来处

    2024年02月06日
    浏览(40)
  • 探索前端跨组件通信:EventBus在Vue和React中的应用

    本文作者系360奇舞团前端开发工程师 事件总线(Event Bus) 是一种用于组件间通信的模式,通常用于解决组件之间的解耦和简化通信的问题。在前端框架中,如 Vue.js,事件总线是一个常见的概念。基本上,事件总线是一个能够触发和监听事件的机制,使得组件能够在不直接依

    2024年02月02日
    浏览(54)
  • Vue-Element-Admin项目学习笔记(9)表单组件封装,父子组件双向通信

    前情回顾: vue-element-admin项目学习笔记(1)安装、配置、启动项目 vue-element-admin项目学习笔记(2)main.js 文件分析 vue-element-admin项目学习笔记(3)路由分析一:静态路由 vue-element-admin项目学习笔记(4)路由分析二:动态路由及permission.js vue-element-admin项目学习笔记(5)路由分析

    2024年02月11日
    浏览(38)
  • vue3组件之间双向绑定

    Vue3中组件的双向绑定统一使用 v-model 进行处理,并且可以和多个数据进行绑定,例如 v-model:foo、v-model:bar。 v-model 等价于 :model-value=\\\"someValue\\\" 和 @update:model-value=\\\"someValue = $event\\\" v-model:foo 等价于 :foo=\\\"someValue\\\" 和 @update:foo=\\\"someValue = $event\\\" 父子组件之间双向绑定 子组件可以结合 i

    2024年02月11日
    浏览(21)
  • 前端开发,Vue的双向数据绑定的原理

    目录 一、什么是前端 二、Vue.JS框架 三、双向数据绑定 四、Vue的双向数据绑定的原理 前端通常指的是网页或应用程序中用户直接交互和感知的部分,也称为客户端。前端开发涉及使用HTML、CSS和JavaScript等技术来构建用户界面和交互功能。前端开发人员负责确保网站或应用程序

    2024年02月19日
    浏览(43)
  • Vue2:给组件绑定自定义事件

    我们在页面开发中,难免要使用事件。 在之前的学习中,我们学过 @click、@keyup、@change 等事件,这些是 Vue 自带的事件。 它一般是用在原生的HTML元素上的。在组件上使用需要加 native 修饰 比如: 这一篇说的自定义事件,可以绑定到我们自己的 Vue 组件上。 实现 子组件给父组

    2024年01月19日
    浏览(31)
  • react 组件之间的通信(父子组件)

    React中 组件内调用其他组件不需要进行 类似于vue 声明组件(components) React 组件内调用其他组件 直接将组件导入 放置在对应的JSX 代码中 父子组件通信(传统): 1、父组件-子组件  通过属性传递 2、子组件-父组件  父组件通过将自身的函数对象传递给子组件, 子组件执行父组件

    2024年02月08日
    浏览(30)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包