• 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 也可以用来传值
    • 有局限性,只能传 input value
    <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 共享给子组件。

  • 相关阅读:
    8.26 树状数组
    8.27 神异之旅
    8.26 雇佣
    8.28 Jack与Rose
    8.28 ISN
    保存和加载网络
    快速搭建网络
    分类网络
    torch中的回归
    pytorch中的Variable
  • 原文地址:https://www.cnblogs.com/guangzan/p/12638228.html
Copyright © 2020-2023  润新知