vue 多种方法实现组件间传值

vue

前置

大小 vue 项目都离不开组件通讯, 在这里总结一下vue组件通讯方式并列出, 下面是一些简单的例子。如有错误,欢迎指正。

温馨提示: 下文没有列出 vuex, vuex 也是重要的组件通讯方式。

props

  • 最常用的组件通讯方式
  • 值可以是数组或对象,使用对象时可以配置高级选项,如类型检测、自定义验证和设置默认值
  • 方向:父 -> 子

Son.vue

export default {

props: {

text: {

type: String,

required: true,

},

},

mounted() {

console.log(this.text) // 我是父组件提供给子组件的值

},

}

App.vue

<template>

<Son text='我是父组件提供给子组件的值'/>

</template>

<script>

import Son from './components/dispatch/Son'

export default {

name: 'app',

components: {

Son,

}

},

</script>

$refs

  • 常用的方式
  • 返回注册过 ref 特性的所有 DOM 元素和组件实例
  • 可以用来操作 DOM
  • 可以用来传值
  • 方向:子 -> 父

Son.vue

export default {

methods: {

sonFunc() {

console.log('我是子组件的值')

},

},

}

App.vue

<template>

<Son ref="sonref"/>

</template>

<script>

import Son from './components/dispatch/Son'

export default {

name: 'app',

components: {

Son,

},

mounted() {

this.$refs.sonref.sonFunc()

},

}

</script>

控制台打印: 我是子组件的值

$emit

  • $emit 用来触发当前实例上的事件

  • 方向:子 -> 父
  • 参数一:来触发的当前实例上的事件函数
  • 参数二:附加参数,传给监听器回调

Son.vue

export default {

mounted() {

this.$emit('customFunc', '我是子组件传给父组件的值')

},

}

App.vue

<template>

<Son v-on:customFunc="fatherFunc" />

</template>

<script>

import Son from './components/dispatch/Son'

export default {

name: 'app',

components: {

Son,

},

methods: {

fatherFunc(value) {

console.log(value) // 我是子组件传给父组件的值

},

},

}

</script>

@update

  • 需要配合 .sync 使用
  • 与上面的 $emit 写法类似
  • 不同之处在于$emit 的第一个参数不在是当前实例上的事件函数
  • 方向:子 -> 父

Son.vue

export default {

mounted() {

this.$emit("update:text", '我是子组件传给父组件的值')

}

}

App.vue

<template>

<Son :text.sync='text'/>

</template>

<script>

import Son from "./components/dispatch/Son"

export default {

data() {

return {

text: ''

}

},

mounted() {

console.log(this.text); // 我是子组件传给父组件的值

}

}

</script>

接下来看下面的写法,上面这种写法是对如下方式的简写, 或者称之为语法糖。可以不借助 .sync

Son.vue

export default {

mounted () {

this.$emit('update:text','我是子组件传给父组件的值')

}

}

App.vue

 <Son @update:text="v => (this.value = v)" />

import Son from "./components/dispatch/Son"

export default {

mounted() {

console.log(this.value) // 我是子组件传给父组件的值

}

}

v-model

  • v-model 常用来给 input 实现双向数据绑定

  • v-model 也可以用来传值

  • 有局限性,只能传 inputvalue

<input v-model="text">

等价于:

<input

v-bind:value="text"

v-on:input="text = $event.target.value"

>

接下来看如何通过 v-model 传值。

Son.vue

<template>

<input

v-bind:value="value"

v-on:input="$emit('input', $event.target.text)"

/>

</template>

<script>

export default {

data() {

return {

value: '我是子组件传给父组件的值',

}

}

}

</script>

App.vue

<template>

<Son v-model="text" />

</template>

<script>

import Son from './components/dispatch/Son'

export default {

name: 'app',

components: {

Son,

}

}

</script>

$parent $childred

  • $parent: 父实例,如果当前实例有的话
  • $children: 当前实例的直接子组件
  • $parent $childred 通过封装可以实现不同方向的传值

$children 并不保证顺序,也不是响应式的。可以使用一个数组配合 v-for 来生成子组件,使用 Array 作为真正的来源。

App.vue

export default {

data() {

return {

value: '我是父组件的值',

}

},

Son.vue

export default {

mounted: {

console.log(this.$parent.value) // 我是父组件的值

this.$parent.value = 666

console.log(this.$parent.value) // 666

},

}

简单封装一下即可实现$parent 配合 $emit 实现跨级向上传值。

main.js

Vue.prototype.$dispatch = function(event, value) {

let parent = this.$parent

while (parent) {

parent.$emit(event, value)

parent = parent.$parent

}

}

这样使用: this.$dispatch('event',value)

简单封装一下即可实现$children 配合 $emit 实现向下传值。

Vue.prototype.$broadcast = function(event, value) {

const broadcast = children => {

children.forEach(child => {

child.$emit(event, value)

if (child.$children) {

broadcast(child.$children)

}

})

}

broadcast(this.$children)

}

这样使用: this.$broadcast('event',value)

$attrs

  • 获取父组件通过 v-bind 传过去的所有值
  • class 和 style 除外
  • 可以通过 v-bind="$attrs" 传入内部组件
  • 只能在 <template> 中使用
  • 方向:父 -> 子

App.vue

<template>

<Son :value1="123" :value2="456" />

</template>

import Son from './components/dispatch/Son'

export default {

name: 'app',

components: {

Son,

},

}

Son.vue

<template>

<div>{{$attrs}}</div>

</template>

<script>

export default {

inheritAttrs: false,

}

</script>

$listener

  • 获取父作用域中的 () v-on 事件监听器。
  • 不含 .native 修饰器修饰的时间监听器。
  • 可以通过 v-on="$listeners" 传入内部组件(孙子组件)。
  • 方向:父 -> 子

App.vue

<template>

<Son @customFunc="fatherFunc"/>

</template>

<script>

import Son from './components/dispatch/Son'

export default {

name: 'app',

components: {

Son,

},

methods: {

fatherFunc() {

console.log('666')

},

},

}

</script>

Son.vue

<template>

<button @click="$listeners.customFunc()">看</button>

</template>

provide inject

  • provideinject 不推荐直接用于应用程序代码中

  • 与 React 的上下文特性很相似。这对选项需要一起使用,以允许一个祖先组件向其所有子孙后代注入一个依赖,不论组件层次有多深,并在起上下游关系成立的时间里始终生效
  • provide 选项应该是一个对象或返回一个对象的函数。该对象包含可注入其子孙的属性。在该对象中你可以使用 ES2015 Symbols 作为 key,但是只在原生支持 Symbol 和 Reflect.ownKeys 的环境下可工作

  • provideinject 绑定并不是可响应的。这是 vue 刻意为之

  • 如果你传入了一个可监听的对象,那么其对象的属性还是可响应的

这里有一个简单的示例:

App.vue

<template>

<Son />

</template>

<script>

import Son from './components/dispatch/Son'

export default {

name: 'app',

components: {

Son,

},

provide() {

return {

text: '我是父组件的值',

}

},

}

</script>

Son.vue

export default {

inject: ['text'],

mounted() {

console.log(this.text) // 我是父组件的值

},

}

事件总线

  • EventBus 又称为事件总线
  • 不是一个具体的 API,EventBus 代表一种思路
  • 可以看作 vuex 的究极压缩版

App.vue

<template>

<div>

<Son />

</div>

</template>

<script>

import Son from './components/dispatch/Son'

export default {

name: 'app',

components: {

Son,

},

mounted() {

this.$EventBus.$emit('event', 'app.vue')

},

}

</script>

Son.vue

export default {

mounted() {

this.$EventBus.$on('event', function(v) {

console.log(v)

})

},

}

Observable

  • observable 可以让一个对象可响应

  • vue 内部会用它来处理 data 函数返回的对象
  • 返回的对象可以直接用于渲染函数和计算属性内,并且会在发生改变时触发相应的更新
  • 可以作为最小化的跨组件状态存储器,用于简单的场景

store.js

import Vue from 'vue'

export const store = Vue.observable({ text: '我是store里的' })

export const mutations = {

setText(text) {

store.text = text

},

}

App.vue

import { store, mutations } from '../store'

export default {

mounted() {

console.log(store.text) //我是store里的

mutations.setText('我在App.vue中将你改变')

console.log(store.text) //我在App.vue将你改变

},

}

composition-api

  • composition-api 包含 vue3 的新特性

  • provideinject 可以实现嵌套组件之间的数据传递

  • 这两个函数只能在 setup 函数中使用
  • 父级组件中使用 provide 函数向下传递数据
  • 子级组件中使用 inject 获取上层传递过来的数据
  • 不限层级。

App.vue

<template>

<provideAndInject />

</template>

<script>

import { provide } from "@vue/composition-api"

import provideAndInject from "./components/provideAndInject"

export default {

name: "app",

components: {

provideAndInject

},

setup() {

// provide('数据名称', 要传递的数据)

provide("customVal", "我是父组件向子组件传递的值");

}

};

</script>

Son.vue

<template>

<h3>{{ customVal }}</h3>

</template>

<script>

import { inject } from "@vue/composition-api";

export default {

setup() {

//调用 inject 函数,通过指定的数据名称,获取到父级共享的数据

const customVal = inject("customVal");

return {

customVal

};

}

};

</script>

父组件可以通过 ref 创建响应式数据通过 provide 共享给子组件。

以上是 vue 多种方法实现组件间传值 的全部内容, 来源链接: utcz.com/z/380254.html

回到顶部