• 彻底理解Vue组件间7种方式通信


    一、父子组件通信:

    1.1、传递静态或动态的 Prop

    单向数据流

    所有的 prop 都使得其父子 prop 之间形成了一个单向下行绑定:父级 prop 的更新会向下流动到子组件中,但是反过来则不行。这样会防止从子组件意外变更父级组件的状态,从而导致你的应用的数据流向难以理解。

    这样,你已经知道了可以像这样给 prop 传入一个静态的值:

    <blog-post title="My journey with Vue"></blog-post>

    你也知道 prop 可以通过 v-bind 或简写 : 动态赋值,例如:

    <!-- 动态赋予一个变量的值 -->
    <blog-post :title="post.title"></blog-post>
    
    <!-- 动态赋予一个复杂表达式的值 -->
    <blog-post :title="post.title + ' by ' + post.author.name"></blog-post>

    举例子:

    父页面:

     子页面:

    展示:

    1.2、子父组件emit通信

    子页面

     <button v-on:click="giveAdvice">Click me for advice </button>
     data() {
        return {
           possibleAdvice: ['Yes', 'No', 'Maybe']
        };
      },
    methods:{
         giveAdvice: function () {
          console.log('子页面', this.possibleAdvice )
          var randomAdviceIndex = Math.floor(Math.random() * this.possibleAdvice.length)
          console.log('子页面randomAdviceIndex---', randomAdviceIndex)
    // 名字give-advice和父元素保持一致
    this.$emit('give-advice', this.possibleAdvice[randomAdviceIndex]) } },

    父页面

    // 名字give-advice和子页面$emit名字保持一致
    <a-blog v-on:give-advice="showAdvice" :title="post.title + ' by ' + post.author.name" :post="post"/>
    methods: {
        showAdvice: function (advice) {
          console.log('-父页面-advice---', advice)
        }
       
      }

    结果:

    1.3、provide / inject

    详细:

    这对选项需要一起使用,以允许一个祖先组件向其所有子孙后代注入一个依赖,不论组件层次有多深,并在其上下游关系成立的时间里始终生效。如果你熟悉 React,这与 React 的上下文特性很相似。

    provide 选项应该是一个对象或返回一个对象的函数。该对象包含可注入其子孙的 property。在该对象中你可以使用 ES2015 Symbols 作为 key,但是只在原生支持 Symbol 和 Reflect.ownKeys 的环境下可工作。

    inject 选项应该是:

    一个字符串数组,或
    一个对象,对象的 key 是本地的绑定名,value 是:
    在可用的注入内容中搜索用的 key (字符串或 Symbol),或
    一个对象,该对象的:
    from property 是在可用的注入内容中搜索用的 key (字符串或 Symbol)
    default property 是降级情况下使用的 value

    父页面APP.vue

    import ABlog from './components/demo/a-blog.vue'
    name: 'App',
    provide: {
        foo: 'I from parents bar'
     },
    
     components: {
       ABlog
    },

    子页面a-blog.vue

    <b-blog  />
    import BBlog from './b-blog.vue'
    
    .....
    name: 'App',
    
    components: {
        BBlog 
     },

    孙子页面:b-blog.vue

    <div class='b-blog'>
          <p>孙子页面:{{foo}}</p>
      </div>
    .....
    name: 'b-blog',
    inject: ['foo'],
    created() {
            console.log('孙子页面inject---', this.foo) // => "bar"
    },


    Vue.observable( object )

    让一个对象可响应。Vue 内部会用它来处理 data 函数返回的对象。

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

    父页面:

    <button @click="() => changeColor()">改变color</button>
    import ABlog from './components/demo/a-blog.vue'
    name: 'App',
     provide() { // 方法二:使用2.6最新API Vue.observable 优化响应式 provide
        this.theme = Vue.observable({
          color: "blue"
        });
        return {
          theme: this.theme
        };
      },
    .....
    methods: {
      
        changeColor(color) {
          if (color) {
            this.theme.color = color;
          } else {
            this.theme.color = this.theme.color === "blue" ? "red" : "blue";
          }
        }
    
       
      }

    儿子页面

    <b-blog  />
    ...
    import BBlog from './b-blog.vue'
    ...
    components: {
        BBlog 
     },

    孙子页面

    <p :style="{ color: theme.color }">孙子页面b-blog 组件</p>
    ...
    inject: {
            theme: {
                //函数式组件取值不一样
                default: () => ({})
            }
    },

    1.4、$parent / $children与 ref

            $parent / $children

    父页面:

    <button @click="changeVal">点击改变子组件的值</button>
    ....
    data() {
        return {
            msg: 'hello, I from parents page!'
        };
      },
    ....
    methods: {
        changeVal(){
          console.log('父页面----', this.$children[0])
          this.$children[0].message = "hello, "
        }
    }

    子页面:

    <span>改变自组建的的值::{{message}}</span>
    <p>子页面this.$parent.msg获取父组件的值:{{parentVal}}</p>
    ....
    data() {
        return {
          possibleAdvice: ['Yes', 'No', 'Maybe'],
          message:'songxiaotao**'
        };
     },
    ....
    components: {
        BBlog 
      },
      computed: {
        parentVal(){
          return this.$parent.msg;
        }
      },
    ...

    点击按钮前

    点击按钮后

          ref的用法

    父页面:

     <a-blog ref="refDom"  v-on:give-advice="showAdvice" :title="post.title + ' by ' + post.author.name"  :post="post"/>
        
    mounted () {
        const refDom = this.$refs.refDom // 打印子页面的refDom的数据和方法
        console.log('mounted---refDom ---', refDom, refDom.message, refDom.possibleAdvice)
        refDom.refFn()// 
        refDom.giveAdvice()// 
      },

    子页面

    1.5、$emit/$on

    假如一个页面AB兄弟组件通信, 可以用此方法 

    var EVENT=new Vue();
    vue.prototype = EVENT
    this.EVENT.$emit(事件名,数据);
    this.EVENT.$on(事件名,data => {});
    this.EVENT.$on('test', function (msg) {
      console.log(msg)
    })
    this.EVENT.$emit('test', 'hi')
    // => "hi"

    1.6、attrs/$listeners

    2.4.0 新增

    • 类型:{ [key: string]: string }

    • 只读

    • 详细:

      包含了父作用域中不作为 prop 被识别 (且获取) 的 attribute 绑定 (class 和 style 除外)。当一个组件没有声明任何 prop 时,这里会包含所有父作用域的绑定 (class 和 style 除外),并且可以通过 v-bind="$attrs" 传入内部组件——在创建高级别的组件时非常有用。

    • vm.$listeners

      2.4.0 新增

      • 类型:{ [key: string]: Function | Array<Function> }

      • 只读

      • 详细:

        包含了父作用域中的 (不含 .native 修饰器的) v-on 事件监听器。它可以通过 v-on="$listeners" 传入内部组件——在创建更高层次的组件时非常有用。

    多级组件嵌套需要传递数据时,通常使用的方法是通过vuex。如果仅仅是传递数据,而不做中间处理,使用 vuex 处理,这就有点大材小用了。所以就有了 $attrs / $listeners ,通常配合 inheritAttrs 一起使用。

    inheritAttrs:默认值为 true。

    默认情况下父作用域的不被认作 props 的 attribute 绑定 (attribute bindings) 将会“回退”且作为普通的 HTML attribute 应用在子组件的根元素上。当撰写包裹一个目标元素或另一个组件的组件时,这可能不会总是符合预期行为。通过设置 inheritAttrs 到 false,这些默认行为将会被去掉。而通过 (同样是 2.4 新增的) 实例 property $attrs 可以让这些 attribute 生效,且可以通过 v-bind 显性的绑定到非根元素上。查 看 官 网

    感觉还是挺晦涩难懂的,简单的说就是 inheritAttrs:true 继承除props之外的所有属性;inheritAttrs:false 只继承class属性

    $attrs:包含了父作用域中不被认为 (且不预期为) props 的特性绑定 (class 和 style 除外),并且可以通过 v-bind=”$attrs” 传入内部组件。当一个组件没有声明任何 props 时,它包含所有父作用域的绑定 (class 和 style 除外)。

    $listeners:包含了父作用域中的 (不含 .native 修饰符) v-on 事件监听器。它可以通过 v-on=”$listeners” 传入内部组件。它是一个对象,里面包含了作用在这个组件上的所有事件监听器,相当于子组件继承了父组件的事件。

    来看看例子加深一下印象

    父组件:

    <template>
      <div id="app">
       <a-blog :width="width" :height="height" :book="book" :fruit="fruit"  @updateFn="handleUpdate" @deleteFn="handleDelete"/>
        
      </div>
    </template>
    data() {
        return {
           300,
          height: 200,
          book: 'java',
          fruit: 'banana',
          weight: '70kg'
    
        };
      },
    ...
    components: {
      ABlog
    },
    ...
    methods: {
        handleUpdate(val){
          console.log('父组件已经接收到--update info', val);
        },
        handleDelete(){
          console.log('delete info');
        }
    }
    ...

    儿子页面:a-blog.vue

    <p> 儿子页面: attrs--      {{ $attrs }} --- {{ $listeners }}</p>
        <b-blog @addInfo="addInfo" v-bind="$attrs"  v-on="$listeners"/>
    ...
    import BBlog from './b-blog.vue'
    props: {
        height:[String, Number],
    },
    components: {
        BBlog 
    },
    ...
    created () {
        console.log('儿子页面-this.$attrs', this.$attrs); 
        console.log('儿子页面-this.$listeners', this.$listeners); // updateInfo: f, delInfo: f
      },
    ...
    methods:{
       addInfo(){
          console.log('---addInfo----')
        }
      },
      
    }

    孙子页面:b-blog

    <template>
       <div class='b-blog'>
          <!-- <p>孙子页面:{{foo}}</p> -->
          <!-- <p :style="{ color: theme.color }">孙子页面b-blog 组件</p> -->
          <p> 孙子页面--- attrs--      {{ $attrs }} --- {{ $listeners }}</p>
       </div>
       
    </template>
    ....
     props: {
           book:[String, Number]
        },
    ...
     created() {
            // console.log('孙子页面inject---', this.theme) // => "bar"
            console.log('孙子页面-this.$attrs', this.$attrs); 
            console.log('孙子页面-this.$listeners', this.$listeners);
            this.$emit('updateFn', {a:'孙子传过来的的值'})
      },

    1.7、vuex 

    -----------------陆续更新中-----

  • 相关阅读:
    Java的Socket通信----通过 Socket 实现 TCP 编程之多线程demo(2)
    MySQL 数据备份与还原
    java实现时钟方法汇总
    java实现二叉树demo
    java实现心型、99乘法demo
    显示本月日历demo
    打开图片并显示在面板上demo
    ArraySort--冒泡排序、选择排序、插入排序工具类demo
    类的实例化顺序
    StringsUtil字符串工具类---灵活截取
  • 原文地址:https://www.cnblogs.com/pikachuworld/p/15252070.html
Copyright © 2020-2023  润新知