在使用Vue3.0时出现Extraneous non-emits event listeners (xxxXxx) were passed to component but could not be automaticall警告,完整警告信息如下:

[Vue warn]: Extraneous non-emits event listeners (addOne) were passed to component but could not be automatically inherited because component renders fragment or text root nodes. If the listener is intended to be a component custom event listener only, declare it using the "emits" option. 
  at <Counter count=1 onAddOne=fn<bound parentAddOne> > 
  at <App>

伪代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Hello World</title>
    <script src="https://unpkg.com/vue@next"></script>
</head>
<body>
<div id="root">
</div>
</body>
<script>
    const app = Vue.createApp({
        data() {
            return {
                num: 1
            }
        },
        methods: {
            parentAddOne() {
                this.num += 1;
                console.log("子组件将父组件中的num+1");
            }
        },
        template: `
          <div>
              <counter :count="num" @add-one="parentAddOne"/>
          </div>`
    });

    app.component('counter', {
        props: ['count'],
        methods: {
            addOne() {
                // 子组件内部向外触发一个addOne的事件
                this.$emit('addOne');
            }
        },
        template: `
          <button @click="addOne">按钮</button>
          <div> 子组件中的count:{{count}} </div>
        `
    })
    app.mount("#root")
</script>
</html>

出现此错误的原因是子组件counter向外触发一个addOne的事件,但是无法自动继承,因为传递事件的子组件没有根节点,他在父组件中渲染为代码片段(可以看到counter的template中有两个根节点)。
第一种解决方式(给两个根节点嵌套一个div):

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Hello World</title>
    <script src="https://unpkg.com/vue@next"></script>
</head>
<body>
<div id="root">
</div>
</body>
<script>
    const app = Vue.createApp({
        data() {
            return {
                num: 1
            }
        },
        methods: {
            parentAddOne() {
                this.num += 1;
                console.log("子组件将父组件中的num+1");
            }
        },
        template: `
          <div>
              <counter :count="num" @add-one="parentAddOne"/>
              <div> 父组件中的num:{{num}}</div>
          </div>`
    });

    app.component('counter', {
        props: ['count'],
        methods: {
            addOne() {
                this.$emit('addOne');
            }
        },
        template: `
          <!-- 在这里 -->
          <div>
              <button @click="addOne">按钮</button>
              <div> 子组件中的count:{{count}} </div>
          </div>
        `
    })
    app.mount("#root")
</script>
</html>

第二种解决方式(在emits属性中声明自定义事件):

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Hello World</title>
    <script src="https://unpkg.com/vue@next"></script>
</head>
<body>
<div id="root">
</div>
</body>
<script>
    const app = Vue.createApp({
        data() {
            return {
                num: 1
            }
        },
        methods: {
            parentAddOne() {
                this.num += 1;
                console.log("子组件将父组件中的num+1");
            }
        },
        template: `
          <div>
              <counter :count="num" @add-one="parentAddOne"/>
              <div> 父组件中的num:{{num}}</div>
          </div>`
    });

    app.component('counter', {
        props: ['count'],
        // 在这里
        emits: ['addOne'],
        methods: {
            addOne() {
                this.$emit('addOne');
            }
        },
        template: `
          <button @click="addOne">点击+1</button>
          <div> 子组件中的count:{{count}} </div>
        `
    })
    app.mount("#root")
</script>
</html>

第三种解决方式(不使用props,不建议使用,此写法可能影响到组件内很多使用父组件参数的地方):

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Hello World</title>
    <script src="https://unpkg.com/vue@next"></script>
</head>
<body>
<div id="root">
</div>
</body>
<script>
    const app = Vue.createApp({
        data() {
            return {
                num: 1
            }
        },
        methods: {
            parentAddOne() {
                this.num += 1;
                console.log("子组件将父组件中的num+1");
            }
        },
        template: `
          <div>
              <counter :count="num" @add-one="parentAddOne"/>
              <div> 父组件中的num:{{num}}</div>
          </div>`
    });

    app.component('counter', {
        methods: {
            addOne() {
                this.$emit('addOne');
            }
        },
        template: `
          <button @click="addOne">按钮</button>
          <div> 子组件中的count:{{this.$attrs.count}} </div>
        `
    })
    app.mount("#root")
</script>
</html>
Logo

基于 Vue 的企业级 UI 组件库和中后台系统解决方案,为数万开发者服务。

更多推荐