Vue.js 从零开始:emit 元件的沟通

上一篇已经学会如何把外部元件的资料传到内部元件,如果是内部传到外部,就需要透过emit来达成。

Props in, Ebent out
https://ithelp.ithome.com.tw/upload/images/20211001/20118347UjfpBRcyfE.png

emit 传递事件

emit除了可以传递资料,也可以只传递事件,来触发外部的事件:

<div id="app">
  {{ text }}:
  <button type="button" @click="add()">add</button>
  {{ num }}
  <br>
  <br>
  <out-text @button-click="add"></out-text>
</div>
const app = Vue.createApp({
  data() {
    return {
      text: "外部元件",
      num: 0,
    }
  },
  methods: {
    add() {
      this.num++;
    }
  }
});
app.component("outText",{
  template: `<button @click="click">emit add</button>`,
  data() {
    return {
      text: "内部元件"
    };
  },
  methods: {
    click() {
      this.$emit('buttonClick');
    }
  }
});
app.mount("#app");

emit起手式:

  1. 定义外层接收的函式 add()
  2. 定义内层 $emit 触发的函式
  3. 透过外层模板 @button-click="add" 来触发外层函式

@button-click="add"Props一样记法前内後外,撰写时可以按照步骤console.log,会比较顺利完成。


emit 传递参数

将内层资料传递到外层元件上使用:

<div id="app">
  <h3> {{ title }} </h3>
  {{ text }}:
  <button type="button" @click="add">add</button>
  {{ num }}
  <br>
  <br>
  <out-text @button-click="add"></out-text>
</div>
const app = Vue.createApp({
  data() {
    return {
      title: "",
      text: "外部元件",
      num: 0,
    }
  },
  methods: {
    add(addtext) {
      this.num++;
      this.title = addtext;
      //addtext 没有值传起来就会变成 事件物件 [object PointerEvent]
    }
  }
});
app.component("outText",{
  template: `<button @click="click">emit add</button>`,
  data() {
    return {
      text: "内部元件",
      insideText: "内部元件传递文字"
    };
  },
  methods: {
    click() {
      this.$emit('buttonClick', this.insideText);
    }
  }
});
app.mount("#app");

https://ithelp.ithome.com.tw/upload/images/20211001/20118347XO7vRrxNm4.png

因为要带参数所以原本$emit里要多带一个this.insideText参数,透过外层模板@button-click="add",传递到外层元件的add(addtext),最後再传回外层data渲染画面。


emits 验证

<div id="app">
  {{ text }}:{{ num }}
  <br>
  <br>
  <out-text @button-click="add"></out-text>
</div>
const app = Vue.createApp({
  data() {
    return {
      text: "外部 num",
      num: 0,
    }
  },
  methods: {
    add(num) {
      this.num = this.num + num;
    }
  }
});
app.component("outText",{
  template: `{{ text }}:<button @click="$emit('buttonClick', num)">emit add</button>`,
  data() {
    return {
      text: "内部元件",
      num: 3,
    };
  },
});
app.mount("#app");

内层元件除了使用methods的方式撰写emit,也可以直接写在template@click="$emit('buttonClick', num)"里面的'buttonClick'就是内层的@button-clicknum则是内层datanum。当我们开启开发者工具Console,会发现跳出这一段警告:
https://ithelp.ithome.com.tw/upload/images/20211002/20118347FjDKWjNgY6.png
这是因为无法正确追踪你带入的变数内层的num,就会跳出这个警告提示,这时只要加上emits:['buttonClick']就能消除警告。

emits正确用法是拿来验证事件参数传出去的值,是否符合预期的型别:

<div id="app">
  {{ text }}:{{ num }}
  <br>
  <br>
  <out-text @button-click="add"></out-text>
  <br>
  <out-text2 @button-click="add"></out-text2>
</div>
const app = Vue.createApp({
  data() {
    return {
      text: "外部 num",
      num: 0,
    }
  },
  methods: {
    add(num) {
      this.num = this.num + num;
    }
  }
});
app.component("outText",{
  template: `{{ text }}:<button @click="$emit('buttonClick', num)">emit add</button>`,
  data() {
    return {
      text: "内部元件",
      num: 3,
    };
  },
  emits: ['buttonClick']
});
app.component("outText2",{
  template: `{{ text }}:<button @click="$emit('buttonClick', '1')">test</button>`,
  data() {
    return {
      text: "emits",
      num: 3,
    };
  },
  emits: {
    buttonClick: (num) => {
      if (typeof num !== 'string') {
        console.warn('buttonClick 事件参数型别须为 String')
      }
      return typeof num === 'string'
    }
  }
});
app.mount("#app");

观察outText2里面的$emit带的参数是一个字串1,而emits要改为物件,把要观察的事件带入buttonClick: (num)(num)就是$emit('buttonClick', '1')的参数,如果参数的型别是字串的话就不会跳出警告,可以试着更改参数型别,警告提示就会显示:[Vue warn]: Invalid event arguments: event validation failed for event 'buttonClick',事件验证失败,就可以知道带出去的参数是否符合预期。

以上如有错误,欢迎指教。

/images/emoticon/emoticon41.gif


参考资料

六角学院
重新认识 Vue.js


<<:  Day 21 Spies 间谍来袭!

>>:  第 20 集:Bootstrap 客制化 Sass variable

Day28 -- Click and Drag

目标 今天要做的是,拖拉然後卷动区块 Step1 const slider = document.q...

Day-21 Child Process

Child Process tags: IT铁人 Context Switching 前面提到电脑会...

IOS、Python自学心得30天 Day-16 训练模型 Overfit(过度拟合)

前言: 前一天提到 val_accuracy 的数值约落在0.6500上下 改成只储存数值高的 ac...

[Day16] TS:在 Mapped Type 中修改物件的 property modifiers:理解 Partial、Required 和 Readonly 的实作

这是我们今天要聊的内容,老样的,如果你已经可以轻松看懂,欢迎直接左转去看同事 Kyle 的精彩文章...

apt-get upgrade 和dist-upgrade的差别

Debian/Ubuntu Linux都使用apt,升级时都是: apt-get update ap...