组件之间通信 - (Communicate Between Components) #16

Open
Tancy opened this Issue Jun 16, 2016 · 29 comments

Projects

None yet
@Tancy
Tancy commented Jun 16, 2016

子-父 通信

子组件可以使用this.$dispatch([String type], [Object detail]) 方法传递消息给父组件。
第一个参数定义消息类型,第二个参数为消息对象。如果父组件中的任何子组件使用$on([String type], [Function callback])注册监听事件,则回调执行第一个参数,参数中的 detail属性是消息数据。

案例:

<we-element name="foo">
  <template>
    <div>
      <image src="{{imageUrl}}" onclick="test"></image>
      <text>{{title}}</text>
    </div>
  </template>
  <script>
    module.exports = {
      data: {
        title: '',
        imageUrl: ''
      },
      methods: {
        test: function () {
          this.$dispatch('notify', {a: 1})
        }
      }
    }
  </script>
</we-element>

<template>
  <foo title="..." image-url="..."></foo>
</template>

<script>
  module.exports = {
    created: function () {
      this.$on('notify', function(e) {
        //  when <foo> image tag  be clicked ,the function will be executing.
        // e.detail is  `{a: 1}`
      })
    }
  }
</script>

父 - 子 通信

父组件可以使用 this.$([String id]) 来获取子组件的上下文。你可以使用上下文对象访问子组件的信息。

<we-element name="foo">
  <template>
    <div>
      <image src="{{imageUrl}}"></image>
      <text>{{title}}</text>
    </div>
  </template>
  <script>
    module.exports = {
      data: {
        title: '',
        imageUrl: ''
      },
      methods: {
        setTitle: function (t) {
          this.title = t
        }
      }
    }
  </script>
</we-element>

<template>
  <div>
    <text onclick="test">click to update foo</text>
    <foo id="fooEl" title="..." image-url="..."></foo>
  </div>
</template>

<script>
  module.exports = {
    methods: {
      test: function (e) {
        var foo = this.$('fooEl')
        foo.setTitle('...')
        foo.imageUrl = '...'
      }
    }
  }
</script>

父 - 子(多子)通信

父组件可以使用this.$broadcast([String type], [Object detail]) 广播消息给所有子组件。

案例:

<we-element name="bar">
  <template>
    <div>
      <image src="{{imageUrl}}"></image>
    </div>
  </template>
  <script>
    module.exports = {
      data: {
        imageUrl: ''
      },
      created: function() {
        var self = this
        this.$on('changeImage', function(e) {
          self.imageUrl = e.detail.imageUrl
        })
      }
    }
  </script>
</we-element>

<we-element name="foo">
  <template>
    <div>
      <bar></bar>
      <text>{{title}}</text>
    </div>
  </template>
  <script>
    module.exports = {
      data: {
        title: ''
      },
      created: function() {
        var self = this
        this.$on('changeTitle', function(e) {
          self.title = e.detail.title
        })
      }
    }
  </script>
</we-element>

<template>
  <div>
    <text onclick="test">click to update foo</text>
    <foo></foo>
    <foo></foo>
  </div>
</template>

<script>
  module.exports = {
    methods: {
      test: function (e) {
        this.$broadcast('changeTitle', {
          title: '...'
        })
        this.$broadcast('changeImage', {
          imageUrl: '...'
        })
      }
    }
  }
</script>

兄弟间通信

兄弟组件间通过公共的父组件作为桥梁来传递消息。

案例:

<we-element name="foo">
  <template>...</template>
  <script>
    module.exports = {
      methods: {
        callbar: function () {
          this.$dispatch('callbar', {a: 1})
        }
      }
    }
  </script>
</we-element>

<we-element name="bar">
  <template>...</template>
  <script>
    module.exports = {
      created: function() {
        this.$on('callbar', function(e) {
          // e.detail.a
        })
      }
    }
  </script>
</we-element>

<template>
  <div>
    <foo></foo>
    <bar></bar>
  </div>
</template>

<script>
  module.exports = {
    created: function () {
      var self = this
      this.$on('callbar', function(e) {
        self.$broadcast('callbar', e.detail)
      })
    }
  }
</script>

最后,你将学习怎么给Weex页面写 配置 & 数据

@emptywalker

<we-element name="foo">这个标签是什么意思

@sandy53
sandy53 commented Aug 12, 2016

@emptywalker
这个标签应该是自定组件的意思,可以看下组件封装这个文档
#2

@mrKylinZhou

自定义组件显示不出来啊 组建封装的例子和这节课的例子都好蒙啊
新东西 希望能解释一下

@ruohuan
ruohuan commented Aug 23, 2016

“如果父组件中的任何子组件使用……”,应该是“在子组件的父组件中通过$on([String type], [Function callback])注册事件监听……”吧

@ruohuan
ruohuan commented Aug 23, 2016

@emptywalker <we-element name="foo">XXX</we-element>的意思是中间的XXX这部分是foo组件代码,因为把子组件都写在一个.we文件里面了,如果不这么设置,文件里如果有多个组件,就会出现同级多个template,多个style和多个script

如果foo组件的代码放在单独的foo.we文件里面,就不需要写 <we-element name="foo">XXX</we-element>,直接写<template>...</template><style>...</style><script>...</script>即可

应该是这么理解的,哈哈

@zhouyuexie

我把子组件写到单独的.we文件里,为何无法和父组件通信?

而且自带的wx-tabbar组件不支持子组件,难道需要自己实现?或者有其他的方法?

@AlenGao
AlenGao commented Oct 8, 2016

@sandy53 你觉得你给的答案 是人家想要的吗

@AlenGao
AlenGao commented Oct 8, 2016

@ruohuan 你这样理解的你自己试过吗

@AlenGao
AlenGao commented Oct 9, 2016

兄弟组建之间的通信,父组建的js代码:
module.exports = {
created: function () {
var self = this
this.$on('callbar', function(e) {
self.$broadcast('callbar', e.detail)
})
}
}
这段代码貌似有问题,广播后父组建也能监听到会陷入死循环造成越界错误
events.js:39 Uncaught RangeError: Maximum call stack size exceeded
所以感觉$broadcast第一个参数不能和父组建监听的消息类型一样。

@codercuixin
codercuixin commented Oct 12, 2016 edited

@Tancy

<!-- foo.we -->
<template>
  <container style="flex-direction: row;">
    <image class='image' src="{{image}}"></image>
    <text>{{title}}</text>
  </container>
</template>
<style>
  .image{width:100;height: 100}
</style>
<script>
  module.exports = {
    data: {
      title: null,
      image: null
    },
     methods: {
        setTitle:function(t){
          this.title=t;
        }
      }
  }
</script>


<!--main.we-->
<template>
  <div>
    <foo  id='fooId' title="Foo" image="http://t.cn/RGE3uo9"></foo>
    <text onclick='updateFoo'>Click to update Foo</text>
  </div>
</template>
<script>
  module.exports = {
   updateFoo:function(){
      var foo=this.$('fooId');
      foo.setTitle('我变了');
   }
  }
</script>

但是点击图片之后,控制台会出现TypeError: fn is undefine
不知道什么原因呢。谢谢了麻烦帮忙看下

@colys
colys commented Oct 17, 2016

Tab里面怎么不能用父子通信?

@codercuixin
codercuixin commented Oct 23, 2016 edited

有些涉及图片的代码,建议个人使用的时候加上<image style="width:200;height:200" src="{{imageUrl}}"></image> ,图片的width,heght都是图片的基本属性,不加图片会显示不出来。这些都是基础 的,作者就没写可能。

@codercuixin
codercuixin commented Oct 23, 2016 edited

@Tancy @emptywalker @sandy53 @mrKylinZhou @ruohuan
兄弟间通信.参数传递问题

为了不进入死循环(即main.we里既广播事件又监听事件),更改了名称,使得foo控件可以发布事件;在main.we使用on监听该事件,收到该事件再发出广播,然后再bar.we对该事件进行监听,然而参数传递还是有问题。。。。
使用上面的参数传递方式也有问题,自己改了一下。然而控制台输出
Object { a=1}
undefined ;
请问如何解决,谢谢了。
代码如下:

<!-- foo.we -->
<template>
<text onclick="callbar">foo dispatch event to call bar</text>
</template>
<script>
  module.exports = {
    methods: {
      callbar: function () {
        this.$dispatch('callbar1', {a: 1});
      }
    }
  }
</script>


<!-- bar.we -->
 <template>
    <text>{{textContent}}</text>
 </template>
<script>
module.exports = {
  created: function() {
    this.$on('callbar2', function(e) {
      // e.detail.a
      console.log(e.detail);
      this.textContent=e.detail;
    })
  }
}
</script>

<!--main.we -->
<template>
  <div>
    <foo></foo>
    <bar></bar>
  </div>
</template>

<script>
  module.exports = {
    created: function () {
      var self = this;
      this.$on('callbar1', function(e) {
        self.$broadcast('callbar2', e.detail);
        console.log(e.datail);
      });
    }
  }
</script>
@wang111588

最后的链接404,目前是这个:#9

@wang111588
wang111588 commented Oct 25, 2016 edited

@codercuixin
这行可以这样写,我这测试通过
self.$broadcast('callbar2', e.detail);
self.$broadcast('callbar2', e.detail.a);
你是前端开发还是native?

@wzj583585700

we-element name="foo" 这是干吗用的

@ltt1987
ltt1987 commented Nov 9, 2016 edited

<we-element name="item"> <template> <div> <text>some text</text> </div> </template> </we-element> <template> <div> <item></item> </div> </template>
以上示例页面没有任何输出

@zhangdefu3

@codercuixin 我也碰到了和你同样的问题,兄弟间通讯有问题。
我就按示例代码运行的;浏览器中,js报错: “events.js:39 Uncaught RangeError: Maximum call stack size exceeded”.

@Jam1zhu
Jam1zhu commented Nov 22, 2016

@codercuixin 求助
default
在父级调用子件的方法,提醒undefined,是哪里写错了吗?

@wzj583585700

跳转页面怎么传递参数啊

@nuptboyzhb
nuptboyzhb commented Nov 22, 2016 edited

兄弟间通信,举例的代码有问题:


this.$on('callbar', function(e) {
        self.$broadcast('callbar', e.detail)
      })

这一块,如果两个兄弟和父组件都使用‘callbar’,会造成broadcast的消息会被自己接收到,造成死循环;栈溢出。

** Uncaught RangeError: Maximum call stack size exceeded(…) **

把文档的举例代码改成如下即可:


<we-element name="foo">
  <template>...</template>
  <script>
    module.exports = {
      methods: {
        callbar: function () {
          this.$dispatch('callbar', {a: 1})
        }
      }
    }
  </script>
</we-element>

<we-element name="bar">
  <template>...</template>
  <script>
    module.exports = {
      created: function() {
        this.$on('callbar2', function(e) {
          // e.detail.a
        })
      }
    }
  </script>
</we-element>

<template>
  <div>
    <foo></foo>
    <bar></bar>
  </div>
</template>

<script>
  module.exports = {
    created: function () {
      var self = this
      this.$on('callbar', function(e) {
        self.$broadcast('callbar2', e.detail)
      })
    }
  }
</script>
@DoranYun
DoranYun commented Dec 9, 2016

@emptywalker
在同一个文件里定义两个组件用的,现在可以直接使用 element

@yimingtang

Typo:

同理,首先子组件要监听特定类型的自定义事件,而父组件可以使用 this.$vm(id) 找到父组件,然后再调用 this.$vm(id).$emit(type, detail) 方法,即可实现自上而下的通信。例如:

『而父组件可以使用 this.$vm(id) 找到父组件』应当是找到『子组件』

@DoranYun

感谢反馈,我在文档里更新一下

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment